Commit 5e3bad2f86665b35155095b91a2d672fc7335870
1 parent
e9a319fb
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.
Showing
12 changed files
with
361 additions
and
79 deletions
ChangeLog
| @@ -3,6 +3,12 @@ | @@ -3,6 +3,12 @@ | ||
| 3 | * Allow anyspace rather than just newline to follow xref header. | 3 | * Allow anyspace rather than just newline to follow xref header. |
| 4 | This allows qpdf to read a wider range of damaged files. | 4 | This allows qpdf to read a wider range of damaged files. |
| 5 | 5 | ||
| 6 | +2013-11-30 Jay Berkenbilt <ejb@ql.org> | ||
| 7 | + | ||
| 8 | + * Allow user-supplied random data provider to be used in place of | ||
| 9 | + OS-provided or insecure random number generation. See | ||
| 10 | + documentation for 5.1.0 for details. | ||
| 11 | + | ||
| 6 | 2013-11-29 Jay Berkenbilt <ejb@ql.org> | 12 | 2013-11-29 Jay Berkenbilt <ejb@ql.org> |
| 7 | 13 | ||
| 8 | * If NO_GET_ENVIRONMENT is #defined, for Windows only, | 14 | * If NO_GET_ENVIRONMENT is #defined, for Windows only, |
include/qpdf/QUtil.hh
| @@ -15,6 +15,8 @@ | @@ -15,6 +15,8 @@ | ||
| 15 | #include <stdexcept> | 15 | #include <stdexcept> |
| 16 | #include <stdio.h> | 16 | #include <stdio.h> |
| 17 | 17 | ||
| 18 | +class RandomDataProvider; | ||
| 19 | + | ||
| 18 | namespace QUtil | 20 | namespace QUtil |
| 19 | { | 21 | { |
| 20 | // This is a collection of useful utility functions that don't | 22 | // This is a collection of useful utility functions that don't |
| @@ -123,8 +125,26 @@ namespace QUtil | @@ -123,8 +125,26 @@ namespace QUtil | ||
| 123 | QPDF_DLL | 125 | QPDF_DLL |
| 124 | void srandom(unsigned int seed); | 126 | void srandom(unsigned int seed); |
| 125 | 127 | ||
| 128 | + // Initialize a buffer with random bytes. By default, qpdf tries | ||
| 129 | + // to use a secure random number source. It can be configured at | ||
| 130 | + // compile time to use an insecure random number source (from | ||
| 131 | + // stdlib). You can also call setRandomDataProvider with a | ||
| 132 | + // RandomDataProvider, in which case this method will get its | ||
| 133 | + // random bytes from that. | ||
| 134 | + | ||
| 126 | QPDF_DLL | 135 | QPDF_DLL |
| 127 | void initializeWithRandomBytes(unsigned char* data, size_t len); | 136 | void initializeWithRandomBytes(unsigned char* data, size_t len); |
| 137 | + | ||
| 138 | + // Supply a random data provider. If not supplied, depending on | ||
| 139 | + // compile time options, qpdf will either use the operating | ||
| 140 | + // system's secure random number source or an insecure random | ||
| 141 | + // source from stdlib. The caller is responsible for managing the | ||
| 142 | + // memory for the RandomDataProvider. This method modifies a | ||
| 143 | + // static variable. If you are providing your own random data | ||
| 144 | + // provider, you should call this at the beginning of your program | ||
| 145 | + // before creating any QPDF objects. | ||
| 146 | + QPDF_DLL | ||
| 147 | + void setRandomDataProvider(RandomDataProvider*); | ||
| 128 | }; | 148 | }; |
| 129 | 149 | ||
| 130 | #endif // __QUTIL_HH__ | 150 | #endif // __QUTIL_HH__ |
include/qpdf/RandomDataProvider.hh
0 → 100644
| 1 | +/* Copyright (c) 2005-2013 Jay Berkenbilt | ||
| 2 | + * | ||
| 3 | + * This file is part of qpdf. This software may be distributed under | ||
| 4 | + * the terms of version 2 of the Artistic License which may be found | ||
| 5 | + * in the source distribution. It is provided "as is" without express | ||
| 6 | + * or implied warranty. | ||
| 7 | + */ | ||
| 8 | + | ||
| 9 | +#ifndef __RANDOMDATAPROVIDER_HH__ | ||
| 10 | +#define __RANDOMDATAPROVIDER_HH__ | ||
| 11 | + | ||
| 12 | +#include <string.h> // for size_t | ||
| 13 | + | ||
| 14 | +class RandomDataProvider | ||
| 15 | +{ | ||
| 16 | + public: | ||
| 17 | + virtual ~RandomDataProvider() | ||
| 18 | + { | ||
| 19 | + } | ||
| 20 | + virtual void provideRandomData(unsigned char* data, size_t len) = 0; | ||
| 21 | + | ||
| 22 | + protected: | ||
| 23 | + RandomDataProvider() | ||
| 24 | + { | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | + private: | ||
| 28 | + RandomDataProvider(RandomDataProvider const&); | ||
| 29 | + RandomDataProvider& operator=(RandomDataProvider const&); | ||
| 30 | +}; | ||
| 31 | + | ||
| 32 | +#endif // __RANDOMDATAPROVIDER_HH__ |
libqpdf/InsecureRandomDataProvider.cc
0 → 100644
| 1 | +#include <qpdf/InsecureRandomDataProvider.hh> | ||
| 2 | + | ||
| 3 | +#include <qpdf/qpdf-config.h> | ||
| 4 | +#include <qpdf/QUtil.hh> | ||
| 5 | +#include <stdlib.h> | ||
| 6 | + | ||
| 7 | +InsecureRandomDataProvider::InsecureRandomDataProvider() : | ||
| 8 | + seeded_random(false) | ||
| 9 | +{ | ||
| 10 | +} | ||
| 11 | + | ||
| 12 | +InsecureRandomDataProvider::~InsecureRandomDataProvider() | ||
| 13 | +{ | ||
| 14 | +} | ||
| 15 | + | ||
| 16 | +void | ||
| 17 | +InsecureRandomDataProvider::provideRandomData(unsigned char* data, size_t len) | ||
| 18 | +{ | ||
| 19 | + for (size_t i = 0; i < len; ++i) | ||
| 20 | + { | ||
| 21 | + data[i] = static_cast<unsigned char>((this->random() & 0xff0) >> 4); | ||
| 22 | + } | ||
| 23 | +} | ||
| 24 | + | ||
| 25 | +long | ||
| 26 | +InsecureRandomDataProvider::random() | ||
| 27 | +{ | ||
| 28 | + if (! this->seeded_random) | ||
| 29 | + { | ||
| 30 | + // Seed the random number generator with something simple, but | ||
| 31 | + // just to be interesting, don't use the unmodified current | ||
| 32 | + // time. It would be better if this were a more secure seed. | ||
| 33 | + QUtil::srandom(QUtil::get_current_time() ^ 0xcccc); | ||
| 34 | + this->seeded_random = true; | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | +# ifdef HAVE_RANDOM | ||
| 38 | + return ::random(); | ||
| 39 | +# else | ||
| 40 | + return rand(); | ||
| 41 | +# endif | ||
| 42 | +} | ||
| 43 | + | ||
| 44 | +RandomDataProvider* | ||
| 45 | +InsecureRandomDataProvider::getInstance() | ||
| 46 | +{ | ||
| 47 | + static InsecureRandomDataProvider instance; | ||
| 48 | + return &instance; | ||
| 49 | +} |
libqpdf/QUtil.cc
| @@ -3,6 +3,10 @@ | @@ -3,6 +3,10 @@ | ||
| 3 | 3 | ||
| 4 | #include <qpdf/QUtil.hh> | 4 | #include <qpdf/QUtil.hh> |
| 5 | #include <qpdf/PointerHolder.hh> | 5 | #include <qpdf/PointerHolder.hh> |
| 6 | +#ifdef USE_INSECURE_RANDOM | ||
| 7 | +# include <qpdf/InsecureRandomDataProvider.hh> | ||
| 8 | +#endif | ||
| 9 | +#include <qpdf/SecureRandomDataProvider.hh> | ||
| 6 | 10 | ||
| 7 | #include <cmath> | 11 | #include <cmath> |
| 8 | #include <iomanip> | 12 | #include <iomanip> |
| @@ -18,7 +22,6 @@ | @@ -18,7 +22,6 @@ | ||
| 18 | #include <Windows.h> | 22 | #include <Windows.h> |
| 19 | #include <direct.h> | 23 | #include <direct.h> |
| 20 | #include <io.h> | 24 | #include <io.h> |
| 21 | -#include <Wincrypt.h> | ||
| 22 | #else | 25 | #else |
| 23 | #include <unistd.h> | 26 | #include <unistd.h> |
| 24 | #endif | 27 | #endif |
| @@ -383,38 +386,7 @@ QUtil::toUTF8(unsigned long uval) | @@ -383,38 +386,7 @@ QUtil::toUTF8(unsigned long uval) | ||
| 383 | return result; | 386 | return result; |
| 384 | } | 387 | } |
| 385 | 388 | ||
| 386 | -#ifdef USE_INSECURE_RANDOM | ||
| 387 | - | ||
| 388 | -long | ||
| 389 | -QUtil::random() | ||
| 390 | -{ | ||
| 391 | - static bool seeded_random = false; | ||
| 392 | - if (! seeded_random) | ||
| 393 | - { | ||
| 394 | - // Seed the random number generator with something simple, but | ||
| 395 | - // just to be interesting, don't use the unmodified current | ||
| 396 | - // time. It would be better if this were a more secure seed. | ||
| 397 | - QUtil::srandom(QUtil::get_current_time() ^ 0xcccc); | ||
| 398 | - seeded_random = true; | ||
| 399 | - } | ||
| 400 | - | ||
| 401 | -# ifdef HAVE_RANDOM | ||
| 402 | - return ::random(); | ||
| 403 | -# else | ||
| 404 | - return rand(); | ||
| 405 | -# endif | ||
| 406 | -} | ||
| 407 | - | ||
| 408 | -void | ||
| 409 | -QUtil::initializeWithRandomBytes(unsigned char* data, size_t len) | ||
| 410 | -{ | ||
| 411 | - for (size_t i = 0; i < len; ++i) | ||
| 412 | - { | ||
| 413 | - data[i] = static_cast<unsigned char>((QUtil::random() & 0xff0) >> 4); | ||
| 414 | - } | ||
| 415 | -} | ||
| 416 | - | ||
| 417 | -#else | 389 | +// Random data support |
| 418 | 390 | ||
| 419 | long | 391 | long |
| 420 | QUtil::random() | 392 | QUtil::random() |
| @@ -426,66 +398,50 @@ QUtil::random() | @@ -426,66 +398,50 @@ QUtil::random() | ||
| 426 | return result; | 398 | return result; |
| 427 | } | 399 | } |
| 428 | 400 | ||
| 429 | -#ifdef _WIN32 | ||
| 430 | -class WindowsCryptProvider | 401 | +static RandomDataProvider* random_data_provider = 0; |
| 402 | + | ||
| 403 | +#ifdef USE_INSECURE_RANDOM | ||
| 404 | +static RandomDataProvider* insecure_random_data_provider = | ||
| 405 | + InsecureRandomDataProvider::getInstance(); | ||
| 406 | +#else | ||
| 407 | +static RandomDataProvider* insecure_random_data_provider = 0; | ||
| 408 | +#endif | ||
| 409 | +static RandomDataProvider* secure_random_data_provider = | ||
| 410 | + SecureRandomDataProvider::getInstance(); | ||
| 411 | + | ||
| 412 | +static void | ||
| 413 | +initialize_random_data_provider() | ||
| 431 | { | 414 | { |
| 432 | - public: | ||
| 433 | - WindowsCryptProvider() | 415 | + if (random_data_provider == 0) |
| 434 | { | 416 | { |
| 435 | - if (! CryptAcquireContext(&crypt_prov, NULL, NULL, PROV_RSA_FULL, 0)) | 417 | + if (secure_random_data_provider) |
| 418 | + { | ||
| 419 | + random_data_provider = secure_random_data_provider; | ||
| 420 | + } | ||
| 421 | + else if (insecure_random_data_provider) | ||
| 436 | { | 422 | { |
| 437 | - throw std::runtime_error("unable to acquire crypt context"); | 423 | + random_data_provider = insecure_random_data_provider; |
| 438 | } | 424 | } |
| 439 | } | 425 | } |
| 440 | - ~WindowsCryptProvider() | 426 | + if (random_data_provider == 0) |
| 441 | { | 427 | { |
| 442 | - // Ignore error | ||
| 443 | - CryptReleaseContext(crypt_prov, 0); | 428 | + throw std::logic_error("QPDF has no random data provider"); |
| 444 | } | 429 | } |
| 430 | +} | ||
| 445 | 431 | ||
| 446 | - HCRYPTPROV crypt_prov; | ||
| 447 | -}; | ||
| 448 | -#endif | 432 | +void |
| 433 | +QUtil::setRandomDataProvider(RandomDataProvider* p) | ||
| 434 | +{ | ||
| 435 | + random_data_provider = p; | ||
| 436 | +} | ||
| 449 | 437 | ||
| 450 | void | 438 | void |
| 451 | QUtil::initializeWithRandomBytes(unsigned char* data, size_t len) | 439 | QUtil::initializeWithRandomBytes(unsigned char* data, size_t len) |
| 452 | { | 440 | { |
| 453 | -#if defined(_WIN32) | ||
| 454 | - | ||
| 455 | - // Optimization: make the WindowsCryptProvider static as long as | ||
| 456 | - // it can be done in a thread-safe fashion. | ||
| 457 | - WindowsCryptProvider c; | ||
| 458 | - if (! CryptGenRandom(c.crypt_prov, len, reinterpret_cast<BYTE*>(data))) | ||
| 459 | - { | ||
| 460 | - throw std::runtime_error("unable to generate secure random data"); | ||
| 461 | - } | ||
| 462 | - | ||
| 463 | -#elif defined(RANDOM_DEVICE) | ||
| 464 | - | ||
| 465 | - // Optimization: wrap the file open and close in a class so that | ||
| 466 | - // the file is closed in a destructor, then make this static to | ||
| 467 | - // keep the file handle open. Only do this if it can be done in a | ||
| 468 | - // thread-safe fashion. | ||
| 469 | - FILE* f = QUtil::safe_fopen(RANDOM_DEVICE, "rb"); | ||
| 470 | - size_t fr = fread(data, 1, len, f); | ||
| 471 | - fclose(f); | ||
| 472 | - if (fr != len) | ||
| 473 | - { | ||
| 474 | - throw std::runtime_error( | ||
| 475 | - "unable to read " + | ||
| 476 | - QUtil::int_to_string(len) + | ||
| 477 | - " bytes from " + std::string(RANDOM_DEVICE)); | ||
| 478 | - } | ||
| 479 | - | ||
| 480 | -#else | ||
| 481 | - | ||
| 482 | -# error "Don't know how to generate secure random numbers on this platform. See random number generation in the top-level README" | ||
| 483 | - | ||
| 484 | -#endif | 441 | + initialize_random_data_provider(); |
| 442 | + random_data_provider->provideRandomData(data, len); | ||
| 485 | } | 443 | } |
| 486 | 444 | ||
| 487 | -#endif | ||
| 488 | - | ||
| 489 | void | 445 | void |
| 490 | QUtil::srandom(unsigned int seed) | 446 | QUtil::srandom(unsigned int seed) |
| 491 | { | 447 | { |
libqpdf/SecureRandomDataProvider.cc
0 → 100644
| 1 | +#include <qpdf/SecureRandomDataProvider.hh> | ||
| 2 | + | ||
| 3 | +#include <qpdf/qpdf-config.h> | ||
| 4 | +#include <qpdf/QUtil.hh> | ||
| 5 | +#ifdef _WIN32 | ||
| 6 | +# include <Windows.h> | ||
| 7 | +# include <direct.h> | ||
| 8 | +# include <io.h> | ||
| 9 | +# ifndef SKIP_OS_SECURE_RANDOM | ||
| 10 | +# include <Wincrypt.h> | ||
| 11 | +# endif | ||
| 12 | +#endif | ||
| 13 | + | ||
| 14 | +SecureRandomDataProvider::SecureRandomDataProvider() | ||
| 15 | +{ | ||
| 16 | +} | ||
| 17 | + | ||
| 18 | +SecureRandomDataProvider::~SecureRandomDataProvider() | ||
| 19 | +{ | ||
| 20 | +} | ||
| 21 | + | ||
| 22 | +#ifdef _WIN32 | ||
| 23 | + | ||
| 24 | +class WindowsCryptProvider | ||
| 25 | +{ | ||
| 26 | + public: | ||
| 27 | + WindowsCryptProvider() | ||
| 28 | + { | ||
| 29 | + if (! CryptAcquireContext(&crypt_prov, NULL, NULL, PROV_RSA_FULL, 0)) | ||
| 30 | + { | ||
| 31 | + throw std::runtime_error("unable to acquire crypt context"); | ||
| 32 | + } | ||
| 33 | + } | ||
| 34 | + ~WindowsCryptProvider() | ||
| 35 | + { | ||
| 36 | + // Ignore error | ||
| 37 | + CryptReleaseContext(crypt_prov, 0); | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + HCRYPTPROV crypt_prov; | ||
| 41 | +}; | ||
| 42 | +#endif | ||
| 43 | + | ||
| 44 | +void | ||
| 45 | +SecureRandomDataProvider::provideRandomData(unsigned char* data, size_t len) | ||
| 46 | +{ | ||
| 47 | +#if defined(_WIN32) | ||
| 48 | + | ||
| 49 | + // Optimization: make the WindowsCryptProvider static as long as | ||
| 50 | + // it can be done in a thread-safe fashion. | ||
| 51 | + WindowsCryptProvider c; | ||
| 52 | + if (! CryptGenRandom(c.crypt_prov, len, reinterpret_cast<BYTE*>(data))) | ||
| 53 | + { | ||
| 54 | + throw std::runtime_error("unable to generate secure random data"); | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | +#elif defined(RANDOM_DEVICE) | ||
| 58 | + | ||
| 59 | + // Optimization: wrap the file open and close in a class so that | ||
| 60 | + // the file is closed in a destructor, then make this static to | ||
| 61 | + // keep the file handle open. Only do this if it can be done in a | ||
| 62 | + // thread-safe fashion. | ||
| 63 | + FILE* f = QUtil::safe_fopen(RANDOM_DEVICE, "rb"); | ||
| 64 | + size_t fr = fread(data, 1, len, f); | ||
| 65 | + fclose(f); | ||
| 66 | + if (fr != len) | ||
| 67 | + { | ||
| 68 | + throw std::runtime_error( | ||
| 69 | + "unable to read " + | ||
| 70 | + QUtil::int_to_string(len) + | ||
| 71 | + " bytes from " + std::string(RANDOM_DEVICE)); | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | +#else | ||
| 75 | + | ||
| 76 | +# error "Don't know how to generate secure random numbers on this platform. See random number generation in the top-level README" | ||
| 77 | + | ||
| 78 | +#endif | ||
| 79 | +} | ||
| 80 | + | ||
| 81 | +RandomDataProvider* | ||
| 82 | +SecureRandomDataProvider::getInstance() | ||
| 83 | +{ | ||
| 84 | + static SecureRandomDataProvider instance; | ||
| 85 | + return &instance; | ||
| 86 | +} |
libqpdf/build.mk
| @@ -11,6 +11,7 @@ SRCS_libqpdf = \ | @@ -11,6 +11,7 @@ SRCS_libqpdf = \ | ||
| 11 | libqpdf/BufferInputSource.cc \ | 11 | libqpdf/BufferInputSource.cc \ |
| 12 | libqpdf/FileInputSource.cc \ | 12 | libqpdf/FileInputSource.cc \ |
| 13 | libqpdf/InputSource.cc \ | 13 | libqpdf/InputSource.cc \ |
| 14 | + libqpdf/InsecureRandomDataProvider.cc \ | ||
| 14 | libqpdf/MD5.cc \ | 15 | libqpdf/MD5.cc \ |
| 15 | libqpdf/OffsetInputSource.cc \ | 16 | libqpdf/OffsetInputSource.cc \ |
| 16 | libqpdf/PCRE.cc \ | 17 | libqpdf/PCRE.cc \ |
| @@ -57,6 +58,7 @@ SRCS_libqpdf = \ | @@ -57,6 +58,7 @@ SRCS_libqpdf = \ | ||
| 57 | libqpdf/QTC.cc \ | 58 | libqpdf/QTC.cc \ |
| 58 | libqpdf/QUtil.cc \ | 59 | libqpdf/QUtil.cc \ |
| 59 | libqpdf/RC4.cc \ | 60 | libqpdf/RC4.cc \ |
| 61 | + libqpdf/SecureRandomDataProvider.cc \ | ||
| 60 | libqpdf/qpdf-c.cc \ | 62 | libqpdf/qpdf-c.cc \ |
| 61 | libqpdf/rijndael.cc \ | 63 | libqpdf/rijndael.cc \ |
| 62 | libqpdf/sha2.c \ | 64 | libqpdf/sha2.c \ |
libqpdf/qpdf/InsecureRandomDataProvider.hh
0 → 100644
| 1 | +#ifndef __INSECURERANDOMDATAPROVIDER_HH__ | ||
| 2 | +#define __INSECURERANDOMDATAPROVIDER_HH__ | ||
| 3 | + | ||
| 4 | +#include <qpdf/RandomDataProvider.hh> | ||
| 5 | +#include <qpdf/DLL.h> | ||
| 6 | + | ||
| 7 | +class InsecureRandomDataProvider: public RandomDataProvider | ||
| 8 | +{ | ||
| 9 | + public: | ||
| 10 | + QPDF_DLL | ||
| 11 | + InsecureRandomDataProvider(); | ||
| 12 | + QPDF_DLL | ||
| 13 | + virtual ~InsecureRandomDataProvider(); | ||
| 14 | + | ||
| 15 | + QPDF_DLL | ||
| 16 | + virtual void provideRandomData(unsigned char* data, size_t len); | ||
| 17 | + | ||
| 18 | + QPDF_DLL | ||
| 19 | + static RandomDataProvider* getInstance(); | ||
| 20 | + | ||
| 21 | + private: | ||
| 22 | + long random(); | ||
| 23 | + | ||
| 24 | + bool seeded_random; | ||
| 25 | +}; | ||
| 26 | + | ||
| 27 | +#endif // __INSECURERANDOMDATAPROVIDER_HH__ |
libqpdf/qpdf/SecureRandomDataProvider.hh
0 → 100644
| 1 | +#ifndef __SECURERANDOMDATAPROVIDER_HH__ | ||
| 2 | +#define __SECURERANDOMDATAPROVIDER_HH__ | ||
| 3 | + | ||
| 4 | +#include <qpdf/RandomDataProvider.hh> | ||
| 5 | +#include <qpdf/DLL.h> | ||
| 6 | + | ||
| 7 | +class SecureRandomDataProvider: public RandomDataProvider | ||
| 8 | +{ | ||
| 9 | + public: | ||
| 10 | + QPDF_DLL | ||
| 11 | + SecureRandomDataProvider(); | ||
| 12 | + QPDF_DLL | ||
| 13 | + virtual ~SecureRandomDataProvider(); | ||
| 14 | + | ||
| 15 | + QPDF_DLL | ||
| 16 | + virtual void provideRandomData(unsigned char* data, size_t len); | ||
| 17 | + | ||
| 18 | + QPDF_DLL | ||
| 19 | + static RandomDataProvider* getInstance(); | ||
| 20 | +}; | ||
| 21 | + | ||
| 22 | +#endif // __SECURERANDOMDATAPROVIDER_HH__ |
libtests/build.mk
libtests/qtest/random.test
0 → 100644
| 1 | +#!/usr/bin/env perl | ||
| 2 | +require 5.008; | ||
| 3 | +BEGIN { $^W = 1; } | ||
| 4 | +use strict; | ||
| 5 | + | ||
| 6 | +require TestDriver; | ||
| 7 | + | ||
| 8 | +my $td = new TestDriver('random'); | ||
| 9 | + | ||
| 10 | +$td->runtest("Random Data Providers", | ||
| 11 | + {$td->COMMAND => "random"}, | ||
| 12 | + {$td->STRING => "random: end of tests\n", | ||
| 13 | + $td->EXIT_STATUS => 0}, | ||
| 14 | + $td->NORMALIZE_NEWLINES); | ||
| 15 | + | ||
| 16 | +$td->report(1); |
libtests/random.cc
0 → 100644
| 1 | +#include <qpdf/QUtil.hh> | ||
| 2 | +#include <qpdf/InsecureRandomDataProvider.hh> | ||
| 3 | +#include <qpdf/SecureRandomDataProvider.hh> | ||
| 4 | +#include <iostream> | ||
| 5 | + | ||
| 6 | +class BogusRandomDataProvider: public RandomDataProvider | ||
| 7 | +{ | ||
| 8 | + public: | ||
| 9 | + virtual ~BogusRandomDataProvider() | ||
| 10 | + { | ||
| 11 | + } | ||
| 12 | + BogusRandomDataProvider() | ||
| 13 | + { | ||
| 14 | + } | ||
| 15 | + virtual void provideRandomData(unsigned char* data, size_t len) | ||
| 16 | + { | ||
| 17 | + for (size_t i = 0; i < len; ++i) | ||
| 18 | + { | ||
| 19 | + data[i] = static_cast<unsigned char>(i & 0xff); | ||
| 20 | + } | ||
| 21 | + } | ||
| 22 | +}; | ||
| 23 | + | ||
| 24 | +int main() | ||
| 25 | +{ | ||
| 26 | + long r1 = QUtil::random(); | ||
| 27 | + long r2 = QUtil::random(); | ||
| 28 | + if (r1 == r2) | ||
| 29 | + { | ||
| 30 | + std::cout << "fail: two randoms were the same\n"; | ||
| 31 | + } | ||
| 32 | + InsecureRandomDataProvider irdp; | ||
| 33 | + irdp.provideRandomData(reinterpret_cast<unsigned char*>(&r1), 4); | ||
| 34 | + irdp.provideRandomData(reinterpret_cast<unsigned char*>(&r2), 4); | ||
| 35 | + if (r1 == r2) | ||
| 36 | + { | ||
| 37 | + std::cout << "fail: two insecure randoms were the same\n"; | ||
| 38 | + } | ||
| 39 | + SecureRandomDataProvider srdp; | ||
| 40 | + srdp.provideRandomData(reinterpret_cast<unsigned char*>(&r1), 4); | ||
| 41 | + srdp.provideRandomData(reinterpret_cast<unsigned char*>(&r2), 4); | ||
| 42 | + if (r1 == r2) | ||
| 43 | + { | ||
| 44 | + std::cout << "fail: two secure randoms were the same\n"; | ||
| 45 | + } | ||
| 46 | + BogusRandomDataProvider brdp; | ||
| 47 | + QUtil::setRandomDataProvider(&brdp); | ||
| 48 | + r1 = QUtil::random(); | ||
| 49 | + r2 = QUtil::random(); | ||
| 50 | + if (r1 != r2) | ||
| 51 | + { | ||
| 52 | + std::cout << "fail: two bogus randoms were different\n"; | ||
| 53 | + } | ||
| 54 | + unsigned char buf[4]; | ||
| 55 | + QUtil::initializeWithRandomBytes(buf, 4); | ||
| 56 | + if (! ((buf[0] == 0) && | ||
| 57 | + (buf[1] == 1) && | ||
| 58 | + (buf[2] == 2) && | ||
| 59 | + (buf[3] == 3))) | ||
| 60 | + { | ||
| 61 | + std::cout << "fail: bogus random didn't provide correct bytes\n"; | ||
| 62 | + } | ||
| 63 | + std::cout << "random: end of tests\n"; | ||
| 64 | + return 0; | ||
| 65 | +} |