1 // randpool.cpp - originally written and placed in the public domain by Wei Dai
2 // RandomPool used to follow the design of randpool in PGP 2.6.x,
3 // but as of version 5.5 it has been redesigned to reduce the risk
4 // of reusing random numbers after state rollback (which may occur
5 // when running in a virtual machine like VMware).
6 
7 #include "pch.h"
8 
9 #ifndef CRYPTOPP_IMPORTS
10 
11 #include "randpool.h"
12 #include "aes.h"
13 #include "sha.h"
14 #include "hrtimer.h"
15 #include "trap.h"
16 
17 // OldRandomPool
18 #include "mdc.h"
19 #include "modes.h"
20 
21 #include <time.h>
22 
NAMESPACE_BEGIN(CryptoPP)23 NAMESPACE_BEGIN(CryptoPP)
24 
25 RandomPool::RandomPool()
26 	: m_pCipher(new AES::Encryption), m_keySet(false)
27 {
28 	std::memset(m_key, 0, m_key.SizeInBytes());
29 	std::memset(m_seed, 0, m_seed.SizeInBytes());
30 }
31 
IncorporateEntropy(const byte * input,size_t length)32 void RandomPool::IncorporateEntropy(const byte *input, size_t length)
33 {
34 	SHA256 hash;
35 	hash.Update(m_key, 32);
36 	hash.Update(input, length);
37 	hash.Final(m_key);
38 	m_keySet = false;
39 }
40 
GenerateIntoBufferedTransformation(BufferedTransformation & target,const std::string & channel,lword size)41 void RandomPool::GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword size)
42 {
43 	if (size > 0)
44 	{
45 		if (!m_keySet)
46 			m_pCipher->SetKey(m_key, 32);
47 
48 		CRYPTOPP_COMPILE_ASSERT(sizeof(TimerWord) <= 16);
49 		CRYPTOPP_COMPILE_ASSERT(sizeof(time_t) <= 8);
50 
51 		Timer timer;
52 		TimerWord tw = timer.GetCurrentTimerValue();
53 
54 		*(TimerWord *)(void*)m_seed.data() += tw;
55 		time_t t = time(NULLPTR);
56 
57 		// UBsan finding: signed integer overflow: 1876017710 + 1446085457 cannot be represented in type 'long int'
58 		// *(time_t *)(m_seed.data()+8) += t;
59 		word64 tt1 = 0, tt2 = (word64)t;
60 		std::memcpy(&tt1, m_seed.data()+8, 8);
61 		std::memcpy(m_seed.data()+8, &(tt2 += tt1), 8);
62 
63 		// Wipe the intermediates
64 		*((volatile TimerWord*)&tw) = 0;
65 		*((volatile word64*)&tt1) = 0;
66 		*((volatile word64*)&tt2) = 0;
67 
68 		do
69 		{
70 			m_pCipher->ProcessBlock(m_seed);
71 			size_t len = UnsignedMin(16, size);
72 			target.ChannelPut(channel, m_seed, len);
73 			size -= len;
74 		} while (size > 0);
75 	}
76 }
77 
78 // OldRandomPool is provided for backwards compatibility for a migration path
79 typedef MDC<SHA1> OldRandomPoolCipher;
80 
OldRandomPool(unsigned int poolSize)81 OldRandomPool::OldRandomPool(unsigned int poolSize)
82         : pool(poolSize), key(OldRandomPoolCipher::DEFAULT_KEYLENGTH), addPos(0), getPos(poolSize)
83 {
84 	CRYPTOPP_ASSERT(poolSize > key.size());
85 	std::memset(pool, 0, poolSize);
86 	std::memset(key, 0, key.size());
87 }
88 
IncorporateEntropy(const byte * input,size_t length)89 void OldRandomPool::IncorporateEntropy(const byte *input, size_t length)
90 {
91 	size_t t;
92 	while (length > (t = pool.size() - addPos))
93 	{
94 		xorbuf(pool+addPos, input, t);
95 		input += t;
96 		length -= t;
97 		Stir();
98 	}
99 
100 	if (length)
101 	{
102 		xorbuf(pool+addPos, input, length);
103 		addPos += length;
104 		getPos = pool.size(); // Force stir on get
105 	}
106 }
107 
Stir()108 void OldRandomPool::Stir()
109 {
110 	CFB_Mode<OldRandomPoolCipher>::Encryption cipher;
111 
112 	for (int i=0; i<2; i++)
113 	{
114 		cipher.SetKeyWithIV(key, key.size(), pool.end()-cipher.IVSize());
115 		cipher.ProcessString(pool, pool.size());
116 		std::memcpy(key, pool, key.size());
117 	}
118 
119 	addPos = 0;
120 	getPos = key.size();
121 }
122 
GenerateIntoBufferedTransformation(BufferedTransformation & target,const std::string & channel,lword size)123 void OldRandomPool::GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword size)
124 {
125 	while (size > 0)
126 	{
127 		if (getPos == pool.size())
128 				Stir();
129 		size_t t = UnsignedMin(pool.size() - getPos, size);
130 		target.ChannelPut(channel, pool+getPos, t);
131 		size -= t;
132 		getPos += t;
133 	}
134 }
135 
GenerateByte()136 byte OldRandomPool::GenerateByte()
137 {
138 	if (getPos == pool.size())
139 		Stir();
140 
141 	return pool[getPos++];
142 }
143 
GenerateBlock(byte * outString,size_t size)144 void OldRandomPool::GenerateBlock(byte *outString, size_t size)
145 {
146 	ArraySink sink(outString, size);
147 	GenerateIntoBufferedTransformation(sink, DEFAULT_CHANNEL, size);
148 }
149 
150 NAMESPACE_END
151 
152 #endif
153