ctr_drbg.c
Go to the documentation of this file.
1 /**
2  * @file ctr_drbg.c
3  * @brief CTR_DRBG pseudorandom number generator
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2025 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.5.4
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/ctr_drbg.h"
37 #include "debug.h"
38 
39 //Check crypto library configuration
40 #if (CTR_DRBG_SUPPORT == ENABLED)
41 
42 //Padding string
43 static const uint8_t padding[MAX_CIPHER_BLOCK_SIZE] = {0};
44 
45 //Common interface for PRNG algorithms
47 {
48  "CTR_DRBG",
49  sizeof(CtrDrbgContext),
50  (PrngAlgoInit) NULL,
55 };
56 
57 
58 /**
59  * @brief Initialize PRNG context
60  * @param[in] context Pointer to the CTR_DRBG context to initialize
61  * @param[in] cipherAlgo Approved block cipher algorithm
62  * @param[in] keyLen Key length, in bits
63  * @param[in] df Use key derivation function
64  * @return Error code
65  **/
66 
67 error_t ctrDrbgInit(CtrDrbgContext *context, const CipherAlgo *cipherAlgo,
68  size_t keyLen, bool_t df)
69 {
70  //Check parameters
71  if(context == NULL || cipherAlgo == NULL)
73 
74  //Clear the internal state
75  osMemset(context, 0, sizeof(CtrDrbgContext));
76 
77  //Create a mutex to prevent simultaneous access to the PRNG state
78  if(!osCreateMutex(&context->mutex))
79  {
80  //Failed to create mutex
82  }
83 
84 #if (DES3_SUPPORT == ENABLED)
85  //TDEA cipher algorithm?
86  if(cipherAlgo == DES3_CIPHER_ALGO)
87  {
88  //TDEA uses 168-bit keys
89  if(keyLen != 168)
91 
92  //TDEA provides 112 bits of security strength
93  context->securityStrength = 14;
94  }
95  else
96 #endif
97 #if (AES_SUPPORT == ENABLED)
98  //AES cipher algorithm?
99  if(cipherAlgo == AES_CIPHER_ALGO)
100  {
101  //TDEA uses 128, 192 or 256-bit keys
102  if(keyLen != 128 && keyLen != 192 && keyLen != 256)
104 
105  //AES provides 128, 192 or 256 bits of security strength
106  context->securityStrength = keyLen / 8;
107  }
108  else
109 #endif
110  //Unknown cipher algorithm?
111  {
112  //CTR_DRBG must use an approved block cipher algorithm
114  }
115 
116  //Save parameters
117  context->cipherAlgo = cipherAlgo;
118  context->keyLen = keyLen / 8;
119  context->ctrLen = cipherAlgo->blockSize;
120  context->df = df;
121 
122  //Determine the seed length
123  context->seedLen = context->keyLen + cipherAlgo->blockSize;
124 
125  //Successful initialization
126  return NO_ERROR;
127 }
128 
129 
130 /**
131  * @brief Seed the PRNG state
132  * @param[in] context Pointer to the CTR_DRBG context
133  * @param[in] seed String of bits obtained from the randomness source
134  * @param[in] length Length of the string, in bytes
135  * @return Error code
136  **/
137 
138 error_t ctrDrbgSeed(CtrDrbgContext *context, const uint8_t *seed,
139  size_t length)
140 {
141  //Seeding process
142  return ctrDrbgSeedEx(context, seed, length, NULL, 0, NULL, 0);
143 }
144 
145 
146 /**
147  * @brief Seed the PRNG state (with nonce and personalization string)
148  * @param[in] context Pointer to the CTR_DRBG context
149  * @param[in] entropyInput String of bits obtained from the randomness source
150  * @param[in] entropyInputLen Length of the string, in bytes
151  * @param[in] nonce Nonce
152  * @param[in] nonceLen Length of the nonce, in bytes
153  * @param[in] personalizationString Personalization string received from the
154  * consuming application
155  * @param[in] personalizationStringLen Length of the personalization string,
156  * in bytes
157  * @return Error code
158  **/
159 
160 error_t ctrDrbgSeedEx(CtrDrbgContext *context, const uint8_t *entropyInput,
161  size_t entropyInputLen, const uint8_t *nonce, size_t nonceLen,
162  const uint8_t *personalizationString, size_t personalizationStringLen)
163 {
164  error_t error;
165  size_t i;
166  uint8_t seedMaterial[CTR_DRBG_MAX_SEED_LEN];
167 
168  //Check parameters
169  if(context == NULL || entropyInput == NULL)
171 
172  //The nonce parameter is optional
173  if(nonce == NULL && nonceLen != 0)
175 
176  //The personalization_string parameter is optional
177  if(personalizationString == NULL && personalizationStringLen != 0)
179 
180  //CTR_DRBG uses an approved block cipher algorithm
181  if(context->cipherAlgo == NULL)
182  return ERROR_PRNG_NOT_READY;
183 
184  //Check is derivation function is used
185  if(context->df)
186  {
187  //The entropy input shall have entropy that is equal to or greater than
188  //the security strength of the instantiation
189  if(entropyInputLen < context->securityStrength)
191 
192  //When instantiation is performed using this method, a nonce is required.
193  //The length of the nonce shall be at least half the maximum security
194  //strength supported
195  if(nonceLen < (context->securityStrength / 2))
197  }
198  else
199  {
200  //The length of the entropy_input must be exactly seedlen
201  if(entropyInputLen != context->seedLen)
203 
204  //The maximum length of the personalization_string is seedlen
205  if(personalizationStringLen > context->seedLen)
207  }
208 
209  //Acquire exclusive access to the PRNG state
210  osAcquireMutex(&context->mutex);
211 
212  //Initialize status code
213  error = NO_ERROR;
214 
215  //Check is derivation function is used
216  if(context->df)
217  {
218  DataChunk input[3];
219 
220  //Let seed_material = entropy_input || nonce || personalization_string
221  input[0].buffer = entropyInput;
222  input[0].length = entropyInputLen;
223  input[1].buffer = nonce;
224  input[1].length = nonceLen;
225  input[2].buffer = personalizationString;
226  input[2].length = personalizationStringLen;
227 
228  //Compute seed_material = df(seed_material, seedlen)
229  error = blockCipherDf(context, input, arraysize(input), seedMaterial,
230  context->seedLen);
231  }
232  else
233  {
234  //Copy entropy input
235  osMemcpy(seedMaterial, entropyInput, context->seedLen);
236 
237  //Compute seed_material = entropy_input + personalization_string
238  for(i = 0; i < personalizationStringLen; i++)
239  {
240  seedMaterial[i] ^= personalizationString[i];
241  }
242  }
243 
244  //Check status code
245  if(!error)
246  {
247  //Let Key be keylen bits of zeros
248  osMemset(context->k, 0, context->keyLen);
249  //Let V be blocklen bits of zeros
250  osMemset(context->v, 0, context->cipherAlgo->blockSize);
251 
252  //Compute (Key, V) = CTR_DRBG_Update(seed_material, Key, V).
253  error = ctrDrbgUpdate(context, seedMaterial, context->seedLen);
254  }
255 
256  //Check status code
257  if(!error)
258  {
259  //Reset reseed_counter
260  context->reseedCounter = 1;
261  }
262 
263  //Release exclusive access to the PRNG state
264  osReleaseMutex(&context->mutex);
265 
266  //Return status code
267  return error;
268 }
269 
270 
271 /**
272  * @brief Reseed the PRNG state
273  * @param[in] context Pointer to the CTR_DRBG context
274  * @param[in] seed String of bits obtained from the randomness source
275  * @param[in] length Length of the string, in bytes
276  * @return Error code
277  **/
278 
279 error_t ctrDrbgReseed(CtrDrbgContext *context, const uint8_t *seed,
280  size_t length)
281 {
282  //Reseeding process
283  return ctrDrbgReseedEx(context, seed, length, NULL, 0);
284 }
285 
286 
287 /**
288  * @brief Reseed the PRNG state (with additional input)
289  * @param[in] context Pointer to the CTR_DRBG context
290  * @param[in] entropyInput String of bits obtained from the randomness source
291  * @param[in] entropyInputLen Length of the string, in bytes
292  * @param[in] additionalInput Additional input string received from the
293  * consuming application
294  * @param[in] additionalInputLen Length of the additional input string, in bytes
295  * @return Error code
296  **/
297 
298 error_t ctrDrbgReseedEx(CtrDrbgContext *context, const uint8_t *entropyInput,
299  size_t entropyInputLen, const uint8_t *additionalInput,
300  size_t additionalInputLen)
301 {
302  error_t error;
303  size_t i;
304  uint8_t seedMaterial[CTR_DRBG_MAX_SEED_LEN];
305 
306  //Check parameters
307  if(context == NULL || entropyInput == NULL)
309 
310  //The additional_input parameter is optional
311  if(additionalInput == NULL && additionalInputLen != 0)
313 
314  //CTR_DRBG uses an approved block cipher algorithm
315  if(context->cipherAlgo == NULL)
316  return ERROR_PRNG_NOT_READY;
317 
318  //Check whether the DRBG has been properly instantiated
319  if(context->reseedCounter == 0)
320  return ERROR_PRNG_NOT_READY;
321 
322  //Check is derivation function is used
323  if(context->df)
324  {
325  //The entropy input shall have entropy that is equal to or greater than
326  //the security strength of the instantiation
327  if(entropyInputLen < context->securityStrength)
329  }
330  else
331  {
332  //The length of the entropy_input must be exactly seedlen
333  if(entropyInputLen != context->seedLen)
335 
336  //The maximum length of the additional_input is seedlen
337  if(additionalInputLen > context->seedLen)
339  }
340 
341  //Initialize status code
342  error = NO_ERROR;
343 
344  //Acquire exclusive access to the PRNG state
345  osAcquireMutex(&context->mutex);
346 
347  //Check is derivation function is used
348  if(context->df)
349  {
350  DataChunk input[2];
351 
352  //Let seed_material = entropy_input || additional_input
353  input[0].buffer = entropyInput;
354  input[0].length = entropyInputLen;
355  input[1].buffer = additionalInput;
356  input[1].length = additionalInputLen;
357 
358  //Compute seed_material = df(seed_material, seedlen)
359  error = blockCipherDf(context, input, arraysize(input), seedMaterial,
360  context->seedLen);
361  }
362  else
363  {
364  //Copy entropy input
365  osMemcpy(seedMaterial, entropyInput, context->seedLen);
366 
367  //Compute seed_material = entropy_input + additional_input
368  for(i = 0; i < additionalInputLen; i++)
369  {
370  seedMaterial[i] ^= additionalInput[i];
371  }
372  }
373 
374  //Check status code
375  if(!error)
376  {
377  //Compute (Key, V) = CTR_DRBG_Update(seed_material, Key, V).
378  error = ctrDrbgUpdate(context, seedMaterial, context->seedLen);
379  }
380 
381  //Check status code
382  if(!error)
383  {
384  //Reset reseed_counter
385  context->reseedCounter = 1;
386  }
387 
388  //Release exclusive access to the PRNG state
389  osReleaseMutex(&context->mutex);
390 
391  //Return status code
392  return error;
393 }
394 
395 
396 /**
397  * @brief Generate pseudorandom data
398  * @param[in] context Pointer to the CTR_DRBG context
399  * @param[out] output Buffer where to store the pseudorandom bytes
400  * @param[in] length Requested number of bytes
401  * @return Error code
402  **/
403 
404 error_t ctrDrbgGenerate(CtrDrbgContext *context, uint8_t *output,
405  size_t length)
406 {
407  //Generation process
408  return ctrDrbgGenerateEx(context, NULL, 0, output, length);
409 }
410 
411 
412 /**
413  * @brief Generate pseudorandom data (with additional input)
414  * @param[in] context Pointer to the CTR_DRBG context
415  * @param[in] additionalInput Additional input string received from the
416  * consuming application
417  * @param[in] additionalInputLen Length of the additional input string, in bytes
418  * @param[out] output Buffer where to store the pseudorandom bytes
419  * @param[in] outputLen Requested number of bytes
420  * @return Error code
421  **/
422 
424  const uint8_t *additionalInput, size_t additionalInputLen, uint8_t *output,
425  size_t outputLen)
426 {
427  error_t error;
428  size_t n;
429  uint8_t temp[CTR_DRBG_MAX_SEED_LEN];
430  uint8_t block[MAX_CIPHER_BLOCK_SIZE];
431  const CipherAlgo *cipherAlgo;
432 
433  //Check parameters
434  if(context == NULL)
436 
437  //The additional_input parameter is optional
438  if(additionalInput == NULL && additionalInputLen != 0)
440 
441  //CTR_DRBG uses an approved block cipher algorithm
442  if(context->cipherAlgo == NULL)
443  return ERROR_PRNG_NOT_READY;
444 
445  //A DRBG shall be instantiated prior to the generation of pseudorandom bits
446  if(context->reseedCounter == 0)
447  return ERROR_PRNG_NOT_READY;
448 
449  //If reseed_counter > reseed_interval, then return an indication that a
450  //reseed is required
452  return ERROR_RESEED_REQUIRED;
453 
454  //Derivation function not used?
455  if(!context->df)
456  {
457  //The maximum length of the additional_input is seedlen
458  if(additionalInputLen > context->seedLen)
460  }
461 
462  //Initialize status code
463  error = NO_ERROR;
464 
465  //Acquire exclusive access to the PRNG state
466  osAcquireMutex(&context->mutex);
467 
468  //The length of the additional input string may be zero
469  if(additionalInputLen > 0)
470  {
471  //Check is derivation function is used
472  if(context->df)
473  {
474  DataChunk input[1];
475 
476  //Let seed_material = entropy_input || additional_input
477  input[0].buffer = additionalInput;
478  input[0].length = additionalInputLen;
479 
480  //Compute additional_input = Block_Cipher_df(additional_input, seedlen)
481  error = blockCipherDf(context, input, arraysize(input), temp,
482  context->seedLen);
483  }
484  else
485  {
486  //If the length of the additional input is less than seedlen, then pad
487  //with zero bits
488  osMemset(temp, 0, context->seedLen);
489  osMemcpy(temp, additionalInput, additionalInputLen);
490  }
491 
492  //Check status code
493  if(!error)
494  {
495  //Compute (Key, V) = CTR_DRBG_Update(additional_input, Key, V)
496  error = ctrDrbgUpdate(context, temp, context->seedLen);
497  }
498  }
499  else
500  {
501  //Let additional_input be seedlen bits of zeros
502  osMemset(temp, 0, context->seedLen);
503  }
504 
505  //Check status code
506  if(!error)
507  {
508  //Load encryption key
509  error = ctrDrbgLoadKey(context, context->k);
510 
511  //Check status code
512  if(!error)
513  {
514  //The block cipher operation uses the selected block cipher algorithm
515  cipherAlgo = context->cipherAlgo;
516 
517  //Generate the requested number of bytes
518  while(outputLen > 0)
519  {
520  //Number of bytes to generate at a time
521  n = MIN(outputLen, cipherAlgo->blockSize);
522 
523  //Increment counter block
524  ctrDrbgIncBlock(context->v, cipherAlgo->blockSize, context->ctrLen);
525 
526  //Compute output_block = Block_Encrypt(Key, V)
527  cipherAlgo->encryptBlock(&context->cipherContext, context->v,
528  block);
529 
530  //Copy data to the output buffer
531  osMemcpy(output, block, n);
532 
533  //Next output block
534  output += n;
535  outputLen -= n;
536  }
537 
538  //Release cipher context
539  cipherAlgo->deinit(&context->cipherContext);
540  }
541  }
542 
543  //Check status code
544  if(!error)
545  {
546  //Compute (Key, V) = CTR_DRBG_Update(additional_input, Key, V)
547  error = ctrDrbgUpdate(context, temp, context->seedLen);
548  }
549 
550  //Check status code
551  if(!error)
552  {
553  //Increment reseed_counter
554  context->reseedCounter++;
555  }
556 
557  //Release exclusive access to the PRNG state
558  osReleaseMutex(&context->mutex);
559 
560  //Return status code
561  return error;
562 }
563 
564 
565 /**
566  * @brief Release PRNG context
567  * @param[in] context Pointer to the CTR_DRBG context
568  **/
569 
571 {
572  //Valid CTR_DRBG context?
573  if(context != NULL)
574  {
575  //Free previously allocated resources
576  osDeleteMutex(&context->mutex);
577 
578  //Erase the contents of the internal state
579  osMemset(context, 0, sizeof(CtrDrbgContext));
580  }
581 }
582 
583 
584 /**
585  * @brief Block cipher derivation function
586  * @param[in] context Pointer to the CTR_DRBG context
587  * @param[in] input The string to be operated on
588  * @param[in] inputLen Number of data chunks representing the input
589  * @param[out] output Buffer where to store the output value
590  * @param[out] outputLen The number of bytes to be returned
591  * @return Error code
592  **/
593 
595  uint_t inputLen, uint8_t *output, size_t outputLen)
596 {
597  error_t error;
598  uint32_t i;
599  size_t j;
600  size_t m;
601  size_t totalInputLen;
602  size_t paddingLen;
603  uint8_t separator;
604  uint8_t l[4];
605  uint8_t n[4];
606  uint8_t k[CTR_DRBG_MAX_KEY_LEN];
607  uint8_t x[MAX_CIPHER_BLOCK_SIZE];
608  uint8_t iv[MAX_CIPHER_BLOCK_SIZE];
609  uint8_t block[MAX_CIPHER_BLOCK_SIZE];
610  uint8_t temp[CTR_DRBG_MAX_SEED_LEN];
611  DataChunk s[8];
612  const CipherAlgo *cipherAlgo;
613 
614  //The maximum length (max_number_of_bits) is 512 bits for the currently
615  //approved block cipher algorithms
616  if(outputLen > 64)
618 
619  //Sanity check
620  if((inputLen + 5) > arraysize(s))
622 
623  //The block cipher operation uses the selected block cipher algorithm
624  cipherAlgo = context->cipherAlgo;
625 
626  //Determine the length of the input string
627  for(totalInputLen = 0, i = 0; i < inputLen; i++)
628  {
629  totalInputLen += input[i].length;
630  }
631 
632  //L is the bitstring representation of the integer resulting from
633  //len(input_string)/8. L shall be represented as a 32-bit integer
634  STORE32BE(totalInputLen, l);
635 
636  //N is the bitstring representation of the integer resulting from
637  //number_of_bits_to_return/8. N shall be represented as a 32-bit integer
638  STORE32BE(outputLen, n);
639 
640  //Padding delimiter character
641  separator = 0x80;
642 
643  //Prepare initialization vector
644  osMemset(iv, 0, cipherAlgo->blockSize);
645 
646  //Let S = L || N || input_string || 0x80
647  s[0].buffer = iv;
648  s[0].length = cipherAlgo->blockSize;
649  s[1].buffer = l;
650  s[1].length = sizeof(l);
651  s[2].buffer = n;
652  s[2].length = sizeof(n);
653 
654  for(i = 0; i < inputLen; i++)
655  {
656  s[3 + i].buffer = input[i].buffer;
657  s[3 + i].length = input[i].length;
658  }
659 
660  s[3 + i].buffer = &separator;
661  s[3 + i].length = sizeof(separator);
662 
663  //Get the actual amount of bytes in the last block
664  paddingLen = (totalInputLen + 9) % cipherAlgo->blockSize;
665 
666  //Determine the length of the padding string
667  if(paddingLen > 0)
668  {
669  paddingLen = cipherAlgo->blockSize - paddingLen;
670  }
671 
672  //Pad S with zeros, if necessary
673  s[4 + i].buffer = padding;
674  s[4 + i].length = paddingLen;
675 
676  //Set K = leftmost(0x00010203...1D1E1F, keylen)
677  for(i = 0; i < context->keyLen; i++)
678  {
679  k[i] = (uint8_t) i;
680  }
681 
682  //Initialize block counter
683  i = 0;
684 
685  //Generate keylen + outlen bytes
686  for(j = 0; j < context->seedLen; j += m)
687  {
688  //Number of bytes to generate at a time
689  m = MIN(context->seedLen - j, cipherAlgo->blockSize);
690 
691  //The 32-bit integer representation of i is padded with zeros to
692  //outlen bits
693  STORE32BE(i, iv);
694 
695  //Compute BCC(K, (IV || S)
696  error = ctrDrbgBcc(context, k, s, inputLen + 5, block);
697  //Any error to report?
698  if(error)
699  return error;
700 
701  //Copy data to the output buffer
702  osMemcpy(temp + j, block, m);
703 
704  //Increment block counter
705  i++;
706  }
707 
708  //Set K = leftmost(temp, keylen)
709  osMemcpy(k, temp, context->keyLen);
710  //Set X = select(temp, keylen+1, keylen+outlen)
711  osMemcpy(x, temp + context->keyLen, cipherAlgo->blockSize);
712 
713  //Load encryption key
714  error = ctrDrbgLoadKey(context, k);
715  //Any error to report?
716  if(error)
717  return error;
718 
719  //Generate the requested number of bytes
720  while(outputLen > 0)
721  {
722  //Number of bytes to generate at a time
723  m = MIN(outputLen, cipherAlgo->blockSize);
724 
725  //Compute X = Block_Encrypt(K, X)
726  cipherAlgo->encryptBlock(&context->cipherContext, x, x);
727 
728  //Set temp = temp || X
729  osMemcpy(output, x, m);
730 
731  //Next output block
732  output += m;
733  outputLen -= m;
734  }
735 
736  //Release cipher context
737  cipherAlgo->deinit(&context->cipherContext);
738 
739  //Successful processing
740  return NO_ERROR;
741 }
742 
743 
744 /**
745  * @brief BCC function
746  * @param[in] context Pointer to the CTR_DRBG context
747  * @param[in] key The key to be used for the block cipher operation
748  * @param[in] data The data to be operated on
749  * @param[in] dataLen Number of data chunks representing the data
750  * @param[out] output The result to be returned from the BCC operation
751  * @return Error code
752  **/
753 
754 error_t ctrDrbgBcc(CtrDrbgContext *context, const uint8_t *key,
755  const DataChunk *data, uint_t dataLen, uint8_t *output)
756 {
757  error_t error;
758  uint_t i;
759  size_t j;
760  size_t n;
761  size_t blockLen;
762  uint8_t block[MAX_CIPHER_BLOCK_SIZE];
763  uint8_t chainingValue[MAX_CIPHER_BLOCK_SIZE];
764  const CipherAlgo *cipherAlgo;
765 
766  //The block cipher operation uses the selected block cipher algorithm
767  cipherAlgo = context->cipherAlgo;
768 
769  //Determine the length of the input data
770  for(n = 0, i = 0; i < dataLen; i++)
771  {
772  n += data[i].length;
773  }
774 
775  //The length of data must be a multiple of outlen
776  if((n % cipherAlgo->blockSize) != 0)
777  return ERROR_INVALID_LENGTH;
778 
779  //Load encryption key
780  error = ctrDrbgLoadKey(context, key);
781  //Any error to report?
782  if(error)
783  return error;
784 
785  //Set the first chaining value to outlen zeros
786  osMemset(chainingValue, 0, cipherAlgo->blockSize);
787 
788  //Initialize block length
789  blockLen = 0;
790 
791  //Process input data
792  for(i = 0; i < dataLen; i++)
793  {
794  for(j = 0; j < data[i].length; j += n)
795  {
796  //Number of bytes to process at a time
797  n = MIN(data[i].length - j, cipherAlgo->blockSize - blockLen);
798 
799  //Copy the data to the buffer
800  osMemcpy(block + blockLen, (uint8_t *) data[i].buffer + j, n);
801  //Adjust the length of the buffer
802  blockLen += n;
803 
804  //Split data into n blocks of outlen bits each
805  if(blockLen == cipherAlgo->blockSize)
806  {
807  //Compute input_block = chaining_value + block(i)
808  ctrDrbgXorBlock(block, chainingValue, block, cipherAlgo->blockSize);
809 
810  //Compute chaining_value = Block_Encrypt(Key, input_block)
811  cipherAlgo->encryptBlock(&context->cipherContext, block,
812  chainingValue);
813 
814  //Empty the buffer
815  blockLen = 0;
816  }
817  }
818  }
819 
820  //Set output_block = chaining_value
821  osMemcpy(output, chainingValue, cipherAlgo->blockSize);
822 
823  //Release cipher context
824  cipherAlgo->deinit(&context->cipherContext);
825 
826  //Successful processing
827  return NO_ERROR;
828 }
829 
830 
831 /**
832  * @brief Update internal state
833  * @param[in] context Pointer to the CTR_DRBG context
834  * @param[in] providedData The data to be used
835  * @param[in] providedDataLen Length of the data, in bytes
836  * @return Error code
837  **/
838 
839 error_t ctrDrbgUpdate(CtrDrbgContext *context, const uint8_t *providedData,
840  size_t providedDataLen)
841 {
842  error_t error;
843  size_t i;
844  size_t n;
845  uint8_t temp[CTR_DRBG_MAX_SEED_LEN];
846  uint8_t block[MAX_CIPHER_BLOCK_SIZE];
847  const CipherAlgo *cipherAlgo;
848 
849  //The provided_data must be exactly seedlen bits in length
850  if(providedDataLen != context->seedLen)
852 
853  //Load encryption key
854  error = ctrDrbgLoadKey(context, context->k);
855  //Any error to report?
856  if(error)
857  return error;
858 
859  //The block cipher operation uses the selected block cipher algorithm
860  cipherAlgo = context->cipherAlgo;
861 
862  //Generate seedlen bits
863  for(i = 0; i < context->seedLen; i += n)
864  {
865  //Number of bytes to generate at a time
866  n = MIN(context->seedLen - i, cipherAlgo->blockSize);
867 
868  //Increment counter block
869  ctrDrbgIncBlock(context->v, cipherAlgo->blockSize, context->ctrLen);
870 
871  //Compute output_block = Block_Encrypt(Key, V)
872  cipherAlgo->encryptBlock(&context->cipherContext, context->v,
873  block);
874 
875  //Set temp = temp || output_block
876  osMemcpy(temp + i, block, n);
877  }
878 
879  //Compute temp = temp + provided_data
880  for(i = 0; i < context->seedLen; i++)
881  {
882  temp[i] ^= providedData[i];
883  }
884 
885  //Set Key = leftmost(temp, keylen)
886  osMemcpy(context->k, temp, context->keyLen);
887  //Set V = rightmost(temp, blocklen)
888  osMemcpy(context->v, temp + context->keyLen, cipherAlgo->blockSize);
889 
890  //Release cipher context
891  cipherAlgo->deinit(&context->cipherContext);
892 
893  //Successful processing
894  return NO_ERROR;
895 }
896 
897 
898 /**
899  * @brief Load encryption key
900  * @param[in] context Pointer to the CTR_DRBG context
901  * @param[in] key Pointer to the Encryption key to load
902  * @return Error code
903  **/
904 
905 error_t ctrDrbgLoadKey(CtrDrbgContext *context, const uint8_t *key)
906 {
907  error_t error;
908  const CipherAlgo *cipherAlgo;
909 
910  //The block cipher operation uses the selected block cipher algorithm
911  cipherAlgo = context->cipherAlgo;
912 
913 #if (DES3_SUPPORT == ENABLED)
914  //TDEA cipher algorithm?
915  if(cipherAlgo == DES3_CIPHER_ALGO && context->keyLen == 21)
916  {
917  uint8_t k[24];
918 
919  //Convert the 168-bit key to a 192-bit key
920  desComputeKeyParity(key, k);
921  desComputeKeyParity(key + 7, k + 8);
922  desComputeKeyParity(key + 14, k + 16);
923 
924  //Load encryption key
925  error = cipherAlgo->init(&context->cipherContext, k, sizeof(k));
926  }
927  else
928 #endif
929  {
930  //Load encryption key
931  error = cipherAlgo->init(&context->cipherContext, key, context->keyLen);
932  }
933 
934  //Return status code
935  return error;
936 }
937 
938 
939 /**
940  * @brief Increment counter block
941  * @param[in,out] ctr Pointer to the counter block
942  * @param[in] blockLen Length of the block, in bytes
943  * @param[in] ctrLen Size of the specific part of the block to be incremented
944  **/
945 
946 void ctrDrbgIncBlock(uint8_t *ctr, size_t blockLen, size_t ctrLen)
947 {
948  size_t i;
949  uint16_t temp;
950 
951  //The function increments the right-most bytes of the block. The remaining
952  //left-most bytes remain unchanged
953  for(temp = 1, i = 1; i <= ctrLen; i++)
954  {
955  //Increment the current byte and propagate the carry
956  temp += ctr[blockLen - i];
957  ctr[blockLen - i] = temp & 0xFF;
958  temp >>= 8;
959  }
960 }
961 
962 
963 /**
964  * @brief XOR operation
965  * @param[out] x Block resulting from the XOR operation
966  * @param[in] a First input block
967  * @param[in] b Second input block
968  * @param[in] n Length of the block, in bytes
969  **/
970 
971 void ctrDrbgXorBlock(uint8_t *x, const uint8_t *a, const uint8_t *b, size_t n)
972 {
973  size_t i;
974 
975  //Perform XOR operation
976  for(i = 0; i < n; i++)
977  {
978  x[i] = a[i] ^ b[i];
979  }
980 }
981 
982 #endif
uint16_t block
Definition: tftp_common.h:115
size_t keyLen
Key length.
Definition: ctr_drbg.h:63
error_t ctrDrbgInit(CtrDrbgContext *context, const CipherAlgo *cipherAlgo, size_t keyLen, bool_t df)
Initialize PRNG context.
Definition: ctr_drbg.c:67
int bool_t
Definition: compiler_port.h:61
uint8_t b
Definition: nbns_common.h:122
bool_t osCreateMutex(OsMutex *mutex)
Create a mutex object.
uint8_t a
Definition: ndp.h:411
#define PrngAlgo
Definition: crypto.h:1008
uint8_t x
Definition: lldp_ext_med.h:211
uint8_t data[]
Definition: ethernet.h:224
const PrngAlgo ctrDrbgPrngAlgo
Definition: ctr_drbg.c:46
const void * buffer
Definition: crypto.h:1053
@ ERROR_OUT_OF_RESOURCES
Definition: error.h:64
error_t(* PrngAlgoSeed)(void *context, const uint8_t *seed, size_t length)
Definition: crypto.h:1107
size_t blockSize
Definition: crypto.h:1168
error_t(* PrngAlgoReseed)(void *context, const uint8_t *seed, size_t length)
Definition: crypto.h:1110
@ ERROR_PRNG_NOT_READY
Definition: error.h:252
CipherAlgoEncryptBlock encryptBlock
Definition: crypto.h:1172
void desComputeKeyParity(const uint8_t *input, uint8_t *output)
Convert a 56-bit key to a 64-bit key (with odd parity)
Definition: des.c:442
#define MAX_CIPHER_BLOCK_SIZE
CipherAlgoInit init
Definition: crypto.h:1169
error_t ctrDrbgGenerate(CtrDrbgContext *context, uint8_t *output, size_t length)
Generate pseudorandom data.
Definition: ctr_drbg.c:404
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
#define osMemcpy(dest, src, length)
Definition: os_port.h:144
#define CTR_DRBG_MAX_KEY_LEN
Definition: ctr_drbg.h:39
error_t
Error codes.
Definition: error.h:43
size_t securityStrength
Security strength.
Definition: ctr_drbg.h:64
CipherContext cipherContext
Cipher context.
Definition: ctr_drbg.h:62
size_t ctrLen
Counter length.
Definition: ctr_drbg.h:66
error_t ctrDrbgBcc(CtrDrbgContext *context, const uint8_t *key, const DataChunk *data, uint_t dataLen, uint8_t *output)
BCC function.
Definition: ctr_drbg.c:754
@ ERROR_RESEED_REQUIRED
Definition: error.h:312
void ctrDrbgXorBlock(uint8_t *x, const uint8_t *a, const uint8_t *b, size_t n)
XOR operation.
Definition: ctr_drbg.c:971
uint64_t reseedCounter
Reseed counter.
Definition: ctr_drbg.h:70
OsMutex mutex
Mutex preventing simultaneous access to the PRNG state.
Definition: ctr_drbg.h:60
const CipherAlgo * cipherAlgo
Cipher function.
Definition: ctr_drbg.h:61
@ ERROR_INVALID_KEY_LENGTH
Definition: error.h:107
@ ERROR_INVALID_LENGTH
Definition: error.h:111
General definitions for cryptographic algorithms.
void ctrDrbgIncBlock(uint8_t *ctr, size_t blockLen, size_t ctrLen)
Increment counter block.
Definition: ctr_drbg.c:946
uint8_t iv[]
Definition: ike.h:1659
uint8_t length
Definition: tcp.h:375
#define MIN(a, b)
Definition: os_port.h:63
error_t ctrDrbgLoadKey(CtrDrbgContext *context, const uint8_t *key)
Load encryption key.
Definition: ctr_drbg.c:905
uint32_t dataLen
Definition: sftp_common.h:229
bool_t df
Use key derivation function.
Definition: ctr_drbg.h:65
error_t ctrDrbgUpdate(CtrDrbgContext *context, const uint8_t *providedData, size_t providedDataLen)
Update internal state.
Definition: ctr_drbg.c:839
error_t blockCipherDf(CtrDrbgContext *context, const DataChunk *input, uint_t inputLen, uint8_t *output, size_t outputLen)
Block cipher derivation function.
Definition: ctr_drbg.c:594
Data chunk descriptor.
Definition: crypto.h:1052
uint8_t l
Definition: ndp.h:412
void(* PrngAlgoDeinit)(void *context)
Definition: crypto.h:1116
void osDeleteMutex(OsMutex *mutex)
Delete a mutex object.
uint8_t k[CTR_DRBG_MAX_KEY_LEN]
Key.
Definition: ctr_drbg.h:69
@ ERROR_UNSUPPORTED_CIPHER_ALGO
Definition: error.h:129
uint8_t m
Definition: ndp.h:304
uint8_t n
void ctrDrbgDeinit(CtrDrbgContext *context)
Release PRNG context.
Definition: ctr_drbg.c:570
error_t ctrDrbgGenerateEx(CtrDrbgContext *context, const uint8_t *additionalInput, size_t additionalInputLen, uint8_t *output, size_t outputLen)
Generate pseudorandom data (with additional input)
Definition: ctr_drbg.c:423
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
error_t(* PrngAlgoGenerate)(void *context, uint8_t *output, size_t length)
Definition: crypto.h:1113
CipherAlgoDeinit deinit
Definition: crypto.h:1174
Common interface for encryption algorithms.
Definition: crypto.h:1164
#define AES_CIPHER_ALGO
Definition: aes.h:45
uint8_t s
Definition: igmp_common.h:234
size_t length
Definition: crypto.h:1054
error_t ctrDrbgReseed(CtrDrbgContext *context, const uint8_t *seed, size_t length)
Reseed the PRNG state.
Definition: ctr_drbg.c:279
#define CTR_DRBG_MAX_SEED_LEN
Definition: ctr_drbg.h:41
CTR_DRBG pseudorandom number generator.
CTR_DRBG PRNG context.
Definition: ctr_drbg.h:59
#define DES3_CIPHER_ALGO
Definition: des3.h:46
error_t ctrDrbgSeedEx(CtrDrbgContext *context, const uint8_t *entropyInput, size_t entropyInputLen, const uint8_t *nonce, size_t nonceLen, const uint8_t *personalizationString, size_t personalizationStringLen)
Seed the PRNG state (with nonce and personalization string)
Definition: ctr_drbg.c:160
size_t seedLen
Seed length.
Definition: ctr_drbg.h:67
unsigned int uint_t
Definition: compiler_port.h:57
error_t ctrDrbgReseedEx(CtrDrbgContext *context, const uint8_t *entropyInput, size_t entropyInputLen, const uint8_t *additionalInput, size_t additionalInputLen)
Reseed the PRNG state (with additional input)
Definition: ctr_drbg.c:298
error_t ctrDrbgSeed(CtrDrbgContext *context, const uint8_t *seed, size_t length)
Seed the PRNG state.
Definition: ctr_drbg.c:138
#define osMemset(p, value, length)
Definition: os_port.h:138
uint8_t v[MAX_CIPHER_BLOCK_SIZE]
Value V.
Definition: ctr_drbg.h:68
error_t(* PrngAlgoInit)(void *context)
Definition: crypto.h:1105
#define STORE32BE(a, p)
Definition: cpu_endian.h:286
uint8_t nonce[]
Definition: ntp_common.h:239
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
#define arraysize(a)
Definition: os_port.h:71
#define CTR_DRBG_MAX_RESEED_INTERVAL
Definition: ctr_drbg.h:43