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