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-2025 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneCRYPTO Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.5.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
33 
34 //Dependencies
35 #include "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 (CTR_SUPPORT == ENABLED)
859 
860 /**
861  * @brief CTR encryption
862  * @param[in] cipher Cipher algorithm
863  * @param[in] context Cipher algorithm context
864  * @param[in] m Size in bits of the specific part of the block to be incremented
865  * @param[in,out] t Initial counter block
866  * @param[in] p Plaintext to be encrypted
867  * @param[out] c Ciphertext resulting from the encryption
868  * @param[in] length Total number of data bytes to be encrypted
869  * @return Error code
870  **/
871 
872 error_t ctrEncrypt(const CipherAlgo *cipher, void *context, uint_t m,
873  uint8_t *t, const uint8_t *p, uint8_t *c, size_t length)
874 {
875  error_t error;
876 
877  //Initialize status code
878  error = NO_ERROR;
879 
880  //Check the value of the parameter
881  if((m % 8) == 0 && m <= (cipher->blockSize * 8))
882  {
883  //Determine the size, in bytes, of the specific part of the block to be
884  //incremented
885  m = m / 8;
886 
887  //AES cipher algorithm?
888  if(cipher == AES_CIPHER_ALGO)
889  {
890  size_t k;
891  size_t n;
892 
893  //Process plaintext
894  while(length > 0)
895  {
896  //Limit the number of blocks to process at a time
897  k = 256 - t[AES_BLOCK_SIZE - 1];
898  n = MIN(length, k * AES_BLOCK_SIZE);
899  k = (n + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE;
900 
901  //Encrypt payload data
902  aesProcessData(context, t, p, c, n, AES_MR_CIPHER |
903  AES_MR_OPMOD_CTR);
904 
905  //Standard incrementing function
907 
908  //Next block
909  p += n;
910  c += n;
911  length -= n;
912  }
913  }
914  else
915  {
916  size_t i;
917  size_t n;
918  uint8_t o[16];
919 
920  //Process plaintext
921  while(length > 0)
922  {
923  //CTR mode operates in a block-by-block fashion
924  n = MIN(length, cipher->blockSize);
925 
926  //Compute O(j) = CIPH(T(j))
927  cipher->encryptBlock(context, t, o);
928 
929  //Compute C(j) = P(j) XOR T(j)
930  for(i = 0; i < n; i++)
931  {
932  c[i] = p[i] ^ o[i];
933  }
934 
935  //Standard incrementing function
936  ctrIncBlock(t, 1, cipher->blockSize, m);
937 
938  //Next block
939  p += n;
940  c += n;
941  length -= n;
942  }
943  }
944  }
945  else
946  {
947  //The value of the parameter is not valid
948  error = ERROR_INVALID_PARAMETER;
949  }
950 
951  //Return status code
952  return error;
953 }
954 
955 #endif
956 #if (GCM_SUPPORT == ENABLED)
957 
958 /**
959  * @brief Update GHASH value
960  * @param[in] data Input block of data
961  **/
962 
963 void gcmUpdateGhash(const uint8_t *data)
964 {
965  uint32_t *p;
966 
967  //Write data block
968  p = (uint32_t *) data;
969  AES->AES_IDATAR[0] = p[0];
970  AES->AES_IDATAR[1] = p[1];
971  AES->AES_IDATAR[2] = p[2];
972  AES->AES_IDATAR[3] = p[3];
973 
974  //The DATRDY bit indicates when the data have been processed. However, no
975  //output data are generated when processing AAD
976  while((AES->AES_ISR & AES_ISR_DATRDY) == 0)
977  {
978  }
979 }
980 
981 
982 /**
983  * @brief Perform AES-GCM encryption or decryption
984  * @param[in] context AES algorithm context
985  * @param[in] iv Initialization vector
986  * @param[in] a Additional authenticated data
987  * @param[in] aLen Length of the additional data
988  * @param[in] input Data to be encrypted/decrypted
989  * @param[out] output Data resulting from the encryption/decryption process
990  * @param[in] length Total number of data bytes to be processed
991  * @param[out] t Authentication tag
992  * @param[in] mode Operation mode
993  **/
994 
995 void gcmProcessData(AesContext *context, const uint8_t *iv,
996  const uint8_t *a, size_t aLen, const uint8_t *input, uint8_t *output,
997  size_t length, uint8_t *t, uint32_t mode)
998 {
999  uint32_t temp;
1000  uint8_t buffer[16];
1001 
1002  //Acquire exclusive access to the AES module
1004 
1005  //Perform software reset
1006  AES->AES_CR = AES_CR_SWRST;
1007 
1008  //Check parameters
1009  if(aLen > 0 || length > 0)
1010  {
1011  //Select GCM operation mode
1012  AES->AES_MR |= AES_MR_SMOD_AUTO_START | AES_MR_OPMOD_GCM |
1013  AES_MR_GTAGEN | mode;
1014 
1015  //Whenever a new key is written to the hardware, the hash subkey is
1016  //automatically generated. The hash subkey generation must be complete
1017  //before doing any other action
1018  aesLoadKey(context);
1019 
1020  //The DATRDY bit of the AES_ISR indicates when the subkey generation is
1021  //complete
1022  while((AES->AES_ISR & AES_ISR_DATRDY) == 0)
1023  {
1024  }
1025 
1026  //When the length of the IV is 96 bits, the padding string is appended to
1027  //the IV to form the pre-counter block
1028  AES->AES_IVR[0] = LOAD32LE(iv);
1029  AES->AES_IVR[1] = LOAD32LE(iv + 4);
1030  AES->AES_IVR[2] = LOAD32LE(iv + 8);
1031  AES->AES_IVR[3] = BETOH32(2);
1032 
1033  //Set AADLEN field in AES_AADLENR and CLEN field in AES_CLENR
1034  AES->AES_AADLENR = aLen;
1035  AES->AES_CLENR = length;
1036 
1037  //Process additional authenticated data
1038  while(aLen > 16)
1039  {
1040  //Additional authenticated data is written block by block
1041  gcmUpdateGhash(a);
1042 
1043  //Next block
1044  a += 16;
1045  aLen -= 16;
1046  }
1047 
1048  //Process final block of additional authenticated data
1049  if(aLen > 0)
1050  {
1051  //Copy partial block
1052  osMemset(buffer, 0, 16);
1053  osMemcpy(buffer, a, aLen);
1054 
1055  //Write the resulting block
1056  gcmUpdateGhash(buffer);
1057  }
1058 
1059  //Process data
1060  while(length >= AES_BLOCK_SIZE)
1061  {
1062  //The data is encrypted block by block
1063  aesProcessDataBlock(input, output);
1064 
1065  //Next block
1066  input += AES_BLOCK_SIZE;
1067  output += AES_BLOCK_SIZE;
1069  }
1070 
1071  //Process final block of data
1072  if(length > 0)
1073  {
1074  //Copy input data
1075  osMemset(buffer, 0, AES_BLOCK_SIZE);
1076  osMemcpy(buffer, input, length);
1077 
1078  //Encrypt the final block of data
1079  aesProcessDataBlock(buffer, buffer);
1080 
1081  //Copy output data
1082  osMemcpy(output, buffer, length);
1083  }
1084 
1085  //Wait for TAGRDY to be set
1086  while((AES->AES_ISR & AES_ISR_TAGRDY) == 0)
1087  {
1088  }
1089 
1090  //Read the value from AES_TAGR registers to obtain the authentication tag
1091  //of the message
1092  temp = AES->AES_TAGR[0];
1093  STORE32LE(temp, t);
1094  temp = AES->AES_TAGR[1];
1095  STORE32LE(temp, t + 4);
1096  temp = AES->AES_TAGR[2];
1097  STORE32LE(temp, t + 8);
1098  temp = AES->AES_TAGR[3];
1099  STORE32LE(temp, t + 12);
1100  }
1101  else
1102  {
1103  //Select CTR operation mode
1104  AES->AES_MR |= AES_MR_SMOD_AUTO_START | AES_MR_OPMOD_CTR |
1105  AES_MR_CIPHER;
1106 
1107  //Set encryption key
1108  aesLoadKey(context);
1109 
1110  //When the length of the IV is 96 bits, the padding string is appended to
1111  //the IV to form the pre-counter block
1112  AES->AES_IVR[0] = LOAD32LE(iv);
1113  AES->AES_IVR[1] = LOAD32LE(iv + 4);
1114  AES->AES_IVR[2] = LOAD32LE(iv + 8);
1115  AES->AES_IVR[3] = BETOH32(1);
1116 
1117  //Clear data block
1118  osMemset(buffer, 0, AES_BLOCK_SIZE);
1119 
1120  //Generate authentication tag
1121  aesProcessDataBlock(buffer, t);
1122  }
1123 
1124  //Release exclusive access to the AES module
1126 }
1127 
1128 
1129 /**
1130  * @brief Initialize GCM context
1131  * @param[in] context Pointer to the GCM context
1132  * @param[in] cipherAlgo Cipher algorithm
1133  * @param[in] cipherContext Pointer to the cipher algorithm context
1134  * @return Error code
1135  **/
1136 
1137 error_t gcmInit(GcmContext *context, const CipherAlgo *cipherAlgo,
1138  void *cipherContext)
1139 {
1140  //Check parameters
1141  if(context == NULL || cipherContext == NULL)
1142  return ERROR_INVALID_PARAMETER;
1143 
1144  //The CRYP module only supports AES cipher algorithm
1145  if(cipherAlgo != AES_CIPHER_ALGO)
1146  return ERROR_INVALID_PARAMETER;
1147 
1148  //Save cipher algorithm context
1149  context->cipherAlgo = cipherAlgo;
1150  context->cipherContext = cipherContext;
1151 
1152  //Successful initialization
1153  return NO_ERROR;
1154 }
1155 
1156 
1157 /**
1158  * @brief Authenticated encryption using GCM
1159  * @param[in] context Pointer to the GCM context
1160  * @param[in] iv Initialization vector
1161  * @param[in] ivLen Length of the initialization vector
1162  * @param[in] a Additional authenticated data
1163  * @param[in] aLen Length of the additional data
1164  * @param[in] p Plaintext to be encrypted
1165  * @param[out] c Ciphertext resulting from the encryption
1166  * @param[in] length Total number of data bytes to be encrypted
1167  * @param[out] t Authentication tag
1168  * @param[in] tLen Length of the authentication tag
1169  * @return Error code
1170  **/
1171 
1172 error_t gcmEncrypt(GcmContext *context, const uint8_t *iv,
1173  size_t ivLen, const uint8_t *a, size_t aLen, const uint8_t *p,
1174  uint8_t *c, size_t length, uint8_t *t, size_t tLen)
1175 {
1176  uint8_t authTag[16];
1177 
1178  //Make sure the GCM context is valid
1179  if(context == NULL)
1180  return ERROR_INVALID_PARAMETER;
1181 
1182  //Check whether the length of the IV is 96 bits
1183  if(ivLen != 12)
1184  return ERROR_INVALID_LENGTH;
1185 
1186  //Check the length of the authentication tag
1187  if(tLen < 4 || tLen > 16)
1188  return ERROR_INVALID_LENGTH;
1189 
1190  //Perform AES-GCM encryption
1191  gcmProcessData(context->cipherContext, iv, a, aLen, p, c, length,
1192  authTag, AES_MR_CIPHER);
1193 
1194  //Copy the resulting authentication tag
1195  osMemcpy(t, authTag, tLen);
1196 
1197  //Successful processing
1198  return NO_ERROR;
1199 }
1200 
1201 
1202 /**
1203  * @brief Authenticated decryption using GCM
1204  * @param[in] context Pointer to the GCM context
1205  * @param[in] iv Initialization vector
1206  * @param[in] ivLen Length of the initialization vector
1207  * @param[in] a Additional authenticated data
1208  * @param[in] aLen Length of the additional data
1209  * @param[in] c Ciphertext to be decrypted
1210  * @param[out] p Plaintext resulting from the decryption
1211  * @param[in] length Total number of data bytes to be decrypted
1212  * @param[in] t Authentication tag
1213  * @param[in] tLen Length of the authentication tag
1214  * @return Error code
1215  **/
1216 
1217 error_t gcmDecrypt(GcmContext *context, const uint8_t *iv,
1218  size_t ivLen, const uint8_t *a, size_t aLen, const uint8_t *c,
1219  uint8_t *p, size_t length, const uint8_t *t, size_t tLen)
1220 {
1221  size_t i;
1222  uint8_t mask;
1223  uint8_t authTag[16];
1224 
1225  //Make sure the GCM context is valid
1226  if(context == NULL)
1227  return ERROR_INVALID_PARAMETER;
1228 
1229  //Check whether the length of the IV is 96 bits
1230  if(ivLen != 12)
1231  return ERROR_INVALID_LENGTH;
1232 
1233  //Check the length of the authentication tag
1234  if(tLen < 4 || tLen > 16)
1235  return ERROR_INVALID_LENGTH;
1236 
1237  //Perform AES-GCM decryption
1238  gcmProcessData(context->cipherContext, iv, a, aLen, c, p, length,
1239  authTag, 0);
1240 
1241  //The calculated tag is bitwise compared to the received tag
1242  for(mask = 0, i = 0; i < tLen; i++)
1243  {
1244  mask |= authTag[i] ^ t[i];
1245  }
1246 
1247  //The message is authenticated if and only if the tags match
1248  return (mask == 0) ? NO_ERROR : ERROR_FAILURE;
1249 }
1250 
1251 #endif
1252 #endif
uint16_t block
Definition: tftp_common.h:115
error_t ecbDecrypt(const CipherAlgo *cipher, void *context, const uint8_t *c, uint8_t *p, size_t length)
ECB decryption.
uint8_t a
Definition: ndp.h:411
void aesProcessDataBlock(const uint8_t *input, uint8_t *output)
Encrypt/decrypt a 16-byte block using AES algorithm.
CipherAlgoDecryptBlock decryptBlock
Definition: crypto.h:1113
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 gcmUpdateGhash(const uint8_t *data)
Update GHASH value.
void aesEncryptBlock(AesContext *context, const uint8_t *input, uint8_t *output)
Encrypt a 16-byte block using AES algorithm.
uint8_t p
Definition: ndp.h:300
uint8_t t
Definition: lldp_ext_med.h:212
uint8_t o
Collection of AEAD algorithms.
uint8_t data[]
Definition: ethernet.h:222
#define STORE32LE(a, p)
Definition: cpu_endian.h:279
size_t blockSize
Definition: crypto.h:1108
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 ctrEncrypt(const CipherAlgo *cipher, void *context, uint_t m, uint8_t *t, const uint8_t *p, uint8_t *c, size_t length)
CTR encryption.
#define BETOH32(value)
Definition: cpu_endian.h:451
error_t ecbEncrypt(const CipherAlgo *cipher, void *context, const uint8_t *p, uint8_t *c, size_t length)
ECB encryption.
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.
SAM4C cipher hardware accelerator.
CipherAlgoEncryptBlock encryptBlock
Definition: crypto.h:1112
AES algorithm context.
Definition: aes.h:58
#define AES_BLOCK_SIZE
Definition: aes.h:43
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
#define osMemcpy(dest, src, length)
Definition: os_port.h:144
void aesDecryptBlock(AesContext *context, const uint8_t *input, uint8_t *output)
Decrypt a 16-byte block using AES algorithm.
error_t
Error codes.
Definition: error.h:43
void aesLoadKey(AesContext *context)
Load AES key.
error_t cbcDecrypt(const CipherAlgo *cipher, void *context, uint8_t *iv, const uint8_t *c, uint8_t *p, size_t length)
CBC decryption.
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
@ ERROR_INVALID_KEY_LENGTH
Definition: error.h:107
@ ERROR_INVALID_LENGTH
Definition: error.h:111
General definitions for cryptographic algorithms.
uint8_t mask
Definition: web_socket.h:319
uint8_t iv[]
Definition: ike.h:1626
Block cipher modes of operation.
const CipherAlgo * cipherAlgo
Cipher algorithm.
Definition: gcm.h:65
uint8_t length
Definition: tcp.h:375
#define MIN(a, b)
Definition: os_port.h:63
SAM4C hardware cryptographic accelerator.
uint_t nr
Definition: aes.h:59
GCM context.
Definition: gcm.h:64
error_t gcmInit(GcmContext *context, const CipherAlgo *cipherAlgo, void *cipherContext)
Initialize GCM context.
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.
uint8_t m
Definition: ndp.h:304
uint8_t n
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
error_t aesInit(AesContext *context, const uint8_t *key, size_t keyLen)
Key expansion.
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 osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
Common interface for encryption algorithms.
Definition: crypto.h:1104
#define AES_CIPHER_ALGO
Definition: aes.h:45
uint8_t s
Definition: igmp_common.h:234
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 LOAD32LE(p)
Definition: cpu_endian.h:203
uint32_t ek[60]
Definition: aes.h:60
unsigned int uint_t
Definition: compiler_port.h:57
#define osMemset(p, value, length)
Definition: os_port.h:138
OsMutex sam4cCryptoMutex
Definition: sam4c_crypto.c:44
void * cipherContext
Cipher algorithm context.
Definition: gcm.h:66
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.
void ctrIncBlock(uint8_t *ctr, uint32_t inc, size_t blockSize, size_t m)
Increment counter block.
Definition: ctr.c:138
@ NO_ERROR
Success.
Definition: error.h:44
uint8_t c
Definition: ndp.h:514
Debugging facilities.
#define osMemmove(dest, src, length)
Definition: os_port.h:150
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.