summaryrefslogtreecommitdiff
path: root/src/SimpleRandomizer.cc
diff options
context:
space:
mode:
authorNils Maier <maierman@web.de>2014-12-30 18:17:44 +0100
committerNils Maier <maierman@web.de>2015-01-20 22:37:24 +0100
commit81bdd5f61a8f8da53e22d68190be700902b7dbae (patch)
treef706934a5e5e208d8d09490d216fe03f10b38654 /src/SimpleRandomizer.cc
parent747131a06c1f1d92a5312a103f4446fabedb6cf7 (diff)
Revise getRandom facilities
Use one of the following to provide random bytes: - Windows CryptGenRandom - Linux getrandom (syscall interface to urandom, without nasty corner cases such as file descriptor exhaustion or re-linked /dev/urandom) - std::device_random (C++ random device, which usually will be urandom) This also equalizes util::getRandom and SimpleRandomizer (the former will now use the latter) instead of having essentially two different PRNG interfaces with potentially different quality. Closes GH-320
Diffstat (limited to 'src/SimpleRandomizer.cc')
-rw-r--r--src/SimpleRandomizer.cc78
1 files changed, 28 insertions, 50 deletions
diff --git a/src/SimpleRandomizer.cc b/src/SimpleRandomizer.cc
index 713a5b5e..746491f1 100644
--- a/src/SimpleRandomizer.cc
+++ b/src/SimpleRandomizer.cc
@@ -43,6 +43,10 @@
#include "a2time.h"
#include "a2functional.h"
+#ifdef HAVE_GETRANDOM_INTERFACE
+# include "getrandom_linux.h"
+#endif
+
namespace aria2 {
std::unique_ptr<SimpleRandomizer> SimpleRandomizer::randomizer_;
@@ -55,75 +59,49 @@ const std::unique_ptr<SimpleRandomizer>& SimpleRandomizer::getInstance()
return randomizer_;
}
-void SimpleRandomizer::init()
-{
-#ifndef __MINGW32__
- // Just in case std::random_device() is fixed, add time and pid too.
- eng_.seed(std::random_device()()^time(nullptr)^getpid());
-#endif // !__MINGW32__
-}
-
SimpleRandomizer::SimpleRandomizer()
{
#ifdef __MINGW32__
- BOOL r = CryptAcquireContext(&cryProvider_, 0, 0, PROV_RSA_FULL,
- CRYPT_VERIFYCONTEXT|CRYPT_SILENT);
+ BOOL r = ::CryptAcquireContext(
+ &provider_,
+ 0, 0, PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT | CRYPT_SILENT);
assert(r);
-#endif // __MINGW32__
+#endif
}
SimpleRandomizer::~SimpleRandomizer()
{
#ifdef __MINGW32__
- CryptReleaseContext(cryProvider_, 0);
-#endif // __MINGW32__
+ CryptReleaseContext(provider_, 0);
+#endif
}
long int SimpleRandomizer::getRandomNumber(long int to)
{
assert(to > 0);
-#ifdef __MINGW32__
- int32_t val;
- BOOL r = CryptGenRandom(cryProvider_, sizeof(val),
- reinterpret_cast<BYTE*>(&val));
- assert(r);
- if(val == INT32_MIN) {
- val = INT32_MAX;
- } else if(val < 0) {
- val = -val;
- }
- return val % to;
-#else // !__MINGW32__
- return std::uniform_int_distribution<long int>(0, to - 1)(eng_);
-#endif // !__MINGW32__
-}
-
-long int SimpleRandomizer::operator()(long int to)
-{
- return getRandomNumber(to);
+ return std::uniform_int_distribution<long int>(0, to - 1)(*this);
}
-void SimpleRandomizer::getRandomBytes(unsigned char *buf, size_t len)
+void SimpleRandomizer::getRandomBytes(unsigned char* buf, size_t len)
{
#ifdef __MINGW32__
- if (!CryptGenRandom(cryProvider_, len, (PBYTE)buf)) {
- throw std::bad_alloc();
- }
-#else
- uint32_t val;
- size_t q = len / sizeof(val);
- size_t r = len % sizeof(val);
- auto gen = std::bind(std::uniform_int_distribution<uint32_t>
- (0, std::numeric_limits<uint32_t>::max()),
- eng_);
- for(; q > 0; --q) {
- val = gen();
- memcpy(buf, &val, sizeof(val));
- buf += sizeof(val);
+ BOOL r = CryptGenRandom(provider_, len, reinterpret_cast<BYTE*>(buf));
+ assert(r);
+#elif defined(HAVE_GETRANDOM_INTERFACE)
+ auto rv = getrandom_linux(buf, len);
+ assert(rv >= 0 && (size_t)rv == len);
+#else // ! __MINGW32__
+ auto ubuf = reinterpret_cast<result_type*>(buf);
+ size_t q = len / sizeof(result_type);
+ auto gen = std::uniform_int_distribution<result_type>();
+ for(; q > 0; --q, ++ubuf) {
+ *ubuf = gen(dev_);
}
- val = gen();
- memcpy(buf, &val, r);
-#endif
+ const size_t r = len % sizeof(result_type);
+ auto last = gen(dev_);
+ memcpy(ubuf, &last, r);
+#endif // ! __MINGW32__
}
} // namespace aria2