Sync with Upstream master
commit
460d7e47dc
36
mdc.h
36
mdc.h
|
|
@ -13,46 +13,47 @@
|
|||
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)
|
||||
{
|
||||
CRYPTOPP_UNUSED(params);
|
||||
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 +66,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;
|
||||
};
|
||||
|
||||
|
|
|
|||
99
randpool.cpp
99
randpool.cpp
|
|
@ -12,15 +12,21 @@
|
|||
#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)
|
||||
|
||||
RandomPool::RandomPool()
|
||||
: m_pCipher(new AES::Encryption), m_keySet(false)
|
||||
{
|
||||
memset(m_key, 0, m_key.SizeInBytes());
|
||||
memset(m_seed, 0, m_seed.SizeInBytes());
|
||||
::memset(m_key, 0, m_key.SizeInBytes());
|
||||
::memset(m_seed, 0, m_seed.SizeInBytes());
|
||||
}
|
||||
|
||||
void RandomPool::IncorporateEntropy(const byte *input, size_t length)
|
||||
|
|
@ -51,8 +57,8 @@ void RandomPool::GenerateIntoBufferedTransformation(BufferedTransformation &targ
|
|||
// UBsan finding: signed integer overflow: 1876017710 + 1446085457 cannot be represented in type 'long int'
|
||||
// *(time_t *)(m_seed.data()+8) += t;
|
||||
word64 tt1 = 0, tt2 = (word64)t;
|
||||
memcpy(&tt1, m_seed.data()+8, 8);
|
||||
memcpy(m_seed.data()+8, &(tt2 += tt1), 8);
|
||||
::memcpy(&tt1, m_seed.data()+8, 8);
|
||||
::memcpy(m_seed.data()+8, &(tt2 += tt1), 8);
|
||||
|
||||
// Wipe the intermediates
|
||||
*((volatile TimerWord*)&tw) = 0;
|
||||
|
|
@ -69,6 +75,89 @@ 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)
|
||||
{
|
||||
CRYPTOPP_UNUSED(messageEnd); CRYPTOPP_UNUSED(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
|
||||
|
|
|
|||
69
randpool.h
69
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,51 @@ 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
|
||||
{
|
||||
CRYPTOPP_UNUSED(target); CRYPTOPP_UNUSED(begin); CRYPTOPP_UNUSED(end);
|
||||
CRYPTOPP_UNUSED(channel); CRYPTOPP_UNUSED(blocking);
|
||||
throw NotImplemented("OldRandomPool: CopyRangeTo2() is not supported by this store");
|
||||
}
|
||||
|
||||
byte GenerateByte();
|
||||
void GenerateBlock(byte *output, size_t size);
|
||||
|
||||
void IsolatedInitialize(const NameValuePairs ¶meters) {CRYPTOPP_UNUSED(parameters);}
|
||||
|
||||
protected:
|
||||
void Stir();
|
||||
|
||||
private:
|
||||
SecByteBlock pool, key;
|
||||
size_t addPos, getPos;
|
||||
};
|
||||
|
||||
NAMESPACE_END
|
||||
|
||||
#endif
|
||||
|
|
|
|||
109
validat1.cpp
109
validat1.cpp
|
|
@ -718,6 +718,115 @@ bool TestRandomPool()
|
|||
}
|
||||
#endif
|
||||
|
||||
// Old, PGP 2.6 style RandomPool. Added because users were still having problems
|
||||
// with it in 2017. The missing functionality was a barrier to upgrades.
|
||||
std::cout << "\nTesting OldRandomPool generator...\n\n";
|
||||
{
|
||||
OldRandomPool prng;
|
||||
static const unsigned int ENTROPY_SIZE = 32;
|
||||
|
||||
// https://github.com/weidai11/cryptopp/issues/452
|
||||
byte result[32], expected[32] = {
|
||||
0x58,0x3E,0x0A,0xAC,0x79,0x71,0x19,0x18,
|
||||
0x51,0x97,0xC6,0x9B,0xEF,0x82,0x18,0x1E,
|
||||
0x9C,0x0F,0x5C,0xEF,0xC7,0x89,0xB2,0x94,
|
||||
0x04,0x96,0xD6,0xD9,0xA4,0x3B,0xB7,0xEC
|
||||
};
|
||||
|
||||
SecByteBlock seed(0x00, 384);
|
||||
prng.Put(seed, seed.size());
|
||||
|
||||
prng.GenerateBlock(result, sizeof(result));
|
||||
fail = (0 != ::memcmp(result, expected, sizeof(expected)));
|
||||
|
||||
pass &= !fail;
|
||||
if (fail)
|
||||
std::cout << "FAILED:";
|
||||
else
|
||||
std::cout << "passed:";
|
||||
std::cout << " Expected sequence from PGP-style RandomPool (2007 version)\n";
|
||||
|
||||
MeterFilter meter(new Redirector(TheBitBucket()));
|
||||
RandomNumberSource test(prng, 100000, true, new Deflator(new Redirector(meter)));
|
||||
|
||||
fail = false;
|
||||
if (meter.GetTotalBytes() < 100000)
|
||||
fail = true;
|
||||
|
||||
pass &= !fail;
|
||||
if (fail)
|
||||
std::cout << "FAILED:";
|
||||
else
|
||||
std::cout << "passed:";
|
||||
std::cout << " 100000 generated bytes compressed to " << meter.GetTotalBytes() << " bytes by DEFLATE\n";
|
||||
|
||||
try
|
||||
{
|
||||
fail = false;
|
||||
prng.DiscardBytes(100000);
|
||||
}
|
||||
catch (const Exception&)
|
||||
{
|
||||
fail = true;
|
||||
}
|
||||
|
||||
pass &= !fail;
|
||||
if (fail)
|
||||
std::cout << "FAILED:";
|
||||
else
|
||||
std::cout << "passed:";
|
||||
std::cout << " discarded 10000 bytes" << std::endl;
|
||||
|
||||
try
|
||||
{
|
||||
fail = false;
|
||||
if(prng.CanIncorporateEntropy())
|
||||
{
|
||||
SecByteBlock entropy(ENTROPY_SIZE);
|
||||
GlobalRNG().GenerateBlock(entropy, entropy.SizeInBytes());
|
||||
|
||||
prng.IncorporateEntropy(entropy, entropy.SizeInBytes());
|
||||
prng.IncorporateEntropy(entropy, entropy.SizeInBytes());
|
||||
prng.IncorporateEntropy(entropy, entropy.SizeInBytes());
|
||||
prng.IncorporateEntropy(entropy, entropy.SizeInBytes());
|
||||
}
|
||||
}
|
||||
catch (const Exception& /*ex*/)
|
||||
{
|
||||
fail = true;
|
||||
}
|
||||
|
||||
pass &= !fail;
|
||||
if (fail)
|
||||
std::cout << "FAILED:";
|
||||
else
|
||||
std::cout << "passed:";
|
||||
std::cout << " IncorporateEntropy with " << 4*ENTROPY_SIZE << " bytes\n";
|
||||
|
||||
try
|
||||
{
|
||||
// Miscellaneous for code coverage
|
||||
fail = false;
|
||||
word32 result = prng.GenerateWord32();
|
||||
result = prng.GenerateWord32((result & 0xff), 0xffffffff - (result & 0xff));
|
||||
prng.GenerateBlock(reinterpret_cast<byte*>(&result), 4);
|
||||
prng.GenerateBlock(reinterpret_cast<byte*>(&result), 3);
|
||||
prng.GenerateBlock(reinterpret_cast<byte*>(&result), 2);
|
||||
prng.GenerateBlock(reinterpret_cast<byte*>(&result), 1);
|
||||
}
|
||||
catch (const Exception&)
|
||||
{
|
||||
fail = true;
|
||||
}
|
||||
|
||||
pass &= !fail;
|
||||
if (fail)
|
||||
std::cout << "FAILED:";
|
||||
else
|
||||
std::cout << "passed:";
|
||||
std::cout << " GenerateWord32 and Crop\n";
|
||||
}
|
||||
|
||||
return pass;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue