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