diff options
Diffstat (limited to 'libqpdf/QUtil.cc')
-rw-r--r-- | libqpdf/QUtil.cc | 95 |
1 files changed, 85 insertions, 10 deletions
diff --git a/libqpdf/QUtil.cc b/libqpdf/QUtil.cc index 84ff004b..de3099d2 100644 --- a/libqpdf/QUtil.cc +++ b/libqpdf/QUtil.cc @@ -17,6 +17,7 @@ #include <Windows.h> #include <direct.h> #include <io.h> +#include <Wincrypt.h> #else #include <unistd.h> #endif @@ -377,6 +378,8 @@ QUtil::toUTF8(unsigned long uval) return result; } +#ifdef USE_INSECURE_RANDOM + long QUtil::random() { @@ -390,28 +393,100 @@ QUtil::random() seeded_random = true; } -#ifdef HAVE_RANDOM +# ifdef HAVE_RANDOM return ::random(); -#else +# else return rand(); -#endif +# endif } void -QUtil::srandom(unsigned int seed) +QUtil::initializeWithRandomBytes(unsigned char* data, size_t len) { -#ifdef HAVE_RANDOM - ::srandom(seed); + for (size_t i = 0; i < len; ++i) + { + data[i] = static_cast<unsigned char>((QUtil::random() & 0xff0) >> 4); + } +} + #else - srand(seed); -#endif + +long +QUtil::random() +{ + long result = 0L; + initializeWithRandomBytes( + reinterpret_cast<unsigned char*>(&result), + sizeof(result)); + return result; } +#ifdef _WIN32 +class WindowsCryptProvider +{ + public: + WindowsCryptProvider() + { + if (! CryptAcquireContext(&crypt_prov, NULL, NULL, PROV_RSA_FULL, 0)) + { + throw std::runtime_error("unable to acquire crypt context"); + } + } + ~WindowsCryptProvider() + { + // Ignore error + CryptReleaseContext(crypt_prov, 0); + } + + HCRYPTPROV crypt_prov; +}; +#endif + void QUtil::initializeWithRandomBytes(unsigned char* data, size_t len) { - for (size_t i = 0; i < len; ++i) +#if defined(_WIN32) + + // Optimization: make the WindowsCryptProvider static as long as + // it can be done in a thread-safe fashion. + WindowsCryptProvider c; + if (! CryptGenRandom(c.crypt_prov, len, reinterpret_cast<BYTE*>(data))) { - data[i] = static_cast<unsigned char>((QUtil::random() & 0xff0) >> 4); + throw std::runtime_error("unable to generate secure random data"); + } + +#elif defined(RANDOM_DEVICE) + + // Optimization: wrap the file open and close in a class so that + // the file is closed in a destructor, then make this static to + // keep the file handle open. Only do this if it can be done in a + // thread-safe fashion. + FILE* f = QUtil::safe_fopen(RANDOM_DEVICE, "rb"); + size_t fr = fread(data, 1, len, f); + fclose(f); + if (fr != len) + { + throw std::runtime_error( + "unable to read " + + QUtil::int_to_string(len) + + " bytes from " + std::string(RANDOM_DEVICE)); } + +#else + +# error "Don't know how to generate secure random numbers on this platform. See random number generation in the top-level README" + +#endif +} + +#endif + +void +QUtil::srandom(unsigned int seed) +{ +#ifdef HAVE_RANDOM + ::srandom(seed); +#else + srand(seed); +#endif } |