mimxrt1040_crypto_cipher.c
Go to the documentation of this file.
1 /**
2  * @file mimxrt1040_crypto_cipher.c
3  * @brief i.MX RT1040 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 "fsl_device_registers.h"
36 #include "fsl_dcp.h"
37 #include "core/crypto.h"
42 #include "debug.h"
43 
44 //Check crypto library configuration
45 #if (MIMXRT1040_CRYPTO_CIPHER_SUPPORT == ENABLED && AES_SUPPORT == ENABLED)
46 
47 //IAR EWARM compiler?
48 #if defined(__ICCARM__)
49 
50 //DCP input buffer
51 #pragma data_alignment = 16
52 #pragma location = MIMXRT1040_DCP_RAM_SECTION
53 static uint8_t dcpBufferIn[MIMXRT1040_DCP_BUFFER_SIZE];
54 
55 //DCP output buffer
56 #pragma data_alignment = 16
57 #pragma location = MIMXRT1040_DCP_RAM_SECTION
58 static uint8_t dcpBufferOut[MIMXRT1040_DCP_BUFFER_SIZE];
59 
60 //ARM or GCC compiler?
61 #else
62 
63 //DCP input buffer
64 static uint8_t dcpBufferIn[MIMXRT1040_DCP_BUFFER_SIZE]
65  __attribute__((aligned(16), __section__(MIMXRT1040_DCP_RAM_SECTION)));
66 
67 //DCP output buffer
68 static uint8_t dcpBufferOut[MIMXRT1040_DCP_BUFFER_SIZE]
69  __attribute__((aligned(16), __section__(MIMXRT1040_DCP_RAM_SECTION)));
70 
71 #endif
72 
73 #if (ECB_SUPPORT == ENABLED)
74 
75 /**
76  * @brief ECB encryption
77  * @param[in] cipher Cipher algorithm
78  * @param[in] context Cipher algorithm context
79  * @param[in] p Plaintext to be encrypted
80  * @param[out] c Ciphertext resulting from the encryption
81  * @param[in] length Total number of data bytes to be encrypted
82  * @return Error code
83  **/
84 
85 error_t ecbEncrypt(const CipherAlgo *cipher, void *context,
86  const uint8_t *p, uint8_t *c, size_t length)
87 {
88  status_t status;
89 
90  //Initialize status code
91  status = kStatus_Success;
92 
93  //AES cipher algorithm?
94  if(cipher == AES_CIPHER_ALGO)
95  {
96  //Check the length of the payload
97  if(length == 0)
98  {
99  //No data to process
100  }
101  else if((length % AES_BLOCK_SIZE) == 0)
102  {
103  size_t i;
104  size_t n;
105  AesContext *aesContext;
106  dcp_handle_t dcpHandle;
107 
108  //Point to the AES context
109  aesContext = (AesContext *) context;
110 
111  //Check the length of the key
112  if(aesContext->nr == 10)
113  {
114  //Set DCP parameters
115  dcpHandle.channel = kDCP_Channel0;
116  dcpHandle.keySlot = kDCP_KeySlot0;
117  dcpHandle.swapConfig = kDCP_NoSwap;
118 
119  //Acquire exclusive access to the DCP module
121 
122  //Set the 128-bit key
123  status = DCP_AES_SetKey(DCP, &dcpHandle,
124  (const uint8_t *) aesContext->ek, 16);
125 
126  //Perform AES-ECB encryption
127  for(i = 0; i < length && status == kStatus_Success; i += n)
128  {
129  //Limit the number of data to process at a time
131  //Copy the plaintext to the buffer
132  osMemcpy(dcpBufferIn, p + i, n);
133 
134  //Encrypt data
135  status = DCP_AES_EncryptEcb(DCP, &dcpHandle, dcpBufferIn,
136  dcpBufferOut, n);
137 
138  //Check status code
139  if(status == kStatus_Success)
140  {
141  //Copy the resulting ciphertext
142  osMemcpy(c + i, dcpBufferOut, n);
143  }
144  }
145 
146  //Release exclusive access to the DCP module
148  }
149  else
150  {
151  //192 and 256-bit keys are not supported
152  status = kStatus_Fail;
153  }
154  }
155  else
156  {
157  //The length of the payload must be a multiple of the block size
158  status = kStatus_InvalidArgument;
159  }
160  }
161  else
162  {
163  //ECB mode operates in a block-by-block fashion
164  while(length >= cipher->blockSize)
165  {
166  //Encrypt current block
167  cipher->encryptBlock(context, p, c);
168 
169  //Next block
170  p += cipher->blockSize;
171  c += cipher->blockSize;
172  length -= cipher->blockSize;
173  }
174 
175  //The length of the payload must be a multiple of the block size
176  if(length != 0)
177  {
178  status = kStatus_InvalidArgument;
179  }
180  }
181 
182  //Return status code
183  return (status == kStatus_Success) ? NO_ERROR : ERROR_FAILURE;
184 }
185 
186 
187 /**
188  * @brief ECB decryption
189  * @param[in] cipher Cipher algorithm
190  * @param[in] context Cipher algorithm context
191  * @param[in] c Ciphertext to be decrypted
192  * @param[out] p Plaintext resulting from the decryption
193  * @param[in] length Total number of data bytes to be decrypted
194  * @return Error code
195  **/
196 
197 error_t ecbDecrypt(const CipherAlgo *cipher, void *context,
198  const uint8_t *c, uint8_t *p, size_t length)
199 {
200  status_t status;
201 
202  //Initialize status code
203  status = kStatus_Success;
204 
205  //AES cipher algorithm?
206  if(cipher == AES_CIPHER_ALGO)
207  {
208  //Check the length of the payload
209  if(length == 0)
210  {
211  //No data to process
212  }
213  else if((length % AES_BLOCK_SIZE) == 0)
214  {
215  size_t i;
216  size_t n;
217  AesContext *aesContext;
218  dcp_handle_t dcpHandle;
219 
220  //Point to the AES context
221  aesContext = (AesContext *) context;
222 
223  //Check the length of the key
224  if(aesContext->nr == 10)
225  {
226  //Set DCP parameters
227  dcpHandle.channel = kDCP_Channel0;
228  dcpHandle.keySlot = kDCP_KeySlot0;
229  dcpHandle.swapConfig = kDCP_NoSwap;
230 
231  //Acquire exclusive access to the DCP module
233 
234  //Set the 128-bit key
235  status = DCP_AES_SetKey(DCP, &dcpHandle,
236  (const uint8_t *) aesContext->ek, 16);
237 
238  //Perform AES-ECB decryption
239  for(i = 0; i < length && status == kStatus_Success; i += n)
240  {
241  //Limit the number of data to process at a time
243  //Copy the ciphertext to the buffer
244  osMemcpy(dcpBufferIn, c + i, n);
245 
246  //Decrypt data
247  status = DCP_AES_DecryptEcb(DCP, &dcpHandle, dcpBufferIn,
248  dcpBufferOut, n);
249 
250  //Check status code
251  if(status == kStatus_Success)
252  {
253  //Copy the resulting plaintext
254  osMemcpy(p + i, dcpBufferOut, n);
255  }
256  }
257  }
258  else
259  {
260  //192 and 256-bit keys are not supported
261  status = kStatus_Fail;
262  }
263 
264  //Release exclusive access to the DCP module
266  }
267  else
268  {
269  //The length of the payload must be a multiple of the block size
270  status = kStatus_InvalidArgument;
271  }
272  }
273  else
274  {
275  //ECB mode operates in a block-by-block fashion
276  while(length >= cipher->blockSize)
277  {
278  //Decrypt current block
279  cipher->decryptBlock(context, c, p);
280 
281  //Next block
282  c += cipher->blockSize;
283  p += cipher->blockSize;
284  length -= cipher->blockSize;
285  }
286 
287  //The length of the payload must be a multiple of the block size
288  if(length != 0)
289  {
290  status = kStatus_InvalidArgument;
291  }
292  }
293 
294  //Return status code
295  return (status == kStatus_Success) ? NO_ERROR : ERROR_FAILURE;
296 }
297 
298 #endif
299 #if (CBC_SUPPORT == ENABLED)
300 
301 /**
302  * @brief CBC encryption
303  * @param[in] cipher Cipher algorithm
304  * @param[in] context Cipher algorithm context
305  * @param[in,out] iv Initialization vector
306  * @param[in] p Plaintext to be encrypted
307  * @param[out] c Ciphertext resulting from the encryption
308  * @param[in] length Total number of data bytes to be encrypted
309  * @return Error code
310  **/
311 
312 error_t cbcEncrypt(const CipherAlgo *cipher, void *context,
313  uint8_t *iv, const uint8_t *p, uint8_t *c, size_t length)
314 {
315  status_t status;
316 
317  //Initialize status code
318  status = kStatus_Success;
319 
320  //AES cipher algorithm?
321  if(cipher == AES_CIPHER_ALGO)
322  {
323  //Check the length of the payload
324  if(length == 0)
325  {
326  //No data to process
327  }
328  else if((length % AES_BLOCK_SIZE) == 0)
329  {
330  size_t i;
331  size_t n;
332  AesContext *aesContext;
333  dcp_handle_t dcpHandle;
334 
335  //Point to the AES context
336  aesContext = (AesContext *) context;
337 
338  //Check the length of the key
339  if(aesContext->nr == 10)
340  {
341  //Set DCP parameters
342  dcpHandle.channel = kDCP_Channel0;
343  dcpHandle.keySlot = kDCP_KeySlot0;
344  dcpHandle.swapConfig = kDCP_NoSwap;
345 
346  //Acquire exclusive access to the DCP module
348 
349  //Set the 128-bit key
350  status = DCP_AES_SetKey(DCP, &dcpHandle,
351  (const uint8_t *) aesContext->ek, 16);
352 
353  //Perform AES-CBC encryption
354  for(i = 0; i < length && status == kStatus_Success; i += n)
355  {
356  //Limit the number of data to process at a time
358  //Copy the plaintext to the buffer
359  osMemcpy(dcpBufferIn, p + i, n);
360 
361  //Encrypt data
362  status = DCP_AES_EncryptCbc(DCP, &dcpHandle, dcpBufferIn,
363  dcpBufferOut, n, iv);
364 
365  //Check status code
366  if(status == kStatus_Success)
367  {
368  //Copy the resulting ciphertext
369  osMemcpy(c + i, dcpBufferOut, n);
370  //Update the value of the initialization vector
371  osMemcpy(iv, dcpBufferOut + n - AES_BLOCK_SIZE, AES_BLOCK_SIZE);
372  }
373  }
374  }
375  else
376  {
377  //192 and 256-bit keys are not supported
378  status = kStatus_Fail;
379  }
380 
381  //Release exclusive access to the DCP module
383  }
384  else
385  {
386  //The length of the payload must be a multiple of the block size
387  status = kStatus_InvalidArgument;
388  }
389  }
390  else
391  {
392  size_t i;
393 
394  //CBC mode operates in a block-by-block fashion
395  while(length >= cipher->blockSize)
396  {
397  //XOR input block with IV contents
398  for(i = 0; i < cipher->blockSize; i++)
399  {
400  c[i] = p[i] ^ iv[i];
401  }
402 
403  //Encrypt the current block based upon the output of the previous
404  //encryption
405  cipher->encryptBlock(context, c, c);
406 
407  //Update IV with output block contents
408  osMemcpy(iv, c, cipher->blockSize);
409 
410  //Next block
411  p += cipher->blockSize;
412  c += cipher->blockSize;
413  length -= cipher->blockSize;
414  }
415 
416  //The length of the payload must be a multiple of the block size
417  if(length != 0)
418  {
419  status = kStatus_InvalidArgument;
420  }
421  }
422 
423  //Return status code
424  return (status == kStatus_Success) ? NO_ERROR : ERROR_FAILURE;
425 }
426 
427 
428 /**
429  * @brief CBC decryption
430  * @param[in] cipher Cipher algorithm
431  * @param[in] context Cipher algorithm context
432  * @param[in,out] iv Initialization vector
433  * @param[in] c Ciphertext to be decrypted
434  * @param[out] p Plaintext resulting from the decryption
435  * @param[in] length Total number of data bytes to be decrypted
436  * @return Error code
437  **/
438 
439 error_t cbcDecrypt(const CipherAlgo *cipher, void *context,
440  uint8_t *iv, const uint8_t *c, uint8_t *p, size_t length)
441 {
442  status_t status;
443 
444  //Initialize status code
445  status = kStatus_Success;
446 
447  //AES cipher algorithm?
448  if(cipher == AES_CIPHER_ALGO)
449  {
450  //Check the length of the payload
451  if(length == 0)
452  {
453  //No data to process
454  }
455  else if((length % AES_BLOCK_SIZE) == 0)
456  {
457  size_t i;
458  size_t n;
459  AesContext *aesContext;
460  dcp_handle_t dcpHandle;
461  uint8_t block[AES_BLOCK_SIZE];
462 
463  //Point to the AES context
464  aesContext = (AesContext *) context;
465 
466  //Check the length of the key
467  if(aesContext->nr == 10)
468  {
469  //Set DCP parameters
470  dcpHandle.channel = kDCP_Channel0;
471  dcpHandle.keySlot = kDCP_KeySlot0;
472  dcpHandle.swapConfig = kDCP_NoSwap;
473 
474  //Acquire exclusive access to the DCP module
476 
477  //Set the 128-bit key
478  status = DCP_AES_SetKey(DCP, &dcpHandle,
479  (const uint8_t *) aesContext->ek, 16);
480 
481  //Perform AES-CBC decryption
482  for(i = 0; i < length && status == kStatus_Success; i += n)
483  {
484  //Limit the number of data to process at a time
486  //Copy the ciphertext to the buffer
487  osMemcpy(dcpBufferIn, c + i, n);
488  //Save the last input block
489  osMemcpy(block, dcpBufferIn + n - AES_BLOCK_SIZE, AES_BLOCK_SIZE);
490 
491  //Decrypt data
492  status = DCP_AES_DecryptCbc(DCP, &dcpHandle, dcpBufferIn,
493  dcpBufferOut, n, iv);
494 
495  //Check status code
496  if(status == kStatus_Success)
497  {
498  //Copy the resulting plaintext
499  osMemcpy(p + i, dcpBufferOut, n);
500  //Update the value of the initialization vector
502  }
503  }
504  }
505  else
506  {
507  //192 and 256-bit keys are not supported
508  status = kStatus_Fail;
509  }
510 
511  //Release exclusive access to the DCP module
513  }
514  else
515  {
516  //The length of the payload must be a multiple of the block size
517  status = kStatus_InvalidArgument;
518  }
519  }
520  else
521  {
522  size_t i;
523  uint8_t t[16];
524 
525  //CBC mode operates in a block-by-block fashion
526  while(length >= cipher->blockSize)
527  {
528  //Save input block
529  osMemcpy(t, c, cipher->blockSize);
530 
531  //Decrypt the current block
532  cipher->decryptBlock(context, c, p);
533 
534  //XOR output block with IV contents
535  for(i = 0; i < cipher->blockSize; i++)
536  {
537  p[i] ^= iv[i];
538  }
539 
540  //Update IV with input block contents
541  osMemcpy(iv, t, cipher->blockSize);
542 
543  //Next block
544  c += cipher->blockSize;
545  p += cipher->blockSize;
546  length -= cipher->blockSize;
547  }
548 
549  //The length of the payload must be a multiple of the block size
550  if(length != 0)
551  {
552  status = kStatus_InvalidArgument;
553  }
554  }
555 
556  //Return status code
557  return (status == kStatus_Success) ? NO_ERROR : ERROR_FAILURE;
558 }
559 
560 #endif
561 #endif
uint16_t block
Definition: tftp_common.h:115
#define MIMXRT1040_DCP_RAM_SECTION
CipherAlgoDecryptBlock decryptBlock
Definition: crypto.h:1077
OsMutex mimxrt1040CryptoMutex
uint8_t p
Definition: ndp.h:300
uint8_t t
Definition: lldp_ext_med.h:212
Collection of AEAD algorithms.
size_t blockSize
Definition: crypto.h:1072
#define MIMXRT1040_DCP_BUFFER_SIZE
CipherAlgoEncryptBlock encryptBlock
Definition: crypto.h:1076
AES algorithm context.
Definition: aes.h:58
#define AES_BLOCK_SIZE
Definition: aes.h:43
#define osMemcpy(dest, src, length)
Definition: os_port.h:141
error_t
Error codes.
Definition: error.h:43
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
i.MX RT1040 cipher hardware accelerator
General definitions for cryptographic algorithms.
uint8_t iv[]
Definition: ike.h:1502
Block cipher modes of operation.
uint8_t length
Definition: tcp.h:368
#define MIN(a, b)
Definition: os_port.h:63
uint_t nr
Definition: aes.h:59
uint8_t n
error_t cbcDecrypt(const CipherAlgo *cipher, void *context, uint8_t *iv, const uint8_t *c, uint8_t *p, size_t length)
CBC decryption.
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
Common interface for encryption algorithms.
Definition: crypto.h:1068
#define AES_CIPHER_ALGO
Definition: aes.h:45
error_t ecbEncrypt(const CipherAlgo *cipher, void *context, const uint8_t *p, uint8_t *c, size_t length)
ECB encryption.
error_t ecbDecrypt(const CipherAlgo *cipher, void *context, const uint8_t *c, uint8_t *p, size_t length)
ECB decryption.
error_t cbcEncrypt(const CipherAlgo *cipher, void *context, uint8_t *iv, const uint8_t *p, uint8_t *c, size_t length)
CBC encryption.
uint32_t ek[60]
Definition: aes.h:60
i.MX RT1040 hardware cryptographic accelerator (DCP)
@ NO_ERROR
Success.
Definition: error.h:44
uint8_t c
Definition: ndp.h:514
__attribute__((naked))
AVR32 Ethernet MAC interrupt wrapper.
Debugging facilities.