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-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneCRYPTO Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.4.4
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  //Update the value of the initialization vector
487  }
488  else
489  {
490  //The length of the payload must be a multiple of the block size
491  error = ERROR_INVALID_LENGTH;
492  }
493  }
494  else
495  {
496  size_t i;
497 
498  //CBC mode operates in a block-by-block fashion
499  while(length >= cipher->blockSize)
500  {
501  //XOR input block with IV contents
502  for(i = 0; i < cipher->blockSize; i++)
503  {
504  c[i] = p[i] ^ iv[i];
505  }
506 
507  //Encrypt the current block based upon the output of the previous
508  //encryption
509  cipher->encryptBlock(context, c, c);
510 
511  //Update IV with output block contents
512  osMemcpy(iv, c, cipher->blockSize);
513 
514  //Next block
515  p += cipher->blockSize;
516  c += cipher->blockSize;
517  length -= cipher->blockSize;
518  }
519 
520  //The length of the payload must be a multiple of the block size
521  if(length != 0)
522  {
523  error = ERROR_INVALID_LENGTH;
524  }
525  }
526 
527  //Return status code
528  return error;
529 }
530 
531 
532 /**
533  * @brief CBC decryption
534  * @param[in] cipher Cipher algorithm
535  * @param[in] context Cipher algorithm context
536  * @param[in,out] iv Initialization vector
537  * @param[in] c Ciphertext to be decrypted
538  * @param[out] p Plaintext resulting from the decryption
539  * @param[in] length Total number of data bytes to be decrypted
540  * @return Error code
541  **/
542 
543 error_t cbcDecrypt(const CipherAlgo *cipher, void *context,
544  uint8_t *iv, const uint8_t *c, uint8_t *p, size_t length)
545 {
546  error_t error;
547 
548  //Initialize status code
549  error = NO_ERROR;
550 
551  //AES cipher algorithm?
552  if(cipher == AES_CIPHER_ALGO)
553  {
554  //Check the length of the payload
555  if(length == 0)
556  {
557  //No data to process
558  }
559  else if((length % AES_BLOCK_SIZE) == 0)
560  {
561  uint8_t block[AES_BLOCK_SIZE];
562 
563  //Save the last input block
565 
566  //Decrypt payload data
568 
569  //Update the value of the initialization vector
571  }
572  else
573  {
574  //The length of the payload must be a multiple of the block size
575  error = ERROR_INVALID_LENGTH;
576  }
577  }
578  else
579  {
580  size_t i;
581  uint8_t t[16];
582 
583  //CBC mode operates in a block-by-block fashion
584  while(length >= cipher->blockSize)
585  {
586  //Save input block
587  osMemcpy(t, c, cipher->blockSize);
588 
589  //Decrypt the current block
590  cipher->decryptBlock(context, c, p);
591 
592  //XOR output block with IV contents
593  for(i = 0; i < cipher->blockSize; i++)
594  {
595  p[i] ^= iv[i];
596  }
597 
598  //Update IV with input block contents
599  osMemcpy(iv, t, cipher->blockSize);
600 
601  //Next block
602  c += cipher->blockSize;
603  p += cipher->blockSize;
604  length -= cipher->blockSize;
605  }
606 
607  //The length of the payload must be a multiple of the block size
608  if(length != 0)
609  {
610  error = ERROR_INVALID_LENGTH;
611  }
612  }
613 
614  //Return status code
615  return error;
616 }
617 
618 #endif
619 #if (CFB_SUPPORT == ENABLED)
620 
621 /**
622  * @brief CFB encryption
623  * @param[in] cipher Cipher algorithm
624  * @param[in] context Cipher algorithm context
625  * @param[in] s Size of the plaintext and ciphertext segments
626  * @param[in,out] iv Initialization vector
627  * @param[in] p Plaintext to be encrypted
628  * @param[out] c Ciphertext resulting from the encryption
629  * @param[in] length Total number of data bytes to be encrypted
630  * @return Error code
631  **/
632 
633 error_t cfbEncrypt(const CipherAlgo *cipher, void *context, uint_t s,
634  uint8_t *iv, const uint8_t *p, uint8_t *c, size_t length)
635 {
636  error_t error;
637 
638  //Initialize status code
639  error = NO_ERROR;
640 
641  //AES cipher algorithm?
642  if(cipher == AES_CIPHER_ALGO)
643  {
644  //Check the value of the parameter
645  if(s == (AES_BLOCK_SIZE * 8))
646  {
647  //Check the length of the payload
648  if(length > 0)
649  {
650  //Encrypt payload data
652  CRPT_AES_CTL_ENCRPT_Msk);
653  }
654  else
655  {
656  //No data to process
657  }
658  }
659  else
660  {
661  //The value of the parameter is not valid
662  error = ERROR_INVALID_PARAMETER;
663  }
664  }
665  else
666  {
667  //Check the value of the parameter
668  if((s % 8) == 0 && s >= 1 && s <= (cipher->blockSize * 8))
669  {
670  size_t i;
671  size_t n;
672  uint8_t o[16];
673 
674  //Determine the size, in bytes, of the plaintext and ciphertext segments
675  s = s / 8;
676 
677  //Process each plaintext segment
678  while(length > 0)
679  {
680  //Compute the number of bytes to process at a time
681  n = MIN(length, s);
682 
683  //Compute O(j) = CIPH(I(j))
684  cipher->encryptBlock(context, iv, o);
685 
686  //Compute C(j) = P(j) XOR MSB(O(j))
687  for(i = 0; i < n; i++)
688  {
689  c[i] = p[i] ^ o[i];
690  }
691 
692  //Compute I(j+1) = LSB(I(j)) | C(j)
693  osMemmove(iv, iv + s, cipher->blockSize - s);
694  osMemcpy(iv + cipher->blockSize - s, c, s);
695 
696  //Next block
697  p += n;
698  c += n;
699  length -= n;
700  }
701  }
702  else
703  {
704  //The value of the parameter is not valid
705  error = ERROR_INVALID_PARAMETER;
706  }
707  }
708 
709  //Return status code
710  return error;
711 }
712 
713 
714 /**
715  * @brief CFB decryption
716  * @param[in] cipher Cipher algorithm
717  * @param[in] context Cipher algorithm context
718  * @param[in] s Size of the plaintext and ciphertext segments
719  * @param[in,out] iv Initialization vector
720  * @param[in] c Ciphertext to be decrypted
721  * @param[out] p Plaintext resulting from the decryption
722  * @param[in] length Total number of data bytes to be decrypted
723  * @return Error code
724  **/
725 
726 error_t cfbDecrypt(const CipherAlgo *cipher, void *context, uint_t s,
727  uint8_t *iv, const uint8_t *c, uint8_t *p, size_t length)
728 {
729  error_t error;
730 
731  //Initialize status code
732  error = NO_ERROR;
733 
734  //AES cipher algorithm?
735  if(cipher == AES_CIPHER_ALGO)
736  {
737  //Check the value of the parameter
738  if(s == (AES_BLOCK_SIZE * 8))
739  {
740  //Check the length of the payload
741  if(length > 0)
742  {
743  //Decrypt payload data
745  }
746  else
747  {
748  //No data to process
749  }
750  }
751  else
752  {
753  //The value of the parameter is not valid
754  error = ERROR_INVALID_PARAMETER;
755  }
756  }
757  else
758  {
759  //Check the value of the parameter
760  if((s % 8) == 0 && s >= 1 && s <= (cipher->blockSize * 8))
761  {
762  size_t i;
763  size_t n;
764  uint8_t o[16];
765 
766  //Determine the size, in bytes, of the plaintext and ciphertext segments
767  s = s / 8;
768 
769  //Process each ciphertext segment
770  while(length > 0)
771  {
772  //Compute the number of bytes to process at a time
773  n = MIN(length, s);
774 
775  //Compute O(j) = CIPH(I(j))
776  cipher->encryptBlock(context, iv, o);
777 
778  //Compute I(j+1) = LSB(I(j)) | C(j)
779  osMemmove(iv, iv + s, cipher->blockSize - s);
780  osMemcpy(iv + cipher->blockSize - s, c, s);
781 
782  //Compute P(j) = C(j) XOR MSB(O(j))
783  for(i = 0; i < n; i++)
784  {
785  p[i] = c[i] ^ o[i];
786  }
787 
788  //Next block
789  c += n;
790  p += n;
791  length -= n;
792  }
793  }
794  else
795  {
796  //The value of the parameter is not valid
797  error = ERROR_INVALID_PARAMETER;
798  }
799  }
800 
801  //Return status code
802  return error;
803 }
804 
805 #endif
806 #if (OFB_SUPPORT == ENABLED)
807 
808 /**
809  * @brief OFB encryption
810  * @param[in] cipher Cipher algorithm
811  * @param[in] context Cipher algorithm context
812  * @param[in] s Size of the plaintext and ciphertext segments
813  * @param[in,out] iv Initialization vector
814  * @param[in] p Plaintext to be encrypted
815  * @param[out] c Ciphertext resulting from the encryption
816  * @param[in] length Total number of data bytes to be encrypted
817  * @return Error code
818  **/
819 
820 error_t ofbEncrypt(const CipherAlgo *cipher, void *context, uint_t s,
821  uint8_t *iv, const uint8_t *p, uint8_t *c, size_t length)
822 {
823  error_t error;
824 
825  //Initialize status code
826  error = NO_ERROR;
827 
828  //AES cipher algorithm?
829  if(cipher == AES_CIPHER_ALGO)
830  {
831  //Check the value of the parameter
832  if(s == (AES_BLOCK_SIZE * 8))
833  {
834  //Check the length of the payload
835  if(length > 0)
836  {
837  //Encrypt payload data
839  CRPT_AES_CTL_ENCRPT_Msk);
840  }
841  else
842  {
843  //No data to process
844  }
845  }
846  else
847  {
848  //The value of the parameter is not valid
849  error = ERROR_INVALID_PARAMETER;
850  }
851  }
852  else
853  {
854  //Check the value of the parameter
855  if((s % 8) == 0 && s >= 1 && s <= (cipher->blockSize * 8))
856  {
857  size_t i;
858  size_t n;
859  uint8_t o[16];
860 
861  //Determine the size, in bytes, of the plaintext and ciphertext segments
862  s = s / 8;
863 
864  //Process each plaintext segment
865  while(length > 0)
866  {
867  //Compute the number of bytes to process at a time
868  n = MIN(length, s);
869 
870  //Compute O(j) = CIPH(I(j))
871  cipher->encryptBlock(context, iv, o);
872 
873  //Compute C(j) = P(j) XOR MSB(O(j))
874  for(i = 0; i < n; i++)
875  {
876  c[i] = p[i] ^ o[i];
877  }
878 
879  //Compute I(j+1) = LSB(I(j)) | O(j)
880  osMemmove(iv, iv + s, cipher->blockSize - s);
881  osMemcpy(iv + cipher->blockSize - s, o, s);
882 
883  //Next block
884  p += n;
885  c += n;
886  length -= n;
887  }
888  }
889  else
890  {
891  //The value of the parameter is not valid
892  error = ERROR_INVALID_PARAMETER;
893  }
894  }
895 
896  //Return status code
897  return error;
898 }
899 
900 #endif
901 #if (CTR_SUPPORT == ENABLED)
902 
903 /**
904  * @brief CTR encryption
905  * @param[in] cipher Cipher algorithm
906  * @param[in] context Cipher algorithm context
907  * @param[in] m Size in bits of the specific part of the block to be incremented
908  * @param[in,out] t Initial counter block
909  * @param[in] p Plaintext to be encrypted
910  * @param[out] c Ciphertext resulting from the encryption
911  * @param[in] length Total number of data bytes to be encrypted
912  * @return Error code
913  **/
914 
915 error_t ctrEncrypt(const CipherAlgo *cipher, void *context, uint_t m,
916  uint8_t *t, const uint8_t *p, uint8_t *c, size_t length)
917 {
918  error_t error;
919 
920  //Initialize status code
921  error = NO_ERROR;
922 
923  //Check the value of the parameter
924  if((m % 8) == 0 && m <= (cipher->blockSize * 8))
925  {
926  //Determine the size, in bytes, of the specific part of the block to be
927  //incremented
928  m = m / 8;
929 
930  //AES cipher algorithm?
931  if(cipher == AES_CIPHER_ALGO)
932  {
933  size_t k;
934  size_t n;
935  uint8_t iv[AES_BLOCK_SIZE];
936 
937  //Process plaintext
938  while(length > 0)
939  {
940  //Limit the number of blocks to process at a time
941  k = 256 - t[AES_BLOCK_SIZE - 1];
942  n = MIN(length, k * AES_BLOCK_SIZE);
943  k = (n + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE;
944 
945  //Copy initial counter value
947 
948  //Encrypt payload data
950  CRPT_AES_CTL_ENCRPT_Msk);
951 
952  //Standard incrementing function
954 
955  //Next block
956  p += n;
957  c += n;
958  length -= n;
959  }
960  }
961  else
962  {
963  size_t i;
964  size_t n;
965  uint8_t o[16];
966 
967  //Process plaintext
968  while(length > 0)
969  {
970  //CTR mode operates in a block-by-block fashion
971  n = MIN(length, cipher->blockSize);
972 
973  //Compute O(j) = CIPH(T(j))
974  cipher->encryptBlock(context, t, o);
975 
976  //Compute C(j) = P(j) XOR T(j)
977  for(i = 0; i < n; i++)
978  {
979  c[i] = p[i] ^ o[i];
980  }
981 
982  //Standard incrementing function
983  ctrIncBlock(t, 1, cipher->blockSize, m);
984 
985  //Next block
986  p += n;
987  c += n;
988  length -= n;
989  }
990  }
991  }
992  else
993  {
994  //The value of the parameter is not valid
995  error = ERROR_INVALID_PARAMETER;
996  }
997 
998  //Return status code
999  return error;
1000 }
1001 
1002 #endif
1003 #if (GCM_SUPPORT == ENABLED)
1004 
1005 /**
1006  * @brief Increment counter block
1007  * @param[in,out] ctr Pointer to the counter block
1008  * @param[in] inc Value of the increment
1009  **/
1010 
1011 void gcmIncBlock(uint8_t *ctr, uint32_t inc)
1012 {
1013  size_t i;
1014  uint32_t temp;
1015 
1016  //The function increments the right-most bytes of the block. The remaining
1017  //left-most bytes remain unchanged
1018  for(temp = inc, i = 0; i <= 3; i++)
1019  {
1020  //Increment the current byte and propagate the carry
1021  temp += ctr[15 - i];
1022  ctr[15 - i] = temp & 0xFF;
1023  temp >>= 8;
1024  }
1025 }
1026 
1027 
1028 /**
1029  * @brief Authenticated encryption using GCM
1030  * @param[in] context Pointer to the GCM context
1031  * @param[in] iv Initialization vector
1032  * @param[in] ivLen Length of the initialization vector
1033  * @param[in] a Additional authenticated data
1034  * @param[in] aLen Length of the additional data
1035  * @param[in] p Plaintext to be encrypted
1036  * @param[out] c Ciphertext resulting from the encryption
1037  * @param[in] length Total number of data bytes to be encrypted
1038  * @param[out] t Authentication tag
1039  * @param[in] tLen Length of the authentication tag
1040  * @return Error code
1041  **/
1042 
1043 error_t gcmEncrypt(GcmContext *context, const uint8_t *iv, size_t ivLen,
1044  const uint8_t *a, size_t aLen, const uint8_t *p, uint8_t *c, size_t length,
1045  uint8_t *t, size_t tLen)
1046 {
1047  size_t i;
1048  size_t n;
1049  uint8_t b[16];
1050  uint8_t j[16];
1051  uint8_t s[16];
1052 
1053  //Make sure the GCM context is valid
1054  if(context == NULL)
1055  return ERROR_INVALID_PARAMETER;
1056 
1057  //The length of the IV shall meet SP 800-38D requirements
1058  if(ivLen < 1)
1059  return ERROR_INVALID_LENGTH;
1060 
1061  //Check the length of the authentication tag
1062  if(tLen < 4 || tLen > 16)
1063  return ERROR_INVALID_LENGTH;
1064 
1065  //Check whether the length of the IV is 96 bits
1066  if(ivLen == 12)
1067  {
1068  //When the length of the IV is 96 bits, the padding string is appended
1069  //to the IV to form the pre-counter block
1070  osMemcpy(j, iv, 12);
1071  STORE32BE(1, j + 12);
1072  }
1073  else
1074  {
1075  //Initialize GHASH calculation
1076  osMemset(j, 0, 16);
1077 
1078  //Process the initialization vector
1079  for(i = 0; i < ivLen; i += n)
1080  {
1081  //The IV is processed in a block-by-block fashion
1082  n = MIN(ivLen - i, 16);
1083 
1084  //Apply GHASH function
1085  gcmXorBlock(j, j, iv + i, n);
1086  gcmMul(context, j);
1087  }
1088 
1089  //The string is appended with 64 additional 0 bits, followed by the
1090  //64-bit representation of the length of the IV
1091  osMemset(b, 0, 8);
1092  STORE64BE(ivLen * 8, b + 8);
1093 
1094  //The GHASH function is applied to the resulting string to form the
1095  //pre-counter block
1096  gcmXorBlock(j, j, b, 16);
1097  gcmMul(context, j);
1098  }
1099 
1100  //Compute MSB(CIPH(J(0)))
1101  context->cipherAlgo->encryptBlock(context->cipherContext, j, b);
1102  osMemcpy(t, b, tLen);
1103 
1104  //Initialize GHASH calculation
1105  osMemset(s, 0, 16);
1106 
1107  //Process AAD
1108  for(i = 0; i < aLen; i += n)
1109  {
1110  //Additional data are processed in a block-by-block fashion
1111  n = MIN(aLen - i, 16);
1112 
1113  //Apply GHASH function
1114  gcmXorBlock(s, s, a + i, n);
1115  gcmMul(context, s);
1116  }
1117 
1118  //Increment counter
1119  gcmIncCounter(j);
1120 
1121  //AES cipher algorithm?
1122  if(context->cipherAlgo == AES_CIPHER_ALGO)
1123  {
1124  //Encrypt plaintext
1125  for(i = 0; i < length; i += n)
1126  {
1127  size_t k;
1128  uint8_t iv[AES_BLOCK_SIZE];
1129 
1130  //Limit the number of blocks to process at a time
1131  k = 256 - j[AES_BLOCK_SIZE - 1];
1132  n = MIN(length, k * AES_BLOCK_SIZE);
1133  k = (n + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE;
1134 
1135  //Copy initial counter value
1136  osMemcpy(iv, j, AES_BLOCK_SIZE);
1137 
1138  //Encrypt payload data
1139  aesProcessData(context->cipherContext, iv, p + i, c + i, n,
1140  CRPT_AES_CTL_OPMODE_CTR | CRPT_AES_CTL_ENCRPT_Msk);
1141 
1142  //Increment the right-most 32 bits of the block
1143  gcmIncBlock(j, k);
1144  }
1145  }
1146  else
1147  {
1148  //Encrypt plaintext
1149  for(i = 0; i < length; i += n)
1150  {
1151  //The encryption operates in a block-by-block fashion
1152  n = MIN(length - i, 16);
1153 
1154  //Encrypt current block
1155  context->cipherAlgo->encryptBlock(context->cipherContext, j, b);
1156  gcmXorBlock(c + i, p + i, b, n);
1157 
1158  //Increment counter
1159  gcmIncCounter(j);
1160  }
1161  }
1162 
1163  //Process ciphertext
1164  for(i = 0; i < length; i += n)
1165  {
1166  //The encryption operates in a block-by-block fashion
1167  n = MIN(length - i, 16);
1168 
1169  //Apply GHASH function
1170  gcmXorBlock(s, s, c + i, n);
1171  gcmMul(context, s);
1172  }
1173 
1174  //Append the 64-bit representation of the length of the AAD and the
1175  //ciphertext
1176  STORE64BE(aLen * 8, b);
1177  STORE64BE(length * 8, b + 8);
1178 
1179  //The GHASH function is applied to the result to produce a single output
1180  //block S
1181  gcmXorBlock(s, s, b, 16);
1182  gcmMul(context, s);
1183 
1184  //Let T = MSB(GCTR(J(0), S)
1185  gcmXorBlock(t, t, s, tLen);
1186 
1187  //Successful encryption
1188  return NO_ERROR;
1189 }
1190 
1191 
1192 /**
1193  * @brief Authenticated decryption using GCM
1194  * @param[in] context Pointer to the GCM context
1195  * @param[in] iv Initialization vector
1196  * @param[in] ivLen Length of the initialization vector
1197  * @param[in] a Additional authenticated data
1198  * @param[in] aLen Length of the additional data
1199  * @param[in] c Ciphertext to be decrypted
1200  * @param[out] p Plaintext resulting from the decryption
1201  * @param[in] length Total number of data bytes to be decrypted
1202  * @param[in] t Authentication tag
1203  * @param[in] tLen Length of the authentication tag
1204  * @return Error code
1205  **/
1206 
1207 error_t gcmDecrypt(GcmContext *context, const uint8_t *iv, size_t ivLen,
1208  const uint8_t *a, size_t aLen, const uint8_t *c, uint8_t *p, size_t length,
1209  const uint8_t *t, size_t tLen)
1210 {
1211  uint8_t mask;
1212  size_t i;
1213  size_t n;
1214  uint8_t b[16];
1215  uint8_t j[16];
1216  uint8_t r[16];
1217  uint8_t s[16];
1218 
1219  //Make sure the GCM context is valid
1220  if(context == NULL)
1221  return ERROR_INVALID_PARAMETER;
1222 
1223  //The length of the IV shall meet SP 800-38D requirements
1224  if(ivLen < 1)
1225  return ERROR_INVALID_LENGTH;
1226 
1227  //Check the length of the authentication tag
1228  if(tLen < 4 || tLen > 16)
1229  return ERROR_INVALID_LENGTH;
1230 
1231  //Check whether the length of the IV is 96 bits
1232  if(ivLen == 12)
1233  {
1234  //When the length of the IV is 96 bits, the padding string is appended
1235  //to the IV to form the pre-counter block
1236  osMemcpy(j, iv, 12);
1237  STORE32BE(1, j + 12);
1238  }
1239  else
1240  {
1241  //Initialize GHASH calculation
1242  osMemset(j, 0, 16);
1243 
1244  //Process the initialization vector
1245  for(i = 0; i < ivLen; i += n)
1246  {
1247  //The IV is processed in a block-by-block fashion
1248  n = MIN(ivLen - i, 16);
1249 
1250  //Apply GHASH function
1251  gcmXorBlock(j, j, iv + i, n);
1252  gcmMul(context, j);
1253  }
1254 
1255  //The string is appended with 64 additional 0 bits, followed by the
1256  //64-bit representation of the length of the IV
1257  osMemset(b, 0, 8);
1258  STORE64BE(ivLen * 8, b + 8);
1259 
1260  //The GHASH function is applied to the resulting string to form the
1261  //pre-counter block
1262  gcmXorBlock(j, j, b, 16);
1263  gcmMul(context, j);
1264  }
1265 
1266  //Compute MSB(CIPH(J(0)))
1267  context->cipherAlgo->encryptBlock(context->cipherContext, j, b);
1268  osMemcpy(r, b, tLen);
1269 
1270  //Initialize GHASH calculation
1271  osMemset(s, 0, 16);
1272 
1273  //Process AAD
1274  for(i = 0; i < aLen; i += n)
1275  {
1276  //Additional data are processed in a block-by-block fashion
1277  n = MIN(aLen - i, 16);
1278 
1279  //Apply GHASH function
1280  gcmXorBlock(s, s, a + i, n);
1281  gcmMul(context, s);
1282  }
1283 
1284  //Process ciphertext
1285  for(i = 0; i < length; i += n)
1286  {
1287  //The decryption operates in a block-by-block fashion
1288  n = MIN(length - i, 16);
1289 
1290  //Apply GHASH function
1291  gcmXorBlock(s, s, c + i, n);
1292  gcmMul(context, s);
1293  }
1294 
1295  //Increment counter
1296  gcmIncCounter(j);
1297 
1298  //AES cipher algorithm?
1299  if(context->cipherAlgo == AES_CIPHER_ALGO)
1300  {
1301  //Decrypt ciphertext
1302  for(i = 0; i < length; i += n)
1303  {
1304  size_t k;
1305  uint8_t iv[AES_BLOCK_SIZE];
1306 
1307  //Limit the number of blocks to process at a time
1308  k = 256 - j[AES_BLOCK_SIZE - 1];
1309  n = MIN(length, k * AES_BLOCK_SIZE);
1310  k = (n + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE;
1311 
1312  //Copy initial counter value
1313  osMemcpy(iv, j, AES_BLOCK_SIZE);
1314 
1315  //Encrypt payload data
1316  aesProcessData(context->cipherContext, iv, c + i, p + i, n,
1317  CRPT_AES_CTL_OPMODE_CTR | CRPT_AES_CTL_ENCRPT_Msk);
1318 
1319  //Increment the right-most 32 bits of the block
1320  gcmIncBlock(j, k);
1321  }
1322  }
1323  else
1324  {
1325  //Decrypt ciphertext
1326  for(i = 0; i < length; i += n)
1327  {
1328  //The decryption operates in a block-by-block fashion
1329  n = MIN(length - i, 16);
1330 
1331  //Decrypt current block
1332  context->cipherAlgo->encryptBlock(context->cipherContext, j, b);
1333  gcmXorBlock(p + i, c + i, b, n);
1334 
1335  //Increment counter
1336  gcmIncCounter(j);
1337  }
1338  }
1339 
1340  //Append the 64-bit representation of the length of the AAD and the
1341  //ciphertext
1342  STORE64BE(aLen * 8, b);
1343  STORE64BE(length * 8, b + 8);
1344 
1345  //The GHASH function is applied to the result to produce a single output
1346  //block S
1347  gcmXorBlock(s, s, b, 16);
1348  gcmMul(context, s);
1349 
1350  //Let R = MSB(GCTR(J(0), S))
1351  gcmXorBlock(r, r, s, tLen);
1352 
1353  //The calculated tag is bitwise compared to the received tag. The message
1354  //is authenticated if and only if the tags match
1355  for(mask = 0, n = 0; n < tLen; n++)
1356  {
1357  mask |= r[n] ^ t[n];
1358  }
1359 
1360  //Return status code
1361  return (mask == 0) ? NO_ERROR : ERROR_FAILURE;
1362 }
1363 
1364 #endif
1365 #endif
uint16_t block
Definition: tftp_common.h:115
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:1077
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
#define CRPT_AES_CTL_OPMODE_ECB
uint8_t o
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.
#define CRPT_AES_CTL_KEYSZ_128B
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:1072
void gcmIncCounter(uint8_t *ctr)
Increment counter block.
Definition: gcm.c:614
CipherAlgoEncryptBlock encryptBlock
Definition: crypto.h:1076
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:141
__weak_func void gcmMul(GcmContext *context, uint8_t *x)
Multiplication operation in GF(2^128)
Definition: gcm.c:508
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_OPMODE_CFB
@ 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:1502
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
uint8_t length
Definition: tcp.h:368
#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
GCM context.
Definition: gcm.h:64
#define STORE64BE(a, p)
Definition: cpu_endian.h:322
#define CRPT_AES_CTL_OPMODE_OFB
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
#define CRPT_AES_CTL_KEYSZ_256B
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:597
#define CRPT_AES_CTL_KEYSZ_192B
M460 hardware cryptographic accelerator.
Common interface for encryption algorithms.
Definition: crypto.h:1068
#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
uint32_t ek[60]
Definition: aes.h:60
unsigned int uint_t
Definition: compiler_port.h:50
#define osMemset(p, value, length)
Definition: os_port.h:135
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.
#define CRPT_AES_CTL_OPMODE_CBC
void * cipherContext
Cipher algorithm context.
Definition: gcm.h:66
#define CRPT_AES_CTL_OPMODE_CTR
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:147