yarrow.c
Go to the documentation of this file.
1 /**
2  * @file yarrow.c
3  * @brief Yarrow PRNG
4  *
5  * @section License
6  *
7  * Copyright (C) 2010-2018 Oryx Embedded SARL. All rights reserved.
8  *
9  * This file is part of CycloneSSL Open.
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software Foundation,
23  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24  *
25  * @author Oryx Embedded SARL (www.oryx-embedded.com)
26  * @version 1.9.0
27  **/
28 
29 //Switch to the appropriate trace level
30 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
31 
32 //Dependencies
33 #include "core/crypto.h"
34 #include "rng/yarrow.h"
35 #include "debug.h"
36 
37 //Check crypto library configuration
38 #if (YARROW_SUPPORT == ENABLED)
39 
40 //Common interface for PRNG algorithms
42 {
43  "Yarrow",
44  sizeof(YarrowContext),
50 };
51 
52 
53 /**
54  * @brief Initialize PRNG context
55  * @param[in] context Pointer to the PRNG context to initialize
56  * @return Error code
57  **/
58 
60 {
61  //Clear PRNG state
62  cryptoMemset(context, 0, sizeof(YarrowContext));
63 
64  //Create a mutex to prevent simultaneous access to the PRNG state
65  if(!osCreateMutex(&context->mutex))
66  {
67  //Failed to create mutex
69  }
70 
71  //Initialize hash contexts
72  sha256Init(&context->fastPool);
73  sha256Init(&context->slowPool);
74 
75  //The PRNG is not ready to generate random data
76  context->ready = FALSE;
77 
78  //Successful initialization
79  return NO_ERROR;
80 }
81 
82 
83 /**
84  * @brief Release PRNG context
85  * @param[in] context Pointer to the PRNG context
86  **/
87 
89 {
90  //Release previously allocated resources
91  osDeleteMutex(&context->mutex);
92 
93  //Clear PRNG state
94  cryptoMemset(context, 0, sizeof(YarrowContext));
95 }
96 
97 
98 /**
99  * @brief Seed the PRNG state
100  * @param[in] context Pointer to the PRNG context
101  * @param[in] input Pointer to the input data
102  * @param[in] length Length of the input data
103  * @return Error code
104  **/
105 
106 error_t yarrowSeed(YarrowContext *context, const uint8_t *input, size_t length)
107 {
108  //Check parameters
109  if(length < sizeof(context->key))
111 
112  //Add entropy to the fast pool
113  sha256Update(&context->fastPool, input, length);
114  //Reseed from the fast pool
115  yarrowFastReseed(context);
116 
117  //Successful processing
118  return NO_ERROR;
119 }
120 
121 
122 /**
123  * @brief Add entropy to the PRNG state
124  * @param[in] context Pointer to the PRNG context
125  * @param[in] source Entropy source identifier
126  * @param[in] input Pointer to the input data
127  * @param[in] length Length of the input data
128  * @param[in] entropy Actual number of bits of entropy
129  * @return Error code
130  **/
131 
133  const uint8_t *input, size_t length, size_t entropy)
134 {
135  uint_t i;
136  uint_t k;
137 
138  //Check parameters
139  if(source >= YARROW_N)
141 
142  //Acquire exclusive access to the PRNG state
143  osAcquireMutex(&context->mutex);
144 
145  //Entropy from samples are collected into two pools
146  if(context->currentPool[source] == YARROW_FAST_POOL_ID)
147  {
148  //Each pool contains running hash of all inputs since last reseed
149  sha256Update(&context->fastPool, input, length);
150  //Estimate the amount of entropy we have collected thus far
151  context->fastPoolEntropy[source] += entropy;
152 
153  //Reseed when any source estimate reaches 100 bits
154  if(context->fastPoolEntropy[source] >= YARROW_FAST_THRESHOLD)
155  yarrowFastReseed(context);
156 
157  //The samples from each source alternate between the two pools
158  context->currentPool[source] = YARROW_SLOW_POOL_ID;
159  }
160  else
161  {
162  //Each pool contains running hash of all inputs since last reseed
163  sha256Update(&context->slowPool, input, length);
164  //Estimate the amount of entropy we have collected thus far
165  context->slowPoolEntropy[source] += entropy;
166 
167  //Prevent overflows while adding up the entropy estimate
168  if(context->slowPoolEntropy[source] >= YARROW_SLOW_THRESHOLD)
169  context->slowPoolEntropy[source] = YARROW_SLOW_THRESHOLD;
170 
171  //At least two different sources must be over 160 bits in the slow
172  //pool before the slow pool reseeds
173  for(k = 0, i = 0; i < YARROW_N; i++)
174  {
175  //Check whether the current source has hit the threshold
176  if(context->slowPoolEntropy[i] >= YARROW_SLOW_THRESHOLD)
177  k++;
178  }
179 
180  //Reseed from the slow pool?
181  if(k >= YARROW_K)
182  yarrowSlowReseed(context);
183 
184  //The samples from each source alternate between the two pools
185  context->currentPool[source] = YARROW_FAST_POOL_ID;
186  }
187 
188  //Release exclusive access to the PRNG state
189  osReleaseMutex(&context->mutex);
190 
191  //Successful processing
192  return NO_ERROR;
193 }
194 
195 
196 /**
197  * @brief Read random data
198  * @param[in] context Pointer to the PRNG context
199  * @param[out] output Buffer where to store the output data
200  * @param[in] length Desired length in bytes
201  * @return Error code
202  **/
203 
204 error_t yarrowRead(YarrowContext *context, uint8_t *output, size_t length)
205 {
206  size_t n;
207  uint8_t buffer[AES_BLOCK_SIZE];
208 
209  //Make sure that the PRNG has been properly seeded
210  if(!context->ready)
211  return ERROR_PRNG_NOT_READY;
212 
213  //Acquire exclusive access to the PRNG state
214  osAcquireMutex(&context->mutex);
215 
216  //Generate random data in a block-by-block fashion
217  while(length > 0)
218  {
219  //Number of bytes to process at a time
221 
222  //Generate a random block
223  yarrowGenerateBlock(context, buffer);
224  //Copy data to the output buffer
225  cryptoMemcpy(output, buffer, n);
226 
227  //We keep track of how many blocks we have output
228  context->blockCount++;
229 
230  //Next block
231  output += n;
232  length -= n;
233  }
234 
235  //Apply generator gate?
236  if(context->blockCount >= YARROW_PG)
237  {
238  //Generate some random bytes
239  yarrowGenerateBlock(context, context->key);
240  //Use them as the new key
241  aesInit(&context->cipherContext, context->key, sizeof(context->key));
242 
243  //Reset block counter
244  context->blockCount = 0;
245  }
246 
247  //Release exclusive access to the PRNG state
248  osReleaseMutex(&context->mutex);
249 
250  //Successful processing
251  return NO_ERROR;
252 }
253 
254 
255 /**
256  * @brief Generate a random block of data
257  * @param[in] context Pointer to the PRNG context
258  * @param[out] output Buffer where to store the output block
259  **/
260 
261 void yarrowGenerateBlock(YarrowContext *context, uint8_t *output)
262 {
263  int_t i;
264 
265  //Encrypt counter block
266  aesEncryptBlock(&context->cipherContext, context->counter, output);
267 
268  //Increment counter value
269  for(i = AES_BLOCK_SIZE - 1; i >= 0; i--)
270  {
271  //Increment the current byte and propagate the carry if necessary
272  if(++(context->counter[i]) != 0)
273  break;
274  }
275 }
276 
277 
278 /**
279  * @brief Reseed from the fast pool
280  * @param[in] context Pointer to the PRNG context
281  **/
282 
284 {
285  size_t i;
286 
287  //Reseeding from the fast pool use the current key and the hash of all
288  //inputs to the fast pool since the last reseed, to generate a new key
289  sha256Update(&context->fastPool, context->key, sizeof(context->key));
290  sha256Final(&context->fastPool, context->key);
291 
292  //Set the new key
293  aesInit(&context->cipherContext, context->key, sizeof(context->key));
294 
295  //Define the new value of the counter
296  cryptoMemset(context->counter, 0, sizeof(context->counter));
297  aesEncryptBlock(&context->cipherContext, context->counter, context->counter);
298 
299  //Reset the hash context
300  sha256Init(&context->fastPool);
301 
302  //The entropy estimates for the fast pool are all reset to zero
303  for(i = 0; i < YARROW_N; i++)
304  context->fastPoolEntropy[i] = 0;
305 
306  //The PRNG is ready to generate random data
307  context->ready = TRUE;
308 }
309 
310 
311 /**
312  * @brief Reseed from the slow pool
313  * @param[in] context Pointer to the PRNG context
314  **/
315 
317 {
318  size_t i;
319 
320  //Compute the hash of all inputs to the fast pool
321  sha256Final(&context->fastPool, NULL);
322 
323  //Reseeding from the slow pool use the current key, the hash of all inputs to the
324  //fast pool and the hash of all inputs to the slow pool, to generate a new key
325  sha256Update(&context->slowPool, context->key, sizeof(context->key));
327  sha256Final(&context->slowPool, context->key);
328 
329  //Set the new key
330  aesInit(&context->cipherContext, context->key, sizeof(context->key));
331 
332  //Define the new value of the counter
333  cryptoMemset(context->counter, 0, sizeof(context->counter));
334  aesEncryptBlock(&context->cipherContext, context->counter, context->counter);
335 
336  //Reset the hash contexts
337  sha256Init(&context->fastPool);
338  sha256Init(&context->slowPool);
339 
340  //The entropy estimates for both pools are reset to zero
341  for(i = 0; i < YARROW_N; i++)
342  {
343  context->fastPoolEntropy[i] = 0;
344  context->slowPoolEntropy[i] = 0;
345  }
346 
347  //The PRNG is ready to generate random data
348  context->ready = TRUE;
349 }
350 
351 #endif
void yarrowFastReseed(YarrowContext *context)
Reseed from the fast pool.
Definition: yarrow.c:283
void osDeleteMutex(OsMutex *mutex)
Delete a mutex object.
error_t yarrowInit(YarrowContext *context)
Initialize PRNG context.
Definition: yarrow.c:59
void yarrowRelease(YarrowContext *context)
Release PRNG context.
Definition: yarrow.c:88
bool_t osCreateMutex(OsMutex *mutex)
Create a mutex object.
void sha256Init(Sha256Context *context)
Initialize SHA-256 message digest context.
Definition: sha256.c:131
#define cryptoMemcpy(dest, src, length)
Definition: crypto.h:590
error_t yarrowRead(YarrowContext *context, uint8_t *output, size_t length)
Read random data.
Definition: yarrow.c:204
size_t blockCount
Definition: yarrow.h:73
Debugging facilities.
error_t yarrowAddEntropy(YarrowContext *context, uint_t source, const uint8_t *input, size_t length, size_t entropy)
Add entropy to the PRNG state.
Definition: yarrow.c:132
uint8_t key[32]
Definition: yarrow.h:71
#define YARROW_SLOW_POOL_ID
Definition: yarrow.h:42
#define SHA256_DIGEST_SIZE
Definition: sha256.h:38
General definitions for cryptographic algorithms.
Invalid parameter.
Definition: error.h:45
uint8_t digest[32]
Definition: sha256.h:59
uint_t currentPool[YARROW_N]
Definition: yarrow.h:65
error_t yarrowSeed(YarrowContext *context, const uint8_t *input, size_t length)
Seed the PRNG state.
Definition: yarrow.c:106
error_t(* PrngAlgoSeed)(void *context, const uint8_t *input, size_t length)
Definition: crypto.h:1035
error_t(* PrngAlgoInit)(void *context)
Definition: crypto.h:1033
bool_t ready
Definition: yarrow.h:64
Sha256Context slowPool
Definition: yarrow.h:68
#define TRUE
Definition: os_port.h:48
void(* PrngAlgoRelease)(void *context)
Definition: crypto.h:1034
#define YARROW_K
Definition: yarrow.h:46
void yarrowGenerateBlock(YarrowContext *context, uint8_t *output)
Generate a random block of data.
Definition: yarrow.c:261
signed int int_t
Definition: compiler_port.h:42
size_t fastPoolEntropy[YARROW_N]
Definition: yarrow.h:67
Yarrow PRNG context.
Definition: yarrow.h:61
void yarrowSlowReseed(YarrowContext *context)
Reseed from the slow pool.
Definition: yarrow.c:316
#define MIN(a, b)
Definition: os_port.h:60
#define YARROW_N
Definition: yarrow.h:45
void sha256Update(Sha256Context *context, const void *data, size_t length)
Update the SHA-256 context with a portion of the message being hashed.
Definition: sha256.c:157
#define YARROW_PG
Definition: yarrow.h:47
Success.
Definition: error.h:42
#define YARROW_FAST_POOL_ID
Definition: yarrow.h:41
Yarrow PRNG.
error_t
Error codes.
Definition: error.h:40
#define AES_BLOCK_SIZE
Definition: aes.h:36
const PrngAlgo yarrowPrngAlgo
Definition: yarrow.c:41
unsigned int uint_t
Definition: compiler_port.h:43
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
Common interface for pseudo-random number generators.
Definition: crypto.h:1091
error_t aesInit(AesContext *context, const uint8_t *key, size_t keyLen)
Key expansion.
Definition: aes.c:200
uint8_t counter[16]
Definition: yarrow.h:72
error_t(* PrngAlgoAddEntropy)(void *context, uint_t source, const uint8_t *input, size_t length, size_t entropy)
Definition: crypto.h:1036
Sha256Context fastPool
Definition: yarrow.h:66
AesContext cipherContext
Definition: yarrow.h:70
size_t slowPoolEntropy[YARROW_N]
Definition: yarrow.h:69
#define cryptoMemset(p, value, length)
Definition: crypto.h:584
void aesEncryptBlock(AesContext *context, const uint8_t *input, uint8_t *output)
Encrypt a 16-byte block using AES algorithm.
Definition: aes.c:304
uint8_t length
Definition: dtls_misc.h:140
uint8_t n
error_t(* PrngAlgoRead)(void *context, uint8_t *output, size_t length)
Definition: crypto.h:1037
#define FALSE
Definition: os_port.h:44
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
#define YARROW_SLOW_THRESHOLD
Definition: yarrow.h:49
void sha256Final(Sha256Context *context, uint8_t *digest)
Finish the SHA-256 message digest.
Definition: sha256.c:196
#define YARROW_FAST_THRESHOLD
Definition: yarrow.h:48
OsMutex mutex
Definition: yarrow.h:63