File: rng.cpp

package info (click to toggle)
libcrypto++ 5.6.4-7
  • links: PTS
  • area: main
  • in suites: stretch
  • size: 11,892 kB
  • ctags: 13,256
  • sloc: cpp: 69,231; sh: 4,117; asm: 4,090; makefile: 363
file content (163 lines) | stat: -rw-r--r-- 4,380 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
// rng.cpp - written and placed in the public domain by Wei Dai

#include "pch.h"

#include "rng.h"
#include "fips140.h"

#include <time.h>
#include <math.h>

NAMESPACE_BEGIN(CryptoPP)

// linear congruential generator
// originally by William S. England

// do not use for cryptographic purposes

/*
** Original_numbers are the original published m and q in the
** ACM article above.  John Burton has furnished numbers for
** a reportedly better generator.  The new numbers are now
** used in this program by default.
*/

#ifndef LCRNG_ORIGINAL_NUMBERS
const word32 LC_RNG::m=2147483647L;
const word32 LC_RNG::q=44488L;

const word16 LC_RNG::a=(unsigned int)48271L;
const word16 LC_RNG::r=3399;
#else
const word32 LC_RNG::m=2147483647L;
const word32 LC_RNG::q=127773L;

const word16 LC_RNG::a=16807;
const word16 LC_RNG::r=2836;
#endif

void LC_RNG::GenerateBlock(byte *output, size_t size)
{
	while (size--)
	{
		word32 hi = seed/q;
		word32 lo = seed%q;

		long test = a*lo - r*hi;

		if (test > 0)
			seed = test;
		else
			seed = test+ m;

		*output++ = byte((GETBYTE(seed, 0) ^ GETBYTE(seed, 1) ^ GETBYTE(seed, 2) ^ GETBYTE(seed, 3)));
	}
}

// ********************************************************

#ifndef CRYPTOPP_IMPORTS

X917RNG::X917RNG(BlockTransformation *c, const byte *seed, const byte *deterministicTimeVector)
	: m_cipher(c),
	  m_size(m_cipher->BlockSize()),
	  m_datetime(m_size),
	  m_randseed(seed, m_size),
	  m_lastBlock(m_size),
	  m_deterministicTimeVector(deterministicTimeVector, deterministicTimeVector ? m_size : 0)
{
	// Valgrind finding, http://github.com/weidai11/cryptopp/issues/105
	// Garbage in the tail creates a non-conforming X9.17 or X9.31 generator.
	if (m_size > 8)
	{
		memset(m_datetime, 0x00, m_size);
		memset(m_lastBlock, 0x00, m_size);
	}

	if (!deterministicTimeVector)
	{
		time_t tstamp1 = time(0);
		xorbuf(m_datetime, (byte *)&tstamp1, UnsignedMin(sizeof(tstamp1), m_size));
		m_cipher->ProcessBlock(m_datetime);
		clock_t tstamp2 = clock();
		xorbuf(m_datetime, (byte *)&tstamp2, UnsignedMin(sizeof(tstamp2), m_size));
		m_cipher->ProcessBlock(m_datetime);
	}

	// for FIPS 140-2
	GenerateBlock(m_lastBlock, m_size);
}

void X917RNG::GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword size)
{
	while (size > 0)
	{
		// calculate new enciphered timestamp
		if (m_deterministicTimeVector.size())
		{
			m_cipher->ProcessBlock(m_deterministicTimeVector, m_datetime);
			IncrementCounterByOne(m_deterministicTimeVector, m_size);
		}
		else
		{
			clock_t c = clock();
			xorbuf(m_datetime, (byte *)&c, UnsignedMin(sizeof(c), m_size));
			time_t t = time(NULL);
			xorbuf(m_datetime+m_size-UnsignedMin(sizeof(t), m_size), (byte *)&t, UnsignedMin(sizeof(t), m_size));
			m_cipher->ProcessBlock(m_datetime);
		}

		// combine enciphered timestamp with seed
		xorbuf(m_randseed, m_datetime, m_size);

		// generate a new block of random bytes
		m_cipher->ProcessBlock(m_randseed);
		if (memcmp(m_lastBlock, m_randseed, m_size) == 0)
			throw SelfTestFailure("X917RNG: Continuous random number generator test failed.");

		// output random bytes
		size_t len = UnsignedMin(m_size, size);
		target.ChannelPut(channel, m_randseed, len);
		size -= len;

		// compute new seed vector
		memcpy(m_lastBlock, m_randseed, m_size);
		xorbuf(m_randseed, m_datetime, m_size);
		m_cipher->ProcessBlock(m_randseed);
	}
}

#endif

MaurerRandomnessTest::MaurerRandomnessTest()
	: sum(0.0), n(0)
{
	for (unsigned i=0; i<V; i++)
		tab[i] = 0;
}

size_t MaurerRandomnessTest::Put2(const byte *inString, size_t length, int /*messageEnd*/, bool /*blocking*/)
{
	while (length--)
	{
		byte inByte = *inString++;
		if (n >= Q)
			sum += log(double(n - tab[inByte]));
		tab[inByte] = n;
		n++;
	}
	return 0;
}

double MaurerRandomnessTest::GetTestValue() const
{
	if (BytesNeeded() > 0)
		throw Exception(Exception::OTHER_ERROR, "MaurerRandomnessTest: " + IntToString(BytesNeeded()) + " more bytes of input needed");

	double fTu = (sum/(n-Q))/log(2.0);	// this is the test value defined by Maurer

	double value = fTu * 0.1392;		// arbitrarily normalize it to
	return value > 1.0 ? 1.0 : value;	// a number between 0 and 1
}

NAMESPACE_END