m2354_crypto_cipher.c
Go to the documentation of this file.
1 /**
2  * @file m2354_crypto_cipher.c
3  * @brief M2354 cipher hardware accelerator
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2025 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneCRYPTO Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.5.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
33 
34 //Dependencies
35 #include "m2354.h"
36 #include "core/crypto.h"
41 #include "aead/aead_algorithms.h"
42 #include "debug.h"
43 
44 //Check crypto library configuration
45 #if (M2354_CRYPTO_CIPHER_SUPPORT == ENABLED)
46 #if (AES_SUPPORT == ENABLED)
47 
48 
49 /**
50  * @brief Load AES key
51  * @param[in] context AES algorithm context
52  **/
53 
54 void aesLoadKey(AesContext *context)
55 {
56  uint32_t temp;
57 
58  //Read mode register
59  temp = CRPT->AES_CTL & ~CRPT_AES_CTL_KEYSZ_Pos;
60 
61  //Check the length of the key
62  if(context->nr == 10)
63  {
64  //10 rounds are required for 128-bit key
65  CRPT->AES_CTL = temp | CRPT_AES_CTL_KEYSZ_128B;
66 
67  //Set the 128-bit encryption key
68  CRPT->AES_KEY[0] = context->ek[0];
69  CRPT->AES_KEY[1] = context->ek[1];
70  CRPT->AES_KEY[2] = context->ek[2];
71  CRPT->AES_KEY[3] = context->ek[3];
72  }
73  else if(context->nr == 12)
74  {
75  //12 rounds are required for 192-bit key
76  CRPT->AES_CTL = temp | CRPT_AES_CTL_KEYSZ_192B;
77 
78  //Set the 192-bit encryption key
79  CRPT->AES_KEY[0] = context->ek[0];
80  CRPT->AES_KEY[1] = context->ek[1];
81  CRPT->AES_KEY[2] = context->ek[2];
82  CRPT->AES_KEY[3] = context->ek[3];
83  CRPT->AES_KEY[4] = context->ek[4];
84  CRPT->AES_KEY[5] = context->ek[5];
85  }
86  else
87  {
88  //14 rounds are required for 256-bit key
89  CRPT->AES_CTL = temp | CRPT_AES_CTL_KEYSZ_256B;
90 
91  //Set the 256-bit encryption key
92  CRPT->AES_KEY[0] = context->ek[0];
93  CRPT->AES_KEY[1] = context->ek[1];
94  CRPT->AES_KEY[2] = context->ek[2];
95  CRPT->AES_KEY[3] = context->ek[3];
96  CRPT->AES_KEY[4] = context->ek[4];
97  CRPT->AES_KEY[5] = context->ek[5];
98  CRPT->AES_KEY[6] = context->ek[6];
99  CRPT->AES_KEY[7] = context->ek[7];
100  }
101 }
102 
103 
104 /**
105  * @brief Encrypt/decrypt a 16-byte block using AES algorithm
106  * @param[in] input Input block to be encrypted/decrypted
107  * @param[out] output Resulting block
108  **/
109 
110 void aesProcessDataBlock(const uint8_t *input, uint8_t *output)
111 {
112  uint32_t temp;
113 
114  //Start AES encryption/decryption
115  CRPT->AES_CTL |= CRPT_AES_CTL_DMALAST_Msk | CRPT_AES_CTL_START_Msk;
116 
117  //Poll INBUFFULL flag
118  while((CRPT->AES_STS & CRPT_AES_STS_INBUFFULL_Msk) != 0)
119  {
120  }
121 
122  //Write input block CRYPTO_AES_DATIN
123  CRPT->AES_DATIN = __UNALIGNED_UINT32_READ(input);
124  CRPT->AES_DATIN = __UNALIGNED_UINT32_READ(input + 4);
125  CRPT->AES_DATIN = __UNALIGNED_UINT32_READ(input + 8);
126  CRPT->AES_DATIN = __UNALIGNED_UINT32_READ(input + 12);
127 
128  //Poll OUTBUFEMPTY flag
129  while((CRPT->AES_STS & CRPT_AES_STS_OUTBUFEMPTY_Msk) != 0)
130  {
131  }
132 
133  //Read output block from CRYPTO_AES_DATOUT
134  temp = CRPT->AES_DATOUT;
135  __UNALIGNED_UINT32_WRITE(output, temp);
136  temp = CRPT->AES_DATOUT;
137  __UNALIGNED_UINT32_WRITE(output + 4, temp);
138  temp = CRPT->AES_DATOUT;
139  __UNALIGNED_UINT32_WRITE(output + 8, temp);
140  temp = CRPT->AES_DATOUT;
141  __UNALIGNED_UINT32_WRITE(output + 12, temp);
142 
143  //Save feedback information
144  CRPT->AES_IV[0] = CRPT->AES_FDBCK[0];
145  CRPT->AES_IV[1] = CRPT->AES_FDBCK[1];
146  CRPT->AES_IV[2] = CRPT->AES_FDBCK[2];
147  CRPT->AES_IV[3] = CRPT->AES_FDBCK[3];
148 }
149 
150 
151 /**
152  * @brief Perform AES encryption or decryption
153  * @param[in] context AES algorithm context
154  * @param[in,out] iv Initialization vector
155  * @param[in] input Data to be encrypted/decrypted
156  * @param[out] output Data resulting from the encryption/decryption process
157  * @param[in] length Total number of data bytes to be processed
158  * @param[in] opmode Operation mode
159  **/
160 
161 void aesProcessData(AesContext *context, uint8_t *iv, const uint8_t *input,
162  uint8_t *output, size_t length, uint32_t opmode)
163 {
164  uint32_t temp;
165 
166  //Acquire exclusive access to the CRYPTO module
168 
169  //Reset CRYPTO controller
170  SYS->IPRST0 |= SYS_IPRST0_CRPTRST_Msk;
171  SYS->IPRST0 &= ~SYS_IPRST0_CRPTRST_Msk;
172 
173  //Configure operation mode
174  CRPT->AES_CTL = CRPT_AES_CTL_KEYPRT_Msk | CRPT_AES_CTL_INSWAP_Msk |
175  CRPT_AES_CTL_OUTSWAP_Msk | opmode;
176 
177  //Set encryption key
178  aesLoadKey(context);
179 
180  //Valid initialization vector?
181  if(iv != NULL)
182  {
183  //Set initialization vector
184  CRPT->AES_IV[0] = LOAD32BE(iv);
185  CRPT->AES_IV[1] = LOAD32BE(iv + 4);
186  CRPT->AES_IV[2] = LOAD32BE(iv + 8);
187  CRPT->AES_IV[3] = LOAD32BE(iv + 12);
188  }
189 
190  //Process data
191  while(length >= AES_BLOCK_SIZE)
192  {
193  //The data is encrypted block by block
194  aesProcessDataBlock(input, output);
195 
196  //Next block
197  input += AES_BLOCK_SIZE;
198  output += AES_BLOCK_SIZE;
200  }
201 
202  //Process final block of data
203  if(length > 0)
204  {
205  uint8_t buffer[AES_BLOCK_SIZE];
206 
207  //Copy input data
208  osMemset(buffer, 0, AES_BLOCK_SIZE);
209  osMemcpy(buffer, input, length);
210 
211  //Encrypt the final block of data
212  aesProcessDataBlock(buffer, buffer);
213 
214  //Copy output data
215  osMemcpy(output, buffer, length);
216  }
217 
218  //Valid initialization vector?
219  if(iv != NULL)
220  {
221  //Update the value of the initialization vector
222  temp = CRPT->AES_FDBCK[0];
223  STORE32BE(temp, iv);
224  temp = CRPT->AES_FDBCK[1];
225  STORE32BE(temp, iv + 4);
226  temp = CRPT->AES_FDBCK[2];
227  STORE32BE(temp, iv + 8);
228  temp = CRPT->AES_FDBCK[3];
229  STORE32BE(temp, iv + 12);
230  }
231 
232  //Stop AES engine
233  CRPT->AES_CTL |= CRPT_AES_CTL_STOP_Msk;
234 
235  //Release exclusive access to the CRYPTO module
237 }
238 
239 
240 /**
241  * @brief Key expansion
242  * @param[in] context Pointer to the AES context to initialize
243  * @param[in] key Pointer to the key
244  * @param[in] keyLen Length of the key
245  * @return Error code
246  **/
247 
248 error_t aesInit(AesContext *context, const uint8_t *key, size_t keyLen)
249 {
250  size_t i;
251 
252  //Check parameters
253  if(context == NULL || key == NULL)
255 
256  //Check the length of the key
257  if(keyLen == 16)
258  {
259  //10 rounds are required for 128-bit key
260  context->nr = 10;
261  }
262  else if(keyLen == 24)
263  {
264  //12 rounds are required for 256-bit key
265  context->nr = 12;
266  }
267  else if(keyLen == 32)
268  {
269  //14 rounds are required for 256-bit key
270  context->nr = 14;
271  }
272  else
273  {
274  //192-bit keys are not supported
276  }
277 
278  //Determine the number of 32-bit words in the key
279  keyLen /= 4;
280 
281  //Copy the original key
282  for(i = 0; i < keyLen; i++)
283  {
284  context->ek[i] = LOAD32BE(key + (i * 4));
285  }
286 
287  //No error to report
288  return NO_ERROR;
289 }
290 
291 
292 /**
293  * @brief Encrypt a 16-byte block using AES algorithm
294  * @param[in] context Pointer to the AES context
295  * @param[in] input Plaintext block to encrypt
296  * @param[out] output Ciphertext block resulting from encryption
297  **/
298 
299 void aesEncryptBlock(AesContext *context, const uint8_t *input, uint8_t *output)
300 {
301  //Perform AES encryption
302  aesProcessData(context, NULL, input, output, AES_BLOCK_SIZE,
303  CRPT_AES_CTL_OPMODE_ECB | CRPT_AES_CTL_ENCRPT_Msk);
304 }
305 
306 
307 /**
308  * @brief Decrypt a 16-byte block using AES algorithm
309  * @param[in] context Pointer to the AES context
310  * @param[in] input Ciphertext block to decrypt
311  * @param[out] output Plaintext block resulting from decryption
312  **/
313 
314 void aesDecryptBlock(AesContext *context, const uint8_t *input, uint8_t *output)
315 {
316  //Perform AES decryption
317  aesProcessData(context, NULL, input, output, AES_BLOCK_SIZE,
319 }
320 
321 #endif
322 #if (SM4_SUPPORT == ENABLED)
323 
324 /**
325  * @brief Encrypt/decrypt a 16-byte block using SM4 algorithm
326  * @param[in] input Input block to be encrypted/decrypted
327  * @param[out] output Resulting block
328  **/
329 
330 void sm4ProcessDataBlock(const uint8_t *input, uint8_t *output)
331 {
332  uint32_t temp;
333 
334  //Start SM4 encryption/decryption
335  CRPT->AES_CTL |= CRPT_AES_CTL_DMALAST_Msk | CRPT_AES_CTL_START_Msk;
336 
337  //Poll INBUFFULL flag
338  while((CRPT->AES_STS & CRPT_AES_STS_INBUFFULL_Msk) != 0)
339  {
340  }
341 
342  //Write input block CRYPTO_AES_DATIN
343  CRPT->AES_DATIN = __UNALIGNED_UINT32_READ(input);
344  CRPT->AES_DATIN = __UNALIGNED_UINT32_READ(input + 4);
345  CRPT->AES_DATIN = __UNALIGNED_UINT32_READ(input + 8);
346  CRPT->AES_DATIN = __UNALIGNED_UINT32_READ(input + 12);
347 
348  //Poll OUTBUFEMPTY flag
349  while((CRPT->AES_STS & CRPT_AES_STS_OUTBUFEMPTY_Msk) != 0)
350  {
351  }
352 
353  //Read output block from CRYPTO_AES_DATOUT
354  temp = CRPT->AES_DATOUT;
355  __UNALIGNED_UINT32_WRITE(output, temp);
356  temp = CRPT->AES_DATOUT;
357  __UNALIGNED_UINT32_WRITE(output + 4, temp);
358  temp = CRPT->AES_DATOUT;
359  __UNALIGNED_UINT32_WRITE(output + 8, temp);
360  temp = CRPT->AES_DATOUT;
361  __UNALIGNED_UINT32_WRITE(output + 12, temp);
362 
363  //Save feedback information
364  CRPT->AES_IV[0] = CRPT->AES_FDBCK[0];
365  CRPT->AES_IV[1] = CRPT->AES_FDBCK[1];
366  CRPT->AES_IV[2] = CRPT->AES_FDBCK[2];
367  CRPT->AES_IV[3] = CRPT->AES_FDBCK[3];
368 }
369 
370 
371 /**
372  * @brief Perform SM4 encryption or decryption
373  * @param[in] context SM4 algorithm context
374  * @param[in,out] iv Initialization vector
375  * @param[in] input Data to be encrypted/decrypted
376  * @param[out] output Data resulting from the encryption/decryption process
377  * @param[in] length Total number of data bytes to be processed
378  * @param[in] opmode Operation mode
379  **/
380 
381 void sm4ProcessData(Sm4Context *context, uint8_t *iv, const uint8_t *input,
382  uint8_t *output, size_t length, uint32_t opmode)
383 {
384  uint32_t temp;
385 
386  //Acquire exclusive access to the CRYPTO module
388 
389  //Reset CRYPTO controller
390  SYS->IPRST0 |= SYS_IPRST0_CRPTRST_Msk;
391  SYS->IPRST0 &= ~SYS_IPRST0_CRPTRST_Msk;
392 
393  //Configure operation mode
394  CRPT->AES_CTL = CRPT_AES_CTL_KEYPRT_Msk | CRPT_AES_CTL_INSWAP_Msk |
395  CRPT_AES_CTL_OUTSWAP_Msk | CRPT_AES_CTL_SM4EN_Msk | opmode;
396 
397  //Set encryption key
398  CRPT->AES_KEY[0] = context->rk[0];
399  CRPT->AES_KEY[1] = context->rk[1];
400  CRPT->AES_KEY[2] = context->rk[2];
401  CRPT->AES_KEY[3] = context->rk[3];
402 
403  //Valid initialization vector?
404  if(iv != NULL)
405  {
406  //Set initialization vector
407  CRPT->AES_IV[0] = LOAD32BE(iv);
408  CRPT->AES_IV[1] = LOAD32BE(iv + 4);
409  CRPT->AES_IV[2] = LOAD32BE(iv + 8);
410  CRPT->AES_IV[3] = LOAD32BE(iv + 12);
411  }
412 
413  //Process data
414  while(length >= SM4_BLOCK_SIZE)
415  {
416  //The data is encrypted block by block
417  sm4ProcessDataBlock(input, output);
418 
419  //Next block
420  input += SM4_BLOCK_SIZE;
421  output += SM4_BLOCK_SIZE;
423  }
424 
425  //Process final block of data
426  if(length > 0)
427  {
428  uint8_t buffer[SM4_BLOCK_SIZE];
429 
430  //Copy input data
431  osMemset(buffer, 0, SM4_BLOCK_SIZE);
432  osMemcpy(buffer, input, length);
433 
434  //Encrypt the final block of data
435  sm4ProcessDataBlock(buffer, buffer);
436 
437  //Copy output data
438  osMemcpy(output, buffer, length);
439  }
440 
441  //Valid initialization vector?
442  if(iv != NULL)
443  {
444  //Update the value of the initialization vector
445  temp = CRPT->AES_FDBCK[0];
446  STORE32BE(temp, iv);
447  temp = CRPT->AES_FDBCK[1];
448  STORE32BE(temp, iv + 4);
449  temp = CRPT->AES_FDBCK[2];
450  STORE32BE(temp, iv + 8);
451  temp = CRPT->AES_FDBCK[3];
452  STORE32BE(temp, iv + 12);
453  }
454 
455  //Stop SM4 engine
456  CRPT->AES_CTL |= CRPT_AES_CTL_STOP_Msk;
457 
458  //Release exclusive access to the CRYPTO module
460 }
461 
462 
463 /**
464  * @brief Key expansion
465  * @param[in] context Pointer to the SM4 context to initialize
466  * @param[in] key Pointer to the key
467  * @param[in] keyLen Length of the key
468  * @return Error code
469  **/
470 
471 error_t sm4Init(Sm4Context *context, const uint8_t *key, size_t keyLen)
472 {
473  size_t i;
474 
475  //Check parameters
476  if(context == NULL || key == NULL)
478 
479  //The SM4 encryption key is 128 bits long
480  if(keyLen != 16)
482 
483  //Copy the original key
484  context->rk[0] = LOAD32BE(key);
485  context->rk[1] = LOAD32BE(key + 4);
486  context->rk[2] = LOAD32BE(key + 8);
487  context->rk[3] = LOAD32BE(key + 12);
488 
489  //No error to report
490  return NO_ERROR;
491 }
492 
493 
494 /**
495  * @brief Encrypt a 16-byte block using SM4 algorithm
496  * @param[in] context Pointer to the SM4 context
497  * @param[in] input Plaintext block to encrypt
498  * @param[out] output Ciphertext block resulting from encryption
499  **/
500 
501 void sm4EncryptBlock(Sm4Context *context, const uint8_t *input, uint8_t *output)
502 {
503  //Perform SM4 encryption
504  sm4ProcessData(context, NULL, input, output, SM4_BLOCK_SIZE,
505  CRPT_AES_CTL_OPMODE_ECB | CRPT_AES_CTL_ENCRPT_Msk);
506 }
507 
508 
509 /**
510  * @brief Decrypt a 16-byte block using SM4 algorithm
511  * @param[in] context Pointer to the SM4 context
512  * @param[in] input Ciphertext block to decrypt
513  * @param[out] output Plaintext block resulting from decryption
514  **/
515 
516 void sm4DecryptBlock(Sm4Context *context, const uint8_t *input, uint8_t *output)
517 {
518  //Perform SM4 decryption
519  sm4ProcessData(context, NULL, input, output, SM4_BLOCK_SIZE,
521 }
522 
523 #endif
524 #if (ECB_SUPPORT == ENABLED)
525 
526 /**
527  * @brief ECB encryption
528  * @param[in] cipher Cipher algorithm
529  * @param[in] context Cipher algorithm context
530  * @param[in] p Plaintext to be encrypted
531  * @param[out] c Ciphertext resulting from the encryption
532  * @param[in] length Total number of data bytes to be encrypted
533  * @return Error code
534  **/
535 
536 error_t ecbEncrypt(const CipherAlgo *cipher, void *context,
537  const uint8_t *p, uint8_t *c, size_t length)
538 {
539  error_t error;
540 
541  //Initialize status code
542  error = NO_ERROR;
543 
544 #if (AES_SUPPORT == ENABLED)
545  //AES cipher algorithm?
546  if(cipher == AES_CIPHER_ALGO)
547  {
548  //Check the length of the payload
549  if(length == 0)
550  {
551  //No data to process
552  }
553  else if((length % AES_BLOCK_SIZE) == 0)
554  {
555  //Encrypt payload data
556  aesProcessData(context, NULL, p, c, length, CRPT_AES_CTL_OPMODE_ECB |
557  CRPT_AES_CTL_ENCRPT_Msk);
558  }
559  else
560  {
561  //The length of the payload must be a multiple of the block size
562  error = ERROR_INVALID_LENGTH;
563  }
564  }
565  else
566 #endif
567 #if (SM4_SUPPORT == ENABLED)
568  //SM4 cipher algorithm?
569  if(cipher == SM4_CIPHER_ALGO)
570  {
571  //Check the length of the payload
572  if(length == 0)
573  {
574  //No data to process
575  }
576  else if((length % SM4_BLOCK_SIZE) == 0)
577  {
578  //Encrypt payload data
579  sm4ProcessData(context, NULL, p, c, length, CRPT_AES_CTL_OPMODE_ECB |
580  CRPT_AES_CTL_ENCRPT_Msk);
581  }
582  else
583  {
584  //The length of the payload must be a multiple of the block size
585  error = ERROR_INVALID_LENGTH;
586  }
587  }
588  else
589 #endif
590  //Unknown cipher algorithm?
591  {
592  //ECB mode operates in a block-by-block fashion
593  while(length >= cipher->blockSize)
594  {
595  //Encrypt current block
596  cipher->encryptBlock(context, p, c);
597 
598  //Next block
599  p += cipher->blockSize;
600  c += cipher->blockSize;
601  length -= cipher->blockSize;
602  }
603 
604  //The length of the payload must be a multiple of the block size
605  if(length != 0)
606  {
607  error = ERROR_INVALID_LENGTH;
608  }
609  }
610 
611  //Return status code
612  return error;
613 }
614 
615 
616 /**
617  * @brief ECB decryption
618  * @param[in] cipher Cipher algorithm
619  * @param[in] context Cipher algorithm context
620  * @param[in] c Ciphertext to be decrypted
621  * @param[out] p Plaintext resulting from the decryption
622  * @param[in] length Total number of data bytes to be decrypted
623  * @return Error code
624  **/
625 
626 error_t ecbDecrypt(const CipherAlgo *cipher, void *context,
627  const uint8_t *c, uint8_t *p, size_t length)
628 {
629  error_t error;
630 
631  //Initialize status code
632  error = NO_ERROR;
633 
634 #if (AES_SUPPORT == ENABLED)
635  //AES cipher algorithm?
636  if(cipher == AES_CIPHER_ALGO)
637  {
638  //Check the length of the payload
639  if(length == 0)
640  {
641  //No data to process
642  }
643  else if((length % AES_BLOCK_SIZE) == 0)
644  {
645  //Decrypt payload data
646  aesProcessData(context, NULL, c, p, length, CRPT_AES_CTL_OPMODE_ECB);
647  }
648  else
649  {
650  //The length of the payload must be a multiple of the block size
651  error = ERROR_INVALID_LENGTH;
652  }
653  }
654  else
655 #endif
656 #if (SM4_SUPPORT == ENABLED)
657  //SM4 cipher algorithm?
658  if(cipher == SM4_CIPHER_ALGO)
659  {
660  //Check the length of the payload
661  if(length == 0)
662  {
663  //No data to process
664  }
665  else if((length % SM4_BLOCK_SIZE) == 0)
666  {
667  //Decrypt payload data
668  sm4ProcessData(context, NULL, c, p, length, CRPT_AES_CTL_OPMODE_ECB);
669  }
670  else
671  {
672  //The length of the payload must be a multiple of the block size
673  error = ERROR_INVALID_LENGTH;
674  }
675  }
676  else
677 #endif
678  //Unknown cipher algorithm?
679  {
680  //ECB mode operates in a block-by-block fashion
681  while(length >= cipher->blockSize)
682  {
683  //Decrypt current block
684  cipher->decryptBlock(context, c, p);
685 
686  //Next block
687  c += cipher->blockSize;
688  p += cipher->blockSize;
689  length -= cipher->blockSize;
690  }
691 
692  //The length of the payload must be a multiple of the block size
693  if(length != 0)
694  {
695  error = ERROR_INVALID_LENGTH;
696  }
697  }
698 
699  //Return status code
700  return error;
701 }
702 
703 #endif
704 #if (CBC_SUPPORT == ENABLED)
705 
706 /**
707  * @brief CBC encryption
708  * @param[in] cipher Cipher algorithm
709  * @param[in] context Cipher algorithm context
710  * @param[in,out] iv Initialization vector
711  * @param[in] p Plaintext to be encrypted
712  * @param[out] c Ciphertext resulting from the encryption
713  * @param[in] length Total number of data bytes to be encrypted
714  * @return Error code
715  **/
716 
717 error_t cbcEncrypt(const CipherAlgo *cipher, void *context,
718  uint8_t *iv, const uint8_t *p, uint8_t *c, size_t length)
719 {
720  error_t error;
721 
722  //Initialize status code
723  error = NO_ERROR;
724 
725 #if (AES_SUPPORT == ENABLED)
726  //AES cipher algorithm?
727  if(cipher == AES_CIPHER_ALGO)
728  {
729  //Check the length of the payload
730  if(length == 0)
731  {
732  //No data to process
733  }
734  else if((length % AES_BLOCK_SIZE) == 0)
735  {
736  //Encrypt payload data
738  CRPT_AES_CTL_ENCRPT_Msk);
739  }
740  else
741  {
742  //The length of the payload must be a multiple of the block size
743  error = ERROR_INVALID_LENGTH;
744  }
745  }
746  else
747 #endif
748 #if (SM4_SUPPORT == ENABLED)
749  //SM4 cipher algorithm?
750  if(cipher == SM4_CIPHER_ALGO)
751  {
752  //Check the length of the payload
753  if(length == 0)
754  {
755  //No data to process
756  }
757  else if((length % SM4_BLOCK_SIZE) == 0)
758  {
759  //Encrypt payload data
761  CRPT_AES_CTL_ENCRPT_Msk);
762  }
763  else
764  {
765  //The length of the payload must be a multiple of the block size
766  error = ERROR_INVALID_LENGTH;
767  }
768  }
769  else
770 #endif
771  //Unknown cipher algorithm?
772  {
773  size_t i;
774 
775  //CBC mode operates in a block-by-block fashion
776  while(length >= cipher->blockSize)
777  {
778  //XOR input block with IV contents
779  for(i = 0; i < cipher->blockSize; i++)
780  {
781  c[i] = p[i] ^ iv[i];
782  }
783 
784  //Encrypt the current block based upon the output of the previous
785  //encryption
786  cipher->encryptBlock(context, c, c);
787 
788  //Update IV with output block contents
789  osMemcpy(iv, c, cipher->blockSize);
790 
791  //Next block
792  p += cipher->blockSize;
793  c += cipher->blockSize;
794  length -= cipher->blockSize;
795  }
796 
797  //The length of the payload must be a multiple of the block size
798  if(length != 0)
799  {
800  error = ERROR_INVALID_LENGTH;
801  }
802  }
803 
804  //Return status code
805  return error;
806 }
807 
808 
809 /**
810  * @brief CBC decryption
811  * @param[in] cipher Cipher algorithm
812  * @param[in] context Cipher algorithm context
813  * @param[in,out] iv Initialization vector
814  * @param[in] c Ciphertext to be decrypted
815  * @param[out] p Plaintext resulting from the decryption
816  * @param[in] length Total number of data bytes to be decrypted
817  * @return Error code
818  **/
819 
820 error_t cbcDecrypt(const CipherAlgo *cipher, void *context,
821  uint8_t *iv, const uint8_t *c, uint8_t *p, size_t length)
822 {
823  error_t error;
824 
825  //Initialize status code
826  error = NO_ERROR;
827 
828 #if (AES_SUPPORT == ENABLED)
829  //AES cipher algorithm?
830  if(cipher == AES_CIPHER_ALGO)
831  {
832  //Check the length of the payload
833  if(length == 0)
834  {
835  //No data to process
836  }
837  else if((length % AES_BLOCK_SIZE) == 0)
838  {
839  //Decrypt payload data
841  }
842  else
843  {
844  //The length of the payload must be a multiple of the block size
845  error = ERROR_INVALID_LENGTH;
846  }
847  }
848  else
849 #endif
850 #if (SM4_SUPPORT == ENABLED)
851  //SM4 cipher algorithm?
852  if(cipher == SM4_CIPHER_ALGO)
853  {
854  //Check the length of the payload
855  if(length == 0)
856  {
857  //No data to process
858  }
859  else if((length % SM4_BLOCK_SIZE) == 0)
860  {
861  //Decrypt payload data
863  }
864  else
865  {
866  //The length of the payload must be a multiple of the block size
867  error = ERROR_INVALID_LENGTH;
868  }
869  }
870  else
871 #endif
872  //Unknown cipher algorithm?
873  {
874  size_t i;
875  uint8_t t[16];
876 
877  //CBC mode operates in a block-by-block fashion
878  while(length >= cipher->blockSize)
879  {
880  //Save input block
881  osMemcpy(t, c, cipher->blockSize);
882 
883  //Decrypt the current block
884  cipher->decryptBlock(context, c, p);
885 
886  //XOR output block with IV contents
887  for(i = 0; i < cipher->blockSize; i++)
888  {
889  p[i] ^= iv[i];
890  }
891 
892  //Update IV with input block contents
893  osMemcpy(iv, t, cipher->blockSize);
894 
895  //Next block
896  c += cipher->blockSize;
897  p += cipher->blockSize;
898  length -= cipher->blockSize;
899  }
900 
901  //The length of the payload must be a multiple of the block size
902  if(length != 0)
903  {
904  error = ERROR_INVALID_LENGTH;
905  }
906  }
907 
908  //Return status code
909  return error;
910 }
911 
912 #endif
913 #if (CFB_SUPPORT == ENABLED)
914 
915 /**
916  * @brief CFB encryption
917  * @param[in] cipher Cipher algorithm
918  * @param[in] context Cipher algorithm context
919  * @param[in] s Size of the plaintext and ciphertext segments
920  * @param[in,out] iv Initialization vector
921  * @param[in] p Plaintext to be encrypted
922  * @param[out] c Ciphertext resulting from the encryption
923  * @param[in] length Total number of data bytes to be encrypted
924  * @return Error code
925  **/
926 
927 error_t cfbEncrypt(const CipherAlgo *cipher, void *context, uint_t s,
928  uint8_t *iv, const uint8_t *p, uint8_t *c, size_t length)
929 {
930  error_t error;
931 
932  //Initialize status code
933  error = NO_ERROR;
934 
935 #if (AES_SUPPORT == ENABLED)
936  //AES cipher algorithm?
937  if(cipher == AES_CIPHER_ALGO)
938  {
939  //Check the value of the parameter
940  if(s == (AES_BLOCK_SIZE * 8))
941  {
942  //Check the length of the payload
943  if(length > 0)
944  {
945  //Encrypt payload data
947  CRPT_AES_CTL_ENCRPT_Msk);
948  }
949  else
950  {
951  //No data to process
952  }
953  }
954  else
955  {
956  //The value of the parameter is not valid
957  error = ERROR_INVALID_PARAMETER;
958  }
959  }
960  else
961 #endif
962 #if (SM4_SUPPORT == ENABLED)
963  //SM4 cipher algorithm?
964  if(cipher == SM4_CIPHER_ALGO)
965  {
966  //Check the value of the parameter
967  if(s == (SM4_BLOCK_SIZE * 8))
968  {
969  //Check the length of the payload
970  if(length > 0)
971  {
972  //Encrypt payload data
974  CRPT_AES_CTL_ENCRPT_Msk);
975  }
976  else
977  {
978  //No data to process
979  }
980  }
981  else
982  {
983  //The value of the parameter is not valid
984  error = ERROR_INVALID_PARAMETER;
985  }
986  }
987  else
988 #endif
989  //Unknown cipher algorithm?
990  {
991  //Check the value of the parameter
992  if((s % 8) == 0 && s >= 1 && s <= (cipher->blockSize * 8))
993  {
994  size_t i;
995  size_t n;
996  uint8_t o[16];
997 
998  //Determine the size, in bytes, of the plaintext and ciphertext segments
999  s = s / 8;
1000 
1001  //Process each plaintext segment
1002  while(length > 0)
1003  {
1004  //Compute the number of bytes to process at a time
1005  n = MIN(length, s);
1006 
1007  //Compute O(j) = CIPH(I(j))
1008  cipher->encryptBlock(context, iv, o);
1009 
1010  //Compute C(j) = P(j) XOR MSB(O(j))
1011  for(i = 0; i < n; i++)
1012  {
1013  c[i] = p[i] ^ o[i];
1014  }
1015 
1016  //Compute I(j+1) = LSB(I(j)) | C(j)
1017  osMemmove(iv, iv + s, cipher->blockSize - s);
1018  osMemcpy(iv + cipher->blockSize - s, c, s);
1019 
1020  //Next block
1021  p += n;
1022  c += n;
1023  length -= n;
1024  }
1025  }
1026  else
1027  {
1028  //The value of the parameter is not valid
1029  error = ERROR_INVALID_PARAMETER;
1030  }
1031  }
1032 
1033  //Return status code
1034  return error;
1035 }
1036 
1037 
1038 /**
1039  * @brief CFB decryption
1040  * @param[in] cipher Cipher algorithm
1041  * @param[in] context Cipher algorithm context
1042  * @param[in] s Size of the plaintext and ciphertext segments
1043  * @param[in,out] iv Initialization vector
1044  * @param[in] c Ciphertext to be decrypted
1045  * @param[out] p Plaintext resulting from the decryption
1046  * @param[in] length Total number of data bytes to be decrypted
1047  * @return Error code
1048  **/
1049 
1050 error_t cfbDecrypt(const CipherAlgo *cipher, void *context, uint_t s,
1051  uint8_t *iv, const uint8_t *c, uint8_t *p, size_t length)
1052 {
1053  error_t error;
1054 
1055  //Initialize status code
1056  error = NO_ERROR;
1057 
1058 #if (AES_SUPPORT == ENABLED)
1059  //AES cipher algorithm?
1060  if(cipher == AES_CIPHER_ALGO)
1061  {
1062  //Check the value of the parameter
1063  if(s == (AES_BLOCK_SIZE * 8))
1064  {
1065  //Check the length of the payload
1066  if(length > 0)
1067  {
1068  //Decrypt payload data
1070  }
1071  else
1072  {
1073  //No data to process
1074  }
1075  }
1076  else
1077  {
1078  //The value of the parameter is not valid
1079  error = ERROR_INVALID_PARAMETER;
1080  }
1081  }
1082  else
1083 #endif
1084 #if (SM4_SUPPORT == ENABLED)
1085  //SM4 cipher algorithm?
1086  if(cipher == SM4_CIPHER_ALGO)
1087  {
1088  //Check the value of the parameter
1089  if(s == (SM4_BLOCK_SIZE * 8))
1090  {
1091  //Check the length of the payload
1092  if(length > 0)
1093  {
1094  //Decrypt payload data
1096  }
1097  else
1098  {
1099  //No data to process
1100  }
1101  }
1102  else
1103  {
1104  //The value of the parameter is not valid
1105  error = ERROR_INVALID_PARAMETER;
1106  }
1107  }
1108  else
1109 #endif
1110  //Unknown cipher algorithm?
1111  {
1112  //Check the value of the parameter
1113  if((s % 8) == 0 && s >= 1 && s <= (cipher->blockSize * 8))
1114  {
1115  size_t i;
1116  size_t n;
1117  uint8_t o[16];
1118 
1119  //Determine the size, in bytes, of the plaintext and ciphertext segments
1120  s = s / 8;
1121 
1122  //Process each ciphertext segment
1123  while(length > 0)
1124  {
1125  //Compute the number of bytes to process at a time
1126  n = MIN(length, s);
1127 
1128  //Compute O(j) = CIPH(I(j))
1129  cipher->encryptBlock(context, iv, o);
1130 
1131  //Compute I(j+1) = LSB(I(j)) | C(j)
1132  osMemmove(iv, iv + s, cipher->blockSize - s);
1133  osMemcpy(iv + cipher->blockSize - s, c, s);
1134 
1135  //Compute P(j) = C(j) XOR MSB(O(j))
1136  for(i = 0; i < n; i++)
1137  {
1138  p[i] = c[i] ^ o[i];
1139  }
1140 
1141  //Next block
1142  c += n;
1143  p += n;
1144  length -= n;
1145  }
1146  }
1147  else
1148  {
1149  //The value of the parameter is not valid
1150  error = ERROR_INVALID_PARAMETER;
1151  }
1152  }
1153 
1154  //Return status code
1155  return error;
1156 }
1157 
1158 #endif
1159 #if (OFB_SUPPORT == ENABLED)
1160 
1161 /**
1162  * @brief OFB encryption
1163  * @param[in] cipher Cipher algorithm
1164  * @param[in] context Cipher algorithm context
1165  * @param[in] s Size of the plaintext and ciphertext segments
1166  * @param[in,out] iv Initialization vector
1167  * @param[in] p Plaintext to be encrypted
1168  * @param[out] c Ciphertext resulting from the encryption
1169  * @param[in] length Total number of data bytes to be encrypted
1170  * @return Error code
1171  **/
1172 
1173 error_t ofbEncrypt(const CipherAlgo *cipher, void *context, uint_t s,
1174  uint8_t *iv, const uint8_t *p, uint8_t *c, size_t length)
1175 {
1176  error_t error;
1177 
1178  //Initialize status code
1179  error = NO_ERROR;
1180 
1181 #if (AES_SUPPORT == ENABLED)
1182  //AES cipher algorithm?
1183  if(cipher == AES_CIPHER_ALGO)
1184  {
1185  //Check the value of the parameter
1186  if(s == (AES_BLOCK_SIZE * 8))
1187  {
1188  //Check the length of the payload
1189  if(length > 0)
1190  {
1191  //Encrypt payload data
1193  CRPT_AES_CTL_ENCRPT_Msk);
1194  }
1195  else
1196  {
1197  //No data to process
1198  }
1199  }
1200  else
1201  {
1202  //The value of the parameter is not valid
1203  error = ERROR_INVALID_PARAMETER;
1204  }
1205  }
1206  else
1207 #endif
1208 #if (SM4_SUPPORT == ENABLED)
1209  //SM4 cipher algorithm?
1210  if(cipher == SM4_CIPHER_ALGO)
1211  {
1212  //Check the value of the parameter
1213  if(s == (SM4_BLOCK_SIZE * 8))
1214  {
1215  //Check the length of the payload
1216  if(length > 0)
1217  {
1218  //Encrypt payload data
1220  CRPT_AES_CTL_ENCRPT_Msk);
1221  }
1222  else
1223  {
1224  //No data to process
1225  }
1226  }
1227  else
1228  {
1229  //The value of the parameter is not valid
1230  error = ERROR_INVALID_PARAMETER;
1231  }
1232  }
1233  else
1234 #endif
1235  //Unknown cipher algorithm?
1236  {
1237  //Check the value of the parameter
1238  if((s % 8) == 0 && s >= 1 && s <= (cipher->blockSize * 8))
1239  {
1240  size_t i;
1241  size_t n;
1242  uint8_t o[16];
1243 
1244  //Determine the size, in bytes, of the plaintext and ciphertext segments
1245  s = s / 8;
1246 
1247  //Process each plaintext segment
1248  while(length > 0)
1249  {
1250  //Compute the number of bytes to process at a time
1251  n = MIN(length, s);
1252 
1253  //Compute O(j) = CIPH(I(j))
1254  cipher->encryptBlock(context, iv, o);
1255 
1256  //Compute C(j) = P(j) XOR MSB(O(j))
1257  for(i = 0; i < n; i++)
1258  {
1259  c[i] = p[i] ^ o[i];
1260  }
1261 
1262  //Compute I(j+1) = LSB(I(j)) | O(j)
1263  osMemmove(iv, iv + s, cipher->blockSize - s);
1264  osMemcpy(iv + cipher->blockSize - s, o, s);
1265 
1266  //Next block
1267  p += n;
1268  c += n;
1269  length -= n;
1270  }
1271  }
1272  else
1273  {
1274  //The value of the parameter is not valid
1275  error = ERROR_INVALID_PARAMETER;
1276  }
1277  }
1278 
1279  //Return status code
1280  return error;
1281 }
1282 
1283 #endif
1284 #if (CTR_SUPPORT == ENABLED)
1285 
1286 /**
1287  * @brief CTR encryption
1288  * @param[in] cipher Cipher algorithm
1289  * @param[in] context Cipher algorithm context
1290  * @param[in] m Size in bits of the specific part of the block to be incremented
1291  * @param[in,out] t Initial counter block
1292  * @param[in] p Plaintext to be encrypted
1293  * @param[out] c Ciphertext resulting from the encryption
1294  * @param[in] length Total number of data bytes to be encrypted
1295  * @return Error code
1296  **/
1297 
1298 error_t ctrEncrypt(const CipherAlgo *cipher, void *context, uint_t m,
1299  uint8_t *t, const uint8_t *p, uint8_t *c, size_t length)
1300 {
1301  error_t error;
1302 
1303  //Initialize status code
1304  error = NO_ERROR;
1305 
1306  //Check the value of the parameter
1307  if((m % 8) == 0 && m <= (cipher->blockSize * 8))
1308  {
1309  //Determine the size, in bytes, of the specific part of the block to be
1310  //incremented
1311  m = m / 8;
1312 
1313 #if (AES_SUPPORT == ENABLED)
1314  //AES cipher algorithm?
1315  if(cipher == AES_CIPHER_ALGO)
1316  {
1317  size_t k;
1318  size_t n;
1319  uint8_t iv[AES_BLOCK_SIZE];
1320 
1321  //Process plaintext
1322  while(length > 0)
1323  {
1324  //Limit the number of blocks to process at a time
1325  k = 256 - t[AES_BLOCK_SIZE - 1];
1326  n = MIN(length, k * AES_BLOCK_SIZE);
1327  k = (n + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE;
1328 
1329  //Copy initial counter value
1331 
1332  //Encrypt payload data
1333  aesProcessData(context, iv, p, c, n, CRPT_AES_CTL_OPMODE_CTR |
1334  CRPT_AES_CTL_ENCRPT_Msk);
1335 
1336  //Standard incrementing function
1337  ctrIncBlock(t, k, AES_BLOCK_SIZE, m);
1338 
1339  //Next block
1340  p += n;
1341  c += n;
1342  length -= n;
1343  }
1344  }
1345  else
1346 #endif
1347 #if (SM4_SUPPORT == ENABLED)
1348  //SM4 cipher algorithm?
1349  if(cipher == SM4_CIPHER_ALGO)
1350  {
1351  size_t k;
1352  size_t n;
1353  uint8_t iv[SM4_BLOCK_SIZE];
1354 
1355  //Process plaintext
1356  while(length > 0)
1357  {
1358  //Limit the number of blocks to process at a time
1359  k = 256 - t[SM4_BLOCK_SIZE - 1];
1360  n = MIN(length, k * SM4_BLOCK_SIZE);
1361  k = (n + SM4_BLOCK_SIZE - 1) / SM4_BLOCK_SIZE;
1362 
1363  //Copy initial counter value
1365 
1366  //Encrypt payload data
1367  sm4ProcessData(context, iv, p, c, n, CRPT_AES_CTL_OPMODE_CTR |
1368  CRPT_AES_CTL_ENCRPT_Msk);
1369 
1370  //Standard incrementing function
1371  ctrIncBlock(t, k, SM4_BLOCK_SIZE, m);
1372 
1373  //Next block
1374  p += n;
1375  c += n;
1376  length -= n;
1377  }
1378  }
1379  else
1380 #endif
1381  //Unknown cipher algorithm?
1382  {
1383  size_t i;
1384  size_t n;
1385  uint8_t o[16];
1386 
1387  //Process plaintext
1388  while(length > 0)
1389  {
1390  //CTR mode operates in a block-by-block fashion
1391  n = MIN(length, cipher->blockSize);
1392 
1393  //Compute O(j) = CIPH(T(j))
1394  cipher->encryptBlock(context, t, o);
1395 
1396  //Compute C(j) = P(j) XOR T(j)
1397  for(i = 0; i < n; i++)
1398  {
1399  c[i] = p[i] ^ o[i];
1400  }
1401 
1402  //Standard incrementing function
1403  ctrIncBlock(t, 1, cipher->blockSize, m);
1404 
1405  //Next block
1406  p += n;
1407  c += n;
1408  length -= n;
1409  }
1410  }
1411  }
1412  else
1413  {
1414  //The value of the parameter is not valid
1415  error = ERROR_INVALID_PARAMETER;
1416  }
1417 
1418  //Return status code
1419  return error;
1420 }
1421 
1422 #endif
1423 #if (GCM_SUPPORT == ENABLED)
1424 
1425 /**
1426  * @brief Increment counter block
1427  * @param[in,out] ctr Pointer to the counter block
1428  * @param[in] inc Value of the increment
1429  **/
1430 
1431 void gcmIncBlock(uint8_t *ctr, uint32_t inc)
1432 {
1433  size_t i;
1434  uint32_t temp;
1435 
1436  //The function increments the right-most bytes of the block. The remaining
1437  //left-most bytes remain unchanged
1438  for(temp = inc, i = 0; i <= 3; i++)
1439  {
1440  //Increment the current byte and propagate the carry
1441  temp += ctr[15 - i];
1442  ctr[15 - i] = temp & 0xFF;
1443  temp >>= 8;
1444  }
1445 }
1446 
1447 
1448 /**
1449  * @brief Authenticated encryption using GCM
1450  * @param[in] context Pointer to the GCM context
1451  * @param[in] iv Initialization vector
1452  * @param[in] ivLen Length of the initialization vector
1453  * @param[in] a Additional authenticated data
1454  * @param[in] aLen Length of the additional data
1455  * @param[in] p Plaintext to be encrypted
1456  * @param[out] c Ciphertext resulting from the encryption
1457  * @param[in] length Total number of data bytes to be encrypted
1458  * @param[out] t Authentication tag
1459  * @param[in] tLen Length of the authentication tag
1460  * @return Error code
1461  **/
1462 
1463 error_t gcmEncrypt(GcmContext *context, const uint8_t *iv, size_t ivLen,
1464  const uint8_t *a, size_t aLen, const uint8_t *p, uint8_t *c, size_t length,
1465  uint8_t *t, size_t tLen)
1466 {
1467  size_t i;
1468  size_t n;
1469  uint8_t b[16];
1470  uint8_t j[16];
1471  uint8_t s[16];
1472 
1473  //Make sure the GCM context is valid
1474  if(context == NULL)
1475  return ERROR_INVALID_PARAMETER;
1476 
1477  //The length of the IV shall meet SP 800-38D requirements
1478  if(ivLen < 1)
1479  return ERROR_INVALID_LENGTH;
1480 
1481  //Check the length of the authentication tag
1482  if(tLen < 4 || tLen > 16)
1483  return ERROR_INVALID_LENGTH;
1484 
1485  //Check whether the length of the IV is 96 bits
1486  if(ivLen == 12)
1487  {
1488  //When the length of the IV is 96 bits, the padding string is appended
1489  //to the IV to form the pre-counter block
1490  osMemcpy(j, iv, 12);
1491  STORE32BE(1, j + 12);
1492  }
1493  else
1494  {
1495  //Initialize GHASH calculation
1496  osMemset(j, 0, 16);
1497 
1498  //Process the initialization vector
1499  for(i = 0; i < ivLen; i += n)
1500  {
1501  //The IV is processed in a block-by-block fashion
1502  n = MIN(ivLen - i, 16);
1503 
1504  //Apply GHASH function
1505  gcmXorBlock(j, j, iv + i, n);
1506  gcmMul(context, j);
1507  }
1508 
1509  //The string is appended with 64 additional 0 bits, followed by the
1510  //64-bit representation of the length of the IV
1511  osMemset(b, 0, 8);
1512  STORE64BE(ivLen * 8, b + 8);
1513 
1514  //The GHASH function is applied to the resulting string to form the
1515  //pre-counter block
1516  gcmXorBlock(j, j, b, 16);
1517  gcmMul(context, j);
1518  }
1519 
1520  //Compute MSB(CIPH(J(0)))
1521  context->cipherAlgo->encryptBlock(context->cipherContext, j, b);
1522  osMemcpy(t, b, tLen);
1523 
1524  //Initialize GHASH calculation
1525  osMemset(s, 0, 16);
1526 
1527  //Process AAD
1528  for(i = 0; i < aLen; i += n)
1529  {
1530  //Additional data are processed in a block-by-block fashion
1531  n = MIN(aLen - i, 16);
1532 
1533  //Apply GHASH function
1534  gcmXorBlock(s, s, a + i, n);
1535  gcmMul(context, s);
1536  }
1537 
1538  //Increment counter
1539  gcmIncCounter(j);
1540 
1541 #if (AES_SUPPORT == ENABLED)
1542  //AES cipher algorithm?
1543  if(context->cipherAlgo == AES_CIPHER_ALGO)
1544  {
1545  //Encrypt plaintext
1546  for(i = 0; i < length; i += n)
1547  {
1548  size_t k;
1549  uint8_t iv[AES_BLOCK_SIZE];
1550 
1551  //Limit the number of blocks to process at a time
1552  k = 256 - j[AES_BLOCK_SIZE - 1];
1553  n = MIN(length, k * AES_BLOCK_SIZE);
1554  k = (n + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE;
1555 
1556  //Copy initial counter value
1557  osMemcpy(iv, j, AES_BLOCK_SIZE);
1558 
1559  //Encrypt payload data
1560  aesProcessData(context->cipherContext, iv, p + i, c + i, n,
1561  CRPT_AES_CTL_OPMODE_CTR | CRPT_AES_CTL_ENCRPT_Msk);
1562 
1563  //Increment the right-most 32 bits of the block
1564  gcmIncBlock(j, k);
1565  }
1566  }
1567  else
1568 #endif
1569 #if (SM4_SUPPORT == ENABLED)
1570  //SM4 cipher algorithm?
1571  if(context->cipherAlgo == SM4_CIPHER_ALGO)
1572  {
1573  //Encrypt plaintext
1574  for(i = 0; i < length; i += n)
1575  {
1576  size_t k;
1577  uint8_t iv[SM4_BLOCK_SIZE];
1578 
1579  //Limit the number of blocks to process at a time
1580  k = 256 - j[SM4_BLOCK_SIZE - 1];
1581  n = MIN(length, k * SM4_BLOCK_SIZE);
1582  k = (n + SM4_BLOCK_SIZE - 1) / SM4_BLOCK_SIZE;
1583 
1584  //Copy initial counter value
1585  osMemcpy(iv, j, SM4_BLOCK_SIZE);
1586 
1587  //Encrypt payload data
1588  sm4ProcessData(context->cipherContext, iv, p + i, c + i, n,
1589  CRPT_AES_CTL_OPMODE_CTR | CRPT_AES_CTL_ENCRPT_Msk);
1590 
1591  //Increment the right-most 32 bits of the block
1592  gcmIncBlock(j, k);
1593  }
1594  }
1595  else
1596 #endif
1597  //Unknown cipher algorithm?
1598  {
1599  //Encrypt plaintext
1600  for(i = 0; i < length; i += n)
1601  {
1602  //The encryption operates in a block-by-block fashion
1603  n = MIN(length - i, 16);
1604 
1605  //Encrypt current block
1606  context->cipherAlgo->encryptBlock(context->cipherContext, j, b);
1607  gcmXorBlock(c + i, p + i, b, n);
1608 
1609  //Increment counter
1610  gcmIncCounter(j);
1611  }
1612  }
1613 
1614  //Process ciphertext
1615  for(i = 0; i < length; i += n)
1616  {
1617  //The encryption operates in a block-by-block fashion
1618  n = MIN(length - i, 16);
1619 
1620  //Apply GHASH function
1621  gcmXorBlock(s, s, c + i, n);
1622  gcmMul(context, s);
1623  }
1624 
1625  //Append the 64-bit representation of the length of the AAD and the
1626  //ciphertext
1627  STORE64BE(aLen * 8, b);
1628  STORE64BE(length * 8, b + 8);
1629 
1630  //The GHASH function is applied to the result to produce a single output
1631  //block S
1632  gcmXorBlock(s, s, b, 16);
1633  gcmMul(context, s);
1634 
1635  //Let T = MSB(GCTR(J(0), S)
1636  gcmXorBlock(t, t, s, tLen);
1637 
1638  //Successful encryption
1639  return NO_ERROR;
1640 }
1641 
1642 
1643 /**
1644  * @brief Authenticated decryption using GCM
1645  * @param[in] context Pointer to the GCM context
1646  * @param[in] iv Initialization vector
1647  * @param[in] ivLen Length of the initialization vector
1648  * @param[in] a Additional authenticated data
1649  * @param[in] aLen Length of the additional data
1650  * @param[in] c Ciphertext to be decrypted
1651  * @param[out] p Plaintext resulting from the decryption
1652  * @param[in] length Total number of data bytes to be decrypted
1653  * @param[in] t Authentication tag
1654  * @param[in] tLen Length of the authentication tag
1655  * @return Error code
1656  **/
1657 
1658 error_t gcmDecrypt(GcmContext *context, const uint8_t *iv, size_t ivLen,
1659  const uint8_t *a, size_t aLen, const uint8_t *c, uint8_t *p, size_t length,
1660  const uint8_t *t, size_t tLen)
1661 {
1662  uint8_t mask;
1663  size_t i;
1664  size_t n;
1665  uint8_t b[16];
1666  uint8_t j[16];
1667  uint8_t r[16];
1668  uint8_t s[16];
1669 
1670  //Make sure the GCM context is valid
1671  if(context == NULL)
1672  return ERROR_INVALID_PARAMETER;
1673 
1674  //The length of the IV shall meet SP 800-38D requirements
1675  if(ivLen < 1)
1676  return ERROR_INVALID_LENGTH;
1677 
1678  //Check the length of the authentication tag
1679  if(tLen < 4 || tLen > 16)
1680  return ERROR_INVALID_LENGTH;
1681 
1682  //Check whether the length of the IV is 96 bits
1683  if(ivLen == 12)
1684  {
1685  //When the length of the IV is 96 bits, the padding string is appended
1686  //to the IV to form the pre-counter block
1687  osMemcpy(j, iv, 12);
1688  STORE32BE(1, j + 12);
1689  }
1690  else
1691  {
1692  //Initialize GHASH calculation
1693  osMemset(j, 0, 16);
1694 
1695  //Process the initialization vector
1696  for(i = 0; i < ivLen; i += n)
1697  {
1698  //The IV is processed in a block-by-block fashion
1699  n = MIN(ivLen - i, 16);
1700 
1701  //Apply GHASH function
1702  gcmXorBlock(j, j, iv + i, n);
1703  gcmMul(context, j);
1704  }
1705 
1706  //The string is appended with 64 additional 0 bits, followed by the
1707  //64-bit representation of the length of the IV
1708  osMemset(b, 0, 8);
1709  STORE64BE(ivLen * 8, b + 8);
1710 
1711  //The GHASH function is applied to the resulting string to form the
1712  //pre-counter block
1713  gcmXorBlock(j, j, b, 16);
1714  gcmMul(context, j);
1715  }
1716 
1717  //Compute MSB(CIPH(J(0)))
1718  context->cipherAlgo->encryptBlock(context->cipherContext, j, b);
1719  osMemcpy(r, b, tLen);
1720 
1721  //Initialize GHASH calculation
1722  osMemset(s, 0, 16);
1723 
1724  //Process AAD
1725  for(i = 0; i < aLen; i += n)
1726  {
1727  //Additional data are processed in a block-by-block fashion
1728  n = MIN(aLen - i, 16);
1729 
1730  //Apply GHASH function
1731  gcmXorBlock(s, s, a + i, n);
1732  gcmMul(context, s);
1733  }
1734 
1735  //Process ciphertext
1736  for(i = 0; i < length; i += n)
1737  {
1738  //The decryption operates in a block-by-block fashion
1739  n = MIN(length - i, 16);
1740 
1741  //Apply GHASH function
1742  gcmXorBlock(s, s, c + i, n);
1743  gcmMul(context, s);
1744  }
1745 
1746  //Increment counter
1747  gcmIncCounter(j);
1748 
1749 #if (AES_SUPPORT == ENABLED)
1750  //AES cipher algorithm?
1751  if(context->cipherAlgo == AES_CIPHER_ALGO)
1752  {
1753  //Decrypt ciphertext
1754  for(i = 0; i < length; i += n)
1755  {
1756  size_t k;
1757  uint8_t iv[AES_BLOCK_SIZE];
1758 
1759  //Limit the number of blocks to process at a time
1760  k = 256 - j[AES_BLOCK_SIZE - 1];
1761  n = MIN(length, k * AES_BLOCK_SIZE);
1762  k = (n + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE;
1763 
1764  //Copy initial counter value
1765  osMemcpy(iv, j, AES_BLOCK_SIZE);
1766 
1767  //Encrypt payload data
1768  aesProcessData(context->cipherContext, iv, c + i, p + i, n,
1769  CRPT_AES_CTL_OPMODE_CTR | CRPT_AES_CTL_ENCRPT_Msk);
1770 
1771  //Increment the right-most 32 bits of the block
1772  gcmIncBlock(j, k);
1773  }
1774  }
1775  else
1776 #endif
1777 #if (SM4_SUPPORT == ENABLED)
1778  //SM4 cipher algorithm?
1779  if(context->cipherAlgo == SM4_CIPHER_ALGO)
1780  {
1781  //Decrypt ciphertext
1782  for(i = 0; i < length; i += n)
1783  {
1784  size_t k;
1785  uint8_t iv[SM4_BLOCK_SIZE];
1786 
1787  //Limit the number of blocks to process at a time
1788  k = 256 - j[SM4_BLOCK_SIZE - 1];
1789  n = MIN(length, k * SM4_BLOCK_SIZE);
1790  k = (n + SM4_BLOCK_SIZE - 1) / SM4_BLOCK_SIZE;
1791 
1792  //Copy initial counter value
1793  osMemcpy(iv, j, SM4_BLOCK_SIZE);
1794 
1795  //Encrypt payload data
1796  sm4ProcessData(context->cipherContext, iv, c + i, p + i, n,
1797  CRPT_AES_CTL_OPMODE_CTR | CRPT_AES_CTL_ENCRPT_Msk);
1798 
1799  //Increment the right-most 32 bits of the block
1800  gcmIncBlock(j, k);
1801  }
1802  }
1803  else
1804 #endif
1805  //Unknown cipher algorithm?
1806  {
1807  //Decrypt ciphertext
1808  for(i = 0; i < length; i += n)
1809  {
1810  //The decryption operates in a block-by-block fashion
1811  n = MIN(length - i, 16);
1812 
1813  //Decrypt current block
1814  context->cipherAlgo->encryptBlock(context->cipherContext, j, b);
1815  gcmXorBlock(p + i, c + i, b, n);
1816 
1817  //Increment counter
1818  gcmIncCounter(j);
1819  }
1820  }
1821 
1822  //Append the 64-bit representation of the length of the AAD and the
1823  //ciphertext
1824  STORE64BE(aLen * 8, b);
1825  STORE64BE(length * 8, b + 8);
1826 
1827  //The GHASH function is applied to the result to produce a single output
1828  //block S
1829  gcmXorBlock(s, s, b, 16);
1830  gcmMul(context, s);
1831 
1832  //Let R = MSB(GCTR(J(0), S))
1833  gcmXorBlock(r, r, s, tLen);
1834 
1835  //The calculated tag is bitwise compared to the received tag. The message
1836  //is authenticated if and only if the tags match
1837  for(mask = 0, n = 0; n < tLen; n++)
1838  {
1839  mask |= r[n] ^ t[n];
1840  }
1841 
1842  //Return status code
1843  return (mask == 0) ? NO_ERROR : ERROR_FAILURE;
1844 }
1845 
1846 #endif
1847 #endif
uint8_t b
Definition: nbns_common.h:104
uint8_t a
Definition: ndp.h:411
#define LOAD32BE(p)
Definition: cpu_endian.h:210
CipherAlgoDecryptBlock decryptBlock
Definition: crypto.h:1113
uint8_t p
Definition: ndp.h:300
uint8_t t
Definition: lldp_ext_med.h:212
uint8_t o
#define CRPT_AES_CTL_OPMODE_OFB
Collection of AEAD algorithms.
M2354 cipher hardware accelerator.
size_t blockSize
Definition: crypto.h:1108
SM4 algorithm context.
Definition: sm4.h:58
void gcmIncCounter(uint8_t *ctr)
Increment counter block.
Definition: gcm.c:609
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.
#define CRPT_AES_CTL_OPMODE_CFB
CipherAlgoEncryptBlock encryptBlock
Definition: crypto.h:1112
void aesDecryptBlock(AesContext *context, const uint8_t *input, uint8_t *output)
Decrypt a 16-byte block using AES algorithm.
uint8_t r
Definition: ndp.h:346
AES algorithm context.
Definition: aes.h:58
#define AES_BLOCK_SIZE
Definition: aes.h:43
error_t cbcEncrypt(const CipherAlgo *cipher, void *context, uint8_t *iv, const uint8_t *p, uint8_t *c, size_t length)
CBC encryption.
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
#define osMemcpy(dest, src, length)
Definition: os_port.h:144
__weak_func void gcmMul(GcmContext *context, uint8_t *x)
Multiplication operation in GF(2^128)
Definition: gcm.c:503
#define CRPT_AES_CTL_OPMODE_ECB
void aesProcessDataBlock(const uint8_t *input, uint8_t *output)
Encrypt/decrypt a 16-byte block using AES algorithm.
error_t
Error codes.
Definition: error.h:43
void aesEncryptBlock(AesContext *context, const uint8_t *input, uint8_t *output)
Encrypt a 16-byte block using AES algorithm.
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_FAILURE
Generic error code.
Definition: error.h:45
error_t gcmEncrypt(GcmContext *context, const uint8_t *iv, size_t ivLen, const uint8_t *a, size_t aLen, const uint8_t *p, uint8_t *c, size_t length, uint8_t *t, size_t tLen)
Authenticated encryption using GCM.
#define CRPT_AES_CTL_KEYSZ_192B
#define SM4_BLOCK_SIZE
Definition: sm4.h:43
@ ERROR_INVALID_KEY_LENGTH
Definition: error.h:107
@ ERROR_INVALID_LENGTH
Definition: error.h:111
void gcmIncBlock(uint8_t *ctr, uint32_t inc)
Increment counter block.
General definitions for cryptographic algorithms.
uint8_t mask
Definition: web_socket.h:319
uint8_t iv[]
Definition: ike.h:1626
Block cipher modes of operation.
const CipherAlgo * cipherAlgo
Cipher algorithm.
Definition: gcm.h:65
#define CRPT_AES_CTL_KEYSZ_256B
uint8_t length
Definition: tcp.h:375
error_t sm4Init(Sm4Context *context, const uint8_t *key, size_t keyLen)
Key expansion.
#define MIN(a, b)
Definition: os_port.h:63
#define SM4_CIPHER_ALGO
Definition: sm4.h:45
error_t aesInit(AesContext *context, const uint8_t *key, size_t keyLen)
Key expansion.
uint_t nr
Definition: aes.h:59
#define CRPT_AES_CTL_OPMODE_CTR
error_t ecbEncrypt(const CipherAlgo *cipher, void *context, const uint8_t *p, uint8_t *c, size_t length)
ECB encryption.
GCM context.
Definition: gcm.h:64
#define STORE64BE(a, p)
Definition: cpu_endian.h:322
void sm4ProcessDataBlock(const uint8_t *input, uint8_t *output)
Encrypt/decrypt a 16-byte block using SM4 algorithm.
void sm4DecryptBlock(Sm4Context *context, const uint8_t *input, uint8_t *output)
Decrypt a 16-byte block using SM4 algorithm.
uint8_t m
Definition: ndp.h:304
uint8_t n
void aesProcessData(AesContext *context, uint8_t *iv, const uint8_t *input, uint8_t *output, size_t length, uint32_t opmode)
Perform AES encryption or decryption.
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
void gcmXorBlock(uint8_t *x, const uint8_t *a, const uint8_t *b, size_t n)
XOR operation.
Definition: gcm.c:592
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.
OsMutex m2354CryptoMutex
Definition: m2354_crypto.c:42
#define CRPT_AES_CTL_KEYSZ_128B
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:1104
error_t ecbDecrypt(const CipherAlgo *cipher, void *context, const uint8_t *c, uint8_t *p, size_t length)
ECB decryption.
#define AES_CIPHER_ALGO
Definition: aes.h:45
void sm4EncryptBlock(Sm4Context *context, const uint8_t *input, uint8_t *output)
Encrypt a 16-byte block using SM4 algorithm.
uint8_t s
Definition: igmp_common.h:234
M2354 hardware cryptographic accelerator.
error_t cbcDecrypt(const CipherAlgo *cipher, void *context, uint8_t *iv, const uint8_t *c, uint8_t *p, size_t length)
CBC decryption.
void aesLoadKey(AesContext *context)
Load AES key.
#define CRPT_AES_CTL_OPMODE_CBC
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.
uint32_t ek[60]
Definition: aes.h:60
unsigned int uint_t
Definition: compiler_port.h:57
#define osMemset(p, value, length)
Definition: os_port.h:138
void sm4ProcessData(Sm4Context *context, uint8_t *iv, const uint8_t *input, uint8_t *output, size_t length, uint32_t opmode)
Perform SM4 encryption or decryption.
void * cipherContext
Cipher algorithm context.
Definition: gcm.h:66
#define STORE32BE(a, p)
Definition: cpu_endian.h:286
uint32_t rk[32]
Definition: sm4.h:60
void ctrIncBlock(uint8_t *ctr, uint32_t inc, size_t blockSize, size_t m)
Increment counter block.
Definition: ctr.c:138
@ NO_ERROR
Success.
Definition: error.h:44
uint8_t c
Definition: ndp.h:514
Debugging facilities.
#define osMemmove(dest, src, length)
Definition: os_port.h:150