/* */ #include "SimpleRandomizer.h" #include #include #include #include #include #include #ifdef __APPLE__ # include #endif // __APPLE__ #ifdef HAVE_LIBGNUTLS # include #endif // HAVE_LIBGNUTLS #ifdef HAVE_OPENSSL # include #endif // HAVE_OPENSSL #include "a2time.h" #include "a2functional.h" #include "LogFactory.h" #include "fmt.h" namespace aria2 { std::unique_ptr SimpleRandomizer::randomizer_; const std::unique_ptr& SimpleRandomizer::getInstance() { if (!randomizer_) { randomizer_.reset(new SimpleRandomizer()); } return randomizer_; } namespace { std::random_device rd; } // namespace #ifdef __MINGW32__ SimpleRandomizer::SimpleRandomizer() { BOOL r = ::CryptAcquireContext(&provider_, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT); assert(r); } #else // !__MINGW32__ SimpleRandomizer::SimpleRandomizer() : gen_(rd()) {} #endif // !__MINGW32__ SimpleRandomizer::~SimpleRandomizer() { #ifdef __MINGW32__ CryptReleaseContext(provider_, 0); #endif } long int SimpleRandomizer::getRandomNumber(long int to) { assert(to > 0); return std::uniform_int_distribution(0, to - 1)(*this); } void SimpleRandomizer::getRandomBytes(unsigned char* buf, size_t len) { #ifdef __MINGW32__ BOOL r = CryptGenRandom(provider_, len, reinterpret_cast(buf)); if (!r) { assert(r); abort(); } #elif defined(__APPLE__) auto rv = SecRandomCopyBytes(kSecRandomDefault, len, buf); assert(errSecSuccess == rv); #elif defined(HAVE_LIBGNUTLS) auto rv = gnutls_rnd(GNUTLS_RND_RANDOM, buf, len); if (rv != 0) { assert(0 == rv); abort(); } #elif defined(HAVE_OPENSSL) auto rv = RAND_bytes(buf, len); if (rv != 1) { assert(1 == rv); abort(); } #else constexpr static size_t blocklen = 256; auto iter = len / blocklen; auto p = buf; for (size_t i = 0; i < iter; ++i) { auto rv = getentropy(p, blocklen); if (rv != 0) { std::cerr << "getentropy: " << strerror(errno) << std::endl; assert(0); abort(); } p += blocklen; } auto rem = len - iter * blocklen; if (rem == 0) { return; } auto rv = getentropy(p, rem); if (rv != 0) { std::cerr << "getentropy: " << strerror(errno) << std::endl; assert(0); abort(); } #endif // !__MINGW32__ && !__APPLE__ && !HAVE_OPENSSL && !HAVE_LIBGNUTLS } } // namespace aria2