summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorweidai <weidai@57ff6487-cd31-0410-9ec3-f628ee90f5f0>2007-05-04 15:04:58 +0000
committerweidai <weidai@57ff6487-cd31-0410-9ec3-f628ee90f5f0>2007-05-04 15:04:58 +0000
commitcdd57fd49c847250ce5d8e3cc39b7d882a529fc3 (patch)
treeaf7086b6bdb722b9a90c1abe0dd994166f32040b
parent061bcd669cf286d0043e1060bb36761df2df907e (diff)
downloadcryptopp-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.cpp76
-rw-r--r--hrtimer.h19
-rw-r--r--osrng.cpp16
-rw-r--r--osrng.h54
-rw-r--r--rng.cpp58
-rw-r--r--rng.h9
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
diff --git a/hrtimer.h b/hrtimer.h
index 03c4310..6bb8301 100644
--- a/hrtimer.h
+++ b/hrtimer.h
@@ -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
diff --git a/osrng.cpp b/osrng.cpp
index 52d1f53..fa6dd36 100644
--- a/osrng.cpp
+++ b/osrng.cpp
@@ -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
diff --git a/osrng.h b/osrng.h
index 448a905..2fa9713 100644
--- a/osrng.h
+++ b/osrng.h
@@ -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
diff --git a/rng.cpp b/rng.cpp
index 711f9a0..fb52a2b 100644
--- a/rng.cpp
+++ b/rng.cpp
@@ -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
diff --git a/rng.h b/rng.h
index 4d1fdca..2439dee 100644
--- a/rng.h
+++ b/rng.h
@@ -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