diff options
author | weidai <weidai@57ff6487-cd31-0410-9ec3-f628ee90f5f0> | 2007-05-04 15:04:58 +0000 |
---|---|---|
committer | weidai <weidai@57ff6487-cd31-0410-9ec3-f628ee90f5f0> | 2007-05-04 15:04:58 +0000 |
commit | cdd57fd49c847250ce5d8e3cc39b7d882a529fc3 (patch) | |
tree | af7086b6bdb722b9a90c1abe0dd994166f32040b | |
parent | 061bcd669cf286d0043e1060bb36761df2df907e (diff) | |
download | cryptopp-cdd57fd49c847250ce5d8e3cc39b7d882a529fc3.tar.gz |
reduce risk of random number reuse after VM rollback
git-svn-id: svn://svn.code.sf.net/p/cryptopp/code/trunk/c5@328 57ff6487-cd31-0410-9ec3-f628ee90f5f0
-rw-r--r-- | hrtimer.cpp | 76 | ||||
-rw-r--r-- | hrtimer.h | 19 | ||||
-rw-r--r-- | osrng.cpp | 16 | ||||
-rw-r--r-- | osrng.h | 54 | ||||
-rw-r--r-- | rng.cpp | 58 | ||||
-rw-r--r-- | rng.h | 9 |
6 files changed, 111 insertions, 121 deletions
diff --git a/hrtimer.cpp b/hrtimer.cpp index 71149ba..2496774 100644 --- a/hrtimer.cpp +++ b/hrtimer.cpp @@ -4,7 +4,6 @@ #include "hrtimer.h" #include "misc.h" #include <stddef.h> // for NULL -#include <time.h> #if defined(CRYPTOPP_WIN32_AVAILABLE) #include <windows.h> @@ -18,6 +17,8 @@ NAMESPACE_BEGIN(CryptoPP) +#ifndef CRYPTOPP_IMPORTS + double TimerBase::ConvertTo(TimerWord t, Unit unit) { static unsigned long unitsPerSecondTable[] = {1, 1000, 1000*1000, 1000*1000*1000}; @@ -56,6 +57,46 @@ unsigned long TimerBase::ElapsedTime() return (unsigned long)elapsed; } +TimerWord Timer::GetCurrentTimerValue() +{ +#if defined(CRYPTOPP_WIN32_AVAILABLE) + LARGE_INTEGER now; + if (!QueryPerformanceCounter(&now)) + throw Exception(Exception::OTHER_ERROR, "Timer: QueryPerformanceCounter failed with error " + IntToString(GetLastError())); + return now.QuadPart; +#elif defined(CRYPTOPP_UNIX_AVAILABLE) + timeval now; + gettimeofday(&now, NULL); + return (TimerWord)now.tv_sec * 1000000 + now.tv_usec; +#else + clock_t now; + return clock(); +#endif +} + +TimerWord Timer::TicksPerSecond() +{ +#if defined(CRYPTOPP_WIN32_AVAILABLE) + static LARGE_INTEGER freq = {0}; + if (freq.QuadPart == 0) + { + if (!QueryPerformanceFrequency(&freq)) + throw Exception(Exception::OTHER_ERROR, "Timer: QueryPerformanceFrequency failed with error " + IntToString(GetLastError())); + } + return freq.QuadPart; +#elif defined(CRYPTOPP_UNIX_AVAILABLE) + return 1000000; +#elif defined(CLOCKS_PER_SEC) + return CLOCKS_PER_SEC; +#elif defined(CLK_TCK) + return CLK_TCK; +#else + return 1000000; +#endif +} + +#endif // #ifndef CRYPTOPP_IMPORTS + TimerWord ThreadUserTimer::GetCurrentTimerValue() { #if defined(CRYPTOPP_WIN32_AVAILABLE) @@ -98,37 +139,4 @@ TimerWord ThreadUserTimer::TicksPerSecond() #endif } -#ifdef HIGHRES_TIMER_AVAILABLE - -TimerWord Timer::GetCurrentTimerValue() -{ -#if defined(CRYPTOPP_WIN32_AVAILABLE) - LARGE_INTEGER now; - if (!QueryPerformanceCounter(&now)) - throw Exception(Exception::OTHER_ERROR, "Timer: QueryPerformanceCounter failed with error " + IntToString(GetLastError())); - return now.QuadPart; -#elif defined(CRYPTOPP_UNIX_AVAILABLE) - timeval now; - gettimeofday(&now, NULL); - return (TimerWord)now.tv_sec * 1000000 + now.tv_usec; -#endif -} - -TimerWord Timer::TicksPerSecond() -{ -#if defined(CRYPTOPP_WIN32_AVAILABLE) - static LARGE_INTEGER freq = {0}; - if (freq.QuadPart == 0) - { - if (!QueryPerformanceFrequency(&freq)) - throw Exception(Exception::OTHER_ERROR, "Timer: QueryPerformanceFrequency failed with error " + IntToString(GetLastError())); - } - return freq.QuadPart; -#elif defined(CRYPTOPP_UNIX_AVAILABLE) - return 1000000; -#endif -} - -#endif // HIGHRES_TIMER_AVAILABLE - NAMESPACE_END @@ -5,14 +5,19 @@ NAMESPACE_BEGIN(CryptoPP) -#ifdef WORD64_AVAILABLE - typedef word64 TimerWord; +#ifdef HIGHRES_TIMER_AVAILABLE + #ifdef WORD64_AVAILABLE + typedef word64 TimerWord; + #else + typedef word32 TimerWord; + #endif #else - typedef word32 TimerWord; + #include <time.h> + typedef clock_t TimerWord; #endif //! _ -class TimerBase +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE TimerBase { public: enum Unit {SECONDS = 0, MILLISECONDS, MICROSECONDS, NANOSECONDS}; @@ -44,10 +49,8 @@ public: TimerWord TicksPerSecond(); }; -#ifdef HIGHRES_TIMER_AVAILABLE - //! high resolution timer -class Timer : public TimerBase +class CRYPTOPP_DLL Timer : public TimerBase { public: Timer(Unit unit = TimerBase::SECONDS, bool stuckAtZero = false) : TimerBase(unit, stuckAtZero) {} @@ -55,8 +58,6 @@ public: TimerWord TicksPerSecond(); }; -#endif // HIGHRES_TIMER_AVAILABLE - NAMESPACE_END #endif @@ -74,13 +74,6 @@ NonblockingRng::~NonblockingRng() #endif } -byte NonblockingRng::GenerateByte() -{ - byte b; - GenerateBlock(&b, 1); - return b; -} - void NonblockingRng::GenerateBlock(byte *output, size_t size) { #ifdef CRYPTOPP_WIN32_AVAILABLE @@ -121,13 +114,6 @@ BlockingRng::~BlockingRng() close(m_fd); } -byte BlockingRng::GenerateByte() -{ - byte b; - GenerateBlock(&b, 1); - return b; -} - void BlockingRng::GenerateBlock(byte *output, size_t size) { while (size) @@ -175,7 +161,7 @@ void AutoSeededRandomPool::Reseed(bool blocking, unsigned int seedSize) { SecByteBlock seed(seedSize); OS_GenerateRandomBlock(blocking, seed, seedSize); - Put(seed, seedSize); + IncorporateEntropy(seed, seedSize); } NAMESPACE_END @@ -7,7 +7,7 @@ #include "randpool.h" #include "rng.h" -#include "des.h" +#include "aes.h" #include "fips140.h" NAMESPACE_BEGIN(CryptoPP) @@ -46,7 +46,6 @@ class CRYPTOPP_DLL NonblockingRng : public RandomNumberGenerator public: NonblockingRng(); ~NonblockingRng(); - byte GenerateByte(); void GenerateBlock(byte *output, size_t size); protected: @@ -69,7 +68,6 @@ class CRYPTOPP_DLL BlockingRng : public RandomNumberGenerator public: BlockingRng(); ~BlockingRng(); - byte GenerateByte(); void GenerateBlock(byte *output, size_t size); protected: @@ -99,39 +97,39 @@ public: //! use blocking to choose seeding with BlockingRng or NonblockingRng. the parameter is ignored if only one of these is available explicit AutoSeededX917RNG(bool blocking = false) {Reseed(blocking);} - void Reseed(bool blocking = false); + void Reseed(bool blocking = false, const byte *additionalEntropy = NULL, size_t length = 0); // exposed for testing void Reseed(const byte *key, size_t keylength, const byte *seed, const byte *timeVector); - byte GenerateByte(); + bool CanIncorporateEntropy() const {return true;} + void IncorporateEntropy(const byte *input, size_t length) {Reseed(false, input, length);} + void GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword length) {m_rng->GenerateIntoBufferedTransformation(target, channel, length);} private: member_ptr<RandomNumberGenerator> m_rng; - SecByteBlock m_lastBlock; - bool m_isDifferent; - unsigned int m_counter; }; template <class BLOCK_CIPHER> void AutoSeededX917RNG<BLOCK_CIPHER>::Reseed(const byte *key, size_t keylength, const byte *seed, const byte *timeVector) { m_rng.reset(new X917RNG(new typename BLOCK_CIPHER::Encryption(key, keylength), seed, timeVector)); - - // for FIPS 140-2 - m_lastBlock.resize(16); - m_rng->GenerateBlock(m_lastBlock, m_lastBlock.size()); - m_counter = 0; - m_isDifferent = false; } template <class BLOCK_CIPHER> -void AutoSeededX917RNG<BLOCK_CIPHER>::Reseed(bool blocking) +void AutoSeededX917RNG<BLOCK_CIPHER>::Reseed(bool blocking, const byte *input, size_t length) { SecByteBlock seed(BLOCK_CIPHER::BLOCKSIZE + BLOCK_CIPHER::DEFAULT_KEYLENGTH); const byte *key; do { OS_GenerateRandomBlock(blocking, seed, seed.size()); + if (length > 0) + { + SHA256 hash; + hash.Update(seed, seed.size()); + hash.Update(input, length); + hash.TruncatedFinal(seed, UnsignedMin(hash.DigestSize(), seed.size())); + } key = seed + BLOCK_CIPHER::BLOCKSIZE; } // check that seed and key don't have same value while (memcmp(key, seed, STDMIN((unsigned int)BLOCK_CIPHER::BLOCKSIZE, (unsigned int)BLOCK_CIPHER::DEFAULT_KEYLENGTH)) == 0); @@ -139,27 +137,13 @@ void AutoSeededX917RNG<BLOCK_CIPHER>::Reseed(bool blocking) Reseed(key, BLOCK_CIPHER::DEFAULT_KEYLENGTH, seed, NULL); } -template <class BLOCK_CIPHER> -byte AutoSeededX917RNG<BLOCK_CIPHER>::GenerateByte() -{ - byte b = m_rng->GenerateByte(); - - // for FIPS 140-2 - m_isDifferent = m_isDifferent || b != m_lastBlock[m_counter]; - m_lastBlock[m_counter] = b; - ++m_counter; - if (m_counter == m_lastBlock.size()) - { - if (!m_isDifferent) - throw SelfTestFailure("AutoSeededX917RNG: Continuous random number generator test failed."); - m_counter = 0; - m_isDifferent = false; - } +CRYPTOPP_DLL_TEMPLATE_CLASS AutoSeededX917RNG<AES>; - return b; -} - -CRYPTOPP_DLL_TEMPLATE_CLASS AutoSeededX917RNG<DES_EDE3>; +#if CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 +typedef AutoSeededX917RNG<AES> DefaultAutoSeededRNG; +#else +typedef AutoSeededRandomPool DefaultAutoSeededRNG; +#endif NAMESPACE_END @@ -3,6 +3,7 @@ #include "pch.h" #include "rng.h" +#include "fips140.h" #include <time.h> #include <math.h> @@ -35,19 +36,22 @@ const word16 LC_RNG::a=16807; const word16 LC_RNG::r=2836; #endif -byte LC_RNG::GenerateByte() +void LC_RNG::GenerateBlock(byte *output, size_t size) { - word32 hi = seed/q; - word32 lo = seed%q; + while (size--) + { + word32 hi = seed/q; + word32 lo = seed%q; - long test = a*lo - r*hi; + long test = a*lo - r*hi; - if (test > 0) - seed = test; - else - seed = test+ m; + if (test > 0) + seed = test; + else + seed = test+ m; - return (GETBYTE(seed, 0) ^ GETBYTE(seed, 1) ^ GETBYTE(seed, 2) ^ GETBYTE(seed, 3)); + *output++ = (GETBYTE(seed, 0) ^ GETBYTE(seed, 1) ^ GETBYTE(seed, 2) ^ GETBYTE(seed, 3)); + } } // ******************************************************** @@ -59,24 +63,26 @@ X917RNG::X917RNG(BlockTransformation *c, const byte *seed, const byte *determini S(cipher->BlockSize()), dtbuf(S), randseed(seed, S), - randbuf(S), - randbuf_counter(0), + m_lastBlock(S), m_deterministicTimeVector(deterministicTimeVector, deterministicTimeVector ? S : 0) { if (!deterministicTimeVector) { time_t tstamp1 = time(0); - xorbuf(dtbuf, (byte *)&tstamp1, STDMIN((int)sizeof(tstamp1), S)); + xorbuf(dtbuf, (byte *)&tstamp1, UnsignedMin(sizeof(tstamp1), S)); cipher->ProcessBlock(dtbuf); clock_t tstamp2 = clock(); - xorbuf(dtbuf, (byte *)&tstamp2, STDMIN((int)sizeof(tstamp2), S)); + xorbuf(dtbuf, (byte *)&tstamp2, UnsignedMin(sizeof(tstamp2), S)); cipher->ProcessBlock(dtbuf); } + + // for FIPS 140-2 + GenerateBlock(m_lastBlock, S); } -byte X917RNG::GenerateByte() +void X917RNG::GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword size) { - if (randbuf_counter==0) + while (size > 0) { // calculate new enciphered timestamp if (m_deterministicTimeVector.size()) @@ -86,8 +92,10 @@ byte X917RNG::GenerateByte() } else { - clock_t tstamp = clock(); - xorbuf(dtbuf, (byte *)&tstamp, STDMIN((int)sizeof(tstamp), S)); + clock_t c = clock(); + xorbuf(dtbuf, (byte *)&c, UnsignedMin(sizeof(c), S)); + time_t t = time(NULL); + xorbuf(dtbuf+S-UnsignedMin(sizeof(t), S), (byte *)&t, UnsignedMin(sizeof(t), S)); cipher->ProcessBlock(dtbuf); } @@ -95,16 +103,20 @@ byte X917RNG::GenerateByte() xorbuf(randseed, dtbuf, S); // generate a new block of random bytes - cipher->ProcessBlock(randseed, randbuf); + cipher->ProcessBlock(randseed); + if (memcmp(m_lastBlock, randseed, S) == 0) + throw SelfTestFailure("X917RNG: Continuous random number generator test failed."); + + // output random bytes + size_t len = UnsignedMin(size, S); + target.ChannelPut(channel, randseed, len); + size -= len; // compute new seed vector - for (int i=0; i<S; i++) - randseed[i] = randbuf[i] ^ dtbuf[i]; + memcpy(m_lastBlock, randseed, S); + xorbuf(randseed, dtbuf, S); cipher->ProcessBlock(randseed); - - randbuf_counter=S; } - return(randbuf[S-randbuf_counter--]); } #endif @@ -16,7 +16,7 @@ public: LC_RNG(word32 init_seed) : seed(init_seed) {} - byte GenerateByte(); + void GenerateBlock(byte *output, size_t size); word32 GetSeed() {return seed;} @@ -37,14 +37,13 @@ public: // cipher will be deleted by destructor, deterministicTimeVector = 0 means obtain time vector from system X917RNG(BlockTransformation *cipher, const byte *seed, const byte *deterministicTimeVector = 0); - byte GenerateByte(); + void GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword size); private: member_ptr<BlockTransformation> cipher; - const int S; // blocksize of cipher + unsigned int S; // blocksize of cipher SecByteBlock dtbuf; // buffer for enciphered timestamp - SecByteBlock randseed, randbuf, m_deterministicTimeVector; - int randbuf_counter; // # of unused bytes left in randbuf + SecByteBlock randseed, m_lastBlock, m_deterministicTimeVector; }; /** This class implements Maurer's Universal Statistical Test for Random Bit Generators |