Botan 1.10.17
randpool.cpp
Go to the documentation of this file.
1/*
2* Randpool
3* (C) 1999-2009 Jack Lloyd
4*
5* Distributed under the terms of the Botan license
6*/
7
8#include <botan/randpool.h>
9#include <botan/get_byte.h>
10#include <botan/internal/xor_buf.h>
11#include <botan/internal/stl_util.h>
12#include <algorithm>
13
14namespace Botan {
15
16namespace {
17
18/*
19* PRF based on a MAC
20*/
21enum RANDPOOL_PRF_TAG {
22 CIPHER_KEY = 0,
23 MAC_KEY = 1,
24 GEN_OUTPUT = 2
25};
26
27}
28
29/*
30* Generate a buffer of random bytes
31*/
32void Randpool::randomize(byte out[], size_t length)
33 {
34 if(!is_seeded())
35 throw PRNG_Unseeded(name());
36
37 update_buffer();
38 while(length)
39 {
40 const size_t copied = std::min<size_t>(length, buffer.size());
41 copy_mem(out, &buffer[0], copied);
42 out += copied;
43 length -= copied;
44 update_buffer();
45 }
46 }
47
48/*
49* Refill the output buffer
50*/
51void Randpool::update_buffer()
52 {
53 for(size_t i = 0; i != counter.size(); ++i)
54 if(++counter[i])
55 break;
56
57 mac->update(static_cast<byte>(GEN_OUTPUT));
58 mac->update(counter);
59 SecureVector<byte> mac_val = mac->final();
60
61 for(size_t i = 0; i != mac_val.size(); ++i)
62 buffer[i % buffer.size()] ^= mac_val[i];
63 cipher->encrypt(buffer);
64
65 if(counter[0] % ITERATIONS_BEFORE_RESEED == 0)
66 mix_pool();
67 }
68
69/*
70* Mix the entropy pool
71*/
72void Randpool::mix_pool()
73 {
74 const size_t BLOCK_SIZE = cipher->block_size();
75
76 mac->update(static_cast<byte>(MAC_KEY));
77 mac->update(pool);
78 mac->set_key(mac->final());
79
80 mac->update(static_cast<byte>(CIPHER_KEY));
81 mac->update(pool);
82 cipher->set_key(mac->final());
83
84 xor_buf(pool, buffer, BLOCK_SIZE);
85 cipher->encrypt(pool);
86 for(size_t i = 1; i != POOL_BLOCKS; ++i)
87 {
88 const byte* previous_block = &pool[BLOCK_SIZE*(i-1)];
89 byte* this_block = &pool[BLOCK_SIZE*i];
90 xor_buf(this_block, previous_block, BLOCK_SIZE);
91 cipher->encrypt(this_block);
92 }
93
94 update_buffer();
95 }
96
97/*
98* Reseed the internal state
99*/
100void Randpool::reseed(size_t poll_bits)
101 {
102 Entropy_Accumulator_BufferedComputation accum(*mac, poll_bits);
103
104 if(!entropy_sources.empty())
105 {
106 size_t poll_attempt = 0;
107
108 while(!accum.polling_goal_achieved() && poll_attempt < poll_bits)
109 {
110 entropy_sources[poll_attempt % entropy_sources.size()]->poll(accum);
111 ++poll_attempt;
112 }
113 }
114
115 SecureVector<byte> mac_val = mac->final();
116
117 xor_buf(pool, mac_val, mac_val.size());
118 mix_pool();
119
120 if(accum.bits_collected() >= poll_bits)
121 seeded = true;
122 }
123
124/*
125* Add user-supplied entropy
126*/
127void Randpool::add_entropy(const byte input[], size_t length)
128 {
129 SecureVector<byte> mac_val = mac->process(input, length);
130 xor_buf(pool, mac_val, mac_val.size());
131 mix_pool();
132
133 if(length)
134 seeded = true;
135 }
136
137/*
138* Add another entropy source to the list
139*/
141 {
142 entropy_sources.push_back(src);
143 }
144
145/*
146* Clear memory of sensitive data
147*/
149 {
150 cipher->clear();
151 mac->clear();
152 zeroise(pool);
153 zeroise(buffer);
154 zeroise(counter);
155 seeded = false;
156 }
157
158/*
159* Return the name of this type
160*/
161std::string Randpool::name() const
162 {
163 return "Randpool(" + cipher->name() + "," + mac->name() + ")";
164 }
165
166/*
167* Randpool Constructor
168*/
171 size_t pool_blocks,
172 size_t iter_before_reseed) :
173 ITERATIONS_BEFORE_RESEED(iter_before_reseed),
174 POOL_BLOCKS(pool_blocks),
175 cipher(cipher_in),
176 mac(mac_in)
177 {
178 const size_t BLOCK_SIZE = cipher->block_size();
179 const size_t OUTPUT_LENGTH = mac->output_length();
180
181 if(OUTPUT_LENGTH < BLOCK_SIZE ||
182 !cipher->valid_keylength(OUTPUT_LENGTH) ||
183 !mac->valid_keylength(OUTPUT_LENGTH))
184 {
185 delete cipher;
186 delete mac;
187 throw Internal_Error("Randpool: Invalid algorithm combination");
188 }
189
190 buffer.resize(BLOCK_SIZE);
191 pool.resize(POOL_BLOCKS * BLOCK_SIZE);
192 counter.resize(12);
193 seeded = false;
194 }
195
196/*
197* Randpool Destructor
198*/
200 {
201 delete cipher;
202 delete mac;
203
204 std::for_each(entropy_sources.begin(), entropy_sources.end(),
206 }
207
208}
void encrypt(const byte in[], byte out[]) const
virtual size_t block_size() const =0
void update(const byte in[], size_t length)
Definition buf_comp.h:33
void final(byte out[])
Definition buf_comp.h:80
bool polling_goal_achieved() const
Definition entropy_src.h:50
size_t bits_collected() const
Definition entropy_src.h:44
size_t size() const
Definition secmem.h:29
void reseed(size_t bits_to_collect)
Definition randpool.cpp:100
void randomize(byte[], size_t)
Definition randpool.cpp:32
void add_entropy_source(EntropySource *es)
Definition randpool.cpp:140
std::string name() const
Definition randpool.cpp:161
bool is_seeded() const
Definition randpool.h:25
Randpool(BlockCipher *cipher, MessageAuthenticationCode *mac, size_t pool_blocks=32, size_t iterations_before_reseed=128)
Definition randpool.cpp:169
void add_entropy(const byte input[], size_t length)
Definition randpool.cpp:127
void set_key(const SymmetricKey &key)
Definition sym_algo.h:60
void zeroise(MemoryRegion< T > &vec)
Definition secmem.h:428
void xor_buf(byte out[], const byte in[], size_t length)
Definition xor_buf.h:21
void copy_mem(T *out, const T *in, size_t n)
Definition mem_ops.h:22
PRNG_Unseeded(const std::string &algo)
Definition exceptn.h:91