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
|
/*
* HMAC_DRBG
* (C) 2014,2015 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
#include <botan/hmac_drbg.h>
#include <algorithm>
namespace Botan {
HMAC_DRBG::HMAC_DRBG(MessageAuthenticationCode* mac,
RandomNumberGenerator* prng) :
m_mac(mac),
m_prng(prng),
m_V(m_mac->output_length(), 0x01),
m_reseed_counter(0)
{
m_mac->set_key(std::vector<byte>(m_mac->output_length(), 0x00));
}
HMAC_DRBG::HMAC_DRBG(const std::string& mac_name,
RandomNumberGenerator* prng) :
m_prng(prng),
m_reseed_counter(0)
{
m_mac = MessageAuthenticationCode::create(mac_name);
if(!m_mac)
throw Algorithm_Not_Found(mac_name);
m_V = secure_vector<byte>(m_mac->output_length(), 0x01),
m_mac->set_key(std::vector<byte>(m_mac->output_length(), 0x00));
}
void HMAC_DRBG::randomize(byte out[], size_t length)
{
if(!is_seeded() || m_reseed_counter > BOTAN_RNG_MAX_OUTPUT_BEFORE_RESEED)
reseed(m_mac->output_length() * 8);
if(!is_seeded())
throw PRNG_Unseeded(name());
while(length)
{
const size_t to_copy = std::min(length, m_V.size());
m_V = m_mac->process(m_V);
copy_mem(out, m_V.data(), to_copy);
length -= to_copy;
out += to_copy;
}
m_reseed_counter += length;
update(nullptr, 0); // additional_data is always empty
}
/*
* Reset V and the mac key with new values
*/
void HMAC_DRBG::update(const byte input[], size_t input_len)
{
m_mac->update(m_V);
m_mac->update(0x00);
m_mac->update(input, input_len);
m_mac->set_key(m_mac->final());
m_V = m_mac->process(m_V);
if(input_len)
{
m_mac->update(m_V);
m_mac->update(0x01);
m_mac->update(input, input_len);
m_mac->set_key(m_mac->final());
m_V = m_mac->process(m_V);
}
}
size_t HMAC_DRBG::reseed_with_sources(Entropy_Sources& srcs,
size_t poll_bits,
std::chrono::milliseconds poll_timeout)
{
if(m_prng)
{
size_t bits = m_prng->reseed_with_sources(srcs, poll_bits, poll_timeout);
if(m_prng->is_seeded())
{
secure_vector<byte> input = m_prng->random_vec(m_mac->output_length());
update(input.data(), input.size());
m_reseed_counter = 1;
}
return bits;
}
return 0;
}
void HMAC_DRBG::add_entropy(const byte input[], size_t length)
{
update(input, length);
m_reseed_counter = 1;
}
bool HMAC_DRBG::is_seeded() const
{
return m_reseed_counter > 0;
}
void HMAC_DRBG::clear()
{
m_reseed_counter = 0;
for(size_t i = 0; i != m_V.size(); ++i)
m_V[i] = 0x01;
m_mac->set_key(std::vector<byte>(m_mac->output_length(), 0x00));
if(m_prng)
m_prng->clear();
}
std::string HMAC_DRBG::name() const
{
return "HMAC_DRBG(" + m_mac->name() + ")";
}
}
|