summaryrefslogtreecommitdiffstats
path: root/libqpdf
diff options
context:
space:
mode:
authorJay Berkenbilt <ejb@ql.org>2013-11-30 18:02:56 +0100
committerJay Berkenbilt <ejb@ql.org>2013-12-14 21:17:35 +0100
commit5e3bad2f86665b35155095b91a2d672fc7335870 (patch)
tree984d4830ee0dd3b8e90bae913f411a84c8e876d4 /libqpdf
parente9a319fb9536347aeab076cdb18e1ff97eb66c07 (diff)
downloadqpdf-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')
-rw-r--r--libqpdf/InsecureRandomDataProvider.cc49
-rw-r--r--libqpdf/QUtil.cc114
-rw-r--r--libqpdf/SecureRandomDataProvider.cc86
-rw-r--r--libqpdf/build.mk2
-rw-r--r--libqpdf/qpdf/InsecureRandomDataProvider.hh27
-rw-r--r--libqpdf/qpdf/SecureRandomDataProvider.hh22
6 files changed, 221 insertions, 79 deletions
diff --git a/libqpdf/InsecureRandomDataProvider.cc b/libqpdf/InsecureRandomDataProvider.cc
new file mode 100644
index 00000000..5f637746
--- /dev/null
+++ b/libqpdf/InsecureRandomDataProvider.cc
@@ -0,0 +1,49 @@
+#include <qpdf/InsecureRandomDataProvider.hh>
+
+#include <qpdf/qpdf-config.h>
+#include <qpdf/QUtil.hh>
+#include <stdlib.h>
+
+InsecureRandomDataProvider::InsecureRandomDataProvider() :
+ seeded_random(false)
+{
+}
+
+InsecureRandomDataProvider::~InsecureRandomDataProvider()
+{
+}
+
+void
+InsecureRandomDataProvider::provideRandomData(unsigned char* data, size_t len)
+{
+ for (size_t i = 0; i < len; ++i)
+ {
+ data[i] = static_cast<unsigned char>((this->random() & 0xff0) >> 4);
+ }
+}
+
+long
+InsecureRandomDataProvider::random()
+{
+ if (! this->seeded_random)
+ {
+ // Seed the random number generator with something simple, but
+ // just to be interesting, don't use the unmodified current
+ // time. It would be better if this were a more secure seed.
+ QUtil::srandom(QUtil::get_current_time() ^ 0xcccc);
+ this->seeded_random = true;
+ }
+
+# ifdef HAVE_RANDOM
+ return ::random();
+# else
+ return rand();
+# endif
+}
+
+RandomDataProvider*
+InsecureRandomDataProvider::getInstance()
+{
+ static InsecureRandomDataProvider instance;
+ return &instance;
+}
diff --git a/libqpdf/QUtil.cc b/libqpdf/QUtil.cc
index 01e0b6e7..c5fe535c 100644
--- a/libqpdf/QUtil.cc
+++ b/libqpdf/QUtil.cc
@@ -3,6 +3,10 @@
#include <qpdf/QUtil.hh>
#include <qpdf/PointerHolder.hh>
+#ifdef USE_INSECURE_RANDOM
+# include <qpdf/InsecureRandomDataProvider.hh>
+#endif
+#include <qpdf/SecureRandomDataProvider.hh>
#include <cmath>
#include <iomanip>
@@ -18,7 +22,6 @@
#include <Windows.h>
#include <direct.h>
#include <io.h>
-#include <Wincrypt.h>
#else
#include <unistd.h>
#endif
@@ -383,38 +386,7 @@ QUtil::toUTF8(unsigned long uval)
return result;
}
-#ifdef USE_INSECURE_RANDOM
-
-long
-QUtil::random()
-{
- static bool seeded_random = false;
- if (! seeded_random)
- {
- // Seed the random number generator with something simple, but
- // just to be interesting, don't use the unmodified current
- // time. It would be better if this were a more secure seed.
- QUtil::srandom(QUtil::get_current_time() ^ 0xcccc);
- seeded_random = true;
- }
-
-# ifdef HAVE_RANDOM
- return ::random();
-# else
- return rand();
-# endif
-}
-
-void
-QUtil::initializeWithRandomBytes(unsigned char* data, size_t len)
-{
- for (size_t i = 0; i < len; ++i)
- {
- data[i] = static_cast<unsigned char>((QUtil::random() & 0xff0) >> 4);
- }
-}
-
-#else
+// Random data support
long
QUtil::random()
@@ -426,66 +398,50 @@ QUtil::random()
return result;
}
-#ifdef _WIN32
-class WindowsCryptProvider
+static RandomDataProvider* random_data_provider = 0;
+
+#ifdef USE_INSECURE_RANDOM
+static RandomDataProvider* insecure_random_data_provider =
+ InsecureRandomDataProvider::getInstance();
+#else
+static RandomDataProvider* insecure_random_data_provider = 0;
+#endif
+static RandomDataProvider* secure_random_data_provider =
+ SecureRandomDataProvider::getInstance();
+
+static void
+initialize_random_data_provider()
{
- public:
- WindowsCryptProvider()
+ if (random_data_provider == 0)
{
- if (! CryptAcquireContext(&crypt_prov, NULL, NULL, PROV_RSA_FULL, 0))
+ if (secure_random_data_provider)
+ {
+ random_data_provider = secure_random_data_provider;
+ }
+ else if (insecure_random_data_provider)
{
- throw std::runtime_error("unable to acquire crypt context");
+ random_data_provider = insecure_random_data_provider;
}
}
- ~WindowsCryptProvider()
+ if (random_data_provider == 0)
{
- // Ignore error
- CryptReleaseContext(crypt_prov, 0);
+ throw std::logic_error("QPDF has no random data provider");
}
+}
- HCRYPTPROV crypt_prov;
-};
-#endif
+void
+QUtil::setRandomDataProvider(RandomDataProvider* p)
+{
+ random_data_provider = p;
+}
void
QUtil::initializeWithRandomBytes(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
+ initialize_random_data_provider();
+ random_data_provider->provideRandomData(data, len);
}
-#endif
-
void
QUtil::srandom(unsigned int seed)
{
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;
+}
diff --git a/libqpdf/build.mk b/libqpdf/build.mk
index 20781230..4287b0de 100644
--- a/libqpdf/build.mk
+++ b/libqpdf/build.mk
@@ -11,6 +11,7 @@ SRCS_libqpdf = \
libqpdf/BufferInputSource.cc \
libqpdf/FileInputSource.cc \
libqpdf/InputSource.cc \
+ libqpdf/InsecureRandomDataProvider.cc \
libqpdf/MD5.cc \
libqpdf/OffsetInputSource.cc \
libqpdf/PCRE.cc \
@@ -57,6 +58,7 @@ SRCS_libqpdf = \
libqpdf/QTC.cc \
libqpdf/QUtil.cc \
libqpdf/RC4.cc \
+ libqpdf/SecureRandomDataProvider.cc \
libqpdf/qpdf-c.cc \
libqpdf/rijndael.cc \
libqpdf/sha2.c \
diff --git a/libqpdf/qpdf/InsecureRandomDataProvider.hh b/libqpdf/qpdf/InsecureRandomDataProvider.hh
new file mode 100644
index 00000000..530ee3cb
--- /dev/null
+++ b/libqpdf/qpdf/InsecureRandomDataProvider.hh
@@ -0,0 +1,27 @@
+#ifndef __INSECURERANDOMDATAPROVIDER_HH__
+#define __INSECURERANDOMDATAPROVIDER_HH__
+
+#include <qpdf/RandomDataProvider.hh>
+#include <qpdf/DLL.h>
+
+class InsecureRandomDataProvider: public RandomDataProvider
+{
+ public:
+ QPDF_DLL
+ InsecureRandomDataProvider();
+ QPDF_DLL
+ virtual ~InsecureRandomDataProvider();
+
+ QPDF_DLL
+ virtual void provideRandomData(unsigned char* data, size_t len);
+
+ QPDF_DLL
+ static RandomDataProvider* getInstance();
+
+ private:
+ long random();
+
+ bool seeded_random;
+};
+
+#endif // __INSECURERANDOMDATAPROVIDER_HH__
diff --git a/libqpdf/qpdf/SecureRandomDataProvider.hh b/libqpdf/qpdf/SecureRandomDataProvider.hh
new file mode 100644
index 00000000..178c73c0
--- /dev/null
+++ b/libqpdf/qpdf/SecureRandomDataProvider.hh
@@ -0,0 +1,22 @@
+#ifndef __SECURERANDOMDATAPROVIDER_HH__
+#define __SECURERANDOMDATAPROVIDER_HH__
+
+#include <qpdf/RandomDataProvider.hh>
+#include <qpdf/DLL.h>
+
+class SecureRandomDataProvider: public RandomDataProvider
+{
+ public:
+ QPDF_DLL
+ SecureRandomDataProvider();
+ QPDF_DLL
+ virtual ~SecureRandomDataProvider();
+
+ QPDF_DLL
+ virtual void provideRandomData(unsigned char* data, size_t len);
+
+ QPDF_DLL
+ static RandomDataProvider* getInstance();
+};
+
+#endif // __SECURERANDOMDATAPROVIDER_HH__