Botan  1.10.9
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 
14 namespace Botan {
15 
16 namespace {
17 
18 /*
19 * PRF based on a MAC
20 */
21 enum 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 */
32 void 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 */
51 void 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 */
72 void 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 */
100 void 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 */
127 void 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 */
161 std::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 resize(size_t n)
Definition: secmem.h:211
virtual void clear()=0
void add_entropy(const byte input[], size_t length)
Definition: randpool.cpp:127
void add_entropy_source(EntropySource *es)
Definition: randpool.cpp:140
std::string name() const
Definition: randpool.cpp:161
Randpool(BlockCipher *cipher, MessageAuthenticationCode *mac, size_t pool_blocks=32, size_t iterations_before_reseed=128)
Definition: randpool.cpp:169
void randomize(byte[], size_t)
Definition: randpool.cpp:32
unsigned char byte
Definition: types.h:22
bool valid_keylength(size_t length) const
Definition: sym_algo.h:51
bool is_seeded() const
Definition: randpool.h:25
void set_key(const SymmetricKey &key)
Definition: sym_algo.h:60
virtual std::string name() const =0
MessageAuthenticationCode * mac
Definition: fpe_fe1.cpp:94
void update(const byte in[], size_t length)
Definition: buf_comp.h:33
bool polling_goal_achieved() const
Definition: entropy_src.h:50
SecureVector< byte > process(const byte in[], size_t length)
Definition: buf_comp.h:101
size_t size() const
Definition: secmem.h:29
size_t bits_collected() const
Definition: entropy_src.h:44
void copy_mem(T *out, const T *in, size_t n)
Definition: mem_ops.h:22
virtual std::string name() const =0
void final(byte out[])
Definition: buf_comp.h:80
void reseed(size_t bits_to_collect)
Definition: randpool.cpp:100
void encrypt(const byte in[], byte out[]) const
Definition: block_cipher.h:47
void xor_buf(byte out[], const byte in[], size_t length)
Definition: xor_buf.h:21
void zeroise(MemoryRegion< T > &vec)
Definition: secmem.h:415
virtual size_t block_size() const =0
virtual size_t output_length() const =0