max32690_crypto_cipher.c
Go to the documentation of this file.
1 /**
2  * @file max32690_crypto_cipher.c
3  * @brief MAX32690 cipher hardware accelerator
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneCRYPTO Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.4.4
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
33 
34 //Dependencies
35 #include "mxc_device.h"
36 #include "mxc_sys.h"
37 #include "ctb.h"
38 #include "core/crypto.h"
43 #include "aead/aead_algorithms.h"
44 #include "debug.h"
45 
46 //Check crypto library configuration
47 #if (MAX32690_CRYPTO_CIPHER_SUPPORT == ENABLED && AES_SUPPORT == ENABLED)
48 
49 
50 /**
51  * @brief Load AES key
52  * @param[in] context AES algorithm context
53  **/
54 
55 void aesLoadKey(AesContext *context)
56 {
57  uint32_t temp;
58 
59  //Read cipher control register
60  temp = MXC_CTB->cipher_ctrl & ~(MXC_F_CTB_CIPHER_CTRL_CIPHER |
61  MXC_F_CTB_CIPHER_CTRL_SRC);
62 
63  //Load cipher key from CTB_CIPHER_KEY registers
64  temp |= MXC_S_CTB_CIPHER_CTRL_SRC_CIPHERKEY;
65 
66  //Check the length of the key
67  if(context->nr == 10)
68  {
69  //10 rounds are required for 128-bit key
70  MXC_CTB->cipher_ctrl = temp | MXC_S_CTB_CIPHER_CTRL_CIPHER_AES128;
71 
72  //Set the 128-bit encryption key
73  MXC_CTB->cipher_key[0] = context->ek[0];
74  MXC_CTB->cipher_key[1] = context->ek[1];
75  MXC_CTB->cipher_key[2] = context->ek[2];
76  MXC_CTB->cipher_key[3] = context->ek[3];
77  }
78  else if(context->nr == 12)
79  {
80  //12 rounds are required for 192-bit key
81  MXC_CTB->cipher_ctrl = temp | MXC_S_CTB_CIPHER_CTRL_CIPHER_AES192;
82 
83  //Set the 192-bit encryption key
84  MXC_CTB->cipher_key[0] = context->ek[0];
85  MXC_CTB->cipher_key[1] = context->ek[1];
86  MXC_CTB->cipher_key[2] = context->ek[2];
87  MXC_CTB->cipher_key[3] = context->ek[3];
88  MXC_CTB->cipher_key[4] = context->ek[4];
89  MXC_CTB->cipher_key[5] = context->ek[5];
90  }
91  else
92  {
93  //14 rounds are required for 256-bit key
94  MXC_CTB->cipher_ctrl = temp | MXC_S_CTB_CIPHER_CTRL_CIPHER_AES256;
95 
96  //Set the 256-bit encryption key
97  MXC_CTB->cipher_key[0] = context->ek[0];
98  MXC_CTB->cipher_key[1] = context->ek[1];
99  MXC_CTB->cipher_key[2] = context->ek[2];
100  MXC_CTB->cipher_key[3] = context->ek[3];
101  MXC_CTB->cipher_key[4] = context->ek[4];
102  MXC_CTB->cipher_key[5] = context->ek[5];
103  MXC_CTB->cipher_key[6] = context->ek[6];
104  MXC_CTB->cipher_key[7] = context->ek[7];
105  }
106 }
107 
108 
109 /**
110  * @brief Perform AES encryption or decryption
111  * @param[in] context AES algorithm context
112  * @param[in,out] iv Initialization vector
113  * @param[in] input Data to be encrypted/decrypted
114  * @param[out] output Data resulting from the encryption/decryption process
115  * @param[in] length Total number of data bytes to be processed
116  * @param[in] mode Operation mode
117  * @param[in] encrypt Encryption or decryption operation
118  **/
119 
120 void aesProcessData(AesContext *context, uint8_t *iv, const uint8_t *input,
121  uint8_t *output, size_t length, uint32_t mode, bool_t encrypt)
122 {
123  uint32_t temp;
124 
125  //Acquire exclusive access to the CTB module
127 
128  //Reset the engine by setting CTB_CTRL.rst
129  MXC_CTB->ctrl = MXC_F_CTB_CTRL_RST;
130 
131  //Software must poll the CTB_CTRL.rst bit until it is set to 1 by hardware,
132  //indicating the cryptographic accelerator is ready for use
133  while((MXC_CTB->ctrl & MXC_F_CTB_CTRL_RDY) == 0)
134  {
135  }
136 
137  //Legacy support for the access behavior of the done flags
138  MXC_CTB->ctrl |= MXC_F_CTB_CTRL_FLAG_MODE;
139  //Clear done flags
140  MXC_CTB->ctrl |= MXC_F_CTB_CTRL_CPH_DONE | MXC_F_CTB_CTRL_GLS_DONE;
141 
142  //Select operation mode
143  MXC_CTB->cipher_ctrl = (mode << MXC_F_CTB_CIPHER_CTRL_MODE_POS) &
144  MXC_F_CTB_CIPHER_CTRL_MODE;
145 
146  //Set encryption key
147  aesLoadKey(context);
148 
149  //Valid initialization vector?
150  if(iv != NULL)
151  {
152  //Set initialization vector
153  MXC_CTB->cipher_init[0] = __UNALIGNED_UINT32_READ(iv);
154  MXC_CTB->cipher_init[1] = __UNALIGNED_UINT32_READ(iv + 4);
155  MXC_CTB->cipher_init[2] = __UNALIGNED_UINT32_READ(iv + 8);
156  MXC_CTB->cipher_init[3] = __UNALIGNED_UINT32_READ(iv + 12);
157  }
158 
159  //Encryption or decryption operation?
160  if(!encrypt)
161  {
162  MXC_CTB->cipher_ctrl |= MXC_F_CTB_CIPHER_CTRL_ENC;
163  }
164  else
165  {
166  MXC_CTB->cipher_ctrl &= ~MXC_F_CTB_CIPHER_CTRL_ENC;
167  }
168 
169  //Process data
170  while(length >= AES_BLOCK_SIZE)
171  {
172  //Write input block
173  MXC_CTB->din[0] = __UNALIGNED_UINT32_READ(input);
174  MXC_CTB->din[1] = __UNALIGNED_UINT32_READ(input + 4);
175  MXC_CTB->din[2] = __UNALIGNED_UINT32_READ(input + 8);
176  MXC_CTB->din[3] = __UNALIGNED_UINT32_READ(input + 12);
177 
178  //Wait until the operation is complete
179  while((MXC_CTB->ctrl & MXC_F_CTB_CTRL_CPH_DONE) == 0)
180  {
181  }
182 
183  //Read output block
184  temp = MXC_CTB->dout[0];
185  __UNALIGNED_UINT32_WRITE(output, temp);
186  temp = MXC_CTB->dout[1];
187  __UNALIGNED_UINT32_WRITE(output + 4, temp);
188  temp = MXC_CTB->dout[2];
189  __UNALIGNED_UINT32_WRITE(output + 8, temp);
190  temp = MXC_CTB->dout[3];
191  __UNALIGNED_UINT32_WRITE(output + 12, temp);
192 
193  //Clear CTB_CTRL.cph_done flag
194  MXC_CTB->ctrl |= MXC_F_CTB_CTRL_CPH_DONE;
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  uint32_t buffer[4];
206 
207  //Copy partial block
208  osMemset(buffer, 0, AES_BLOCK_SIZE);
209  osMemcpy(buffer, input, length);
210 
211  //Write input block
212  MXC_CTB->din[0] = buffer[0];
213  MXC_CTB->din[1] = buffer[1];
214  MXC_CTB->din[2] = buffer[2];
215  MXC_CTB->din[3] = buffer[3];
216 
217  //Wait until the operation is complete
218  while((MXC_CTB->ctrl & MXC_F_CTB_CTRL_CPH_DONE) == 0)
219  {
220  }
221 
222  //Read output block
223  buffer[0] = MXC_CTB->dout[0];
224  buffer[1] = MXC_CTB->dout[1];
225  buffer[2] = MXC_CTB->dout[2];
226  buffer[3] = MXC_CTB->dout[3];
227 
228  //Clear CTB_CTRL.cph_done flag
229  MXC_CTB->ctrl |= MXC_F_CTB_CTRL_CPH_DONE;
230 
231  //Copy partial block
232  osMemcpy(output, buffer, length);
233  }
234 
235  //Disable block cipher engine
236  temp = MXC_CTB->cipher_ctrl & ~MXC_F_CTB_CIPHER_CTRL_CIPHER;
237  MXC_CTB->cipher_ctrl = temp |= MXC_S_CTB_CIPHER_CTRL_CIPHER_DIS;
238 
239  //Release exclusive access to the CTB module
241 }
242 
243 
244 /**
245  * @brief Key expansion
246  * @param[in] context Pointer to the AES context to initialize
247  * @param[in] key Pointer to the key
248  * @param[in] keyLen Length of the key
249  * @return Error code
250  **/
251 
252 error_t aesInit(AesContext *context, const uint8_t *key, size_t keyLen)
253 {
254  //Check parameters
255  if(context == NULL || key == NULL)
257 
258  //Check the length of the key
259  if(keyLen == 16)
260  {
261  //10 rounds are required for 128-bit key
262  context->nr = 10;
263  }
264  else if(keyLen == 24)
265  {
266  //12 rounds are required for 192-bit key
267  context->nr = 12;
268  }
269  else if(keyLen == 32)
270  {
271  //14 rounds are required for 256-bit key
272  context->nr = 14;
273  }
274  else
275  {
276  //Report an error
278  }
279 
280  //Copy the original key
281  osMemcpy(context->ek, key, keyLen);
282 
283  //No error to report
284  return NO_ERROR;
285 }
286 
287 
288 /**
289  * @brief Encrypt a 16-byte block using AES algorithm
290  * @param[in] context Pointer to the AES context
291  * @param[in] input Plaintext block to encrypt
292  * @param[out] output Ciphertext block resulting from encryption
293  **/
294 
295 void aesEncryptBlock(AesContext *context, const uint8_t *input, uint8_t *output)
296 {
297  //Perform AES encryption
298  aesProcessData(context, NULL, input, output, AES_BLOCK_SIZE,
299  MXC_CTB_MODE_ECB, TRUE);
300 }
301 
302 
303 /**
304  * @brief Decrypt a 16-byte block using AES algorithm
305  * @param[in] context Pointer to the AES context
306  * @param[in] input Ciphertext block to decrypt
307  * @param[out] output Plaintext block resulting from decryption
308  **/
309 
310 void aesDecryptBlock(AesContext *context, const uint8_t *input, uint8_t *output)
311 {
312  //Perform AES decryption
313  aesProcessData(context, NULL, input, output, AES_BLOCK_SIZE,
314  MXC_CTB_MODE_ECB, FALSE);
315 }
316 
317 
318 #if (ECB_SUPPORT == ENABLED)
319 
320 /**
321  * @brief ECB encryption
322  * @param[in] cipher Cipher algorithm
323  * @param[in] context Cipher algorithm context
324  * @param[in] p Plaintext to be encrypted
325  * @param[out] c Ciphertext resulting from the encryption
326  * @param[in] length Total number of data bytes to be encrypted
327  * @return Error code
328  **/
329 
330 error_t ecbEncrypt(const CipherAlgo *cipher, void *context,
331  const uint8_t *p, uint8_t *c, size_t length)
332 {
333  error_t error;
334 
335  //Initialize status code
336  error = NO_ERROR;
337 
338  //AES cipher algorithm?
339  if(cipher == AES_CIPHER_ALGO)
340  {
341  //Check the length of the payload
342  if(length == 0)
343  {
344  //No data to process
345  }
346  else if((length % AES_BLOCK_SIZE) == 0)
347  {
348  //Encrypt payload data
349  aesProcessData(context, NULL, p, c, length, MXC_CTB_MODE_ECB, TRUE);
350  }
351  else
352  {
353  //The length of the payload must be a multiple of the block size
354  error = ERROR_INVALID_LENGTH;
355  }
356  }
357  else
358  {
359  //ECB mode operates in a block-by-block fashion
360  while(length >= cipher->blockSize)
361  {
362  //Encrypt current block
363  cipher->encryptBlock(context, p, c);
364 
365  //Next block
366  p += cipher->blockSize;
367  c += cipher->blockSize;
368  length -= cipher->blockSize;
369  }
370 
371  //The length of the payload must be a multiple of the block size
372  if(length != 0)
373  {
374  error = ERROR_INVALID_LENGTH;
375  }
376  }
377 
378  //Return status code
379  return error;
380 }
381 
382 
383 /**
384  * @brief ECB decryption
385  * @param[in] cipher Cipher algorithm
386  * @param[in] context Cipher algorithm context
387  * @param[in] c Ciphertext to be decrypted
388  * @param[out] p Plaintext resulting from the decryption
389  * @param[in] length Total number of data bytes to be decrypted
390  * @return Error code
391  **/
392 
393 error_t ecbDecrypt(const CipherAlgo *cipher, void *context,
394  const uint8_t *c, uint8_t *p, size_t length)
395 {
396  error_t error;
397 
398  //Initialize status code
399  error = NO_ERROR;
400 
401  //AES cipher algorithm?
402  if(cipher == AES_CIPHER_ALGO)
403  {
404  //Check the length of the payload
405  if(length == 0)
406  {
407  //No data to process
408  }
409  else if((length % AES_BLOCK_SIZE) == 0)
410  {
411  //Decrypt payload data
412  aesProcessData(context, NULL, c, p, length, MXC_CTB_MODE_ECB, FALSE);
413  }
414  else
415  {
416  //The length of the payload must be a multiple of the block size
417  error = ERROR_INVALID_LENGTH;
418  }
419  }
420  else
421  {
422  //ECB mode operates in a block-by-block fashion
423  while(length >= cipher->blockSize)
424  {
425  //Decrypt current block
426  cipher->decryptBlock(context, c, p);
427 
428  //Next block
429  c += cipher->blockSize;
430  p += cipher->blockSize;
431  length -= cipher->blockSize;
432  }
433 
434  //The length of the payload must be a multiple of the block size
435  if(length != 0)
436  {
437  error = ERROR_INVALID_LENGTH;
438  }
439  }
440 
441  //Return status code
442  return error;
443 }
444 
445 #endif
446 #if (CBC_SUPPORT == ENABLED)
447 
448 /**
449  * @brief CBC encryption
450  * @param[in] cipher Cipher algorithm
451  * @param[in] context Cipher algorithm context
452  * @param[in,out] iv Initialization vector
453  * @param[in] p Plaintext to be encrypted
454  * @param[out] c Ciphertext resulting from the encryption
455  * @param[in] length Total number of data bytes to be encrypted
456  * @return Error code
457  **/
458 
459 error_t cbcEncrypt(const CipherAlgo *cipher, void *context,
460  uint8_t *iv, const uint8_t *p, uint8_t *c, size_t length)
461 {
462  error_t error;
463 
464  //Initialize status code
465  error = NO_ERROR;
466 
467  //AES cipher algorithm?
468  if(cipher == AES_CIPHER_ALGO)
469  {
470  //Check the length of the payload
471  if(length == 0)
472  {
473  //No data to process
474  }
475  else if((length % AES_BLOCK_SIZE) == 0)
476  {
477  //Encrypt payload data
478  aesProcessData(context, iv, p, c, length, MXC_CTB_MODE_CBC, TRUE);
479 
480  //Update the value of the initialization vector
482  }
483  else
484  {
485  //The length of the payload must be a multiple of the block size
486  error = ERROR_INVALID_LENGTH;
487  }
488  }
489  else
490  {
491  size_t i;
492 
493  //CBC mode operates in a block-by-block fashion
494  while(length >= cipher->blockSize)
495  {
496  //XOR input block with IV contents
497  for(i = 0; i < cipher->blockSize; i++)
498  {
499  c[i] = p[i] ^ iv[i];
500  }
501 
502  //Encrypt the current block based upon the output of the previous
503  //encryption
504  cipher->encryptBlock(context, c, c);
505 
506  //Update IV with output block contents
507  osMemcpy(iv, c, cipher->blockSize);
508 
509  //Next block
510  p += cipher->blockSize;
511  c += cipher->blockSize;
512  length -= cipher->blockSize;
513  }
514 
515  //The length of the payload must be a multiple of the block size
516  if(length != 0)
517  {
518  error = ERROR_INVALID_LENGTH;
519  }
520  }
521 
522  //Return status code
523  return error;
524 }
525 
526 
527 /**
528  * @brief CBC decryption
529  * @param[in] cipher Cipher algorithm
530  * @param[in] context Cipher algorithm context
531  * @param[in,out] iv Initialization vector
532  * @param[in] c Ciphertext to be decrypted
533  * @param[out] p Plaintext resulting from the decryption
534  * @param[in] length Total number of data bytes to be decrypted
535  * @return Error code
536  **/
537 
538 error_t cbcDecrypt(const CipherAlgo *cipher, void *context,
539  uint8_t *iv, const uint8_t *c, uint8_t *p, size_t length)
540 {
541  error_t error;
542 
543  //Initialize status code
544  error = NO_ERROR;
545 
546  //AES cipher algorithm?
547  if(cipher == AES_CIPHER_ALGO)
548  {
549  //Check the length of the payload
550  if(length == 0)
551  {
552  //No data to process
553  }
554  else if((length % AES_BLOCK_SIZE) == 0)
555  {
556  uint8_t block[AES_BLOCK_SIZE];
557 
558  //Save the last input block
560 
561  //Decrypt payload data
562  aesProcessData(context, iv, c, p, length, MXC_CTB_MODE_CBC, FALSE);
563 
564  //Update the value of the initialization vector
566  }
567  else
568  {
569  //The length of the payload must be a multiple of the block size
570  error = ERROR_INVALID_LENGTH;
571  }
572  }
573  else
574  {
575  size_t i;
576  uint8_t t[16];
577 
578  //CBC mode operates in a block-by-block fashion
579  while(length >= cipher->blockSize)
580  {
581  //Save input block
582  osMemcpy(t, c, cipher->blockSize);
583 
584  //Decrypt the current block
585  cipher->decryptBlock(context, c, p);
586 
587  //XOR output block with IV contents
588  for(i = 0; i < cipher->blockSize; i++)
589  {
590  p[i] ^= iv[i];
591  }
592 
593  //Update IV with input block contents
594  osMemcpy(iv, t, cipher->blockSize);
595 
596  //Next block
597  c += cipher->blockSize;
598  p += 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 #endif
614 #if (CFB_SUPPORT == ENABLED)
615 
616 /**
617  * @brief CFB encryption
618  * @param[in] cipher Cipher algorithm
619  * @param[in] context Cipher algorithm context
620  * @param[in] s Size of the plaintext and ciphertext segments
621  * @param[in,out] iv Initialization vector
622  * @param[in] p Plaintext to be encrypted
623  * @param[out] c Ciphertext resulting from the encryption
624  * @param[in] length Total number of data bytes to be encrypted
625  * @return Error code
626  **/
627 
628 error_t cfbEncrypt(const CipherAlgo *cipher, void *context, uint_t s,
629  uint8_t *iv, const uint8_t *p, uint8_t *c, size_t length)
630 {
631  error_t error;
632 
633  //Initialize status code
634  error = NO_ERROR;
635 
636  //AES cipher algorithm?
637  if(cipher == AES_CIPHER_ALGO)
638  {
639  //Check the value of the parameter
640  if(s == (AES_BLOCK_SIZE * 8))
641  {
642  //Check the length of the payload
643  if(length > 0)
644  {
645  //Encrypt payload data
646  aesProcessData(context, iv, p, c, length, MXC_CTB_MODE_CFB, TRUE);
647  }
648  else
649  {
650  //No data to process
651  }
652  }
653  else
654  {
655  //The value of the parameter is not valid
656  error = ERROR_INVALID_PARAMETER;
657  }
658  }
659  else
660  {
661  //Check the value of the parameter
662  if((s % 8) == 0 && s >= 1 && s <= (cipher->blockSize * 8))
663  {
664  size_t i;
665  size_t n;
666  uint8_t o[16];
667 
668  //Determine the size, in bytes, of the plaintext and ciphertext segments
669  s = s / 8;
670 
671  //Process each plaintext segment
672  while(length > 0)
673  {
674  //Compute the number of bytes to process at a time
675  n = MIN(length, s);
676 
677  //Compute O(j) = CIPH(I(j))
678  cipher->encryptBlock(context, iv, o);
679 
680  //Compute C(j) = P(j) XOR MSB(O(j))
681  for(i = 0; i < n; i++)
682  {
683  c[i] = p[i] ^ o[i];
684  }
685 
686  //Compute I(j+1) = LSB(I(j)) | C(j)
687  osMemmove(iv, iv + s, cipher->blockSize - s);
688  osMemcpy(iv + cipher->blockSize - s, c, s);
689 
690  //Next block
691  p += n;
692  c += n;
693  length -= n;
694  }
695  }
696  else
697  {
698  //The value of the parameter is not valid
699  error = ERROR_INVALID_PARAMETER;
700  }
701  }
702 
703  //Return status code
704  return error;
705 }
706 
707 
708 /**
709  * @brief CFB decryption
710  * @param[in] cipher Cipher algorithm
711  * @param[in] context Cipher algorithm context
712  * @param[in] s Size of the plaintext and ciphertext segments
713  * @param[in,out] iv Initialization vector
714  * @param[in] c Ciphertext to be decrypted
715  * @param[out] p Plaintext resulting from the decryption
716  * @param[in] length Total number of data bytes to be decrypted
717  * @return Error code
718  **/
719 
720 error_t cfbDecrypt(const CipherAlgo *cipher, void *context, uint_t s,
721  uint8_t *iv, const uint8_t *c, uint8_t *p, size_t length)
722 {
723  error_t error;
724 
725  //Initialize status code
726  error = NO_ERROR;
727 
728  //AES cipher algorithm?
729  if(cipher == AES_CIPHER_ALGO)
730  {
731  //Check the value of the parameter
732  if(s == (AES_BLOCK_SIZE * 8))
733  {
734  //Check the length of the payload
735  if(length > 0)
736  {
737  //Decrypt payload data
738  aesProcessData(context, iv, c, p, length, MXC_CTB_MODE_CFB, FALSE);
739  }
740  else
741  {
742  //No data to process
743  }
744  }
745  else
746  {
747  //The value of the parameter is not valid
748  error = ERROR_INVALID_PARAMETER;
749  }
750  }
751  else
752  {
753  //Check the value of the parameter
754  if((s % 8) == 0 && s >= 1 && s <= (cipher->blockSize * 8))
755  {
756  size_t i;
757  size_t n;
758  uint8_t o[16];
759 
760  //Determine the size, in bytes, of the plaintext and ciphertext segments
761  s = s / 8;
762 
763  //Process each ciphertext segment
764  while(length > 0)
765  {
766  //Compute the number of bytes to process at a time
767  n = MIN(length, s);
768 
769  //Compute O(j) = CIPH(I(j))
770  cipher->encryptBlock(context, iv, o);
771 
772  //Compute I(j+1) = LSB(I(j)) | C(j)
773  osMemmove(iv, iv + s, cipher->blockSize - s);
774  osMemcpy(iv + cipher->blockSize - s, c, s);
775 
776  //Compute P(j) = C(j) XOR MSB(O(j))
777  for(i = 0; i < n; i++)
778  {
779  p[i] = c[i] ^ o[i];
780  }
781 
782  //Next block
783  c += n;
784  p += n;
785  length -= n;
786  }
787  }
788  else
789  {
790  //The value of the parameter is not valid
791  error = ERROR_INVALID_PARAMETER;
792  }
793  }
794 
795  //Return status code
796  return error;
797 }
798 
799 #endif
800 #if (OFB_SUPPORT == ENABLED)
801 
802 /**
803  * @brief OFB encryption
804  * @param[in] cipher Cipher algorithm
805  * @param[in] context Cipher algorithm context
806  * @param[in] s Size of the plaintext and ciphertext segments
807  * @param[in,out] iv Initialization vector
808  * @param[in] p Plaintext to be encrypted
809  * @param[out] c Ciphertext resulting from the encryption
810  * @param[in] length Total number of data bytes to be encrypted
811  * @return Error code
812  **/
813 
814 error_t ofbEncrypt(const CipherAlgo *cipher, void *context, uint_t s,
815  uint8_t *iv, const uint8_t *p, uint8_t *c, size_t length)
816 {
817  error_t error;
818 
819  //Initialize status code
820  error = NO_ERROR;
821 
822  //AES cipher algorithm?
823  if(cipher == AES_CIPHER_ALGO)
824  {
825  //Check the value of the parameter
826  if(s == (AES_BLOCK_SIZE * 8))
827  {
828  //Check the length of the payload
829  if(length > 0)
830  {
831  //Encrypt payload data
832  aesProcessData(context, iv, p, c, length, MXC_CTB_MODE_OFB, TRUE);
833  }
834  else
835  {
836  //No data to process
837  }
838  }
839  else
840  {
841  //The value of the parameter is not valid
842  error = ERROR_INVALID_PARAMETER;
843  }
844  }
845  else
846  {
847  //Check the value of the parameter
848  if((s % 8) == 0 && s >= 1 && s <= (cipher->blockSize * 8))
849  {
850  size_t i;
851  size_t n;
852  uint8_t o[16];
853 
854  //Determine the size, in bytes, of the plaintext and ciphertext segments
855  s = s / 8;
856 
857  //Process each plaintext segment
858  while(length > 0)
859  {
860  //Compute the number of bytes to process at a time
861  n = MIN(length, s);
862 
863  //Compute O(j) = CIPH(I(j))
864  cipher->encryptBlock(context, iv, o);
865 
866  //Compute C(j) = P(j) XOR MSB(O(j))
867  for(i = 0; i < n; i++)
868  {
869  c[i] = p[i] ^ o[i];
870  }
871 
872  //Compute I(j+1) = LSB(I(j)) | O(j)
873  osMemmove(iv, iv + s, cipher->blockSize - s);
874  osMemcpy(iv + cipher->blockSize - s, o, s);
875 
876  //Next block
877  p += n;
878  c += n;
879  length -= n;
880  }
881  }
882  else
883  {
884  //The value of the parameter is not valid
885  error = ERROR_INVALID_PARAMETER;
886  }
887  }
888 
889  //Return status code
890  return error;
891 }
892 
893 #endif
894 #if (CTR_SUPPORT == ENABLED)
895 
896 /**
897  * @brief CTR encryption
898  * @param[in] cipher Cipher algorithm
899  * @param[in] context Cipher algorithm context
900  * @param[in] m Size in bits of the specific part of the block to be incremented
901  * @param[in,out] t Initial counter block
902  * @param[in] p Plaintext to be encrypted
903  * @param[out] c Ciphertext resulting from the encryption
904  * @param[in] length Total number of data bytes to be encrypted
905  * @return Error code
906  **/
907 
908 error_t ctrEncrypt(const CipherAlgo *cipher, void *context, uint_t m,
909  uint8_t *t, const uint8_t *p, uint8_t *c, size_t length)
910 {
911  error_t error;
912 
913  //Initialize status code
914  error = NO_ERROR;
915 
916  //Check the value of the parameter
917  if((m % 8) == 0 && m <= (cipher->blockSize * 8))
918  {
919  //Determine the size, in bytes, of the specific part of the block to be
920  //incremented
921  m = m / 8;
922 
923  //AES cipher algorithm?
924  if(cipher == AES_CIPHER_ALGO)
925  {
926  size_t k;
927  size_t n;
928 
929  //Process plaintext
930  while(length > 0)
931  {
932  //Limit the number of blocks to process at a time
933  k = 256 - t[AES_BLOCK_SIZE - 1];
934  n = MIN(length, k * AES_BLOCK_SIZE);
935  k = (n + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE;
936 
937  //Encrypt payload data
938  aesProcessData(context, t, p, c, n, MXC_CTB_MODE_CTR, TRUE);
939 
940  //Standard incrementing function
942 
943  //Next block
944  p += n;
945  c += n;
946  length -= n;
947  }
948  }
949  else
950  {
951  size_t i;
952  size_t n;
953  uint8_t o[16];
954 
955  //Process plaintext
956  while(length > 0)
957  {
958  //CTR mode operates in a block-by-block fashion
959  n = MIN(length, cipher->blockSize);
960 
961  //Compute O(j) = CIPH(T(j))
962  cipher->encryptBlock(context, t, o);
963 
964  //Compute C(j) = P(j) XOR T(j)
965  for(i = 0; i < n; i++)
966  {
967  c[i] = p[i] ^ o[i];
968  }
969 
970  //Standard incrementing function
971  ctrIncBlock(t, 1, cipher->blockSize, m);
972 
973  //Next block
974  p += n;
975  c += n;
976  length -= n;
977  }
978  }
979  }
980  else
981  {
982  //The value of the parameter is not valid
983  error = ERROR_INVALID_PARAMETER;
984  }
985 
986  //Return status code
987  return error;
988 }
989 
990 #endif
991 #if (GCM_SUPPORT == ENABLED)
992 
993 /**
994  * @brief Authenticated encryption using GCM
995  * @param[in] context Pointer to the GCM context
996  * @param[in] iv Initialization vector
997  * @param[in] ivLen Length of the initialization vector
998  * @param[in] a Additional authenticated data
999  * @param[in] aLen Length of the additional data
1000  * @param[in] p Plaintext to be encrypted
1001  * @param[out] c Ciphertext resulting from the encryption
1002  * @param[in] length Total number of data bytes to be encrypted
1003  * @param[out] t Authentication tag
1004  * @param[in] tLen Length of the authentication tag
1005  * @return Error code
1006  **/
1007 
1008 error_t gcmEncrypt(GcmContext *context, const uint8_t *iv, size_t ivLen,
1009  const uint8_t *a, size_t aLen, const uint8_t *p, uint8_t *c, size_t length,
1010  uint8_t *t, size_t tLen)
1011 {
1012  size_t i;
1013  size_t n;
1014  uint8_t b[16];
1015  uint8_t j[16];
1016  uint8_t s[16];
1017 
1018  //Make sure the GCM context is valid
1019  if(context == NULL)
1020  return ERROR_INVALID_PARAMETER;
1021 
1022  //The length of the IV shall meet SP 800-38D requirements
1023  if(ivLen < 1)
1024  return ERROR_INVALID_LENGTH;
1025 
1026  //Check the length of the authentication tag
1027  if(tLen < 4 || tLen > 16)
1028  return ERROR_INVALID_LENGTH;
1029 
1030  //Check whether the length of the IV is 96 bits
1031  if(ivLen == 12)
1032  {
1033  //When the length of the IV is 96 bits, the padding string is appended
1034  //to the IV to form the pre-counter block
1035  osMemcpy(j, iv, 12);
1036  STORE32BE(1, j + 12);
1037  }
1038  else
1039  {
1040  //Initialize GHASH calculation
1041  osMemset(j, 0, 16);
1042 
1043  //Process the initialization vector
1044  for(i = 0; i < ivLen; i += n)
1045  {
1046  //The IV is processed in a block-by-block fashion
1047  n = MIN(ivLen - i, 16);
1048 
1049  //Apply GHASH function
1050  gcmXorBlock(j, j, iv + i, n);
1051  gcmMul(context, j);
1052  }
1053 
1054  //The string is appended with 64 additional 0 bits, followed by the
1055  //64-bit representation of the length of the IV
1056  osMemset(b, 0, 8);
1057  STORE64BE(ivLen * 8, b + 8);
1058 
1059  //The GHASH function is applied to the resulting string to form the
1060  //pre-counter block
1061  gcmXorBlock(j, j, b, 16);
1062  gcmMul(context, j);
1063  }
1064 
1065  //Compute MSB(CIPH(J(0)))
1066  context->cipherAlgo->encryptBlock(context->cipherContext, j, b);
1067  osMemcpy(t, b, tLen);
1068 
1069  //Initialize GHASH calculation
1070  osMemset(s, 0, 16);
1071 
1072  //Process AAD
1073  for(i = 0; i < aLen; i += n)
1074  {
1075  //Additional data are processed in a block-by-block fashion
1076  n = MIN(aLen - i, 16);
1077 
1078  //Apply GHASH function
1079  gcmXorBlock(s, s, a + i, n);
1080  gcmMul(context, s);
1081  }
1082 
1083  //Increment counter
1084  gcmIncCounter(j);
1085 
1086  //AES cipher algorithm?
1087  if(context->cipherAlgo == AES_CIPHER_ALGO)
1088  {
1089  //Encrypt plaintext
1090  aesProcessData(context->cipherContext, j, p, c, length, MXC_CTB_MODE_CTR,
1091  TRUE);
1092  }
1093  else
1094  {
1095  //Encrypt plaintext
1096  for(i = 0; i < length; i += n)
1097  {
1098  //The encryption operates in a block-by-block fashion
1099  n = MIN(length - i, 16);
1100 
1101  //Encrypt current block
1102  context->cipherAlgo->encryptBlock(context->cipherContext, j, b);
1103  gcmXorBlock(c + i, p + i, b, n);
1104 
1105  //Increment counter
1106  gcmIncCounter(j);
1107  }
1108  }
1109 
1110  //Process ciphertext
1111  for(i = 0; i < length; i += n)
1112  {
1113  //The encryption operates in a block-by-block fashion
1114  n = MIN(length - i, 16);
1115 
1116  //Apply GHASH function
1117  gcmXorBlock(s, s, c + i, n);
1118  gcmMul(context, s);
1119  }
1120 
1121  //Append the 64-bit representation of the length of the AAD and the
1122  //ciphertext
1123  STORE64BE(aLen * 8, b);
1124  STORE64BE(length * 8, b + 8);
1125 
1126  //The GHASH function is applied to the result to produce a single output
1127  //block S
1128  gcmXorBlock(s, s, b, 16);
1129  gcmMul(context, s);
1130 
1131  //Let T = MSB(GCTR(J(0), S)
1132  gcmXorBlock(t, t, s, tLen);
1133 
1134  //Successful encryption
1135  return NO_ERROR;
1136 }
1137 
1138 
1139 /**
1140  * @brief Authenticated decryption using GCM
1141  * @param[in] context Pointer to the GCM context
1142  * @param[in] iv Initialization vector
1143  * @param[in] ivLen Length of the initialization vector
1144  * @param[in] a Additional authenticated data
1145  * @param[in] aLen Length of the additional data
1146  * @param[in] c Ciphertext to be decrypted
1147  * @param[out] p Plaintext resulting from the decryption
1148  * @param[in] length Total number of data bytes to be decrypted
1149  * @param[in] t Authentication tag
1150  * @param[in] tLen Length of the authentication tag
1151  * @return Error code
1152  **/
1153 
1154 error_t gcmDecrypt(GcmContext *context, const uint8_t *iv, size_t ivLen,
1155  const uint8_t *a, size_t aLen, const uint8_t *c, uint8_t *p, size_t length,
1156  const uint8_t *t, size_t tLen)
1157 {
1158  uint8_t mask;
1159  size_t i;
1160  size_t n;
1161  uint8_t b[16];
1162  uint8_t j[16];
1163  uint8_t r[16];
1164  uint8_t s[16];
1165 
1166  //Make sure the GCM context is valid
1167  if(context == NULL)
1168  return ERROR_INVALID_PARAMETER;
1169 
1170  //The length of the IV shall meet SP 800-38D requirements
1171  if(ivLen < 1)
1172  return ERROR_INVALID_LENGTH;
1173 
1174  //Check the length of the authentication tag
1175  if(tLen < 4 || tLen > 16)
1176  return ERROR_INVALID_LENGTH;
1177 
1178  //Check whether the length of the IV is 96 bits
1179  if(ivLen == 12)
1180  {
1181  //When the length of the IV is 96 bits, the padding string is appended
1182  //to the IV to form the pre-counter block
1183  osMemcpy(j, iv, 12);
1184  STORE32BE(1, j + 12);
1185  }
1186  else
1187  {
1188  //Initialize GHASH calculation
1189  osMemset(j, 0, 16);
1190 
1191  //Process the initialization vector
1192  for(i = 0; i < ivLen; i += n)
1193  {
1194  //The IV is processed in a block-by-block fashion
1195  n = MIN(ivLen - i, 16);
1196 
1197  //Apply GHASH function
1198  gcmXorBlock(j, j, iv + i, n);
1199  gcmMul(context, j);
1200  }
1201 
1202  //The string is appended with 64 additional 0 bits, followed by the
1203  //64-bit representation of the length of the IV
1204  osMemset(b, 0, 8);
1205  STORE64BE(ivLen * 8, b + 8);
1206 
1207  //The GHASH function is applied to the resulting string to form the
1208  //pre-counter block
1209  gcmXorBlock(j, j, b, 16);
1210  gcmMul(context, j);
1211  }
1212 
1213  //Compute MSB(CIPH(J(0)))
1214  context->cipherAlgo->encryptBlock(context->cipherContext, j, b);
1215  osMemcpy(r, b, tLen);
1216 
1217  //Initialize GHASH calculation
1218  osMemset(s, 0, 16);
1219 
1220  //Process AAD
1221  for(i = 0; i < aLen; i += n)
1222  {
1223  //Additional data are processed in a block-by-block fashion
1224  n = MIN(aLen - i, 16);
1225 
1226  //Apply GHASH function
1227  gcmXorBlock(s, s, a + i, n);
1228  gcmMul(context, s);
1229  }
1230 
1231  //Process ciphertext
1232  for(i = 0; i < length; i += n)
1233  {
1234  //The decryption operates in a block-by-block fashion
1235  n = MIN(length - i, 16);
1236 
1237  //Apply GHASH function
1238  gcmXorBlock(s, s, c + i, n);
1239  gcmMul(context, s);
1240  }
1241 
1242  //Increment counter
1243  gcmIncCounter(j);
1244 
1245  //AES cipher algorithm?
1246  if(context->cipherAlgo == AES_CIPHER_ALGO)
1247  {
1248  //Decrypt ciphertext
1249  aesProcessData(context->cipherContext, j, c, p, length, MXC_CTB_MODE_CTR,
1250  TRUE);
1251  }
1252  else
1253  {
1254  //Decrypt ciphertext
1255  for(i = 0; i < length; i += n)
1256  {
1257  //The decryption operates in a block-by-block fashion
1258  n = MIN(length - i, 16);
1259 
1260  //Decrypt current block
1261  context->cipherAlgo->encryptBlock(context->cipherContext, j, b);
1262  gcmXorBlock(p + i, c + i, b, n);
1263 
1264  //Increment counter
1265  gcmIncCounter(j);
1266  }
1267  }
1268 
1269  //Append the 64-bit representation of the length of the AAD and the
1270  //ciphertext
1271  STORE64BE(aLen * 8, b);
1272  STORE64BE(length * 8, b + 8);
1273 
1274  //The GHASH function is applied to the result to produce a single output
1275  //block S
1276  gcmXorBlock(s, s, b, 16);
1277  gcmMul(context, s);
1278 
1279  //Let R = MSB(GCTR(J(0), S))
1280  gcmXorBlock(r, r, s, tLen);
1281 
1282  //The calculated tag is bitwise compared to the received tag. The message
1283  //is authenticated if and only if the tags match
1284  for(mask = 0, n = 0; n < tLen; n++)
1285  {
1286  mask |= r[n] ^ t[n];
1287  }
1288 
1289  //Return status code
1290  return (mask == 0) ? NO_ERROR : ERROR_FAILURE;
1291 }
1292 
1293 #endif
1294 #endif
uint16_t block
Definition: tftp_common.h:115
int bool_t
Definition: compiler_port.h:53
uint8_t b
Definition: nbns_common.h:104
MAX32690 hardware cryptographic accelerator.
uint8_t a
Definition: ndp.h:411
CipherAlgoDecryptBlock decryptBlock
Definition: crypto.h:1077
uint8_t p
Definition: ndp.h:300
uint8_t t
Definition: lldp_ext_med.h:212
uint8_t o
#define TRUE
Definition: os_port.h:50
Collection of AEAD algorithms.
void aesLoadKey(AesContext *context)
Load AES key.
size_t blockSize
Definition: crypto.h:1072
void gcmIncCounter(uint8_t *ctr)
Increment counter block.
Definition: gcm.c:614
MAX32690 cipher hardware accelerator.
CipherAlgoEncryptBlock encryptBlock
Definition: crypto.h:1076
uint8_t r
Definition: ndp.h:346
AES algorithm context.
Definition: aes.h:58
#define AES_BLOCK_SIZE
Definition: aes.h:43
#define FALSE
Definition: os_port.h:46
error_t aesInit(AesContext *context, const uint8_t *key, size_t keyLen)
Key expansion.
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:141
__weak_func void gcmMul(GcmContext *context, uint8_t *x)
Multiplication operation in GF(2^128)
Definition: gcm.c:508
error_t
Error codes.
Definition: error.h:43
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.
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
error_t cbcDecrypt(const CipherAlgo *cipher, void *context, uint8_t *iv, const uint8_t *c, uint8_t *p, size_t length)
CBC decryption.
@ ERROR_INVALID_KEY_LENGTH
Definition: error.h:107
error_t ecbEncrypt(const CipherAlgo *cipher, void *context, const uint8_t *p, uint8_t *c, size_t length)
ECB encryption.
@ ERROR_INVALID_LENGTH
Definition: error.h:111
General definitions for cryptographic algorithms.
error_t cfbDecrypt(const CipherAlgo *cipher, void *context, uint_t s, uint8_t *iv, const uint8_t *c, uint8_t *p, size_t length)
CFB decryption.
error_t ctrEncrypt(const CipherAlgo *cipher, void *context, uint_t m, uint8_t *t, const uint8_t *p, uint8_t *c, size_t length)
CTR encryption.
uint8_t mask
Definition: web_socket.h:319
uint8_t iv[]
Definition: ike.h:1502
Block cipher modes of operation.
const CipherAlgo * cipherAlgo
Cipher algorithm.
Definition: gcm.h:65
uint8_t length
Definition: tcp.h:368
#define MIN(a, b)
Definition: os_port.h:63
uint_t nr
Definition: aes.h:59
GCM context.
Definition: gcm.h:64
#define STORE64BE(a, p)
Definition: cpu_endian.h:322
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.
uint8_t m
Definition: ndp.h:304
uint8_t n
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
void aesEncryptBlock(AesContext *context, const uint8_t *input, uint8_t *output)
Encrypt a 16-byte block using AES algorithm.
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:597
Common interface for encryption algorithms.
Definition: crypto.h:1068
void aesDecryptBlock(AesContext *context, const uint8_t *input, uint8_t *output)
Decrypt a 16-byte block using AES 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 AES_CIPHER_ALGO
Definition: aes.h:45
uint8_t s
Definition: igmp_common.h:234
OsMutex max32690CryptoMutex
uint32_t ek[60]
Definition: aes.h:60
unsigned int uint_t
Definition: compiler_port.h:50
#define osMemset(p, value, length)
Definition: os_port.h:135
error_t ecbDecrypt(const CipherAlgo *cipher, void *context, const uint8_t *c, uint8_t *p, size_t length)
ECB decryption.
void * cipherContext
Cipher algorithm context.
Definition: gcm.h:66
void aesProcessData(AesContext *context, uint8_t *iv, const uint8_t *input, uint8_t *output, size_t length, uint32_t mode, bool_t encrypt)
Perform AES encryption or decryption.
#define STORE32BE(a, p)
Definition: cpu_endian.h:286
void ctrIncBlock(uint8_t *ctr, uint32_t inc, size_t blockSize, size_t m)
Increment counter block.
Definition: ctr.c:138
@ NO_ERROR
Success.
Definition: error.h:44
uint8_t c
Definition: ndp.h:514
Debugging facilities.
#define osMemmove(dest, src, length)
Definition: os_port.h:147
error_t 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.