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