m460_crypto_cipher.c
Go to the documentation of this file.
1 /**
2  * @file m460_crypto_cipher.c
3  * @brief M460 cipher hardware accelerator
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.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
33 
34 //Dependencies
35 #include "m460.h"
36 #include "core/crypto.h"
41 #include "aead/aead_algorithms.h"
42 #include "debug.h"
43 
44 //Check crypto library configuration
45 #if (M460_CRYPTO_CIPHER_SUPPORT == ENABLED && AES_SUPPORT == ENABLED)
46 
47 
48 /**
49  * @brief Load AES key
50  * @param[in] context AES algorithm context
51  **/
52 
53 void aesLoadKey(AesContext *context)
54 {
55  uint32_t temp;
56 
57  //Read mode register
58  temp = CRPT->AES_CTL & ~CRPT_AES_CTL_KEYSZ_Pos;
59 
60  //Check the length of the key
61  if(context->nr == 10)
62  {
63  //10 rounds are required for 128-bit key
64  CRPT->AES_CTL = temp | CRPT_AES_CTL_KEYSZ_128B;
65 
66  //Set the 128-bit encryption key
67  CRPT->AES_KEY[0] = context->ek[0];
68  CRPT->AES_KEY[1] = context->ek[1];
69  CRPT->AES_KEY[2] = context->ek[2];
70  CRPT->AES_KEY[3] = context->ek[3];
71  }
72  else if(context->nr == 12)
73  {
74  //12 rounds are required for 192-bit key
75  CRPT->AES_CTL = temp | CRPT_AES_CTL_KEYSZ_192B;
76 
77  //Set the 192-bit encryption key
78  CRPT->AES_KEY[0] = context->ek[0];
79  CRPT->AES_KEY[1] = context->ek[1];
80  CRPT->AES_KEY[2] = context->ek[2];
81  CRPT->AES_KEY[3] = context->ek[3];
82  CRPT->AES_KEY[4] = context->ek[4];
83  CRPT->AES_KEY[5] = context->ek[5];
84  }
85  else
86  {
87  //14 rounds are required for 256-bit key
88  CRPT->AES_CTL = temp | CRPT_AES_CTL_KEYSZ_256B;
89 
90  //Set the 256-bit encryption key
91  CRPT->AES_KEY[0] = context->ek[0];
92  CRPT->AES_KEY[1] = context->ek[1];
93  CRPT->AES_KEY[2] = context->ek[2];
94  CRPT->AES_KEY[3] = context->ek[3];
95  CRPT->AES_KEY[4] = context->ek[4];
96  CRPT->AES_KEY[5] = context->ek[5];
97  CRPT->AES_KEY[6] = context->ek[6];
98  CRPT->AES_KEY[7] = context->ek[7];
99  }
100 }
101 
102 
103 /**
104  * @brief Encrypt/decrypt a 16-byte block using AES algorithm
105  * @param[in] input Input block to be encrypted/decrypted
106  * @param[out] output Resulting block
107  **/
108 
109 void aesProcessDataBlock(const uint8_t *input, uint8_t *output)
110 {
111  uint32_t temp;
112 
113  //Start AES encryption/decryption
114  CRPT->AES_CTL |= CRPT_AES_CTL_DMALAST_Msk | CRPT_AES_CTL_START_Msk;
115 
116  //Poll INBUFFULL flag
117  while((CRPT->AES_STS & CRPT_AES_STS_INBUFFULL_Msk) != 0)
118  {
119  }
120 
121  //Write input block CRYPTO_AES_DATIN
122  CRPT->AES_DATIN = __UNALIGNED_UINT32_READ(input);
123  CRPT->AES_DATIN = __UNALIGNED_UINT32_READ(input + 4);
124  CRPT->AES_DATIN = __UNALIGNED_UINT32_READ(input + 8);
125  CRPT->AES_DATIN = __UNALIGNED_UINT32_READ(input + 12);
126 
127  //Poll OUTBUFEMPTY flag
128  while((CRPT->AES_STS & CRPT_AES_STS_OUTBUFEMPTY_Msk) != 0)
129  {
130  }
131 
132  //Read output block from CRYPTO_AES_DATOUT
133  temp = CRPT->AES_DATOUT;
134  __UNALIGNED_UINT32_WRITE(output, temp);
135  temp = CRPT->AES_DATOUT;
136  __UNALIGNED_UINT32_WRITE(output + 4, temp);
137  temp = CRPT->AES_DATOUT;
138  __UNALIGNED_UINT32_WRITE(output + 8, temp);
139  temp = CRPT->AES_DATOUT;
140  __UNALIGNED_UINT32_WRITE(output + 12, temp);
141 
142  //Save feedback information
143  CRPT->AES_IV[0] = CRPT->AES_FDBCK[0];
144  CRPT->AES_IV[1] = CRPT->AES_FDBCK[1];
145  CRPT->AES_IV[2] = CRPT->AES_FDBCK[2];
146  CRPT->AES_IV[3] = CRPT->AES_FDBCK[3];
147 }
148 
149 
150 /**
151  * @brief Perform AES encryption or decryption
152  * @param[in] context AES algorithm context
153  * @param[in,out] iv Initialization vector
154  * @param[in] input Data to be encrypted/decrypted
155  * @param[out] output Data resulting from the encryption/decryption process
156  * @param[in] length Total number of data bytes to be processed
157  * @param[in] opmode Operation mode
158  **/
159 
160 void aesProcessData(AesContext *context, uint8_t *iv, const uint8_t *input,
161  uint8_t *output, size_t length, uint32_t opmode)
162 {
163  uint32_t temp;
164 
165  //Acquire exclusive access to the CRYPTO module
167 
168  //Reset CRYPTO controller
169  SYS->IPRST0 |= SYS_IPRST0_CRPTRST_Msk;
170  SYS->IPRST0 &= ~SYS_IPRST0_CRPTRST_Msk;
171 
172  //Configure operation mode
173  CRPT->AES_CTL = CRPT_AES_CTL_KEYPRT_Msk | CRPT_AES_CTL_INSWAP_Msk |
174  CRPT_AES_CTL_OUTSWAP_Msk | opmode;
175 
176  //Set encryption key
177  aesLoadKey(context);
178 
179  //Valid initialization vector?
180  if(iv != NULL)
181  {
182  //Set initialization vector
183  CRPT->AES_IV[0] = LOAD32BE(iv);
184  CRPT->AES_IV[1] = LOAD32BE(iv + 4);
185  CRPT->AES_IV[2] = LOAD32BE(iv + 8);
186  CRPT->AES_IV[3] = LOAD32BE(iv + 12);
187  }
188 
189  //Process data
190  while(length >= AES_BLOCK_SIZE)
191  {
192  //The data is encrypted block by block
193  aesProcessDataBlock(input, output);
194 
195  //Next block
196  input += AES_BLOCK_SIZE;
197  output += AES_BLOCK_SIZE;
199  }
200 
201  //Process final block of data
202  if(length > 0)
203  {
204  uint8_t buffer[AES_BLOCK_SIZE];
205 
206  //Copy input data
207  osMemset(buffer, 0, AES_BLOCK_SIZE);
208  osMemcpy(buffer, input, length);
209 
210  //Encrypt the final block of data
211  aesProcessDataBlock(buffer, buffer);
212 
213  //Copy output data
214  osMemcpy(output, buffer, length);
215  }
216 
217  //Valid initialization vector?
218  if(iv != NULL)
219  {
220  //Update the value of the initialization vector
221  temp = CRPT->AES_FDBCK[0];
222  STORE32BE(temp, iv);
223  temp = CRPT->AES_FDBCK[1];
224  STORE32BE(temp, iv + 4);
225  temp = CRPT->AES_FDBCK[2];
226  STORE32BE(temp, iv + 8);
227  temp = CRPT->AES_FDBCK[3];
228  STORE32BE(temp, iv + 12);
229  }
230 
231  //Stop AES engine
232  CRPT->AES_CTL |= CRPT_AES_CTL_STOP_Msk;
233 
234  //Release exclusive access to the CRYPTO module
236 }
237 
238 
239 /**
240  * @brief Key expansion
241  * @param[in] context Pointer to the AES context to initialize
242  * @param[in] key Pointer to the key
243  * @param[in] keyLen Length of the key
244  * @return Error code
245  **/
246 
247 error_t aesInit(AesContext *context, const uint8_t *key, size_t keyLen)
248 {
249  size_t i;
250 
251  //Check parameters
252  if(context == NULL || key == NULL)
254 
255  //Check the length of the key
256  if(keyLen == 16)
257  {
258  //10 rounds are required for 128-bit key
259  context->nr = 10;
260  }
261  else if(keyLen == 24)
262  {
263  //12 rounds are required for 256-bit key
264  context->nr = 12;
265  }
266  else if(keyLen == 32)
267  {
268  //14 rounds are required for 256-bit key
269  context->nr = 14;
270  }
271  else
272  {
273  //192-bit keys are not supported
275  }
276 
277  //Determine the number of 32-bit words in the key
278  keyLen /= 4;
279 
280  //Copy the original key
281  for(i = 0; i < keyLen; i++)
282  {
283  context->ek[i] = LOAD32BE(key + (i * 4));
284  }
285 
286  //No error to report
287  return NO_ERROR;
288 }
289 
290 
291 /**
292  * @brief Encrypt a 16-byte block using AES algorithm
293  * @param[in] context Pointer to the AES context
294  * @param[in] input Plaintext block to encrypt
295  * @param[out] output Ciphertext block resulting from encryption
296  **/
297 
298 void aesEncryptBlock(AesContext *context, const uint8_t *input, uint8_t *output)
299 {
300  //Perform AES encryption
301  aesProcessData(context, NULL, input, output, AES_BLOCK_SIZE,
302  CRPT_AES_CTL_OPMODE_ECB | CRPT_AES_CTL_ENCRPT_Msk);
303 }
304 
305 
306 /**
307  * @brief Decrypt a 16-byte block using AES algorithm
308  * @param[in] context Pointer to the AES context
309  * @param[in] input Ciphertext block to decrypt
310  * @param[out] output Plaintext block resulting from decryption
311  **/
312 
313 void aesDecryptBlock(AesContext *context, const uint8_t *input, uint8_t *output)
314 {
315  //Perform AES decryption
316  aesProcessData(context, NULL, input, output, AES_BLOCK_SIZE,
318 }
319 
320 
321 #if (ECB_SUPPORT == ENABLED)
322 
323 /**
324  * @brief ECB encryption
325  * @param[in] cipher Cipher algorithm
326  * @param[in] context Cipher algorithm context
327  * @param[in] p Plaintext to be encrypted
328  * @param[out] c Ciphertext resulting from the encryption
329  * @param[in] length Total number of data bytes to be encrypted
330  * @return Error code
331  **/
332 
333 error_t ecbEncrypt(const CipherAlgo *cipher, void *context,
334  const uint8_t *p, uint8_t *c, size_t length)
335 {
336  error_t error;
337 
338  //Initialize status code
339  error = NO_ERROR;
340 
341  //AES cipher algorithm?
342  if(cipher == AES_CIPHER_ALGO)
343  {
344  //Check the length of the payload
345  if(length == 0)
346  {
347  //No data to process
348  }
349  else if((length % AES_BLOCK_SIZE) == 0)
350  {
351  //Encrypt payload data
352  aesProcessData(context, NULL, p, c, length, CRPT_AES_CTL_OPMODE_ECB |
353  CRPT_AES_CTL_ENCRPT_Msk);
354  }
355  else
356  {
357  //The length of the payload must be a multiple of the block size
358  error = ERROR_INVALID_LENGTH;
359  }
360  }
361  else
362  {
363  //ECB mode operates in a block-by-block fashion
364  while(length >= cipher->blockSize)
365  {
366  //Encrypt current block
367  cipher->encryptBlock(context, p, c);
368 
369  //Next block
370  p += cipher->blockSize;
371  c += cipher->blockSize;
372  length -= cipher->blockSize;
373  }
374 
375  //The length of the payload must be a multiple of the block size
376  if(length != 0)
377  {
378  error = ERROR_INVALID_LENGTH;
379  }
380  }
381 
382  //Return status code
383  return error;
384 }
385 
386 
387 /**
388  * @brief ECB decryption
389  * @param[in] cipher Cipher algorithm
390  * @param[in] context Cipher algorithm context
391  * @param[in] c Ciphertext to be decrypted
392  * @param[out] p Plaintext resulting from the decryption
393  * @param[in] length Total number of data bytes to be decrypted
394  * @return Error code
395  **/
396 
397 error_t ecbDecrypt(const CipherAlgo *cipher, void *context,
398  const uint8_t *c, uint8_t *p, size_t length)
399 {
400  error_t error;
401 
402  //Initialize status code
403  error = NO_ERROR;
404 
405  //AES cipher algorithm?
406  if(cipher == AES_CIPHER_ALGO)
407  {
408  //Check the length of the payload
409  if(length == 0)
410  {
411  //No data to process
412  }
413  else if((length % AES_BLOCK_SIZE) == 0)
414  {
415  //Decrypt payload data
416  aesProcessData(context, NULL, c, p, length, CRPT_AES_CTL_OPMODE_ECB);
417  }
418  else
419  {
420  //The length of the payload must be a multiple of the block size
421  error = ERROR_INVALID_LENGTH;
422  }
423  }
424  else
425  {
426  //ECB mode operates in a block-by-block fashion
427  while(length >= cipher->blockSize)
428  {
429  //Decrypt current block
430  cipher->decryptBlock(context, c, p);
431 
432  //Next block
433  c += cipher->blockSize;
434  p += cipher->blockSize;
435  length -= cipher->blockSize;
436  }
437 
438  //The length of the payload must be a multiple of the block size
439  if(length != 0)
440  {
441  error = ERROR_INVALID_LENGTH;
442  }
443  }
444 
445  //Return status code
446  return error;
447 }
448 
449 #endif
450 #if (CBC_SUPPORT == ENABLED)
451 
452 /**
453  * @brief CBC encryption
454  * @param[in] cipher Cipher algorithm
455  * @param[in] context Cipher algorithm context
456  * @param[in,out] iv Initialization vector
457  * @param[in] p Plaintext to be encrypted
458  * @param[out] c Ciphertext resulting from the encryption
459  * @param[in] length Total number of data bytes to be encrypted
460  * @return Error code
461  **/
462 
463 error_t cbcEncrypt(const CipherAlgo *cipher, void *context,
464  uint8_t *iv, const uint8_t *p, uint8_t *c, size_t length)
465 {
466  error_t error;
467 
468  //Initialize status code
469  error = NO_ERROR;
470 
471  //AES cipher algorithm?
472  if(cipher == AES_CIPHER_ALGO)
473  {
474  //Check the length of the payload
475  if(length == 0)
476  {
477  //No data to process
478  }
479  else if((length % AES_BLOCK_SIZE) == 0)
480  {
481  //Encrypt payload data
483  CRPT_AES_CTL_ENCRPT_Msk);
484  }
485  else
486  {
487  //The length of the payload must be a multiple of the block size
488  error = ERROR_INVALID_LENGTH;
489  }
490  }
491  else
492  {
493  size_t i;
494 
495  //CBC mode operates in a block-by-block fashion
496  while(length >= cipher->blockSize)
497  {
498  //XOR input block with IV contents
499  for(i = 0; i < cipher->blockSize; i++)
500  {
501  c[i] = p[i] ^ iv[i];
502  }
503 
504  //Encrypt the current block based upon the output of the previous
505  //encryption
506  cipher->encryptBlock(context, c, c);
507 
508  //Update IV with output block contents
509  osMemcpy(iv, c, cipher->blockSize);
510 
511  //Next block
512  p += cipher->blockSize;
513  c += cipher->blockSize;
514  length -= cipher->blockSize;
515  }
516 
517  //The length of the payload must be a multiple of the block size
518  if(length != 0)
519  {
520  error = ERROR_INVALID_LENGTH;
521  }
522  }
523 
524  //Return status code
525  return error;
526 }
527 
528 
529 /**
530  * @brief CBC decryption
531  * @param[in] cipher Cipher algorithm
532  * @param[in] context Cipher algorithm context
533  * @param[in,out] iv Initialization vector
534  * @param[in] c Ciphertext to be decrypted
535  * @param[out] p Plaintext resulting from the decryption
536  * @param[in] length Total number of data bytes to be decrypted
537  * @return Error code
538  **/
539 
540 error_t cbcDecrypt(const CipherAlgo *cipher, void *context,
541  uint8_t *iv, const uint8_t *c, uint8_t *p, size_t length)
542 {
543  error_t error;
544 
545  //Initialize status code
546  error = NO_ERROR;
547 
548  //AES cipher algorithm?
549  if(cipher == AES_CIPHER_ALGO)
550  {
551  //Check the length of the payload
552  if(length == 0)
553  {
554  //No data to process
555  }
556  else if((length % AES_BLOCK_SIZE) == 0)
557  {
558  //Decrypt payload data
560  }
561  else
562  {
563  //The length of the payload must be a multiple of the block size
564  error = ERROR_INVALID_LENGTH;
565  }
566  }
567  else
568  {
569  size_t i;
570  uint8_t t[16];
571 
572  //CBC mode operates in a block-by-block fashion
573  while(length >= cipher->blockSize)
574  {
575  //Save input block
576  osMemcpy(t, c, cipher->blockSize);
577 
578  //Decrypt the current block
579  cipher->decryptBlock(context, c, p);
580 
581  //XOR output block with IV contents
582  for(i = 0; i < cipher->blockSize; i++)
583  {
584  p[i] ^= iv[i];
585  }
586 
587  //Update IV with input block contents
588  osMemcpy(iv, t, cipher->blockSize);
589 
590  //Next block
591  c += cipher->blockSize;
592  p += cipher->blockSize;
593  length -= cipher->blockSize;
594  }
595 
596  //The length of the payload must be a multiple of the block size
597  if(length != 0)
598  {
599  error = ERROR_INVALID_LENGTH;
600  }
601  }
602 
603  //Return status code
604  return error;
605 }
606 
607 #endif
608 #if (CFB_SUPPORT == ENABLED)
609 
610 /**
611  * @brief CFB encryption
612  * @param[in] cipher Cipher algorithm
613  * @param[in] context Cipher algorithm context
614  * @param[in] s Size of the plaintext and ciphertext segments
615  * @param[in,out] iv Initialization vector
616  * @param[in] p Plaintext to be encrypted
617  * @param[out] c Ciphertext resulting from the encryption
618  * @param[in] length Total number of data bytes to be encrypted
619  * @return Error code
620  **/
621 
622 error_t cfbEncrypt(const CipherAlgo *cipher, void *context, uint_t s,
623  uint8_t *iv, const uint8_t *p, uint8_t *c, size_t length)
624 {
625  error_t error;
626 
627  //Initialize status code
628  error = NO_ERROR;
629 
630  //AES cipher algorithm?
631  if(cipher == AES_CIPHER_ALGO)
632  {
633  //Check the value of the parameter
634  if(s == (AES_BLOCK_SIZE * 8))
635  {
636  //Check the length of the payload
637  if(length > 0)
638  {
639  //Encrypt payload data
641  CRPT_AES_CTL_ENCRPT_Msk);
642  }
643  else
644  {
645  //No data to process
646  }
647  }
648  else
649  {
650  //The value of the parameter is not valid
651  error = ERROR_INVALID_PARAMETER;
652  }
653  }
654  else
655  {
656  //Check the value of the parameter
657  if((s % 8) == 0 && s >= 1 && s <= (cipher->blockSize * 8))
658  {
659  size_t i;
660  size_t n;
661  uint8_t o[16];
662 
663  //Determine the size, in bytes, of the plaintext and ciphertext segments
664  s = s / 8;
665 
666  //Process each plaintext segment
667  while(length > 0)
668  {
669  //Compute the number of bytes to process at a time
670  n = MIN(length, s);
671 
672  //Compute O(j) = CIPH(I(j))
673  cipher->encryptBlock(context, iv, o);
674 
675  //Compute C(j) = P(j) XOR MSB(O(j))
676  for(i = 0; i < n; i++)
677  {
678  c[i] = p[i] ^ o[i];
679  }
680 
681  //Compute I(j+1) = LSB(I(j)) | C(j)
682  osMemmove(iv, iv + s, cipher->blockSize - s);
683  osMemcpy(iv + cipher->blockSize - s, c, s);
684 
685  //Next block
686  p += n;
687  c += n;
688  length -= n;
689  }
690  }
691  else
692  {
693  //The value of the parameter is not valid
694  error = ERROR_INVALID_PARAMETER;
695  }
696  }
697 
698  //Return status code
699  return error;
700 }
701 
702 
703 /**
704  * @brief CFB decryption
705  * @param[in] cipher Cipher algorithm
706  * @param[in] context Cipher algorithm context
707  * @param[in] s Size of the plaintext and ciphertext segments
708  * @param[in,out] iv Initialization vector
709  * @param[in] c Ciphertext to be decrypted
710  * @param[out] p Plaintext resulting from the decryption
711  * @param[in] length Total number of data bytes to be decrypted
712  * @return Error code
713  **/
714 
715 error_t cfbDecrypt(const CipherAlgo *cipher, void *context, uint_t s,
716  uint8_t *iv, const uint8_t *c, uint8_t *p, size_t length)
717 {
718  error_t error;
719 
720  //Initialize status code
721  error = NO_ERROR;
722 
723  //AES cipher algorithm?
724  if(cipher == AES_CIPHER_ALGO)
725  {
726  //Check the value of the parameter
727  if(s == (AES_BLOCK_SIZE * 8))
728  {
729  //Check the length of the payload
730  if(length > 0)
731  {
732  //Decrypt payload data
734  }
735  else
736  {
737  //No data to process
738  }
739  }
740  else
741  {
742  //The value of the parameter is not valid
743  error = ERROR_INVALID_PARAMETER;
744  }
745  }
746  else
747  {
748  //Check the value of the parameter
749  if((s % 8) == 0 && s >= 1 && s <= (cipher->blockSize * 8))
750  {
751  size_t i;
752  size_t n;
753  uint8_t o[16];
754 
755  //Determine the size, in bytes, of the plaintext and ciphertext segments
756  s = s / 8;
757 
758  //Process each ciphertext segment
759  while(length > 0)
760  {
761  //Compute the number of bytes to process at a time
762  n = MIN(length, s);
763 
764  //Compute O(j) = CIPH(I(j))
765  cipher->encryptBlock(context, iv, o);
766 
767  //Compute I(j+1) = LSB(I(j)) | C(j)
768  osMemmove(iv, iv + s, cipher->blockSize - s);
769  osMemcpy(iv + cipher->blockSize - s, c, s);
770 
771  //Compute P(j) = C(j) XOR MSB(O(j))
772  for(i = 0; i < n; i++)
773  {
774  p[i] = c[i] ^ o[i];
775  }
776 
777  //Next block
778  c += n;
779  p += n;
780  length -= n;
781  }
782  }
783  else
784  {
785  //The value of the parameter is not valid
786  error = ERROR_INVALID_PARAMETER;
787  }
788  }
789 
790  //Return status code
791  return error;
792 }
793 
794 #endif
795 #if (OFB_SUPPORT == ENABLED)
796 
797 /**
798  * @brief OFB encryption
799  * @param[in] cipher Cipher algorithm
800  * @param[in] context Cipher algorithm context
801  * @param[in] s Size of the plaintext and ciphertext segments
802  * @param[in,out] iv Initialization vector
803  * @param[in] p Plaintext to be encrypted
804  * @param[out] c Ciphertext resulting from the encryption
805  * @param[in] length Total number of data bytes to be encrypted
806  * @return Error code
807  **/
808 
809 error_t ofbEncrypt(const CipherAlgo *cipher, void *context, uint_t s,
810  uint8_t *iv, const uint8_t *p, uint8_t *c, size_t length)
811 {
812  error_t error;
813 
814  //Initialize status code
815  error = NO_ERROR;
816 
817  //AES cipher algorithm?
818  if(cipher == AES_CIPHER_ALGO)
819  {
820  //Check the value of the parameter
821  if(s == (AES_BLOCK_SIZE * 8))
822  {
823  //Check the length of the payload
824  if(length > 0)
825  {
826  //Encrypt payload data
828  CRPT_AES_CTL_ENCRPT_Msk);
829  }
830  else
831  {
832  //No data to process
833  }
834  }
835  else
836  {
837  //The value of the parameter is not valid
838  error = ERROR_INVALID_PARAMETER;
839  }
840  }
841  else
842  {
843  //Check the value of the parameter
844  if((s % 8) == 0 && s >= 1 && s <= (cipher->blockSize * 8))
845  {
846  size_t i;
847  size_t n;
848  uint8_t o[16];
849 
850  //Determine the size, in bytes, of the plaintext and ciphertext segments
851  s = s / 8;
852 
853  //Process each plaintext segment
854  while(length > 0)
855  {
856  //Compute the number of bytes to process at a time
857  n = MIN(length, s);
858 
859  //Compute O(j) = CIPH(I(j))
860  cipher->encryptBlock(context, iv, o);
861 
862  //Compute C(j) = P(j) XOR MSB(O(j))
863  for(i = 0; i < n; i++)
864  {
865  c[i] = p[i] ^ o[i];
866  }
867 
868  //Compute I(j+1) = LSB(I(j)) | O(j)
869  osMemmove(iv, iv + s, cipher->blockSize - s);
870  osMemcpy(iv + cipher->blockSize - s, o, s);
871 
872  //Next block
873  p += n;
874  c += n;
875  length -= n;
876  }
877  }
878  else
879  {
880  //The value of the parameter is not valid
881  error = ERROR_INVALID_PARAMETER;
882  }
883  }
884 
885  //Return status code
886  return error;
887 }
888 
889 #endif
890 #if (CTR_SUPPORT == ENABLED)
891 
892 /**
893  * @brief CTR encryption
894  * @param[in] cipher Cipher algorithm
895  * @param[in] context Cipher algorithm context
896  * @param[in] m Size in bits of the specific part of the block to be incremented
897  * @param[in,out] t Initial counter block
898  * @param[in] p Plaintext to be encrypted
899  * @param[out] c Ciphertext resulting from the encryption
900  * @param[in] length Total number of data bytes to be encrypted
901  * @return Error code
902  **/
903 
904 error_t ctrEncrypt(const CipherAlgo *cipher, void *context, uint_t m,
905  uint8_t *t, const uint8_t *p, uint8_t *c, size_t length)
906 {
907  error_t error;
908 
909  //Initialize status code
910  error = NO_ERROR;
911 
912  //Check the value of the parameter
913  if((m % 8) == 0 && m <= (cipher->blockSize * 8))
914  {
915  //Determine the size, in bytes, of the specific part of the block to be
916  //incremented
917  m = m / 8;
918 
919  //AES cipher algorithm?
920  if(cipher == AES_CIPHER_ALGO)
921  {
922  size_t k;
923  size_t n;
924  uint8_t iv[AES_BLOCK_SIZE];
925 
926  //Process plaintext
927  while(length > 0)
928  {
929  //Limit the number of blocks to process at a time
930  k = 256 - t[AES_BLOCK_SIZE - 1];
931  n = MIN(length, k * AES_BLOCK_SIZE);
932  k = (n + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE;
933 
934  //Copy initial counter value
936 
937  //Encrypt payload data
939  CRPT_AES_CTL_ENCRPT_Msk);
940 
941  //Standard incrementing function
943 
944  //Next block
945  p += n;
946  c += n;
947  length -= n;
948  }
949  }
950  else
951  {
952  size_t i;
953  size_t n;
954  uint8_t o[16];
955 
956  //Process plaintext
957  while(length > 0)
958  {
959  //CTR mode operates in a block-by-block fashion
960  n = MIN(length, cipher->blockSize);
961 
962  //Compute O(j) = CIPH(T(j))
963  cipher->encryptBlock(context, t, o);
964 
965  //Compute C(j) = P(j) XOR T(j)
966  for(i = 0; i < n; i++)
967  {
968  c[i] = p[i] ^ o[i];
969  }
970 
971  //Standard incrementing function
972  ctrIncBlock(t, 1, cipher->blockSize, m);
973 
974  //Next block
975  p += n;
976  c += n;
977  length -= n;
978  }
979  }
980  }
981  else
982  {
983  //The value of the parameter is not valid
984  error = ERROR_INVALID_PARAMETER;
985  }
986 
987  //Return status code
988  return error;
989 }
990 
991 #endif
992 #if (GCM_SUPPORT == ENABLED)
993 
994 /**
995  * @brief Increment counter block
996  * @param[in,out] ctr Pointer to the counter block
997  * @param[in] inc Value of the increment
998  **/
999 
1000 void gcmIncBlock(uint8_t *ctr, uint32_t inc)
1001 {
1002  size_t i;
1003  uint32_t temp;
1004 
1005  //The function increments the right-most bytes of the block. The remaining
1006  //left-most bytes remain unchanged
1007  for(temp = inc, i = 0; i <= 3; i++)
1008  {
1009  //Increment the current byte and propagate the carry
1010  temp += ctr[15 - i];
1011  ctr[15 - i] = temp & 0xFF;
1012  temp >>= 8;
1013  }
1014 }
1015 
1016 
1017 /**
1018  * @brief Authenticated encryption using GCM
1019  * @param[in] context Pointer to the GCM context
1020  * @param[in] iv Initialization vector
1021  * @param[in] ivLen Length of the initialization vector
1022  * @param[in] a Additional authenticated data
1023  * @param[in] aLen Length of the additional data
1024  * @param[in] p Plaintext to be encrypted
1025  * @param[out] c Ciphertext resulting from the encryption
1026  * @param[in] length Total number of data bytes to be encrypted
1027  * @param[out] t Authentication tag
1028  * @param[in] tLen Length of the authentication tag
1029  * @return Error code
1030  **/
1031 
1032 error_t gcmEncrypt(GcmContext *context, const uint8_t *iv, size_t ivLen,
1033  const uint8_t *a, size_t aLen, const uint8_t *p, uint8_t *c, size_t length,
1034  uint8_t *t, size_t tLen)
1035 {
1036  size_t i;
1037  size_t n;
1038  uint8_t b[16];
1039  uint8_t j[16];
1040  uint8_t s[16];
1041 
1042  //Make sure the GCM context is valid
1043  if(context == NULL)
1044  return ERROR_INVALID_PARAMETER;
1045 
1046  //The length of the IV shall meet SP 800-38D requirements
1047  if(ivLen < 1)
1048  return ERROR_INVALID_LENGTH;
1049 
1050  //Check the length of the authentication tag
1051  if(tLen < 4 || tLen > 16)
1052  return ERROR_INVALID_LENGTH;
1053 
1054  //Check whether the length of the IV is 96 bits
1055  if(ivLen == 12)
1056  {
1057  //When the length of the IV is 96 bits, the padding string is appended
1058  //to the IV to form the pre-counter block
1059  osMemcpy(j, iv, 12);
1060  STORE32BE(1, j + 12);
1061  }
1062  else
1063  {
1064  //Initialize GHASH calculation
1065  osMemset(j, 0, 16);
1066 
1067  //Process the initialization vector
1068  for(i = 0; i < ivLen; i += n)
1069  {
1070  //The IV is processed in a block-by-block fashion
1071  n = MIN(ivLen - i, 16);
1072 
1073  //Apply GHASH function
1074  gcmXorBlock(j, j, iv + i, n);
1075  gcmMul(context, j);
1076  }
1077 
1078  //The string is appended with 64 additional 0 bits, followed by the
1079  //64-bit representation of the length of the IV
1080  osMemset(b, 0, 8);
1081  STORE64BE(ivLen * 8, b + 8);
1082 
1083  //The GHASH function is applied to the resulting string to form the
1084  //pre-counter block
1085  gcmXorBlock(j, j, b, 16);
1086  gcmMul(context, j);
1087  }
1088 
1089  //Compute MSB(CIPH(J(0)))
1090  context->cipherAlgo->encryptBlock(context->cipherContext, j, b);
1091  osMemcpy(t, b, tLen);
1092 
1093  //Initialize GHASH calculation
1094  osMemset(s, 0, 16);
1095 
1096  //Process AAD
1097  for(i = 0; i < aLen; i += n)
1098  {
1099  //Additional data are processed in a block-by-block fashion
1100  n = MIN(aLen - i, 16);
1101 
1102  //Apply GHASH function
1103  gcmXorBlock(s, s, a + i, n);
1104  gcmMul(context, s);
1105  }
1106 
1107  //Increment counter
1108  gcmIncCounter(j);
1109 
1110  //AES cipher algorithm?
1111  if(context->cipherAlgo == AES_CIPHER_ALGO)
1112  {
1113  //Encrypt plaintext
1114  for(i = 0; i < length; i += n)
1115  {
1116  size_t k;
1117  uint8_t iv[AES_BLOCK_SIZE];
1118 
1119  //Limit the number of blocks to process at a time
1120  k = 256 - j[AES_BLOCK_SIZE - 1];
1121  n = MIN(length, k * AES_BLOCK_SIZE);
1122  k = (n + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE;
1123 
1124  //Copy initial counter value
1125  osMemcpy(iv, j, AES_BLOCK_SIZE);
1126 
1127  //Encrypt payload data
1128  aesProcessData(context->cipherContext, iv, p + i, c + i, n,
1129  CRPT_AES_CTL_OPMODE_CTR | CRPT_AES_CTL_ENCRPT_Msk);
1130 
1131  //Increment the right-most 32 bits of the block
1132  gcmIncBlock(j, k);
1133  }
1134  }
1135  else
1136  {
1137  //Encrypt plaintext
1138  for(i = 0; i < length; i += n)
1139  {
1140  //The encryption operates in a block-by-block fashion
1141  n = MIN(length - i, 16);
1142 
1143  //Encrypt current block
1144  context->cipherAlgo->encryptBlock(context->cipherContext, j, b);
1145  gcmXorBlock(c + i, p + i, b, n);
1146 
1147  //Increment counter
1148  gcmIncCounter(j);
1149  }
1150  }
1151 
1152  //Process ciphertext
1153  for(i = 0; i < length; i += n)
1154  {
1155  //The encryption operates in a block-by-block fashion
1156  n = MIN(length - i, 16);
1157 
1158  //Apply GHASH function
1159  gcmXorBlock(s, s, c + i, n);
1160  gcmMul(context, s);
1161  }
1162 
1163  //Append the 64-bit representation of the length of the AAD and the
1164  //ciphertext
1165  STORE64BE(aLen * 8, b);
1166  STORE64BE(length * 8, b + 8);
1167 
1168  //The GHASH function is applied to the result to produce a single output
1169  //block S
1170  gcmXorBlock(s, s, b, 16);
1171  gcmMul(context, s);
1172 
1173  //Let T = MSB(GCTR(J(0), S)
1174  gcmXorBlock(t, t, s, tLen);
1175 
1176  //Successful encryption
1177  return NO_ERROR;
1178 }
1179 
1180 
1181 /**
1182  * @brief Authenticated decryption using GCM
1183  * @param[in] context Pointer to the GCM context
1184  * @param[in] iv Initialization vector
1185  * @param[in] ivLen Length of the initialization vector
1186  * @param[in] a Additional authenticated data
1187  * @param[in] aLen Length of the additional data
1188  * @param[in] c Ciphertext to be decrypted
1189  * @param[out] p Plaintext resulting from the decryption
1190  * @param[in] length Total number of data bytes to be decrypted
1191  * @param[in] t Authentication tag
1192  * @param[in] tLen Length of the authentication tag
1193  * @return Error code
1194  **/
1195 
1196 error_t gcmDecrypt(GcmContext *context, const uint8_t *iv, size_t ivLen,
1197  const uint8_t *a, size_t aLen, const uint8_t *c, uint8_t *p, size_t length,
1198  const uint8_t *t, size_t tLen)
1199 {
1200  uint8_t mask;
1201  size_t i;
1202  size_t n;
1203  uint8_t b[16];
1204  uint8_t j[16];
1205  uint8_t r[16];
1206  uint8_t s[16];
1207 
1208  //Make sure the GCM context is valid
1209  if(context == NULL)
1210  return ERROR_INVALID_PARAMETER;
1211 
1212  //The length of the IV shall meet SP 800-38D requirements
1213  if(ivLen < 1)
1214  return ERROR_INVALID_LENGTH;
1215 
1216  //Check the length of the authentication tag
1217  if(tLen < 4 || tLen > 16)
1218  return ERROR_INVALID_LENGTH;
1219 
1220  //Check whether the length of the IV is 96 bits
1221  if(ivLen == 12)
1222  {
1223  //When the length of the IV is 96 bits, the padding string is appended
1224  //to the IV to form the pre-counter block
1225  osMemcpy(j, iv, 12);
1226  STORE32BE(1, j + 12);
1227  }
1228  else
1229  {
1230  //Initialize GHASH calculation
1231  osMemset(j, 0, 16);
1232 
1233  //Process the initialization vector
1234  for(i = 0; i < ivLen; i += n)
1235  {
1236  //The IV is processed in a block-by-block fashion
1237  n = MIN(ivLen - i, 16);
1238 
1239  //Apply GHASH function
1240  gcmXorBlock(j, j, iv + i, n);
1241  gcmMul(context, j);
1242  }
1243 
1244  //The string is appended with 64 additional 0 bits, followed by the
1245  //64-bit representation of the length of the IV
1246  osMemset(b, 0, 8);
1247  STORE64BE(ivLen * 8, b + 8);
1248 
1249  //The GHASH function is applied to the resulting string to form the
1250  //pre-counter block
1251  gcmXorBlock(j, j, b, 16);
1252  gcmMul(context, j);
1253  }
1254 
1255  //Compute MSB(CIPH(J(0)))
1256  context->cipherAlgo->encryptBlock(context->cipherContext, j, b);
1257  osMemcpy(r, b, tLen);
1258 
1259  //Initialize GHASH calculation
1260  osMemset(s, 0, 16);
1261 
1262  //Process AAD
1263  for(i = 0; i < aLen; i += n)
1264  {
1265  //Additional data are processed in a block-by-block fashion
1266  n = MIN(aLen - i, 16);
1267 
1268  //Apply GHASH function
1269  gcmXorBlock(s, s, a + i, n);
1270  gcmMul(context, s);
1271  }
1272 
1273  //Process ciphertext
1274  for(i = 0; i < length; i += n)
1275  {
1276  //The decryption operates in a block-by-block fashion
1277  n = MIN(length - i, 16);
1278 
1279  //Apply GHASH function
1280  gcmXorBlock(s, s, c + i, n);
1281  gcmMul(context, s);
1282  }
1283 
1284  //Increment counter
1285  gcmIncCounter(j);
1286 
1287  //AES cipher algorithm?
1288  if(context->cipherAlgo == AES_CIPHER_ALGO)
1289  {
1290  //Decrypt ciphertext
1291  for(i = 0; i < length; i += n)
1292  {
1293  size_t k;
1294  uint8_t iv[AES_BLOCK_SIZE];
1295 
1296  //Limit the number of blocks to process at a time
1297  k = 256 - j[AES_BLOCK_SIZE - 1];
1298  n = MIN(length, k * AES_BLOCK_SIZE);
1299  k = (n + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE;
1300 
1301  //Copy initial counter value
1302  osMemcpy(iv, j, AES_BLOCK_SIZE);
1303 
1304  //Encrypt payload data
1305  aesProcessData(context->cipherContext, iv, c + i, p + i, n,
1306  CRPT_AES_CTL_OPMODE_CTR | CRPT_AES_CTL_ENCRPT_Msk);
1307 
1308  //Increment the right-most 32 bits of the block
1309  gcmIncBlock(j, k);
1310  }
1311  }
1312  else
1313  {
1314  //Decrypt ciphertext
1315  for(i = 0; i < length; i += n)
1316  {
1317  //The decryption operates in a block-by-block fashion
1318  n = MIN(length - i, 16);
1319 
1320  //Decrypt current block
1321  context->cipherAlgo->encryptBlock(context->cipherContext, j, b);
1322  gcmXorBlock(p + i, c + i, b, n);
1323 
1324  //Increment counter
1325  gcmIncCounter(j);
1326  }
1327  }
1328 
1329  //Append the 64-bit representation of the length of the AAD and the
1330  //ciphertext
1331  STORE64BE(aLen * 8, b);
1332  STORE64BE(length * 8, b + 8);
1333 
1334  //The GHASH function is applied to the result to produce a single output
1335  //block S
1336  gcmXorBlock(s, s, b, 16);
1337  gcmMul(context, s);
1338 
1339  //Let R = MSB(GCTR(J(0), S))
1340  gcmXorBlock(r, r, s, tLen);
1341 
1342  //The calculated tag is bitwise compared to the received tag. The message
1343  //is authenticated if and only if the tags match
1344  for(mask = 0, n = 0; n < tLen; n++)
1345  {
1346  mask |= r[n] ^ t[n];
1347  }
1348 
1349  //Return status code
1350  return (mask == 0) ? NO_ERROR : ERROR_FAILURE;
1351 }
1352 
1353 #endif
1354 #endif
uint8_t b
Definition: nbns_common.h:104
error_t cfbEncrypt(const CipherAlgo *cipher, void *context, uint_t s, uint8_t *iv, const uint8_t *p, uint8_t *c, size_t length)
CFB encryption.
uint8_t a
Definition: ndp.h:411
#define LOAD32BE(p)
Definition: cpu_endian.h:210
CipherAlgoDecryptBlock decryptBlock
Definition: crypto.h:1113
void aesLoadKey(AesContext *context)
Load AES key.
uint8_t p
Definition: ndp.h:300
error_t aesInit(AesContext *context, const uint8_t *key, size_t keyLen)
Key expansion.
uint8_t t
Definition: lldp_ext_med.h:212
uint8_t o
#define CRPT_AES_CTL_OPMODE_OFB
Collection of AEAD algorithms.
error_t gcmDecrypt(GcmContext *context, const uint8_t *iv, size_t ivLen, const uint8_t *a, size_t aLen, const uint8_t *c, uint8_t *p, size_t length, const uint8_t *t, size_t tLen)
Authenticated decryption using GCM.
error_t cfbDecrypt(const CipherAlgo *cipher, void *context, uint_t s, uint8_t *iv, const uint8_t *c, uint8_t *p, size_t length)
CFB decryption.
error_t cbcDecrypt(const CipherAlgo *cipher, void *context, uint8_t *iv, const uint8_t *c, uint8_t *p, size_t length)
CBC decryption.
size_t blockSize
Definition: crypto.h:1108
void gcmIncCounter(uint8_t *ctr)
Increment counter block.
Definition: gcm.c:609
#define CRPT_AES_CTL_OPMODE_CFB
CipherAlgoEncryptBlock encryptBlock
Definition: crypto.h:1112
uint8_t r
Definition: ndp.h:346
AES algorithm context.
Definition: aes.h:58
#define AES_BLOCK_SIZE
Definition: aes.h:43
void gcmIncBlock(uint8_t *ctr, uint32_t inc)
Increment counter block.
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
#define osMemcpy(dest, src, length)
Definition: os_port.h:144
__weak_func void gcmMul(GcmContext *context, uint8_t *x)
Multiplication operation in GF(2^128)
Definition: gcm.c:503
#define CRPT_AES_CTL_OPMODE_ECB
M460 cipher hardware accelerator.
error_t
Error codes.
Definition: error.h:43
void aesDecryptBlock(AesContext *context, const uint8_t *input, uint8_t *output)
Decrypt a 16-byte block using AES algorithm.
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
#define CRPT_AES_CTL_KEYSZ_192B
@ ERROR_INVALID_KEY_LENGTH
Definition: error.h:107
@ ERROR_INVALID_LENGTH
Definition: error.h:111
General definitions for cryptographic algorithms.
uint8_t mask
Definition: web_socket.h:319
uint8_t iv[]
Definition: ike.h:1626
Block cipher modes of operation.
void aesProcessData(AesContext *context, uint8_t *iv, const uint8_t *input, uint8_t *output, size_t length, uint32_t opmode)
Perform AES encryption or decryption.
const CipherAlgo * cipherAlgo
Cipher algorithm.
Definition: gcm.h:65
#define CRPT_AES_CTL_KEYSZ_256B
uint8_t length
Definition: tcp.h:375
#define MIN(a, b)
Definition: os_port.h:63
error_t cbcEncrypt(const CipherAlgo *cipher, void *context, uint8_t *iv, const uint8_t *p, uint8_t *c, size_t length)
CBC encryption.
error_t ecbDecrypt(const CipherAlgo *cipher, void *context, const uint8_t *c, uint8_t *p, size_t length)
ECB decryption.
uint_t nr
Definition: aes.h:59
#define CRPT_AES_CTL_OPMODE_CTR
GCM context.
Definition: gcm.h:64
#define STORE64BE(a, p)
Definition: cpu_endian.h:322
error_t ofbEncrypt(const CipherAlgo *cipher, void *context, uint_t s, uint8_t *iv, const uint8_t *p, uint8_t *c, size_t length)
OFB encryption.
void aesEncryptBlock(AesContext *context, const uint8_t *input, uint8_t *output)
Encrypt a 16-byte block using AES algorithm.
uint8_t m
Definition: ndp.h:304
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.
void gcmXorBlock(uint8_t *x, const uint8_t *a, const uint8_t *b, size_t n)
XOR operation.
Definition: gcm.c:592
#define CRPT_AES_CTL_KEYSZ_128B
M460 hardware cryptographic accelerator.
Common interface for encryption algorithms.
Definition: crypto.h:1104
#define AES_CIPHER_ALGO
Definition: aes.h:45
error_t ctrEncrypt(const CipherAlgo *cipher, void *context, uint_t m, uint8_t *t, const uint8_t *p, uint8_t *c, size_t length)
CTR encryption.
uint8_t s
Definition: igmp_common.h:234
#define CRPT_AES_CTL_OPMODE_CBC
uint32_t ek[60]
Definition: aes.h:60
unsigned int uint_t
Definition: compiler_port.h:57
#define osMemset(p, value, length)
Definition: os_port.h:138
error_t gcmEncrypt(GcmContext *context, const uint8_t *iv, size_t ivLen, const uint8_t *a, size_t aLen, const uint8_t *p, uint8_t *c, size_t length, uint8_t *t, size_t tLen)
Authenticated encryption using GCM.
void * cipherContext
Cipher algorithm context.
Definition: gcm.h:66
OsMutex m460CryptoMutex
Definition: m460_crypto.c:42
#define STORE32BE(a, p)
Definition: cpu_endian.h:286
void ctrIncBlock(uint8_t *ctr, uint32_t inc, size_t blockSize, size_t m)
Increment counter block.
Definition: ctr.c:138
error_t ecbEncrypt(const CipherAlgo *cipher, void *context, const uint8_t *p, uint8_t *c, size_t length)
ECB encryption.
@ NO_ERROR
Success.
Definition: error.h:44
uint8_t c
Definition: ndp.h:514
void aesProcessDataBlock(const uint8_t *input, uint8_t *output)
Encrypt/decrypt a 16-byte block using AES algorithm.
Debugging facilities.
#define osMemmove(dest, src, length)
Definition: os_port.h:150