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