summaryrefslogtreecommitdiffstats
path: root/libqpdf/SecureRandomDataProvider.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libqpdf/SecureRandomDataProvider.cc')
-rw-r--r--libqpdf/SecureRandomDataProvider.cc86
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;
+}