bug fixes and KAT for X9.17 RNG
parent
0e0049180d
commit
deea52fd3b
|
|
@ -1,5 +1,5 @@
|
||||||
Crypto++: a C++ Class Library of Cryptographic Primitives
|
Crypto++: a C++ Class Library of Cryptographic Primitives
|
||||||
Version 5.0 9/11/2002
|
Version 5.1 (in development)
|
||||||
|
|
||||||
This library includes:
|
This library includes:
|
||||||
|
|
||||||
|
|
@ -241,3 +241,9 @@ History
|
||||||
- is being evaluated for FIPS 140-2 compliance
|
- is being evaluated for FIPS 140-2 compliance
|
||||||
- fixed a bug in HMAC::TruncatedFinal()
|
- fixed a bug in HMAC::TruncatedFinal()
|
||||||
- fixed SKIPJACK byte ordering following NIST clarification dated 5/9/02
|
- fixed SKIPJACK byte ordering following NIST clarification dated 5/9/02
|
||||||
|
|
||||||
|
5.01 (special FIPS 140-2 release, in development)
|
||||||
|
- added known answer test for X9.17 RNG in FIPS 140 power-up self test
|
||||||
|
|
||||||
|
5.1 (in development)
|
||||||
|
- fixed a bug in CBC and ECB modes with processing non-aligned data
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,11 @@
|
||||||
|
|
||||||
NAMESPACE_BEGIN(CryptoPP)
|
NAMESPACE_BEGIN(CryptoPP)
|
||||||
|
|
||||||
const std::type_info &g_typeidInteger = typeid(Integer);
|
const std::type_info & IntegerTypeId()
|
||||||
|
{
|
||||||
|
static const std::type_info &s_typeidInteger = typeid(Integer);
|
||||||
|
return s_typeidInteger;
|
||||||
|
}
|
||||||
|
|
||||||
void AssignIntToInteger(void *pInteger, const void *pInt)
|
void AssignIntToInteger(void *pInteger, const void *pInt)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -241,7 +241,7 @@ AssignFromHelperClass<T, T> AssignFromHelper(T *pObject, const NameValuePairs &s
|
||||||
|
|
||||||
void AssignIntToInteger(void *pInteger, const void *pInt);
|
void AssignIntToInteger(void *pInteger, const void *pInt);
|
||||||
|
|
||||||
extern const std::type_info &g_typeidInteger;
|
const std::type_info & IntegerTypeId();
|
||||||
|
|
||||||
template <class BASE, class T>
|
template <class BASE, class T>
|
||||||
class AlgorithmParameters : public NameValuePairs
|
class AlgorithmParameters : public NameValuePairs
|
||||||
|
|
@ -283,7 +283,7 @@ public:
|
||||||
else if (strcmp(name, m_name) == 0)
|
else if (strcmp(name, m_name) == 0)
|
||||||
{
|
{
|
||||||
// special case for retrieving an Integer parameter when an int was passed in
|
// special case for retrieving an Integer parameter when an int was passed in
|
||||||
if (valueType == g_typeidInteger && typeid(T) == typeid(int))
|
if (valueType == IntegerTypeId() && typeid(T) == typeid(int))
|
||||||
AssignIntToInteger(pValue, &m_value);
|
AssignIntToInteger(pValue, &m_value);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
classes that provide a uniform interface to this library.
|
classes that provide a uniform interface to this library.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*! \mainpage <a href="http://www.cryptopp.com">Crypto++</a><sup><small>TM</small></sup> Library 5.0 Reference Manual
|
/*! \mainpage <a href="http://www.cryptopp.com">Crypto++</a><sup><small>TM</small></sup> Library 5.1 Reference Manual
|
||||||
<dl>
|
<dl>
|
||||||
<dt>Abstract Base Classes<dd>
|
<dt>Abstract Base Classes<dd>
|
||||||
cryptlib.h
|
cryptlib.h
|
||||||
|
|
|
||||||
34
fipstest.cpp
34
fipstest.cpp
|
|
@ -23,6 +23,34 @@ NAMESPACE_BEGIN(CryptoPP)
|
||||||
|
|
||||||
extern PowerUpSelfTestStatus g_powerUpSelfTestStatus;
|
extern PowerUpSelfTestStatus g_powerUpSelfTestStatus;
|
||||||
|
|
||||||
|
void KnownAnswerTest(RandomNumberGenerator &rng, const char *output)
|
||||||
|
{
|
||||||
|
EqualityComparisonFilter comparison;
|
||||||
|
|
||||||
|
RandomNumberStore(rng, strlen(output)/2).TransferAllTo(comparison, "0");
|
||||||
|
StringSource(output, true, new HexDecoder(new ChannelSwitch(comparison, "1")));
|
||||||
|
|
||||||
|
comparison.ChannelMessageSeriesEnd("0");
|
||||||
|
comparison.ChannelMessageSeriesEnd("1");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class CIPHER>
|
||||||
|
void X917RNG_KnownAnswerTest(
|
||||||
|
const char *key,
|
||||||
|
const char *seed,
|
||||||
|
const char *output,
|
||||||
|
unsigned int deterministicTimeVector,
|
||||||
|
CIPHER *dummy = NULL)
|
||||||
|
{
|
||||||
|
std::string decodedKey, decodedSeed;
|
||||||
|
StringSource(key, true, new HexDecoder(new StringSink(decodedKey)));
|
||||||
|
StringSource(seed, true, new HexDecoder(new StringSink(decodedSeed)));
|
||||||
|
|
||||||
|
AutoSeededX917RNG<CIPHER> rng;
|
||||||
|
rng.Reseed((const byte *)decodedKey.data(), decodedKey.size(), (const byte *)decodedSeed.data(), deterministicTimeVector);
|
||||||
|
KnownAnswerTest(rng, output);
|
||||||
|
}
|
||||||
|
|
||||||
void KnownAnswerTest(StreamTransformation &encryption, StreamTransformation &decryption, const char *plaintext, const char *ciphertext)
|
void KnownAnswerTest(StreamTransformation &encryption, StreamTransformation &decryption, const char *plaintext, const char *ciphertext)
|
||||||
{
|
{
|
||||||
EqualityComparisonFilter comparison;
|
EqualityComparisonFilter comparison;
|
||||||
|
|
@ -208,6 +236,12 @@ void DoPowerUpSelfTest(const char *moduleFilename, const byte *expectedModuleSha
|
||||||
|
|
||||||
// algorithm tests
|
// algorithm tests
|
||||||
|
|
||||||
|
X917RNG_KnownAnswerTest<DES_EDE3>(
|
||||||
|
"48851090B4992453E83CDA86416534E53EA2FCE1A0B3A40C", // key
|
||||||
|
"7D00BD0A79F6B0F5", // seed
|
||||||
|
"22B590B08B53363AEB89AD65F81A5B6FB83F326CE06BF35751E6C41B43B729C4", // output
|
||||||
|
1489728269); // time vector
|
||||||
|
|
||||||
SymmetricEncryptionKnownAnswerTest<DES>(
|
SymmetricEncryptionKnownAnswerTest<DES>(
|
||||||
"0123456789abcdef", // key
|
"0123456789abcdef", // key
|
||||||
"1234567890abcdef", // IV
|
"1234567890abcdef", // IV
|
||||||
|
|
|
||||||
|
|
@ -144,11 +144,11 @@ void BlockOrientedCipherModeBase::ProcessData(byte *outString, const byte *inStr
|
||||||
unsigned int s = BlockSize();
|
unsigned int s = BlockSize();
|
||||||
assert(length % s == 0);
|
assert(length % s == 0);
|
||||||
unsigned int alignment = m_cipher->BlockAlignment();
|
unsigned int alignment = m_cipher->BlockAlignment();
|
||||||
bool requireAlignedInput = RequireAlignedInput();
|
bool inputAlignmentOk = !RequireAlignedInput() || IsAlignedOn(inString, alignment);
|
||||||
|
|
||||||
if (IsAlignedOn(outString, alignment))
|
if (IsAlignedOn(outString, alignment))
|
||||||
{
|
{
|
||||||
if (!requireAlignedInput || IsAlignedOn(inString, alignment))
|
if (inputAlignmentOk)
|
||||||
ProcessBlocks(outString, inString, length / s);
|
ProcessBlocks(outString, inString, length / s);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -160,7 +160,7 @@ void BlockOrientedCipherModeBase::ProcessData(byte *outString, const byte *inStr
|
||||||
{
|
{
|
||||||
while (length)
|
while (length)
|
||||||
{
|
{
|
||||||
if (!requireAlignedInput || IsAlignedOn(inString, alignment))
|
if (inputAlignmentOk)
|
||||||
ProcessBlocks(m_buffer, inString, 1);
|
ProcessBlocks(m_buffer, inString, 1);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -168,6 +168,8 @@ void BlockOrientedCipherModeBase::ProcessData(byte *outString, const byte *inStr
|
||||||
ProcessBlocks(m_buffer, m_buffer, 1);
|
ProcessBlocks(m_buffer, m_buffer, 1);
|
||||||
}
|
}
|
||||||
memcpy(outString, m_buffer, s);
|
memcpy(outString, m_buffer, s);
|
||||||
|
inString += s;
|
||||||
|
outString += s;
|
||||||
length -= s;
|
length -= s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
25
osrng.h
25
osrng.h
|
|
@ -96,6 +96,8 @@ public:
|
||||||
explicit AutoSeededX917RNG(bool blocking = false)
|
explicit AutoSeededX917RNG(bool blocking = false)
|
||||||
{Reseed(blocking);}
|
{Reseed(blocking);}
|
||||||
void Reseed(bool blocking = false);
|
void Reseed(bool blocking = false);
|
||||||
|
// exposed for testing
|
||||||
|
void Reseed(const byte *key, unsigned int keylength, const byte *seed, unsigned long timeVector);
|
||||||
|
|
||||||
byte GenerateByte();
|
byte GenerateByte();
|
||||||
|
|
||||||
|
|
@ -106,6 +108,20 @@ private:
|
||||||
unsigned int m_counter;
|
unsigned int m_counter;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <class BLOCK_CIPHER>
|
||||||
|
void AutoSeededX917RNG<BLOCK_CIPHER>::Reseed(const byte *key, unsigned int keylength, const byte *seed, unsigned long timeVector)
|
||||||
|
{
|
||||||
|
m_rng.reset(new X917RNG(new typename BLOCK_CIPHER::Encryption(key, keylength), seed, timeVector));
|
||||||
|
|
||||||
|
if (FIPS_140_2_ComplianceEnabled())
|
||||||
|
{
|
||||||
|
m_lastBlock.resize(16);
|
||||||
|
m_rng->GenerateBlock(m_lastBlock, m_lastBlock.size());
|
||||||
|
m_counter = 0;
|
||||||
|
m_isDifferent = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template <class BLOCK_CIPHER>
|
template <class BLOCK_CIPHER>
|
||||||
void AutoSeededX917RNG<BLOCK_CIPHER>::Reseed(bool blocking)
|
void AutoSeededX917RNG<BLOCK_CIPHER>::Reseed(bool blocking)
|
||||||
{
|
{
|
||||||
|
|
@ -117,15 +133,8 @@ void AutoSeededX917RNG<BLOCK_CIPHER>::Reseed(bool blocking)
|
||||||
key = seed + BLOCK_CIPHER::BLOCKSIZE;
|
key = seed + BLOCK_CIPHER::BLOCKSIZE;
|
||||||
} // check that seed and key don't have same value
|
} // 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);
|
while (memcmp(key, seed, STDMIN((unsigned int)BLOCK_CIPHER::BLOCKSIZE, (unsigned int)BLOCK_CIPHER::DEFAULT_KEYLENGTH)) == 0);
|
||||||
m_rng.reset(new X917RNG(new typename BLOCK_CIPHER::Encryption(key, BLOCK_CIPHER::DEFAULT_KEYLENGTH), seed));
|
|
||||||
|
|
||||||
if (FIPS_140_2_ComplianceEnabled())
|
Reseed(key, BLOCK_CIPHER::DEFAULT_KEYLENGTH, seed, 0);
|
||||||
{
|
|
||||||
m_lastBlock.resize(16);
|
|
||||||
m_rng->GenerateBlock(m_lastBlock, m_lastBlock.size());
|
|
||||||
m_counter = 0;
|
|
||||||
m_isDifferent = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class BLOCK_CIPHER>
|
template <class BLOCK_CIPHER>
|
||||||
|
|
|
||||||
37
rng.cpp
37
rng.cpp
|
|
@ -51,20 +51,29 @@ byte LC_RNG::GenerateByte()
|
||||||
|
|
||||||
// ********************************************************
|
// ********************************************************
|
||||||
|
|
||||||
X917RNG::X917RNG(BlockTransformation *c, const byte *seed)
|
X917RNG::X917RNG(BlockTransformation *c, const byte *seed, unsigned long deterministicTimeVector)
|
||||||
: cipher(c),
|
: cipher(c),
|
||||||
S(cipher->BlockSize()),
|
S(cipher->BlockSize()),
|
||||||
dtbuf(S),
|
dtbuf(S),
|
||||||
randseed(seed, S),
|
randseed(seed, S),
|
||||||
randbuf(S),
|
randbuf(S),
|
||||||
randbuf_counter(0)
|
randbuf_counter(0),
|
||||||
|
m_deterministicTimeVector(deterministicTimeVector)
|
||||||
{
|
{
|
||||||
time_t tstamp1 = time(0);
|
if (m_deterministicTimeVector)
|
||||||
xorbuf(dtbuf, (byte *)&tstamp1, STDMIN((int)sizeof(tstamp1), S));
|
{
|
||||||
cipher->ProcessBlock(dtbuf);
|
memset(dtbuf, 0, S);
|
||||||
clock_t tstamp2 = clock();
|
memcpy(dtbuf, (byte *)&m_deterministicTimeVector, STDMIN((int)sizeof(m_deterministicTimeVector), S));
|
||||||
xorbuf(dtbuf, (byte *)&tstamp2, STDMIN((int)sizeof(tstamp2), S));
|
}
|
||||||
cipher->ProcessBlock(dtbuf);
|
else
|
||||||
|
{
|
||||||
|
time_t tstamp1 = time(0);
|
||||||
|
xorbuf(dtbuf, (byte *)&tstamp1, STDMIN((int)sizeof(tstamp1), S));
|
||||||
|
cipher->ProcessBlock(dtbuf);
|
||||||
|
clock_t tstamp2 = clock();
|
||||||
|
xorbuf(dtbuf, (byte *)&tstamp2, STDMIN((int)sizeof(tstamp2), S));
|
||||||
|
cipher->ProcessBlock(dtbuf);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
byte X917RNG::GenerateByte()
|
byte X917RNG::GenerateByte()
|
||||||
|
|
@ -72,8 +81,16 @@ byte X917RNG::GenerateByte()
|
||||||
if (randbuf_counter==0)
|
if (randbuf_counter==0)
|
||||||
{
|
{
|
||||||
// calculate new enciphered timestamp
|
// calculate new enciphered timestamp
|
||||||
clock_t tstamp = clock();
|
if (m_deterministicTimeVector)
|
||||||
xorbuf(dtbuf, (byte *)&tstamp, STDMIN((int)sizeof(tstamp), S));
|
{
|
||||||
|
xorbuf(dtbuf, (byte *)&m_deterministicTimeVector, STDMIN((int)sizeof(m_deterministicTimeVector), S));
|
||||||
|
while (++m_deterministicTimeVector == 0) {} // skip 0
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
clock_t tstamp = clock();
|
||||||
|
xorbuf(dtbuf, (byte *)&tstamp, STDMIN((int)sizeof(tstamp), S));
|
||||||
|
}
|
||||||
cipher->ProcessBlock(dtbuf);
|
cipher->ProcessBlock(dtbuf);
|
||||||
|
|
||||||
// combine enciphered timestamp with seed
|
// combine enciphered timestamp with seed
|
||||||
|
|
|
||||||
5
rng.h
5
rng.h
|
|
@ -32,8 +32,8 @@ private:
|
||||||
class X917RNG : public RandomNumberGenerator
|
class X917RNG : public RandomNumberGenerator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// cipher will be deleted by destructor
|
// cipher will be deleted by destructor, deterministicTimeVector = 0 means obtain time vector from system
|
||||||
X917RNG(BlockTransformation *cipher, const byte *seed);
|
X917RNG(BlockTransformation *cipher, const byte *seed, unsigned long deterministicTimeVector = 0);
|
||||||
|
|
||||||
byte GenerateByte();
|
byte GenerateByte();
|
||||||
|
|
||||||
|
|
@ -43,6 +43,7 @@ private:
|
||||||
SecByteBlock dtbuf; // buffer for enciphered timestamp
|
SecByteBlock dtbuf; // buffer for enciphered timestamp
|
||||||
SecByteBlock randseed, randbuf;
|
SecByteBlock randseed, randbuf;
|
||||||
int randbuf_counter; // # of unused bytes left in randbuf
|
int randbuf_counter; // # of unused bytes left in randbuf
|
||||||
|
unsigned long m_deterministicTimeVector;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** This class implements Maurer's Universal Statistical Test for Random Bit Generators
|
/** This class implements Maurer's Universal Statistical Test for Random Bit Generators
|
||||||
|
|
|
||||||
|
|
@ -226,7 +226,7 @@ bool TestOS_RNG()
|
||||||
member_ptr<RandomNumberGenerator> rng;
|
member_ptr<RandomNumberGenerator> rng;
|
||||||
#ifdef BLOCKING_RNG_AVAILABLE
|
#ifdef BLOCKING_RNG_AVAILABLE
|
||||||
try {rng.reset(new BlockingRng);}
|
try {rng.reset(new BlockingRng);}
|
||||||
catch (OS_RNG_Err &e) {}
|
catch (OS_RNG_Err &) {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (rng.get())
|
if (rng.get())
|
||||||
|
|
@ -304,7 +304,7 @@ bool TestOS_RNG()
|
||||||
rng.reset(NULL);
|
rng.reset(NULL);
|
||||||
#ifdef NONBLOCKING_RNG_AVAILABLE
|
#ifdef NONBLOCKING_RNG_AVAILABLE
|
||||||
try {rng.reset(new NonblockingRng);}
|
try {rng.reset(new NonblockingRng);}
|
||||||
catch (OS_RNG_Err &e) {}
|
catch (OS_RNG_Err &) {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (rng.get())
|
if (rng.get())
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue