diff options
author | Jay Berkenbilt <ejb@ql.org> | 2013-11-30 18:02:56 +0100 |
---|---|---|
committer | Jay Berkenbilt <ejb@ql.org> | 2013-12-14 21:17:35 +0100 |
commit | 5e3bad2f86665b35155095b91a2d672fc7335870 (patch) | |
tree | 984d4830ee0dd3b8e90bae913f411a84c8e876d4 /libqpdf/SecureRandomDataProvider.cc | |
parent | e9a319fb9536347aeab076cdb18e1ff97eb66c07 (diff) | |
download | qpdf-5e3bad2f86665b35155095b91a2d672fc7335870.tar.zst |
Refactor random data generation
Add new RandomDataProvider object and implement existing random number
generation in terms of that. This enables end users to supply their
own random data providers.
Diffstat (limited to 'libqpdf/SecureRandomDataProvider.cc')
-rw-r--r-- | libqpdf/SecureRandomDataProvider.cc | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/libqpdf/SecureRandomDataProvider.cc b/libqpdf/SecureRandomDataProvider.cc new file mode 100644 index 00000000..14ef55a7 --- /dev/null +++ b/libqpdf/SecureRandomDataProvider.cc @@ -0,0 +1,86 @@ +#include <qpdf/SecureRandomDataProvider.hh> + +#include <qpdf/qpdf-config.h> +#include <qpdf/QUtil.hh> +#ifdef _WIN32 +# include <Windows.h> +# include <direct.h> +# include <io.h> +# ifndef SKIP_OS_SECURE_RANDOM +# include <Wincrypt.h> +# endif +#endif + +SecureRandomDataProvider::SecureRandomDataProvider() +{ +} + +SecureRandomDataProvider::~SecureRandomDataProvider() +{ +} + +#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 +SecureRandomDataProvider::provideRandomData(unsigned char* data, size_t len) +{ +#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))) + { + 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 +} + +RandomDataProvider* +SecureRandomDataProvider::getInstance() +{ + static SecureRandomDataProvider instance; + return &instance; +} |