Add OldRandomPool class (Issue 452)
RandomPool used to be a PGP-style deterministic generator and folks used it as a key generation function. At Crypto++ 5.5 the design changed to harden it agianst rollback attacks. The design change resulted in an upgrade barrier. That is, some folks are stuck at Crypto++ 4.2 or Crypto++ 5.2 because they must interoperate with existing software.
Below is the test program we used for the test vector. It was run against Crypto++ 5.4.
RandomPool prng;
SecByteBlock seed(0x00, 384), result(64);
prng.Put(seed, seed.size());
prng.GenerateBlock(result, result.size());
HexEncoder encoder(new FileSink(std::cout));
std::cout << "RandomPool: ";
encoder.Put(result, sizeof(result));
std::cout << std::endl;
pull/461/head
parent
2171a3a379
commit
02e3a79444
35
mdc.h
35
mdc.h
|
|
@ -13,46 +13,46 @@
|
||||||
NAMESPACE_BEGIN(CryptoPP)
|
NAMESPACE_BEGIN(CryptoPP)
|
||||||
|
|
||||||
//! \class MDC_Info
|
//! \class MDC_Info
|
||||||
|
//! \tparam B BlockCipher derived class
|
||||||
//! \brief MDC_Info cipher information
|
//! \brief MDC_Info cipher information
|
||||||
template <class T>
|
template <class B>
|
||||||
struct MDC_Info : public FixedBlockSize<T::DIGESTSIZE>, public FixedKeyLength<T::BLOCKSIZE>
|
struct MDC_Info : public FixedBlockSize<B::DIGESTSIZE>, public FixedKeyLength<B::BLOCKSIZE>
|
||||||
{
|
{
|
||||||
static std::string StaticAlgorithmName() {return std::string("MDC/")+T::StaticAlgorithmName();}
|
static std::string StaticAlgorithmName() {return std::string("MDC/")+B::StaticAlgorithmName();}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//! \class MDC
|
|
||||||
//! \brief MDC cipher
|
//! \brief MDC cipher
|
||||||
|
//! \tparam T HashTransformation derived class
|
||||||
//! \details MDC() is a construction by Peter Gutmann to turn an iterated hash function into a PRF
|
//! \details MDC() is a construction by Peter Gutmann to turn an iterated hash function into a PRF
|
||||||
//! \sa <a href="http://www.weidai.com/scan-mirror/cs.html#MDC">MDC</a>
|
//! \sa <a href="http://www.weidai.com/scan-mirror/cs.html#MDC">MDC</a>
|
||||||
template <class T>
|
template <class H>
|
||||||
class MDC : public MDC_Info<T>
|
class MDC : public MDC_Info<H>
|
||||||
{
|
{
|
||||||
//! \class Enc
|
//! \class Enc
|
||||||
//! \brief MDC cipher encryption operation
|
//! \brief MDC cipher encryption operation
|
||||||
class CRYPTOPP_NO_VTABLE Enc : public BlockCipherImpl<MDC_Info<T> >
|
class CRYPTOPP_NO_VTABLE Enc : public BlockCipherImpl<MDC_Info<H> >
|
||||||
{
|
{
|
||||||
typedef typename T::HashWordType HashWordType;
|
typedef typename H::HashWordType HashWordType;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms)
|
void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms)
|
||||||
{
|
{
|
||||||
this->AssertValidKeyLength(length);
|
this->AssertValidKeyLength(length);
|
||||||
memcpy_s(m_key, m_key.size(), userKey, this->KEYLENGTH);
|
memcpy_s(m_key, m_key.size(), userKey, this->KEYLENGTH);
|
||||||
T::CorrectEndianess(Key(), Key(), this->KEYLENGTH);
|
m_hash.CorrectEndianess(Key(), Key(), this->KEYLENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const
|
void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const
|
||||||
{
|
{
|
||||||
T::CorrectEndianess(Buffer(), (HashWordType *)inBlock, this->BLOCKSIZE);
|
m_hash.CorrectEndianess(Buffer(), (HashWordType *)inBlock, this->BLOCKSIZE);
|
||||||
T::Transform(Buffer(), Key());
|
H::Transform(Buffer(), Key());
|
||||||
if (xorBlock)
|
if (xorBlock)
|
||||||
{
|
{
|
||||||
T::CorrectEndianess(Buffer(), Buffer(), this->BLOCKSIZE);
|
m_hash.CorrectEndianess(Buffer(), Buffer(), this->BLOCKSIZE);
|
||||||
xorbuf(outBlock, xorBlock, m_buffer, this->BLOCKSIZE);
|
xorbuf(outBlock, xorBlock, m_buffer, this->BLOCKSIZE);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
T::CorrectEndianess((HashWordType *)outBlock, Buffer(), this->BLOCKSIZE);
|
m_hash.CorrectEndianess((HashWordType *)outBlock, Buffer(), this->BLOCKSIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsPermutation() const {return false;}
|
bool IsPermutation() const {return false;}
|
||||||
|
|
@ -65,12 +65,13 @@ class MDC : public MDC_Info<T>
|
||||||
HashWordType *Buffer() const {return (HashWordType *)m_buffer.data();}
|
HashWordType *Buffer() const {return (HashWordType *)m_buffer.data();}
|
||||||
|
|
||||||
// VC60 workaround: bug triggered if using FixedSizeAllocatorWithCleanup
|
// VC60 workaround: bug triggered if using FixedSizeAllocatorWithCleanup
|
||||||
FixedSizeSecBlock<byte, MDC_Info<T>::KEYLENGTH, AllocatorWithCleanup<byte> > m_key;
|
FixedSizeSecBlock<byte, MDC_Info<H>::KEYLENGTH, AllocatorWithCleanup<byte> > m_key;
|
||||||
mutable FixedSizeSecBlock<byte, MDC_Info<T>::BLOCKSIZE, AllocatorWithCleanup<byte> > m_buffer;
|
mutable FixedSizeSecBlock<byte, MDC_Info<H>::BLOCKSIZE, AllocatorWithCleanup<byte> > m_buffer;
|
||||||
|
mutable H m_hash;
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
//! use BlockCipher interface
|
// use BlockCipher interface
|
||||||
typedef BlockCipherFinal<ENCRYPTION, Enc> Encryption;
|
typedef BlockCipherFinal<ENCRYPTION, Enc> Encryption;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
90
randpool.cpp
90
randpool.cpp
|
|
@ -12,7 +12,13 @@
|
||||||
#include "aes.h"
|
#include "aes.h"
|
||||||
#include "sha.h"
|
#include "sha.h"
|
||||||
#include "hrtimer.h"
|
#include "hrtimer.h"
|
||||||
#include <time.h>
|
#include "trap.h"
|
||||||
|
|
||||||
|
// OldRandomPool
|
||||||
|
#include "mdc.h"
|
||||||
|
#include "modes.h"
|
||||||
|
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
NAMESPACE_BEGIN(CryptoPP)
|
NAMESPACE_BEGIN(CryptoPP)
|
||||||
|
|
||||||
|
|
@ -69,6 +75,88 @@ void RandomPool::GenerateIntoBufferedTransformation(BufferedTransformation &targ
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OldRandomPool is provided for backwards compatibility for a migration path
|
||||||
|
typedef MDC<SHA1> OldRandomPoolCipher;
|
||||||
|
|
||||||
|
OldRandomPool::OldRandomPool(unsigned int poolSize)
|
||||||
|
: pool(poolSize), key(OldRandomPoolCipher::DEFAULT_KEYLENGTH), addPos(0), getPos(poolSize)
|
||||||
|
{
|
||||||
|
CRYPTOPP_ASSERT(poolSize > key.size());
|
||||||
|
memset(pool, 0, poolSize);
|
||||||
|
memset(key, 0, key.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void OldRandomPool::Stir()
|
||||||
|
{
|
||||||
|
CFB_Mode<OldRandomPoolCipher>::Encryption cipher;
|
||||||
|
|
||||||
|
for (int i=0; i<2; i++)
|
||||||
|
{
|
||||||
|
cipher.SetKeyWithIV(key, key.size(), pool.end()-cipher.IVSize());
|
||||||
|
cipher.ProcessString(pool, pool.size());
|
||||||
|
memcpy(key, pool, key.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
addPos = 0;
|
||||||
|
getPos = key.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t OldRandomPool::Put2(const byte *inString, size_t length, int messageEnd, bool blocking)
|
||||||
|
{
|
||||||
|
size_t t;
|
||||||
|
|
||||||
|
while (length > (t = pool.size() - addPos))
|
||||||
|
{
|
||||||
|
xorbuf(pool+addPos, inString, t);
|
||||||
|
inString += t;
|
||||||
|
length -= t;
|
||||||
|
Stir();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length)
|
||||||
|
{
|
||||||
|
xorbuf(pool+addPos, inString, length);
|
||||||
|
addPos += length;
|
||||||
|
getPos = pool.size(); // Force stir on get
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t OldRandomPool::TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel, bool blocking)
|
||||||
|
{
|
||||||
|
if (!blocking)
|
||||||
|
throw NotImplemented("OldRandomPool: nonblocking transfer is not implemented by this object");
|
||||||
|
|
||||||
|
lword size = transferBytes;
|
||||||
|
|
||||||
|
while (size > 0)
|
||||||
|
{
|
||||||
|
if (getPos == pool.size())
|
||||||
|
Stir();
|
||||||
|
size_t t = UnsignedMin(pool.size() - getPos, size);
|
||||||
|
target.ChannelPut(channel, pool+getPos, t);
|
||||||
|
size -= t;
|
||||||
|
getPos += t;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte OldRandomPool::GenerateByte()
|
||||||
|
{
|
||||||
|
if (getPos == pool.size())
|
||||||
|
Stir();
|
||||||
|
|
||||||
|
return pool[getPos++];
|
||||||
|
}
|
||||||
|
|
||||||
|
void OldRandomPool::GenerateBlock(byte *outString, size_t size)
|
||||||
|
{
|
||||||
|
ArraySink sink(outString, size);
|
||||||
|
TransferTo(sink, size);
|
||||||
|
}
|
||||||
|
|
||||||
NAMESPACE_END
|
NAMESPACE_END
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
67
randpool.h
67
randpool.h
|
|
@ -1,4 +1,5 @@
|
||||||
// randpool.h - originally written and placed in the public domain by Wei Dai
|
// randpool.h - originally written and placed in the public domain by Wei Dai
|
||||||
|
// OldRandPool added by JW in August, 2017.
|
||||||
|
|
||||||
//! \file randpool.h
|
//! \file randpool.h
|
||||||
//! \brief Class file for Randomness Pool
|
//! \brief Class file for Randomness Pool
|
||||||
|
|
@ -9,20 +10,9 @@
|
||||||
//! RandomPool was redesigned to reduce the risk of reusing random numbers after state
|
//! RandomPool was redesigned to reduce the risk of reusing random numbers after state
|
||||||
//! rollback (which may occur when running in a virtual machine like VMware or a hosted
|
//! rollback (which may occur when running in a virtual machine like VMware or a hosted
|
||||||
//! environment).
|
//! environment).
|
||||||
//! \details If you need the pre-Crypto++ 5.5 generator then you can find it with:
|
//! \details If you need the pre-Crypto++ 5.5 generator then use OldRandomPool class. You
|
||||||
//! <pre>
|
//! should migrate away from OldRandomPool at the earliest opportunity. Use RandomPool
|
||||||
//! $ git clone https://github.com/weidai11/cryptopp cryptopp-ancient
|
//! or AutoSeededRandomPool instead.
|
||||||
//! $ cryptopp-ancient
|
|
||||||
//!
|
|
||||||
//! # Checkout the RandomPool change
|
|
||||||
//! $ git checkout f41245df6fb9b85574260eca9cd32777e8ab5136
|
|
||||||
//!
|
|
||||||
//! # Go back one more
|
|
||||||
//! git checkout HEAD~1
|
|
||||||
//!
|
|
||||||
//! $ grep 'MDC<SHA1>' *.h *.cpp
|
|
||||||
//! randpool.cpp:typedef MDC<SHA1> RandomPoolCipher;
|
|
||||||
//! </pre>
|
|
||||||
//! \since Crypto++ 4.0 (PGP 2.6.x style), Crypto++ 5.5 (AES-256 based)
|
//! \since Crypto++ 4.0 (PGP 2.6.x style), Crypto++ 5.5 (AES-256 based)
|
||||||
|
|
||||||
#ifndef CRYPTOPP_RANDPOOL_H
|
#ifndef CRYPTOPP_RANDPOOL_H
|
||||||
|
|
@ -45,6 +35,9 @@ NAMESPACE_BEGIN(CryptoPP)
|
||||||
//! RandomPool was redesigned to reduce the risk of reusing random numbers after state
|
//! RandomPool was redesigned to reduce the risk of reusing random numbers after state
|
||||||
//! rollback (which may occur when running in a virtual machine like VMware or a hosted
|
//! rollback (which may occur when running in a virtual machine like VMware or a hosted
|
||||||
//! environment).
|
//! environment).
|
||||||
|
//! \details If you need the pre-Crypto++ 5.5 generator then use OldRandomPool class. You
|
||||||
|
//! should migrate away from OldRandomPool at the earliest opportunity. Use RandomPool
|
||||||
|
//! or AutoSeededRandomPool instead.
|
||||||
//! \since Crypto++ 4.0 (PGP 2.6.x style), Crypto++ 5.5 (AES-256 based)
|
//! \since Crypto++ 4.0 (PGP 2.6.x style), Crypto++ 5.5 (AES-256 based)
|
||||||
class CRYPTOPP_DLL RandomPool : public RandomNumberGenerator, public NotCopyable
|
class CRYPTOPP_DLL RandomPool : public RandomNumberGenerator, public NotCopyable
|
||||||
{
|
{
|
||||||
|
|
@ -56,7 +49,8 @@ public:
|
||||||
void IncorporateEntropy(const byte *input, size_t length);
|
void IncorporateEntropy(const byte *input, size_t length);
|
||||||
void GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword size);
|
void GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword size);
|
||||||
|
|
||||||
// for backwards compatibility. use RandomNumberSource, RandomNumberStore, and RandomNumberSink for other BufferTransformation functionality
|
// for backwards compatibility. use RandomNumberSource, RandomNumberStore, and
|
||||||
|
// RandomNumberSink for other BufferTransformation functionality
|
||||||
void Put(const byte *input, size_t length) {IncorporateEntropy(input, length);}
|
void Put(const byte *input, size_t length) {IncorporateEntropy(input, length);}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -66,6 +60,49 @@ private:
|
||||||
bool m_keySet;
|
bool m_keySet;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//! \class OldRandomPool
|
||||||
|
//! \brief Randomness Pool based on PGP 2.6.x with MDC
|
||||||
|
//! \details If you need the pre-Crypto++ 5.5 generator then use OldRandomPool class. The
|
||||||
|
//! OldRandomPool class is always available so you dont need to define
|
||||||
|
//! CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY. However, you should migrate away from
|
||||||
|
//! OldRandomPool at the earliest opportunity. Use RandomPool or AutoSeededRandomPool instead.
|
||||||
|
//! \deprecated This class uses an old style PGP 2.6.x with MDC. The generator risks reusing
|
||||||
|
//! random random numbers after state rollback. Migrate to RandomPool or AutoSeededRandomPool
|
||||||
|
//! at the earliest opportunity.
|
||||||
|
//! \since Crypto++ 6.0 (PGP 2.6.x style)
|
||||||
|
class CRYPTOPP_DLL OldRandomPool : public RandomNumberGenerator,
|
||||||
|
public Bufferless<BufferedTransformation>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//! \brief Construct an OldRandomPool
|
||||||
|
//! \param poolSize internal pool size of the generator
|
||||||
|
//! \details poolSize must be greater than 16
|
||||||
|
OldRandomPool(unsigned int poolSize=384);
|
||||||
|
|
||||||
|
size_t Put2(const byte *begin, size_t length, int messageEnd, bool blocking);
|
||||||
|
|
||||||
|
bool AnyRetrievable() const {return true;}
|
||||||
|
lword MaxRetrievable() const {return ULONG_MAX;}
|
||||||
|
|
||||||
|
size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true);
|
||||||
|
size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const
|
||||||
|
{
|
||||||
|
throw NotImplemented("OldRandomPool: CopyRangeTo2() is not supported by this store");
|
||||||
|
}
|
||||||
|
|
||||||
|
byte GenerateByte();
|
||||||
|
void GenerateBlock(byte *output, size_t size);
|
||||||
|
|
||||||
|
void IsolatedInitialize(const NameValuePairs ¶meters) {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void Stir();
|
||||||
|
|
||||||
|
private:
|
||||||
|
SecByteBlock pool, key;
|
||||||
|
size_t addPos, getPos;
|
||||||
|
};
|
||||||
|
|
||||||
NAMESPACE_END
|
NAMESPACE_END
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue