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