Coverage Report

Created: 2024-11-21 07:03

/src/cryptopp/randpool.cpp
Line
Count
Source (jump to first uncovered line)
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
23
NAMESPACE_BEGIN(CryptoPP)
24
25
RandomPool::RandomPool()
26
  : m_pCipher(new AES::Encryption), m_keySet(false)
27
28
{
28
28
  std::memset(m_key, 0, m_key.SizeInBytes());
29
28
  std::memset(m_seed, 0, m_seed.SizeInBytes());
30
28
}
31
32
void RandomPool::IncorporateEntropy(const byte *input, size_t length)
33
28
{
34
28
  SHA256 hash;
35
28
  hash.Update(m_key, 32);
36
28
  hash.Update(input, length);
37
28
  hash.Final(m_key);
38
28
  m_keySet = false;
39
28
}
40
41
void RandomPool::GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword size)
42
0
{
43
0
  if (size > 0)
44
0
  {
45
0
    if (!m_keySet)
46
0
      m_pCipher->SetKey(m_key, 32);
47
48
0
    CRYPTOPP_COMPILE_ASSERT(sizeof(TimerWord) <= 16);
49
0
    CRYPTOPP_COMPILE_ASSERT(sizeof(time_t) <= 8);
50
51
0
    Timer timer;
52
0
    TimerWord tw = timer.GetCurrentTimerValue();
53
54
0
    *(TimerWord *)(void*)m_seed.data() += tw;
55
0
    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
0
    word64 tt1 = 0, tt2 = (word64)t;
60
0
    std::memcpy(&tt1, m_seed.data()+8, 8);
61
0
    std::memcpy(m_seed.data()+8, &(tt2 += tt1), 8);
62
63
    // Wipe the intermediates
64
0
    *((volatile TimerWord*)&tw) = 0;
65
0
    *((volatile word64*)&tt1) = 0;
66
0
    *((volatile word64*)&tt2) = 0;
67
68
0
    do
69
0
    {
70
0
      m_pCipher->ProcessBlock(m_seed);
71
0
      size_t len = UnsignedMin(16u, size);
72
0
      target.ChannelPut(channel, m_seed, len);
73
0
      size -= len;
74
0
    } while (size > 0);
75
0
  }
76
0
}
77
78
// OldRandomPool is provided for backwards compatibility for a migration path
79
typedef MDC<SHA1> OldRandomPoolCipher;
80
81
OldRandomPool::OldRandomPool(unsigned int poolSize)
82
        : pool(poolSize), key(OldRandomPoolCipher::DEFAULT_KEYLENGTH), addPos(0), getPos(poolSize)
83
0
{
84
0
  CRYPTOPP_ASSERT(poolSize > key.size());
85
0
  std::memset(pool, 0, poolSize);
86
0
  std::memset(key, 0, key.size());
87
0
}
88
89
void OldRandomPool::IncorporateEntropy(const byte *input, size_t length)
90
0
{
91
0
  size_t t;
92
0
  while (length > (t = pool.size() - addPos))
93
0
  {
94
0
    xorbuf(pool+addPos, input, t);
95
0
    input += t;
96
0
    length -= t;
97
0
    Stir();
98
0
  }
99
100
0
  if (length)
101
0
  {
102
0
    xorbuf(pool+addPos, input, length);
103
0
    addPos += length;
104
0
    getPos = pool.size(); // Force stir on get
105
0
  }
106
0
}
107
108
// GenerateWord32 is overridden and provides Crypto++ 5.4 behavior.
109
// Taken from RandomNumberGenerator::GenerateWord32 in cryptlib.cpp.
110
word32 OldRandomPool::GenerateWord32 (word32 min, word32 max)
111
0
{
112
0
  const word32 range = max-min;
113
0
  const unsigned int maxBytes = BytePrecision(range);
114
0
  const unsigned int maxBits = BitPrecision(range);
115
116
0
  word32 value;
117
118
0
  do
119
0
  {
120
0
    value = 0;
121
0
    for (unsigned int i=0; i<maxBytes; i++)
122
0
      value = (value << 8) | GenerateByte();
123
124
0
    value = Crop(value, maxBits);
125
0
  } while (value > range);
126
127
0
  return value+min;
128
0
}
129
130
void OldRandomPool::Stir()
131
0
{
132
0
  CFB_Mode<OldRandomPoolCipher>::Encryption cipher;
133
134
0
  for (int i=0; i<2; i++)
135
0
  {
136
0
    cipher.SetKeyWithIV(key, key.size(), pool.end()-cipher.IVSize());
137
0
    cipher.ProcessString(pool, pool.size());
138
0
    std::memcpy(key, pool, key.size());
139
0
  }
140
141
0
  addPos = 0;
142
0
  getPos = key.size();
143
0
}
144
145
void OldRandomPool::GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword size)
146
0
{
147
0
  while (size > 0)
148
0
  {
149
0
    if (getPos == pool.size())
150
0
        Stir();
151
0
    size_t t = UnsignedMin(pool.size() - getPos, size);
152
0
    target.ChannelPut(channel, pool+getPos, t);
153
0
    size -= t;
154
0
    getPos += t;
155
0
  }
156
0
}
157
158
byte OldRandomPool::GenerateByte()
159
0
{
160
0
  if (getPos == pool.size())
161
0
    Stir();
162
163
0
  return pool[getPos++];
164
0
}
165
166
void OldRandomPool::GenerateBlock(byte *outString, size_t size)
167
0
{
168
0
  ArraySink sink(outString, size);
169
0
  GenerateIntoBufferedTransformation(sink, DEFAULT_CHANNEL, size);
170
0
}
171
172
NAMESPACE_END
173
174
#endif