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