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-2024 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 2.4.0
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 Seed the PRNG state
87  * @param[in] context Pointer to the PRNG context
88  * @param[in] input Pointer to the input data
89  * @param[in] length Length of the input data
90  * @return Error code
91  **/
92 
93 error_t yarrowSeed(YarrowContext *context, const uint8_t *input, size_t length)
94 {
95  //Check parameters
96  if(length < sizeof(context->key))
98 
99  //Add entropy to the fast pool
100  sha256Update(&context->fastPool, input, length);
101  //Reseed from the fast pool
102  yarrowFastReseed(context);
103 
104  //Successful processing
105  return NO_ERROR;
106 }
107 
108 
109 /**
110  * @brief Add entropy to the PRNG state
111  * @param[in] context Pointer to the PRNG context
112  * @param[in] source Entropy source identifier
113  * @param[in] input Pointer to the input data
114  * @param[in] length Length of the input data
115  * @param[in] entropy Actual number of bits of entropy
116  * @return Error code
117  **/
118 
120  const uint8_t *input, size_t length, size_t entropy)
121 {
122  uint_t i;
123  uint_t k;
124 
125  //Check parameters
126  if(source >= YARROW_N)
128 
129  //Acquire exclusive access to the PRNG state
130  osAcquireMutex(&context->mutex);
131 
132  //Entropy from samples are collected into two pools
133  if(context->currentPool[source] == YARROW_FAST_POOL_ID)
134  {
135  //Each pool contains running hash of all inputs since last reseed
136  sha256Update(&context->fastPool, input, length);
137  //Estimate the amount of entropy we have collected thus far
138  context->fastPoolEntropy[source] += entropy;
139 
140  //Reseed when any source estimate reaches 100 bits
141  if(context->fastPoolEntropy[source] >= YARROW_FAST_THRESHOLD)
142  {
143  yarrowFastReseed(context);
144  }
145 
146  //The samples from each source alternate between the two pools
147  context->currentPool[source] = YARROW_SLOW_POOL_ID;
148  }
149  else
150  {
151  //Each pool contains running hash of all inputs since last reseed
152  sha256Update(&context->slowPool, input, length);
153  //Estimate the amount of entropy we have collected thus far
154  context->slowPoolEntropy[source] += entropy;
155 
156  //Prevent overflows while adding up the entropy estimate
157  if(context->slowPoolEntropy[source] >= YARROW_SLOW_THRESHOLD)
158  {
159  context->slowPoolEntropy[source] = YARROW_SLOW_THRESHOLD;
160  }
161 
162  //At least two different sources must be over 160 bits in the slow
163  //pool before the slow pool reseeds
164  for(k = 0, i = 0; i < YARROW_N; i++)
165  {
166  //Check whether the current source has hit the threshold
167  if(context->slowPoolEntropy[i] >= YARROW_SLOW_THRESHOLD)
168  {
169  k++;
170  }
171  }
172 
173  //Reseed from the slow pool?
174  if(k >= YARROW_K)
175  {
176  yarrowSlowReseed(context);
177  }
178 
179  //The samples from each source alternate between the two pools
180  context->currentPool[source] = YARROW_FAST_POOL_ID;
181  }
182 
183  //Release exclusive access to the PRNG state
184  osReleaseMutex(&context->mutex);
185 
186  //Successful processing
187  return NO_ERROR;
188 }
189 
190 
191 /**
192  * @brief Read random data
193  * @param[in] context Pointer to the PRNG context
194  * @param[out] output Buffer where to store the output data
195  * @param[in] length Desired length in bytes
196  * @return Error code
197  **/
198 
199 error_t yarrowRead(YarrowContext *context, uint8_t *output, size_t length)
200 {
201  size_t n;
202  uint8_t buffer[AES_BLOCK_SIZE];
203 
204  //Make sure that the PRNG has been properly seeded
205  if(!context->ready)
206  return ERROR_PRNG_NOT_READY;
207 
208  //Acquire exclusive access to the PRNG state
209  osAcquireMutex(&context->mutex);
210 
211  //Generate random data in a block-by-block fashion
212  while(length > 0)
213  {
214  //Number of bytes to process at a time
216 
217  //Generate a random block
218  yarrowGenerateBlock(context, buffer);
219  //Copy data to the output buffer
220  osMemcpy(output, buffer, n);
221 
222  //We keep track of how many blocks we have output
223  context->blockCount++;
224 
225  //Next block
226  output += n;
227  length -= n;
228  }
229 
230  //Apply generator gate?
231  if(context->blockCount >= YARROW_PG)
232  {
233  //Generate some random bytes
234  yarrowGenerateBlock(context, context->key);
235 
236  //Use them as the new key
237  aesDeinit(&context->cipherContext);
238  aesInit(&context->cipherContext, context->key, sizeof(context->key));
239 
240  //Reset block counter
241  context->blockCount = 0;
242  }
243 
244  //Release exclusive access to the PRNG state
245  osReleaseMutex(&context->mutex);
246 
247  //Successful processing
248  return NO_ERROR;
249 }
250 
251 
252 /**
253  * @brief Generate a random block of data
254  * @param[in] context Pointer to the PRNG context
255  * @param[out] output Buffer where to store the output block
256  **/
257 
258 void yarrowGenerateBlock(YarrowContext *context, uint8_t *output)
259 {
260  int_t i;
261 
262  //Encrypt counter block
263  aesEncryptBlock(&context->cipherContext, context->counter, output);
264 
265  //Increment counter value
266  for(i = AES_BLOCK_SIZE - 1; i >= 0; i--)
267  {
268  //Increment the current byte and propagate the carry if necessary
269  if(++(context->counter[i]) != 0)
270  {
271  break;
272  }
273  }
274 }
275 
276 
277 /**
278  * @brief Reseed from the fast pool
279  * @param[in] context Pointer to the PRNG context
280  **/
281 
283 {
284  size_t i;
285 
286  //Erase AES context
287  if(context->ready)
288  {
289  aesDeinit(&context->cipherContext);
290  }
291 
292  //Reseeding from the fast pool use the current key and the hash of all
293  //inputs to the fast pool since the last reseed, to generate a new key
294  sha256Update(&context->fastPool, context->key, sizeof(context->key));
295  sha256Final(&context->fastPool, context->key);
296 
297  //Set the new key
298  aesInit(&context->cipherContext, context->key, sizeof(context->key));
299 
300  //Define the new value of the counter
301  osMemset(context->counter, 0, sizeof(context->counter));
302  aesEncryptBlock(&context->cipherContext, context->counter, context->counter);
303 
304  //Reset the hash context
305  sha256Init(&context->fastPool);
306 
307  //The entropy estimates for the fast pool are all reset to zero
308  for(i = 0; i < YARROW_N; i++)
309  {
310  context->fastPoolEntropy[i] = 0;
311  }
312 
313  //The PRNG is ready to generate random data
314  context->ready = TRUE;
315 }
316 
317 
318 /**
319  * @brief Reseed from the slow pool
320  * @param[in] context Pointer to the PRNG context
321  **/
322 
324 {
325  size_t i;
326 
327  //Erase AES context
328  if(context->ready)
329  {
330  aesDeinit(&context->cipherContext);
331  }
332 
333  //Compute the hash of all inputs to the fast pool
334  sha256Final(&context->fastPool, NULL);
335 
336  //Reseeding from the slow pool use the current key, the hash of all inputs to the
337  //fast pool and the hash of all inputs to the slow pool, to generate a new key
338  sha256Update(&context->slowPool, context->key, sizeof(context->key));
340  sha256Final(&context->slowPool, context->key);
341 
342  //Set the new key
343  aesInit(&context->cipherContext, context->key, sizeof(context->key));
344 
345  //Define the new value of the counter
346  osMemset(context->counter, 0, sizeof(context->counter));
347  aesEncryptBlock(&context->cipherContext, context->counter, context->counter);
348 
349  //Reset the hash contexts
350  sha256Init(&context->fastPool);
351  sha256Init(&context->slowPool);
352 
353  //The entropy estimates for both pools are reset to zero
354  for(i = 0; i < YARROW_N; i++)
355  {
356  context->fastPoolEntropy[i] = 0;
357  context->slowPoolEntropy[i] = 0;
358  }
359 
360  //The PRNG is ready to generate random data
361  context->ready = TRUE;
362 }
363 
364 
365 /**
366  * @brief Release PRNG context
367  * @param[in] context Pointer to the PRNG context
368  **/
369 
371 {
372  //Erase AES context
373  if(context->ready)
374  {
375  aesDeinit(&context->cipherContext);
376  }
377 
378  //Free previously allocated resources
379  osDeleteMutex(&context->mutex);
380 
381  //Clear PRNG state
382  osMemset(context, 0, sizeof(YarrowContext));
383 }
384 
385 #endif
__weak_func void aesDeinit(AesContext *context)
Release AES context.
Definition: aes.c:571
__weak_func void aesEncryptBlock(AesContext *context, const uint8_t *input, uint8_t *output)
Encrypt a 16-byte block using AES algorithm.
Definition: aes.c:351
__weak_func error_t aesInit(AesContext *context, const uint8_t *key, size_t keyLen)
Key expansion.
Definition: aes.c:242
#define AES_BLOCK_SIZE
Definition: aes.h:43
signed int int_t
Definition: compiler_port.h:49
unsigned int uint_t
Definition: compiler_port.h:50
General definitions for cryptographic algorithms.
void(* PrngAlgoDeinit)(void *context)
Definition: crypto.h:1006
error_t(* PrngAlgoRead)(void *context, uint8_t *output, size_t length)
Definition: crypto.h:1004
error_t(* PrngAlgoSeed)(void *context, const uint8_t *input, size_t length)
Definition: crypto.h:998
error_t(* PrngAlgoAddEntropy)(void *context, uint_t source, const uint8_t *input, size_t length, size_t entropy)
Definition: crypto.h:1001
error_t(* PrngAlgoInit)(void *context)
Definition: crypto.h:996
#define PrngAlgo
Definition: crypto.h:917
Debugging facilities.
uint8_t n
error_t
Error codes.
Definition: error.h:43
@ ERROR_PRNG_NOT_READY
Definition: error.h:250
@ ERROR_OUT_OF_RESOURCES
Definition: error.h:64
@ NO_ERROR
Success.
Definition: error.h:44
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
void sha256Update(Sha256Context *context, const void *data, size_t length)
Update the SHA-256 context with a portion of the message being hashed.
void sha256Final(Sha256Context *context, uint8_t *digest)
Finish the SHA-256 message digest.
void sha256Init(Sha256Context *context)
Initialize SHA-256 message digest context.
#define osMemset(p, value, length)
Definition: os_port.h:135
#define osMemcpy(dest, src, length)
Definition: os_port.h:141
#define MIN(a, b)
Definition: os_port.h:63
#define TRUE
Definition: os_port.h:50
#define FALSE
Definition: os_port.h:46
bool_t osCreateMutex(OsMutex *mutex)
Create a mutex object.
void osDeleteMutex(OsMutex *mutex)
Delete a mutex object.
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
#define SHA256_DIGEST_SIZE
Definition: sha256.h:45
uint8_t digest[32]
Definition: sha256.h:66
Yarrow PRNG context.
Definition: yarrow.h:64
size_t slowPoolEntropy[YARROW_N]
Definition: yarrow.h:71
size_t blockCount
Definition: yarrow.h:75
uint_t currentPool[YARROW_N]
Definition: yarrow.h:67
Sha256Context slowPool
Definition: yarrow.h:70
Sha256Context fastPool
Definition: yarrow.h:68
uint8_t counter[16]
Definition: yarrow.h:74
uint8_t key[32]
Definition: yarrow.h:73
bool_t ready
Definition: yarrow.h:66
size_t fastPoolEntropy[YARROW_N]
Definition: yarrow.h:69
AesContext cipherContext
Definition: yarrow.h:72
OsMutex mutex
Definition: yarrow.h:65
uint8_t length
Definition: tcp.h:368
error_t yarrowRead(YarrowContext *context, uint8_t *output, size_t length)
Read random data.
Definition: yarrow.c:199
void yarrowFastReseed(YarrowContext *context)
Reseed from the fast pool.
Definition: yarrow.c:282
error_t yarrowSeed(YarrowContext *context, const uint8_t *input, size_t length)
Seed the PRNG state.
Definition: yarrow.c:93
error_t yarrowInit(YarrowContext *context)
Initialize PRNG context.
Definition: yarrow.c:61
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:119
const PrngAlgo yarrowPrngAlgo
Definition: yarrow.c:43
void yarrowDeinit(YarrowContext *context)
Release PRNG context.
Definition: yarrow.c:370
void yarrowGenerateBlock(YarrowContext *context, uint8_t *output)
Generate a random block of data.
Definition: yarrow.c:258
void yarrowSlowReseed(YarrowContext *context)
Reseed from the slow pool.
Definition: yarrow.c:323
TRNG (True Random Number Generator)
#define YARROW_SLOW_POOL_ID
Definition: yarrow.h:44
#define YARROW_N
Definition: yarrow.h:47
#define YARROW_FAST_THRESHOLD
Definition: yarrow.h:50
#define YARROW_PG
Definition: yarrow.h:49
#define YARROW_SLOW_THRESHOLD
Definition: yarrow.h:51
#define YARROW_K
Definition: yarrow.h:48
#define YARROW_FAST_POOL_ID
Definition: yarrow.h:43