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