// randpool.cpp - originally written and placed in the public domain by Wei Dai // RandomPool used to follow the design of randpool in PGP 2.6.x, // but as of version 5.5 it has been redesigned to reduce the risk // of reusing random numbers after state rollback (which may occur // when running in a virtual machine like VMware). #include "pch.h" #ifndef CRYPTOPP_IMPORTS #include "randpool.h" #include "aes.h" #include "sha.h" #include "hrtimer.h" #include "trap.h" // OldRandomPool #include "mdc.h" #include "modes.h" #include 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()); } void RandomPool::IncorporateEntropy(const byte *input, size_t length) { SHA256 hash; hash.Update(m_key, 32); hash.Update(input, length); hash.Final(m_key); m_keySet = false; } void RandomPool::GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword size) { if (size > 0) { if (!m_keySet) m_pCipher->SetKey(m_key, 32); CRYPTOPP_COMPILE_ASSERT(sizeof(TimerWord) <= 16); CRYPTOPP_COMPILE_ASSERT(sizeof(time_t) <= 8); Timer timer; TimerWord tw = timer.GetCurrentTimerValue(); *(TimerWord *)(void*)m_seed.data() += tw; time_t t = time(NULLPTR); // 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); // Wipe the intermediates *((volatile TimerWord*)&tw) = 0; *((volatile word64*)&tt1) = 0; *((volatile word64*)&tt2) = 0; do { m_pCipher->ProcessBlock(m_seed); size_t len = UnsignedMin(16, size); target.ChannelPut(channel, m_seed, len); size -= len; } while (size > 0); } } // OldRandomPool is provided for backwards compatibility for a migration path typedef MDC 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::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