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)
|
||||
|
||||
//! \class MDC_Info
|
||||
//! \tparam B BlockCipher derived class
|
||||
//! \brief MDC_Info cipher information
|
||||
template <class T>
|
||||
struct MDC_Info : public FixedBlockSize<T::DIGESTSIZE>, public FixedKeyLength<T::BLOCKSIZE>
|
||||
template <class B>
|
||||
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
|
||||
//! \tparam T HashTransformation derived class
|
||||
//! \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>
|
||||
template <class T>
|
||||
class MDC : public MDC_Info<T>
|
||||
template <class H>
|
||||
class MDC : public MDC_Info<H>
|
||||
{
|
||||
//! \class Enc
|
||||
//! \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:
|
||||
void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms)
|
||||
{
|
||||
this->AssertValidKeyLength(length);
|
||||
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
|
||||
{
|
||||
T::CorrectEndianess(Buffer(), (HashWordType *)inBlock, this->BLOCKSIZE);
|
||||
T::Transform(Buffer(), Key());
|
||||
m_hash.CorrectEndianess(Buffer(), (HashWordType *)inBlock, this->BLOCKSIZE);
|
||||
H::Transform(Buffer(), Key());
|
||||
if (xorBlock)
|
||||
{
|
||||
T::CorrectEndianess(Buffer(), Buffer(), this->BLOCKSIZE);
|
||||
m_hash.CorrectEndianess(Buffer(), Buffer(), this->BLOCKSIZE);
|
||||
xorbuf(outBlock, xorBlock, m_buffer, this->BLOCKSIZE);
|
||||
}
|
||||
else
|
||||
T::CorrectEndianess((HashWordType *)outBlock, Buffer(), this->BLOCKSIZE);
|
||||
m_hash.CorrectEndianess((HashWordType *)outBlock, Buffer(), this->BLOCKSIZE);
|
||||
}
|
||||
|
||||
bool IsPermutation() const {return false;}
|
||||
|
|
@ -65,12 +65,13 @@ class MDC : public MDC_Info<T>
|
|||
HashWordType *Buffer() const {return (HashWordType *)m_buffer.data();}
|
||||
|
||||
// VC60 workaround: bug triggered if using FixedSizeAllocatorWithCleanup
|
||||
FixedSizeSecBlock<byte, MDC_Info<T>::KEYLENGTH, AllocatorWithCleanup<byte> > m_key;
|
||||
mutable FixedSizeSecBlock<byte, MDC_Info<T>::BLOCKSIZE, AllocatorWithCleanup<byte> > m_buffer;
|
||||
FixedSizeSecBlock<byte, MDC_Info<H>::KEYLENGTH, AllocatorWithCleanup<byte> > m_key;
|
||||
mutable FixedSizeSecBlock<byte, MDC_Info<H>::BLOCKSIZE, AllocatorWithCleanup<byte> > m_buffer;
|
||||
mutable H m_hash;
|
||||
};
|
||||
|
||||
public:
|
||||
//! use BlockCipher interface
|
||||
// use BlockCipher interface
|
||||
typedef BlockCipherFinal<ENCRYPTION, Enc> Encryption;
|
||||
};
|
||||
|
||||
|
|
|
|||
90
randpool.cpp
90
randpool.cpp
|
|
@ -12,7 +12,13 @@
|
|||
#include "aes.h"
|
||||
#include "sha.h"
|
||||
#include "hrtimer.h"
|
||||
#include <time.h>
|
||||
#include "trap.h"
|
||||
|
||||
// OldRandomPool
|
||||
#include "mdc.h"
|
||||
#include "modes.h"
|
||||
|
||||
#include <ctime>
|
||||
|
||||
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
|
||||
|
||||
#endif
|
||||
|
|
|
|||
67
randpool.h
67
randpool.h
|
|
@ -1,4 +1,5 @@
|
|||
// randpool.h - originally written and placed in the public domain by Wei Dai
|
||||
// OldRandPool added by JW in August, 2017.
|
||||
|
||||
//! \file randpool.h
|
||||
//! \brief Class file for Randomness Pool
|
||||
|
|
@ -9,20 +10,9 @@
|
|||
//! 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
|
||||
//! environment).
|
||||
//! \details If you need the pre-Crypto++ 5.5 generator then you can find it with:
|
||||
//! <pre>
|
||||
//! $ git clone https://github.com/weidai11/cryptopp cryptopp-ancient
|
||||
//! $ 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>
|
||||
//! \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)
|
||||
|
||||
#ifndef CRYPTOPP_RANDPOOL_H
|
||||
|
|
@ -45,6 +35,9 @@ NAMESPACE_BEGIN(CryptoPP)
|
|||
//! 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
|
||||
//! 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)
|
||||
class CRYPTOPP_DLL RandomPool : public RandomNumberGenerator, public NotCopyable
|
||||
{
|
||||
|
|
@ -56,7 +49,8 @@ public:
|
|||
void IncorporateEntropy(const byte *input, size_t length);
|
||||
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);}
|
||||
|
||||
private:
|
||||
|
|
@ -66,6 +60,49 @@ private:
|
|||
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
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in New Issue