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