summaryrefslogtreecommitdiffstats
path: root/libqpdf
diff options
context:
space:
mode:
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__