same70_crypto_cipher.c
Go to the documentation of this file.
1 /**
2  * @file same70_crypto_cipher.c
3  * @brief SAME70 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.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
33 
34 //Dependencies
35 #include "sam.h"
36 #include "core/crypto.h"
41 #include "aead/aead_algorithms.h"
42 #include "debug.h"
43 
44 //Check crypto library configuration
45 #if (SAME70_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 = AES_REGS->AES_MR & ~AES_MR_KEYSIZE_Msk;
59 
60  //Check the length of the key
61  if(context->nr == 10)
62  {
63  //10 rounds are required for 128-bit key
64  AES_REGS->AES_MR = temp | AES_MR_KEYSIZE_AES128;
65 
66  //Set the 128-bit encryption key
67  AES_REGS->AES_KEYWR[0] = context->ek[0];
68  AES_REGS->AES_KEYWR[1] = context->ek[1];
69  AES_REGS->AES_KEYWR[2] = context->ek[2];
70  AES_REGS->AES_KEYWR[3] = context->ek[3];
71  }
72  else if(context->nr == 12)
73  {
74  //12 rounds are required for 192-bit key
75  AES_REGS->AES_MR = temp | AES_MR_KEYSIZE_AES192;
76 
77  //Set the 192-bit encryption key
78  AES_REGS->AES_KEYWR[0] = context->ek[0];
79  AES_REGS->AES_KEYWR[1] = context->ek[1];
80  AES_REGS->AES_KEYWR[2] = context->ek[2];
81  AES_REGS->AES_KEYWR[3] = context->ek[3];
82  AES_REGS->AES_KEYWR[4] = context->ek[4];
83  AES_REGS->AES_KEYWR[5] = context->ek[5];
84  }
85  else
86  {
87  //14 rounds are required for 256-bit key
88  AES_REGS->AES_MR = temp | AES_MR_KEYSIZE_AES256;
89 
90  //Set the 256-bit encryption key
91  AES_REGS->AES_KEYWR[0] = context->ek[0];
92  AES_REGS->AES_KEYWR[1] = context->ek[1];
93  AES_REGS->AES_KEYWR[2] = context->ek[2];
94  AES_REGS->AES_KEYWR[3] = context->ek[3];
95  AES_REGS->AES_KEYWR[4] = context->ek[4];
96  AES_REGS->AES_KEYWR[5] = context->ek[5];
97  AES_REGS->AES_KEYWR[6] = context->ek[6];
98  AES_REGS->AES_KEYWR[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 *p;
112 
113  //Write input block
114  p = (uint32_t *) input;
115  AES_REGS->AES_IDATAR[0] = p[0];
116  AES_REGS->AES_IDATAR[1] = p[1];
117  AES_REGS->AES_IDATAR[2] = p[2];
118  AES_REGS->AES_IDATAR[3] = p[3];
119 
120  //Start encryption/decryption
121  AES_REGS->AES_CR = AES_CR_START_Msk;
122 
123  //When processing completes, the DATRDY flag is raised
124  while((AES_REGS->AES_ISR & AES_ISR_DATRDY_Msk) == 0)
125  {
126  }
127 
128  //Read output block
129  p = (uint32_t *) output;
130  p[0] = AES_REGS->AES_ODATAR[0];
131  p[1] = AES_REGS->AES_ODATAR[1];
132  p[2] = AES_REGS->AES_ODATAR[2];
133  p[3] = AES_REGS->AES_ODATAR[3];
134 }
135 
136 
137 /**
138  * @brief Perform AES encryption or decryption
139  * @param[in] context AES algorithm context
140  * @param[in] iv Initialization vector
141  * @param[in] input Data to be encrypted/decrypted
142  * @param[out] output Data resulting from the encryption/decryption process
143  * @param[in] length Total number of data bytes to be processed
144  * @param[in] mode Operation mode
145  **/
146 
147 void aesProcessData(AesContext *context, uint8_t *iv, const uint8_t *input,
148  uint8_t *output, size_t length, uint32_t mode)
149 {
150  uint32_t *p;
151 
152  //Acquire exclusive access to the AES module
154 
155  //Perform software reset
156  AES_REGS->AES_CR = AES_CR_SWRST_Msk;
157 
158  //Set operation mode
159  AES_REGS->AES_MR = AES_MR_SMOD_MANUAL_START | mode;
160  //Set encryption key
161  aesLoadKey(context);
162 
163  //Valid initialization vector?
164  if(iv != NULL)
165  {
166  //Set initialization vector
167  p = (uint32_t *) iv;
168  AES_REGS->AES_IVR[0] = p[0];
169  AES_REGS->AES_IVR[1] = p[1];
170  AES_REGS->AES_IVR[2] = p[2];
171  AES_REGS->AES_IVR[3] = p[3];
172  }
173 
174  //Process data
175  while(length >= AES_BLOCK_SIZE)
176  {
177  //The data is encrypted block by block
178  aesProcessDataBlock(input, output);
179 
180  //Next block
181  input += AES_BLOCK_SIZE;
182  output += AES_BLOCK_SIZE;
184  }
185 
186  //Process final block of data
187  if(length > 0)
188  {
189  uint8_t buffer[AES_BLOCK_SIZE];
190 
191  //Copy input data
192  osMemset(buffer, 0, AES_BLOCK_SIZE);
193  osMemcpy(buffer, input, length);
194 
195  //Encrypt the final block of data
196  aesProcessDataBlock(buffer, buffer);
197 
198  //Copy output data
199  osMemcpy(output, buffer, length);
200  }
201 
202  //Release exclusive access to the AES module
204 }
205 
206 
207 /**
208  * @brief Key expansion
209  * @param[in] context Pointer to the AES context to initialize
210  * @param[in] key Pointer to the key
211  * @param[in] keyLen Length of the key
212  * @return Error code
213  **/
214 
215 error_t aesInit(AesContext *context, const uint8_t *key, size_t keyLen)
216 {
217  //Check parameters
218  if(context == NULL || key == NULL)
220 
221  //Check the length of the key
222  if(keyLen == 16)
223  {
224  //10 rounds are required for 128-bit key
225  context->nr = 10;
226  }
227  else if(keyLen == 24)
228  {
229  //12 rounds are required for 192-bit key
230  context->nr = 12;
231  }
232  else if(keyLen == 32)
233  {
234  //14 rounds are required for 256-bit key
235  context->nr = 14;
236  }
237  else
238  {
239  //Report an error
241  }
242 
243  //Copy the original key
244  osMemcpy(context->ek, key, keyLen);
245 
246  //No error to report
247  return NO_ERROR;
248 }
249 
250 
251 /**
252  * @brief Encrypt a 16-byte block using AES algorithm
253  * @param[in] context Pointer to the AES context
254  * @param[in] input Plaintext block to encrypt
255  * @param[out] output Ciphertext block resulting from encryption
256  **/
257 
258 void aesEncryptBlock(AesContext *context, const uint8_t *input, uint8_t *output)
259 {
260  //Perform AES encryption
261  aesProcessData(context, NULL, input, output, AES_BLOCK_SIZE,
262  AES_MR_CIPHER_Msk | AES_MR_OPMOD_ECB);
263 }
264 
265 
266 /**
267  * @brief Decrypt a 16-byte block using AES algorithm
268  * @param[in] context Pointer to the AES context
269  * @param[in] input Ciphertext block to decrypt
270  * @param[out] output Plaintext block resulting from decryption
271  **/
272 
273 void aesDecryptBlock(AesContext *context, const uint8_t *input, uint8_t *output)
274 {
275  //Perform AES decryption
276  aesProcessData(context, NULL, input, output, AES_BLOCK_SIZE,
277  AES_MR_OPMOD_ECB);
278 }
279 
280 
281 #if (ECB_SUPPORT == ENABLED)
282 
283 /**
284  * @brief ECB encryption
285  * @param[in] cipher Cipher algorithm
286  * @param[in] context Cipher algorithm context
287  * @param[in] p Plaintext to be encrypted
288  * @param[out] c Ciphertext resulting from the encryption
289  * @param[in] length Total number of data bytes to be encrypted
290  * @return Error code
291  **/
292 
293 error_t ecbEncrypt(const CipherAlgo *cipher, void *context,
294  const uint8_t *p, uint8_t *c, size_t length)
295 {
296  error_t error;
297 
298  //Initialize status code
299  error = NO_ERROR;
300 
301  //AES cipher algorithm?
302  if(cipher == AES_CIPHER_ALGO)
303  {
304  //Check the length of the payload
305  if(length == 0)
306  {
307  //No data to process
308  }
309  else if((length % AES_BLOCK_SIZE) == 0)
310  {
311  //Encrypt payload data
312  aesProcessData(context, NULL, p, c, length, AES_MR_CIPHER_Msk |
313  AES_MR_OPMOD_ECB);
314  }
315  else
316  {
317  //The length of the payload must be a multiple of the block size
318  error = ERROR_INVALID_LENGTH;
319  }
320  }
321  else
322  {
323  //ECB mode operates in a block-by-block fashion
324  while(length >= cipher->blockSize)
325  {
326  //Encrypt current block
327  cipher->encryptBlock(context, p, c);
328 
329  //Next block
330  p += cipher->blockSize;
331  c += cipher->blockSize;
332  length -= cipher->blockSize;
333  }
334 
335  //The length of the payload must be a multiple of the block size
336  if(length != 0)
337  {
338  error = ERROR_INVALID_LENGTH;
339  }
340  }
341 
342  //Return status code
343  return error;
344 }
345 
346 
347 /**
348  * @brief ECB decryption
349  * @param[in] cipher Cipher algorithm
350  * @param[in] context Cipher algorithm context
351  * @param[in] c Ciphertext to be decrypted
352  * @param[out] p Plaintext resulting from the decryption
353  * @param[in] length Total number of data bytes to be decrypted
354  * @return Error code
355  **/
356 
357 error_t ecbDecrypt(const CipherAlgo *cipher, void *context,
358  const uint8_t *c, uint8_t *p, size_t length)
359 {
360  error_t error;
361 
362  //Initialize status code
363  error = NO_ERROR;
364 
365  //AES cipher algorithm?
366  if(cipher == AES_CIPHER_ALGO)
367  {
368  //Check the length of the payload
369  if(length == 0)
370  {
371  //No data to process
372  }
373  else if((length % AES_BLOCK_SIZE) == 0)
374  {
375  //Decrypt payload data
376  aesProcessData(context, NULL, c, p, length, AES_MR_OPMOD_ECB);
377  }
378  else
379  {
380  //The length of the payload must be a multiple of the block size
381  error = ERROR_INVALID_LENGTH;
382  }
383  }
384  else
385  {
386  //ECB mode operates in a block-by-block fashion
387  while(length >= cipher->blockSize)
388  {
389  //Decrypt current block
390  cipher->decryptBlock(context, c, p);
391 
392  //Next block
393  c += cipher->blockSize;
394  p += cipher->blockSize;
395  length -= cipher->blockSize;
396  }
397 
398  //The length of the payload must be a multiple of the block size
399  if(length != 0)
400  {
401  error = ERROR_INVALID_LENGTH;
402  }
403  }
404 
405  //Return status code
406  return error;
407 }
408 
409 #endif
410 #if (CBC_SUPPORT == ENABLED)
411 
412 /**
413  * @brief CBC encryption
414  * @param[in] cipher Cipher algorithm
415  * @param[in] context Cipher algorithm context
416  * @param[in,out] iv Initialization vector
417  * @param[in] p Plaintext to be encrypted
418  * @param[out] c Ciphertext resulting from the encryption
419  * @param[in] length Total number of data bytes to be encrypted
420  * @return Error code
421  **/
422 
423 error_t cbcEncrypt(const CipherAlgo *cipher, void *context,
424  uint8_t *iv, const uint8_t *p, uint8_t *c, size_t length)
425 {
426  error_t error;
427 
428  //Initialize status code
429  error = NO_ERROR;
430 
431  //AES cipher algorithm?
432  if(cipher == AES_CIPHER_ALGO)
433  {
434  //Check the length of the payload
435  if(length == 0)
436  {
437  //No data to process
438  }
439  else if((length % AES_BLOCK_SIZE) == 0)
440  {
441  //Encrypt payload data
442  aesProcessData(context, iv, p, c, length, AES_MR_CIPHER_Msk |
443  AES_MR_OPMOD_CBC);
444 
445  //Update the value of the initialization vector
447  }
448  else
449  {
450  //The length of the payload must be a multiple of the block size
451  error = ERROR_INVALID_LENGTH;
452  }
453  }
454  else
455  {
456  size_t i;
457 
458  //CBC mode operates in a block-by-block fashion
459  while(length >= cipher->blockSize)
460  {
461  //XOR input block with IV contents
462  for(i = 0; i < cipher->blockSize; i++)
463  {
464  c[i] = p[i] ^ iv[i];
465  }
466 
467  //Encrypt the current block based upon the output of the previous
468  //encryption
469  cipher->encryptBlock(context, c, c);
470 
471  //Update IV with output block contents
472  osMemcpy(iv, c, cipher->blockSize);
473 
474  //Next block
475  p += cipher->blockSize;
476  c += cipher->blockSize;
477  length -= cipher->blockSize;
478  }
479 
480  //The length of the payload must be a multiple of the block size
481  if(length != 0)
482  {
483  error = ERROR_INVALID_LENGTH;
484  }
485  }
486 
487  //Return status code
488  return error;
489 }
490 
491 
492 /**
493  * @brief CBC decryption
494  * @param[in] cipher Cipher algorithm
495  * @param[in] context Cipher algorithm context
496  * @param[in,out] iv Initialization vector
497  * @param[in] c Ciphertext to be decrypted
498  * @param[out] p Plaintext resulting from the decryption
499  * @param[in] length Total number of data bytes to be decrypted
500  * @return Error code
501  **/
502 
503 error_t cbcDecrypt(const CipherAlgo *cipher, void *context,
504  uint8_t *iv, const uint8_t *c, uint8_t *p, size_t length)
505 {
506  error_t error;
507 
508  //Initialize status code
509  error = NO_ERROR;
510 
511  //AES cipher algorithm?
512  if(cipher == AES_CIPHER_ALGO)
513  {
514  //Check the length of the payload
515  if(length == 0)
516  {
517  //No data to process
518  }
519  else if((length % AES_BLOCK_SIZE) == 0)
520  {
521  uint8_t block[AES_BLOCK_SIZE];
522 
523  //Save the last input block
525 
526  //Decrypt payload data
527  aesProcessData(context, iv, c, p, length, AES_MR_OPMOD_CBC);
528 
529  //Update the value of the initialization vector
531  }
532  else
533  {
534  //The length of the payload must be a multiple of the block size
535  error = ERROR_INVALID_LENGTH;
536  }
537  }
538  else
539  {
540  size_t i;
541  uint8_t t[16];
542 
543  //CBC mode operates in a block-by-block fashion
544  while(length >= cipher->blockSize)
545  {
546  //Save input block
547  osMemcpy(t, c, cipher->blockSize);
548 
549  //Decrypt the current block
550  cipher->decryptBlock(context, c, p);
551 
552  //XOR output block with IV contents
553  for(i = 0; i < cipher->blockSize; i++)
554  {
555  p[i] ^= iv[i];
556  }
557 
558  //Update IV with input block contents
559  osMemcpy(iv, t, cipher->blockSize);
560 
561  //Next block
562  c += cipher->blockSize;
563  p += cipher->blockSize;
564  length -= cipher->blockSize;
565  }
566 
567  //The length of the payload must be a multiple of the block size
568  if(length != 0)
569  {
570  error = ERROR_INVALID_LENGTH;
571  }
572  }
573 
574  //Return status code
575  return error;
576 }
577 
578 #endif
579 #if (CFB_SUPPORT == ENABLED)
580 
581 /**
582  * @brief CFB encryption
583  * @param[in] cipher Cipher algorithm
584  * @param[in] context Cipher algorithm context
585  * @param[in] s Size of the plaintext and ciphertext segments
586  * @param[in,out] iv Initialization vector
587  * @param[in] p Plaintext to be encrypted
588  * @param[out] c Ciphertext resulting from the encryption
589  * @param[in] length Total number of data bytes to be encrypted
590  * @return Error code
591  **/
592 
593 error_t cfbEncrypt(const CipherAlgo *cipher, void *context, uint_t s,
594  uint8_t *iv, const uint8_t *p, uint8_t *c, size_t length)
595 {
596  error_t error;
597 
598  //Initialize status code
599  error = NO_ERROR;
600 
601  //AES cipher algorithm?
602  if(cipher == AES_CIPHER_ALGO)
603  {
604  //Check the value of the parameter
605  if(s == (AES_BLOCK_SIZE * 8))
606  {
607  //Check the length of the payload
608  if(length > 0)
609  {
610  //Encrypt payload data
611  aesProcessData(context, iv, p, c, length, AES_MR_CIPHER_Msk |
612  AES_MR_OPMOD_CFB | AES_MR_CFBS_SIZE_128BIT);
613  }
614  else
615  {
616  //No data to process
617  }
618  }
619  else
620  {
621  //The value of the parameter is not valid
622  error = ERROR_INVALID_PARAMETER;
623  }
624  }
625  else
626  {
627  //Check the value of the parameter
628  if((s % 8) == 0 && s >= 1 && s <= (cipher->blockSize * 8))
629  {
630  size_t i;
631  size_t n;
632  uint8_t o[16];
633 
634  //Determine the size, in bytes, of the plaintext and ciphertext segments
635  s = s / 8;
636 
637  //Process each plaintext segment
638  while(length > 0)
639  {
640  //Compute the number of bytes to process at a time
641  n = MIN(length, s);
642 
643  //Compute O(j) = CIPH(I(j))
644  cipher->encryptBlock(context, iv, o);
645 
646  //Compute C(j) = P(j) XOR MSB(O(j))
647  for(i = 0; i < n; i++)
648  {
649  c[i] = p[i] ^ o[i];
650  }
651 
652  //Compute I(j+1) = LSB(I(j)) | C(j)
653  osMemmove(iv, iv + s, cipher->blockSize - s);
654  osMemcpy(iv + cipher->blockSize - s, c, s);
655 
656  //Next block
657  p += n;
658  c += n;
659  length -= n;
660  }
661  }
662  else
663  {
664  //The value of the parameter is not valid
665  error = ERROR_INVALID_PARAMETER;
666  }
667  }
668 
669  //Return status code
670  return error;
671 }
672 
673 
674 /**
675  * @brief CFB decryption
676  * @param[in] cipher Cipher algorithm
677  * @param[in] context Cipher algorithm context
678  * @param[in] s Size of the plaintext and ciphertext segments
679  * @param[in,out] iv Initialization vector
680  * @param[in] c Ciphertext to be decrypted
681  * @param[out] p Plaintext resulting from the decryption
682  * @param[in] length Total number of data bytes to be decrypted
683  * @return Error code
684  **/
685 
686 error_t cfbDecrypt(const CipherAlgo *cipher, void *context, uint_t s,
687  uint8_t *iv, const uint8_t *c, uint8_t *p, size_t length)
688 {
689  error_t error;
690 
691  //Initialize status code
692  error = NO_ERROR;
693 
694  //AES cipher algorithm?
695  if(cipher == AES_CIPHER_ALGO)
696  {
697  //Check the value of the parameter
698  if(s == (AES_BLOCK_SIZE * 8))
699  {
700  //Check the length of the payload
701  if(length > 0)
702  {
703  //Decrypt payload data
704  aesProcessData(context, iv, c, p, length, AES_MR_OPMOD_CFB |
705  AES_MR_CFBS_SIZE_128BIT);
706  }
707  else
708  {
709  //No data to process
710  }
711  }
712  else
713  {
714  //The value of the parameter is not valid
715  error = ERROR_INVALID_PARAMETER;
716  }
717  }
718  else
719  {
720  //Check the value of the parameter
721  if((s % 8) == 0 && s >= 1 && s <= (cipher->blockSize * 8))
722  {
723  size_t i;
724  size_t n;
725  uint8_t o[16];
726 
727  //Determine the size, in bytes, of the plaintext and ciphertext segments
728  s = s / 8;
729 
730  //Process each ciphertext segment
731  while(length > 0)
732  {
733  //Compute the number of bytes to process at a time
734  n = MIN(length, s);
735 
736  //Compute O(j) = CIPH(I(j))
737  cipher->encryptBlock(context, iv, o);
738 
739  //Compute I(j+1) = LSB(I(j)) | C(j)
740  osMemmove(iv, iv + s, cipher->blockSize - s);
741  osMemcpy(iv + cipher->blockSize - s, c, s);
742 
743  //Compute P(j) = C(j) XOR MSB(O(j))
744  for(i = 0; i < n; i++)
745  {
746  p[i] = c[i] ^ o[i];
747  }
748 
749  //Next block
750  c += n;
751  p += n;
752  length -= n;
753  }
754  }
755  else
756  {
757  //The value of the parameter is not valid
758  error = ERROR_INVALID_PARAMETER;
759  }
760  }
761 
762  //Return status code
763  return error;
764 }
765 
766 #endif
767 #if (OFB_SUPPORT == ENABLED)
768 
769 /**
770  * @brief OFB encryption
771  * @param[in] cipher Cipher algorithm
772  * @param[in] context Cipher algorithm context
773  * @param[in] s Size of the plaintext and ciphertext segments
774  * @param[in,out] iv Initialization vector
775  * @param[in] p Plaintext to be encrypted
776  * @param[out] c Ciphertext resulting from the encryption
777  * @param[in] length Total number of data bytes to be encrypted
778  * @return Error code
779  **/
780 
781 error_t ofbEncrypt(const CipherAlgo *cipher, void *context, uint_t s,
782  uint8_t *iv, const uint8_t *p, uint8_t *c, size_t length)
783 {
784  error_t error;
785 
786  //Initialize status code
787  error = NO_ERROR;
788 
789  //AES cipher algorithm?
790  if(cipher == AES_CIPHER_ALGO)
791  {
792  //Check the value of the parameter
793  if(s == (AES_BLOCK_SIZE * 8))
794  {
795  //Check the length of the payload
796  if(length > 0)
797  {
798  //Encrypt payload data
799  aesProcessData(context, iv, p, c, length, AES_MR_CIPHER_Msk |
800  AES_MR_OPMOD_OFB);
801  }
802  else
803  {
804  //No data to process
805  }
806  }
807  else
808  {
809  //The value of the parameter is not valid
810  error = ERROR_INVALID_PARAMETER;
811  }
812  }
813  else
814  {
815  //Check the value of the parameter
816  if((s % 8) == 0 && s >= 1 && s <= (cipher->blockSize * 8))
817  {
818  size_t i;
819  size_t n;
820  uint8_t o[16];
821 
822  //Determine the size, in bytes, of the plaintext and ciphertext segments
823  s = s / 8;
824 
825  //Process each plaintext segment
826  while(length > 0)
827  {
828  //Compute the number of bytes to process at a time
829  n = MIN(length, s);
830 
831  //Compute O(j) = CIPH(I(j))
832  cipher->encryptBlock(context, iv, o);
833 
834  //Compute C(j) = P(j) XOR MSB(O(j))
835  for(i = 0; i < n; i++)
836  {
837  c[i] = p[i] ^ o[i];
838  }
839 
840  //Compute I(j+1) = LSB(I(j)) | O(j)
841  osMemmove(iv, iv + s, cipher->blockSize - s);
842  osMemcpy(iv + cipher->blockSize - s, o, s);
843 
844  //Next block
845  p += n;
846  c += n;
847  length -= n;
848  }
849  }
850  else
851  {
852  //The value of the parameter is not valid
853  error = ERROR_INVALID_PARAMETER;
854  }
855  }
856 
857  //Return status code
858  return error;
859 }
860 
861 #endif
862 #if (GCM_SUPPORT == ENABLED)
863 
864 /**
865  * @brief Update GHASH value
866  * @param[in] data Input block of data
867  **/
868 
869 void gcmUpdateGhash(const uint8_t *data)
870 {
871  uint32_t *p;
872 
873  //Write data block
874  p = (uint32_t *) data;
875  AES_REGS->AES_IDATAR[0] = p[0];
876  AES_REGS->AES_IDATAR[1] = p[1];
877  AES_REGS->AES_IDATAR[2] = p[2];
878  AES_REGS->AES_IDATAR[3] = p[3];
879 
880  //Process data
881  AES_REGS->AES_CR = AES_CR_START_Msk;
882 
883  //The DATRDY bit indicates when the data have been processed. However, no
884  //output data are generated when processing AAD
885  while((AES_REGS->AES_ISR & AES_ISR_DATRDY_Msk) == 0)
886  {
887  }
888 }
889 
890 
891 /**
892  * @brief Perform AES-GCM encryption or decryption
893  * @param[in] context AES algorithm context
894  * @param[in] iv Initialization vector
895  * @param[in] a Additional authenticated data
896  * @param[in] aLen Length of the additional data
897  * @param[in] input Data to be encrypted/decrypted
898  * @param[out] output Data resulting from the encryption/decryption process
899  * @param[in] length Total number of data bytes to be processed
900  * @param[out] t Authentication tag
901  * @param[in] mode Operation mode
902  **/
903 
904 void gcmProcessData(AesContext *context, const uint8_t *iv,
905  const uint8_t *a, size_t aLen, const uint8_t *input, uint8_t *output,
906  size_t length, uint8_t *t, uint32_t mode)
907 {
908  uint32_t temp;
909  uint8_t buffer[16];
910 
911  //Acquire exclusive access to the AES module
913 
914  //Perform software reset
915  AES_REGS->AES_CR = AES_CR_SWRST_Msk;
916 
917  //Check parameters
918  if(aLen > 0 || length > 0)
919  {
920  //Select GCM operation mode
921  AES_REGS->AES_MR |= AES_MR_SMOD_MANUAL_START | AES_MR_OPMOD_GCM |
922  AES_MR_GTAGEN_Msk | mode;
923 
924  //Whenever a new key is written to the hardware, the hash subkey is
925  //automatically generated. The hash subkey generation must be complete
926  //before doing any other action
927  aesLoadKey(context);
928 
929  //The DATRDY bit of the AES_ISR indicates when the subkey generation is
930  //complete
931  while((AES_REGS->AES_ISR & AES_ISR_DATRDY_Msk) == 0)
932  {
933  }
934 
935  //When the length of the IV is 96 bits, the padding string is appended to
936  //the IV to form the pre-counter block
937  AES_REGS->AES_IVR[0] = LOAD32LE(iv);
938  AES_REGS->AES_IVR[1] = LOAD32LE(iv + 4);
939  AES_REGS->AES_IVR[2] = LOAD32LE(iv + 8);
940  AES_REGS->AES_IVR[3] = BETOH32(2);
941 
942  //Set AADLEN field in AES_AADLENR and CLEN field in AES_CLENR
943  AES_REGS->AES_AADLENR = aLen;
944  AES_REGS->AES_CLENR = length;
945 
946  //Process additional authenticated data
947  while(aLen > 16)
948  {
949  //Additional authenticated data is written block by block
950  gcmUpdateGhash(a);
951 
952  //Next block
953  a += 16;
954  aLen -= 16;
955  }
956 
957  //Process final block of additional authenticated data
958  if(aLen > 0)
959  {
960  //Copy partial block
961  osMemset(buffer, 0, 16);
962  osMemcpy(buffer, a, aLen);
963 
964  //Write the resulting block
965  gcmUpdateGhash(buffer);
966  }
967 
968  //Process data
969  while(length >= AES_BLOCK_SIZE)
970  {
971  //The data is encrypted block by block
972  aesProcessDataBlock(input, output);
973 
974  //Next block
975  input += AES_BLOCK_SIZE;
976  output += AES_BLOCK_SIZE;
978  }
979 
980  //Process final block of data
981  if(length > 0)
982  {
983  //Copy input data
984  osMemset(buffer, 0, AES_BLOCK_SIZE);
985  osMemcpy(buffer, input, length);
986 
987  //Encrypt the final block of data
988  aesProcessDataBlock(buffer, buffer);
989 
990  //Copy output data
991  osMemcpy(output, buffer, length);
992  }
993 
994  //Wait for TAGRDY to be set
995  while((AES_REGS->AES_ISR & AES_ISR_TAGRDY_Msk) == 0)
996  {
997  }
998 
999  //Read the value from AES_TAGR registers to obtain the authentication tag
1000  //of the message
1001  temp = AES_REGS->AES_TAGR[0];
1002  STORE32LE(temp, t);
1003  temp = AES_REGS->AES_TAGR[1];
1004  STORE32LE(temp, t + 4);
1005  temp = AES_REGS->AES_TAGR[2];
1006  STORE32LE(temp, t + 8);
1007  temp = AES_REGS->AES_TAGR[3];
1008  STORE32LE(temp, t + 12);
1009  }
1010  else
1011  {
1012  //Select CTR operation mode
1013  AES_REGS->AES_MR |= AES_MR_SMOD_MANUAL_START | AES_MR_OPMOD_CTR |
1014  AES_MR_CIPHER_Msk;
1015 
1016  //Set encryption key
1017  aesLoadKey(context);
1018 
1019  //When the length of the IV is 96 bits, the padding string is appended to
1020  //the IV to form the pre-counter block
1021  AES_REGS->AES_IVR[0] = LOAD32LE(iv);
1022  AES_REGS->AES_IVR[1] = LOAD32LE(iv + 4);
1023  AES_REGS->AES_IVR[2] = LOAD32LE(iv + 8);
1024  AES_REGS->AES_IVR[3] = BETOH32(1);
1025 
1026  //Clear data block
1027  osMemset(buffer, 0, AES_BLOCK_SIZE);
1028 
1029  //Generate authentication tag
1030  aesProcessDataBlock(buffer, t);
1031  }
1032 
1033  //Release exclusive access to the AES module
1035 }
1036 
1037 
1038 /**
1039  * @brief Initialize GCM context
1040  * @param[in] context Pointer to the GCM context
1041  * @param[in] cipherAlgo Cipher algorithm
1042  * @param[in] cipherContext Pointer to the cipher algorithm context
1043  * @return Error code
1044  **/
1045 
1046 error_t gcmInit(GcmContext *context, const CipherAlgo *cipherAlgo,
1047  void *cipherContext)
1048 {
1049  //Check parameters
1050  if(context == NULL || cipherContext == NULL)
1051  return ERROR_INVALID_PARAMETER;
1052 
1053  //The CRYP module only supports AES cipher algorithm
1054  if(cipherAlgo != AES_CIPHER_ALGO)
1055  return ERROR_INVALID_PARAMETER;
1056 
1057  //Save cipher algorithm context
1058  context->cipherAlgo = cipherAlgo;
1059  context->cipherContext = cipherContext;
1060 
1061  //Successful initialization
1062  return NO_ERROR;
1063 }
1064 
1065 
1066 /**
1067  * @brief Authenticated encryption using GCM
1068  * @param[in] context Pointer to the GCM context
1069  * @param[in] iv Initialization vector
1070  * @param[in] ivLen Length of the initialization vector
1071  * @param[in] a Additional authenticated data
1072  * @param[in] aLen Length of the additional data
1073  * @param[in] p Plaintext to be encrypted
1074  * @param[out] c Ciphertext resulting from the encryption
1075  * @param[in] length Total number of data bytes to be encrypted
1076  * @param[out] t Authentication tag
1077  * @param[in] tLen Length of the authentication tag
1078  * @return Error code
1079  **/
1080 
1081 error_t gcmEncrypt(GcmContext *context, const uint8_t *iv,
1082  size_t ivLen, const uint8_t *a, size_t aLen, const uint8_t *p,
1083  uint8_t *c, size_t length, uint8_t *t, size_t tLen)
1084 {
1085  uint8_t authTag[16];
1086 
1087  //Make sure the GCM context is valid
1088  if(context == NULL)
1089  return ERROR_INVALID_PARAMETER;
1090 
1091  //Check whether the length of the IV is 96 bits
1092  if(ivLen != 12)
1093  return ERROR_INVALID_LENGTH;
1094 
1095  //Check the length of the authentication tag
1096  if(tLen < 4 || tLen > 16)
1097  return ERROR_INVALID_LENGTH;
1098 
1099  //Perform AES-GCM encryption
1100  gcmProcessData(context->cipherContext, iv, a, aLen, p, c, length,
1101  authTag, AES_MR_CIPHER_Msk);
1102 
1103  //Copy the resulting authentication tag
1104  osMemcpy(t, authTag, tLen);
1105 
1106  //Successful processing
1107  return NO_ERROR;
1108 }
1109 
1110 
1111 /**
1112  * @brief Authenticated decryption using GCM
1113  * @param[in] context Pointer to the GCM context
1114  * @param[in] iv Initialization vector
1115  * @param[in] ivLen Length of the initialization vector
1116  * @param[in] a Additional authenticated data
1117  * @param[in] aLen Length of the additional data
1118  * @param[in] c Ciphertext to be decrypted
1119  * @param[out] p Plaintext resulting from the decryption
1120  * @param[in] length Total number of data bytes to be decrypted
1121  * @param[in] t Authentication tag
1122  * @param[in] tLen Length of the authentication tag
1123  * @return Error code
1124  **/
1125 
1126 error_t gcmDecrypt(GcmContext *context, const uint8_t *iv,
1127  size_t ivLen, const uint8_t *a, size_t aLen, const uint8_t *c,
1128  uint8_t *p, size_t length, const uint8_t *t, size_t tLen)
1129 {
1130  size_t i;
1131  uint8_t mask;
1132  uint8_t authTag[16];
1133 
1134  //Make sure the GCM context is valid
1135  if(context == NULL)
1136  return ERROR_INVALID_PARAMETER;
1137 
1138  //Check whether the length of the IV is 96 bits
1139  if(ivLen != 12)
1140  return ERROR_INVALID_LENGTH;
1141 
1142  //Check the length of the authentication tag
1143  if(tLen < 4 || tLen > 16)
1144  return ERROR_INVALID_LENGTH;
1145 
1146  //Perform AES-GCM decryption
1147  gcmProcessData(context->cipherContext, iv, a, aLen, c, p, length,
1148  authTag, 0);
1149 
1150  //The calculated tag is bitwise compared to the received tag
1151  for(mask = 0, i = 0; i < tLen; i++)
1152  {
1153  mask |= authTag[i] ^ t[i];
1154  }
1155 
1156  //The message is authenticated if and only if the tags match
1157  return (mask == 0) ? NO_ERROR : ERROR_FAILURE;
1158 }
1159 
1160 #endif
1161 #endif
#define AES_CIPHER_ALGO
Definition: aes.h:45
#define AES_BLOCK_SIZE
Definition: aes.h:43
Collection of AEAD algorithms.
Block cipher modes of operation.
unsigned int uint_t
Definition: compiler_port.h:50
#define BETOH32(value)
Definition: cpu_endian.h:451
#define LOAD32LE(p)
Definition: cpu_endian.h:203
#define STORE32LE(a, p)
Definition: cpu_endian.h:279
General definitions for cryptographic algorithms.
Debugging facilities.
uint8_t n
uint8_t o
error_t
Error codes.
Definition: error.h:43
@ ERROR_INVALID_KEY_LENGTH
Definition: error.h:107
@ NO_ERROR
Success.
Definition: error.h:44
@ ERROR_INVALID_LENGTH
Definition: error.h:111
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
uint8_t data[]
Definition: ethernet.h:222
uint8_t iv[]
Definition: ike.h:1502
uint8_t t
Definition: lldp_ext_med.h:212
uint8_t c
Definition: ndp.h:514
uint8_t s
Definition: ndp.h:345
uint8_t p
Definition: ndp.h:300
uint8_t a
Definition: ndp.h:411
#define osMemset(p, value, length)
Definition: os_port.h:135
#define osMemmove(dest, src, length)
Definition: os_port.h:147
#define osMemcpy(dest, src, length)
Definition: os_port.h:141
#define MIN(a, b)
Definition: os_port.h:63
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
OsMutex same70CryptoMutex
Definition: same70_crypto.c:44
SAME70 hardware cryptographic accelerator.
error_t aesInit(AesContext *context, const uint8_t *key, size_t keyLen)
Key expansion.
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 aesLoadKey(AesContext *context)
Load AES key.
void aesProcessData(AesContext *context, uint8_t *iv, const uint8_t *input, uint8_t *output, size_t length, uint32_t mode)
Perform AES encryption or decryption.
void gcmProcessData(AesContext *context, const uint8_t *iv, const uint8_t *a, size_t aLen, const uint8_t *input, uint8_t *output, size_t length, uint8_t *t, uint32_t mode)
Perform AES-GCM encryption or decryption.
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 cbcDecrypt(const CipherAlgo *cipher, void *context, uint8_t *iv, const uint8_t *c, uint8_t *p, size_t length)
CBC decryption.
void aesDecryptBlock(AesContext *context, const uint8_t *input, uint8_t *output)
Decrypt a 16-byte block using AES algorithm.
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.
void aesEncryptBlock(AesContext *context, const uint8_t *input, uint8_t *output)
Encrypt a 16-byte block using AES algorithm.
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 ecbEncrypt(const CipherAlgo *cipher, void *context, const uint8_t *p, uint8_t *c, size_t length)
ECB encryption.
error_t gcmInit(GcmContext *context, const CipherAlgo *cipherAlgo, void *cipherContext)
Initialize GCM context.
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.
void aesProcessDataBlock(const uint8_t *input, uint8_t *output)
Encrypt/decrypt a 16-byte block using AES algorithm.
void gcmUpdateGhash(const uint8_t *data)
Update GHASH value.
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.
error_t ecbDecrypt(const CipherAlgo *cipher, void *context, const uint8_t *c, uint8_t *p, size_t length)
ECB decryption.
SAME70 cipher hardware accelerator.
AES algorithm context.
Definition: aes.h:58
uint_t nr
Definition: aes.h:59
uint32_t ek[60]
Definition: aes.h:60
Common interface for encryption algorithms.
Definition: crypto.h:1036
CipherAlgoEncryptBlock encryptBlock
Definition: crypto.h:1044
CipherAlgoDecryptBlock decryptBlock
Definition: crypto.h:1045
size_t blockSize
Definition: crypto.h:1040
GCM context.
Definition: gcm.h:64
const CipherAlgo * cipherAlgo
Cipher algorithm.
Definition: gcm.h:65
void * cipherContext
Cipher algorithm context.
Definition: gcm.h:66
uint8_t length
Definition: tcp.h:368
uint16_t block
Definition: tftp_common.h:115
uint8_t mask
Definition: web_socket.h:319