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