Coverage Report

Created: 2024-11-21 07:03

/src/cryptopp/rng.cpp
Line
Count
Source (jump to first uncovered line)
1
// rng.cpp - originally written and placed in the public domain by Wei Dai
2
3
#include "pch.h"
4
5
#include "rng.h"
6
#include "fips140.h"
7
8
#include <time.h>
9
#include <math.h>
10
11
NAMESPACE_BEGIN(CryptoPP)
12
13
// linear congruential generator
14
// originally by William S. England
15
16
// do not use for cryptographic purposes
17
18
/*
19
** Original_numbers are the original published m and q in the
20
** ACM article above.  John Burton has furnished numbers for
21
** a reportedly better generator.  The new numbers are now
22
** used in this program by default.
23
*/
24
25
#ifndef LCRNG_ORIGINAL_NUMBERS
26
const word32 LC_RNG::m=2147483647L;
27
const word32 LC_RNG::q=44488L;
28
29
const word16 LC_RNG::a=(unsigned int)48271L;
30
const word16 LC_RNG::r=3399;
31
#else
32
const word32 LC_RNG::m=2147483647L;
33
const word32 LC_RNG::q=127773L;
34
35
const word16 LC_RNG::a=16807;
36
const word16 LC_RNG::r=2836;
37
#endif
38
39
void LC_RNG::GenerateBlock(byte *output, size_t size)
40
0
{
41
0
  while (size--)
42
0
  {
43
0
    const word32 hi = seed/q;
44
0
    const word32 lo = seed%q;
45
0
    const sword64 test = a*lo - r*hi;
46
47
0
    if (test > 0)
48
0
      seed = static_cast<word32>(test);
49
0
    else
50
0
      seed = static_cast<word32>(test + m);
51
52
0
    *output++ = byte((GETBYTE(seed, 0) ^ GETBYTE(seed, 1) ^ GETBYTE(seed, 2) ^ GETBYTE(seed, 3)));
53
0
  }
54
0
}
55
56
// ********************************************************
57
58
#ifndef CRYPTOPP_IMPORTS
59
60
X917RNG::X917RNG(BlockTransformation *c, const byte *seed, const byte *deterministicTimeVector)
61
  : m_cipher(c),
62
    m_size(m_cipher->BlockSize()),
63
    m_datetime(m_size),
64
    m_randseed(seed, m_size),
65
    m_lastBlock(m_size),
66
    m_deterministicTimeVector(deterministicTimeVector, deterministicTimeVector ? m_size : 0)
67
0
{
68
  // Valgrind finding, http://github.com/weidai11/cryptopp/issues/105
69
  // Garbage in the tail creates a non-conforming X9.17 or X9.31 generator.
70
0
  if (m_size > 8)
71
0
  {
72
0
    std::memset(m_datetime, 0x00, m_size);
73
0
    std::memset(m_lastBlock, 0x00, m_size);
74
0
  }
75
76
0
  if (!deterministicTimeVector)
77
0
  {
78
0
    time_t tstamp1 = ::time(NULLPTR);
79
0
    xorbuf(m_datetime, (byte *)&tstamp1, UnsignedMin(sizeof(tstamp1), m_size));
80
0
    m_cipher->ProcessBlock(m_datetime);
81
0
    clock_t tstamp2 = clock();
82
0
    xorbuf(m_datetime, (byte *)&tstamp2, UnsignedMin(sizeof(tstamp2), m_size));
83
0
    m_cipher->ProcessBlock(m_datetime);
84
0
  }
85
86
  // for FIPS 140-2
87
  // GenerateBlock(m_lastBlock, m_size);
88
89
  // Make explicit call to avoid virtual-dispatch findings in ctor
90
0
  ArraySink target(m_lastBlock, m_size);
91
0
  X917RNG::GenerateIntoBufferedTransformation(target, DEFAULT_CHANNEL, m_size);
92
0
}
93
94
void X917RNG::GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword size)
95
0
{
96
0
  while (size > 0)
97
0
  {
98
    // calculate new enciphered timestamp
99
0
    if (m_deterministicTimeVector.size())
100
0
    {
101
0
      m_cipher->ProcessBlock(m_deterministicTimeVector, m_datetime);
102
0
      IncrementCounterByOne(m_deterministicTimeVector, m_size);
103
0
    }
104
0
    else
105
0
    {
106
0
      clock_t c = clock();
107
0
      xorbuf(m_datetime, (byte *)&c, UnsignedMin(sizeof(c), m_size));
108
0
      time_t t = ::time(NULLPTR);
109
0
      xorbuf(m_datetime+m_size-UnsignedMin(sizeof(t), m_size), (byte *)&t, UnsignedMin(sizeof(t), m_size));
110
0
      m_cipher->ProcessBlock(m_datetime);
111
0
    }
112
113
    // combine enciphered timestamp with seed
114
0
    xorbuf(m_randseed, m_datetime, m_size);
115
116
    // generate a new block of random bytes
117
0
    m_cipher->ProcessBlock(m_randseed);
118
0
    if (std::memcmp(m_lastBlock, m_randseed, m_size) == 0)
119
0
      throw SelfTestFailure("X917RNG: Continuous random number generator test failed.");
120
121
    // output random bytes
122
0
    size_t len = UnsignedMin(m_size, size);
123
0
    target.ChannelPut(channel, m_randseed, len);
124
0
    size -= len;
125
126
    // compute new seed vector
127
0
    std::memcpy(m_lastBlock, m_randseed, m_size);
128
0
    xorbuf(m_randseed, m_datetime, m_size);
129
0
    m_cipher->ProcessBlock(m_randseed);
130
0
  }
131
0
}
132
133
#endif
134
135
MaurerRandomnessTest::MaurerRandomnessTest()
136
  : sum(0.0), n(0)
137
0
{
138
0
  for (unsigned i=0; i<V; i++)
139
0
    tab[i] = 0;
140
0
}
141
142
size_t MaurerRandomnessTest::Put2(const byte *inString, size_t length, int /*messageEnd*/, bool /*blocking*/)
143
0
{
144
0
  while (length--)
145
0
  {
146
0
    byte inByte = *inString++;
147
0
    if (n >= Q)
148
0
      sum += ::log(double(n - tab[inByte]));
149
0
    tab[inByte] = n;
150
0
    n++;
151
0
  }
152
0
  return 0;
153
0
}
154
155
double MaurerRandomnessTest::GetTestValue() const
156
0
{
157
0
  if (BytesNeeded() > 0)
158
0
    throw Exception(Exception::OTHER_ERROR, "MaurerRandomnessTest: " + IntToString(BytesNeeded()) + " more bytes of input needed");
159
160
0
  double fTu = (sum/(n-Q))/::log(2.0);  // this is the test value defined by Maurer
161
162
0
  double value = fTu * 0.1392;    // arbitrarily normalize it to
163
0
  return value > 1.0 ? 1.0 : value; // a number between 0 and 1
164
0
}
165
166
NAMESPACE_END