s32k1_crypto_cipher.c
Go to the documentation of this file.
1 /**
2  * @file s32k1_crypto_cipher.c
3  * @brief S32K1 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 "fsl_device_registers.h"
36 #include "core/crypto.h"
40 #include "debug.h"
41 
42 //Check crypto library configuration
43 #if (S32K1_CRYPTO_CIPHER_SUPPORT == ENABLED && AES_SUPPORT == ENABLED)
44 
45 
46 /**
47  * @brief Load AES key
48  * @param[in] key 128-bit encryption key
49  * @return CSEq error code
50  **/
51 
52 uint32_t aesLoadKey(const uint32_t *key)
53 {
54  //Check for the previous CSEq command to complete
55  while((FTFC->FSTAT & FTFC_FSTAT_CCIF_MASK) == 0)
56  {
57  }
58 
59  //Clear error flags
60  FTFC->FSTAT = FTFC_FSTAT_FPVIOL_MASK | FTFC_FSTAT_ACCERR_MASK;
61 
62  //Copy the 128-bit key to CSEq RAM
63  CSE_PRAM->RAMn[4].DATA_32 = htobe32(key[0]);
64  CSE_PRAM->RAMn[5].DATA_32 = htobe32(key[1]);
65  CSE_PRAM->RAMn[6].DATA_32 = htobe32(key[2]);
66  CSE_PRAM->RAMn[7].DATA_32 = htobe32(key[3]);
67 
68  //Start CSEq command
69  CSE_PRAM->RAMn[0].DATA_32 = CSEQ_CMD_LOAD_PLAIN_KEY | CSEQ_FORMAT_COPY |
71 
72  //Wait for the CSEq command to complete
73  while((FTFC->FSTAT & FTFC_FSTAT_CCIF_MASK) == 0)
74  {
75  }
76 
77  //Return status code
78  return CSE_PRAM->RAMn[1].DATA_32 >> 16;
79 }
80 
81 
82 /**
83  * @brief Perform AES encryption or decryption
84  * @param[in] command CSEq command
85  * @param[in] offset CSEq RAM offset
86  * @param[in] input Data to be encrypted/decrypted
87  * @param[out] output Data resulting from the encryption/decryption process
88  * @param[in] length Total number of data bytes to be processed
89  * @return CSEq error code
90  **/
91 
92 uint32_t aesProcessData(uint32_t command, size_t offset, const uint8_t *input,
93  uint8_t *output, size_t length)
94 {
95  size_t i;
96  size_t j;
97  uint32_t temp;
98  uint32_t status;
99 
100  //Write input data to CSEq RAM
101  for(i = offset, j = 0; j < length; i += 4, j += AES_BLOCK_SIZE)
102  {
103  CSE_PRAM->RAMn[i].DATA_32 = LOAD32BE(input);
104  CSE_PRAM->RAMn[i + 1].DATA_32 = LOAD32BE(input + 4);
105  CSE_PRAM->RAMn[i + 2].DATA_32 = LOAD32BE(input + 8);
106  CSE_PRAM->RAMn[i + 3].DATA_32 = LOAD32BE(input + 12);
107 
108  //Next block
109  input += AES_BLOCK_SIZE;
110  }
111 
112  //Start CSEq command
113  CSE_PRAM->RAMn[0].DATA_32 = command | CSEQ_FORMAT_COPY | CSEQ_RAM_KEY;
114 
115  //Wait for the CSEq command to complete
116  while((FTFC->FSTAT & FTFC_FSTAT_CCIF_MASK) == 0)
117  {
118  }
119 
120  //Retrieve status code
121  status = CSE_PRAM->RAMn[1].DATA_32 >> 16;
122 
123  //Check status code
124  if(status == CSEQ_ERC_NO_ERROR)
125  {
126  //Read output data from CSEq RAM
127  for(i = offset, j = 0; j < length; i += 4, j += AES_BLOCK_SIZE)
128  {
129  temp = CSE_PRAM->RAMn[i].DATA_32;
130  STORE32BE(temp, output);
131  temp = CSE_PRAM->RAMn[i + 1].DATA_32;
132  STORE32BE(temp, output + 4);
133  temp = CSE_PRAM->RAMn[i + 2].DATA_32;
134  STORE32BE(temp, output + 8);
135  temp = CSE_PRAM->RAMn[i + 3].DATA_32;
136  STORE32BE(temp, output + 12);
137 
138  //Next block
139  output += AES_BLOCK_SIZE;
140  }
141  }
142 
143  //Return status code
144  return status;
145 }
146 
147 
148 #if (ECB_SUPPORT == ENABLED)
149 
150 /**
151  * @brief ECB encryption
152  * @param[in] cipher Cipher algorithm
153  * @param[in] context Cipher algorithm context
154  * @param[in] p Plaintext to be encrypted
155  * @param[out] c Ciphertext resulting from the encryption
156  * @param[in] length Total number of data bytes to be encrypted
157  * @return Error code
158  **/
159 
160 error_t ecbEncrypt(const CipherAlgo *cipher, void *context,
161  const uint8_t *p, uint8_t *c, size_t length)
162 {
163  uint32_t status;
164 
165  //Initialize status code
166  status = CSEQ_ERC_NO_ERROR;
167 
168  //AES cipher algorithm?
169  if(cipher == AES_CIPHER_ALGO)
170  {
171  //Check the length of the payload
172  if(length == 0)
173  {
174  //No data to process
175  }
176  else if((length % AES_BLOCK_SIZE) == 0)
177  {
178  size_t n;
179  AesContext *aesContext;
180 
181  //Point to the AES context
182  aesContext = (AesContext *) context;
183 
184  //Check the length of the key
185  if(aesContext->nr == 10)
186  {
187  //Acquire exclusive access to the CSEq module
189 
190  //Set encryption key
191  status = aesLoadKey(aesContext->ek);
192 
193  //Process data blocks
194  while(length > 0 && status == CSEQ_ERC_NO_ERROR)
195  {
196  //Limit the number of data to process at a time
197  n = MIN(length, AES_BLOCK_SIZE * 7);
198 
199  //Specify the number of data blocks
200  CSE_PRAM->RAMn[3].DATA_32 = n / AES_BLOCK_SIZE;
201 
202  //Perform AES-ECB encryption
203  status = aesProcessData(CSEQ_CMD_ENC_ECB, 4, p, c, n);
204 
205  //Next block
206  p += n;
207  c += n;
208  length -= n;
209  }
210 
211  //Release exclusive access to the CSEq module
213  }
214  else
215  {
216  //192 and 256-bit keys are not supported
217  status = CSEQ_ERC_KEY_INVALID;
218  }
219  }
220  else
221  {
222  //The length of the payload must be a multiple of the block size
223  status = CSEQ_ERC_GENERAL_ERROR;
224  }
225  }
226  else
227  {
228  //ECB mode operates in a block-by-block fashion
229  while(length >= cipher->blockSize)
230  {
231  //Encrypt current block
232  cipher->encryptBlock(context, p, c);
233 
234  //Next block
235  p += cipher->blockSize;
236  c += cipher->blockSize;
237  length -= cipher->blockSize;
238  }
239 
240  //The length of the payload must be a multiple of the block size
241  if(length != 0)
242  {
243  status = CSEQ_ERC_GENERAL_ERROR;
244  }
245  }
246 
247  //Return status code
248  return (status == CSEQ_ERC_NO_ERROR) ? NO_ERROR : ERROR_FAILURE;
249 }
250 
251 
252 /**
253  * @brief ECB decryption
254  * @param[in] cipher Cipher algorithm
255  * @param[in] context Cipher algorithm context
256  * @param[in] c Ciphertext to be decrypted
257  * @param[out] p Plaintext resulting from the decryption
258  * @param[in] length Total number of data bytes to be decrypted
259  * @return Error code
260  **/
261 
262 error_t ecbDecrypt(const CipherAlgo *cipher, void *context,
263  const uint8_t *c, uint8_t *p, size_t length)
264 {
265  uint32_t status;
266 
267  //Initialize status code
268  status = CSEQ_ERC_NO_ERROR;
269 
270  //AES cipher algorithm?
271  if(cipher == AES_CIPHER_ALGO)
272  {
273  //Check the length of the payload
274  if(length == 0)
275  {
276  //No data to process
277  }
278  else if((length % AES_BLOCK_SIZE) == 0)
279  {
280  size_t n;
281  AesContext *aesContext;
282 
283  //Point to the AES context
284  aesContext = (AesContext *) context;
285 
286  //Check the length of the key
287  if(aesContext->nr == 10)
288  {
289  //Acquire exclusive access to the CSEq module
291 
292  //Set encryption key
293  status = aesLoadKey(aesContext->ek);
294 
295  //Process data blocks
296  while(length > 0 && status == CSEQ_ERC_NO_ERROR)
297  {
298  //Limit the number of data to process at a time
299  n = MIN(length, AES_BLOCK_SIZE * 7);
300 
301  //Specify the number of data blocks
302  CSE_PRAM->RAMn[3].DATA_32 = n / AES_BLOCK_SIZE;
303 
304  //Perform AES-ECB decryption
305  status = aesProcessData(CSEQ_CMD_DEC_ECB, 4, c, p, n);
306 
307  //Next block
308  c += n;
309  p += n;
310  length -= n;
311  }
312 
313  //Release exclusive access to the CSEq module
315  }
316  else
317  {
318  //192 and 256-bit keys are not supported
319  status = CSEQ_ERC_KEY_INVALID;
320  }
321  }
322  else
323  {
324  //The length of the payload must be a multiple of the block size
325  status = CSEQ_ERC_GENERAL_ERROR;
326  }
327  }
328  else
329  {
330  //ECB mode operates in a block-by-block fashion
331  while(length >= cipher->blockSize)
332  {
333  //Decrypt current block
334  cipher->decryptBlock(context, c, p);
335 
336  //Next block
337  c += cipher->blockSize;
338  p += cipher->blockSize;
339  length -= cipher->blockSize;
340  }
341 
342  //The length of the payload must be a multiple of the block size
343  if(length != 0)
344  {
345  status = CSEQ_ERC_GENERAL_ERROR;
346  }
347  }
348 
349  //Return status code
350  return (status == CSEQ_ERC_NO_ERROR) ? NO_ERROR : ERROR_FAILURE;
351 }
352 
353 #endif
354 #if (CBC_SUPPORT == ENABLED)
355 
356 /**
357  * @brief CBC encryption
358  * @param[in] cipher Cipher algorithm
359  * @param[in] context Cipher algorithm context
360  * @param[in,out] iv Initialization vector
361  * @param[in] p Plaintext to be encrypted
362  * @param[out] c Ciphertext resulting from the encryption
363  * @param[in] length Total number of data bytes to be encrypted
364  * @return Error code
365  **/
366 
367 error_t cbcEncrypt(const CipherAlgo *cipher, void *context,
368  uint8_t *iv, const uint8_t *p, uint8_t *c, size_t length)
369 {
370  uint32_t status;
371 
372  //Initialize status code
373  status = CSEQ_ERC_NO_ERROR;
374 
375  //AES cipher algorithm?
376  if(cipher == AES_CIPHER_ALGO)
377  {
378  //Check the length of the payload
379  if(length == 0)
380  {
381  //No data to process
382  }
383  else if((length % AES_BLOCK_SIZE) == 0)
384  {
385  size_t n;
386  AesContext *aesContext;
387 
388  //Point to the AES context
389  aesContext = (AesContext *) context;
390 
391  //Check the length of the key
392  if(aesContext->nr == 10)
393  {
394  //Acquire exclusive access to the CSEq module
396 
397  //Set encryption key
398  status = aesLoadKey(aesContext->ek);
399 
400  //Process first data blocks
401  if(status == CSEQ_ERC_NO_ERROR)
402  {
403  //Set initialization vector
404  CSE_PRAM->RAMn[4].DATA_32 = LOAD32BE(iv);
405  CSE_PRAM->RAMn[5].DATA_32 = LOAD32BE(iv + 4);
406  CSE_PRAM->RAMn[6].DATA_32 = LOAD32BE(iv + 8);
407  CSE_PRAM->RAMn[7].DATA_32 = LOAD32BE(iv + 12);
408 
409  //Specify the number of data blocks
410  CSE_PRAM->RAMn[3].DATA_32 = length / AES_BLOCK_SIZE;
411 
412  //Limit the number of data to process at a time
413  n = MIN(length, AES_BLOCK_SIZE * 6);
414 
415  //Perform AES-CBC encryption
417  8, p, c, n);
418 
419  //Check status code
420  if(status == CSEQ_ERC_NO_ERROR)
421  {
422  //Update the value of the initialization vector
424  }
425 
426  //Next block
427  p += n;
428  c += n;
429  length -= n;
430  }
431 
432  //Process subsequent data blocks
433  while(length > 0 && status == CSEQ_ERC_NO_ERROR)
434  {
435  //Limit the number of data to process at a time
436  n = MIN(length, AES_BLOCK_SIZE * 7);
437 
438  //Perform AES-CBC encryption
440  4, p, c, n);
441 
442  //Check status code
443  if(status == CSEQ_ERC_NO_ERROR)
444  {
445  //Update the value of the initialization vector
447  }
448 
449  //Next block
450  p += n;
451  c += n;
452  length -= n;
453  }
454 
455  //Release exclusive access to the CSEq module
457  }
458  else
459  {
460  //192 and 256-bit keys are not supported
461  status = CSEQ_ERC_KEY_INVALID;
462  }
463  }
464  else
465  {
466  //The length of the payload must be a multiple of the block size
467  status = CSEQ_ERC_GENERAL_ERROR;
468  }
469  }
470  else
471  {
472  size_t i;
473 
474  //CBC mode operates in a block-by-block fashion
475  while(length >= cipher->blockSize)
476  {
477  //XOR input block with IV contents
478  for(i = 0; i < cipher->blockSize; i++)
479  {
480  c[i] = p[i] ^ iv[i];
481  }
482 
483  //Encrypt the current block based upon the output of the previous
484  //encryption
485  cipher->encryptBlock(context, c, c);
486 
487  //Update IV with output block contents
488  osMemcpy(iv, c, cipher->blockSize);
489 
490  //Next block
491  p += cipher->blockSize;
492  c += cipher->blockSize;
493  length -= cipher->blockSize;
494  }
495 
496  //The length of the payload must be a multiple of the block size
497  if(length != 0)
498  {
499  status = CSEQ_ERC_GENERAL_ERROR;
500  }
501  }
502 
503  //Return status code
504  return (status == CSEQ_ERC_NO_ERROR) ? NO_ERROR : ERROR_FAILURE;
505 }
506 
507 
508 /**
509  * @brief CBC decryption
510  * @param[in] cipher Cipher algorithm
511  * @param[in] context Cipher algorithm context
512  * @param[in,out] iv Initialization vector
513  * @param[in] c Ciphertext to be decrypted
514  * @param[out] p Plaintext resulting from the decryption
515  * @param[in] length Total number of data bytes to be decrypted
516  * @return Error code
517  **/
518 
519 error_t cbcDecrypt(const CipherAlgo *cipher, void *context,
520  uint8_t *iv, const uint8_t *c, uint8_t *p, size_t length)
521 {
522  uint32_t status;
523 
524  //Initialize status code
525  status = CSEQ_ERC_NO_ERROR;
526 
527  //AES cipher algorithm?
528  if(cipher == AES_CIPHER_ALGO)
529  {
530  //Check the length of the payload
531  if(length == 0)
532  {
533  //No data to process
534  }
535  else if((length % AES_BLOCK_SIZE) == 0)
536  {
537  size_t n;
538  AesContext *aesContext;
539  uint8_t block[AES_BLOCK_SIZE];
540 
541  //Point to the AES context
542  aesContext = (AesContext *) context;
543 
544  //Check the length of the key
545  if(aesContext->nr == 10)
546  {
547  //Acquire exclusive access to the CSEq module
549 
550  //Set encryption key
551  status = aesLoadKey(aesContext->ek);
552 
553  //Process first data blocks
554  if(status == CSEQ_ERC_NO_ERROR)
555  {
556  //Set initialization vector
557  CSE_PRAM->RAMn[4].DATA_32 = LOAD32BE(iv);
558  CSE_PRAM->RAMn[5].DATA_32 = LOAD32BE(iv + 4);
559  CSE_PRAM->RAMn[6].DATA_32 = LOAD32BE(iv + 8);
560  CSE_PRAM->RAMn[7].DATA_32 = LOAD32BE(iv + 12);
561 
562  //Specify the number of data blocks
563  CSE_PRAM->RAMn[3].DATA_32 = length / AES_BLOCK_SIZE;
564 
565  //Limit the number of data to process at a time
566  n = MIN(length, AES_BLOCK_SIZE * 6);
567  //Save the last input block
569 
570  //Perform AES-CBC decryption
572  8, c, p, n);
573 
574  //Check status code
575  if(status == CSEQ_ERC_NO_ERROR)
576  {
577  //Update the value of the initialization vector
579  }
580 
581  //Next block
582  c += n;
583  p += n;
584  length -= n;
585  }
586 
587  //Process subsequent data blocks
588  while(length > 0 && status == CSEQ_ERC_NO_ERROR)
589  {
590  //Limit the number of data to process at a time
591  n = MIN(length, AES_BLOCK_SIZE * 7);
592  //Save the last input block
594 
595  //Perform AES-CBC decryption
597  4, c, p, n);
598 
599  //Check status code
600  if(status == CSEQ_ERC_NO_ERROR)
601  {
602  //Update the value of the initialization vector
604  }
605 
606  //Next block
607  c += n;
608  p += n;
609  length -= n;
610  }
611 
612  //Release exclusive access to the CSEq module
614  }
615  else
616  {
617  //192 and 256-bit keys are not supported
618  status = CSEQ_ERC_KEY_INVALID;
619  }
620  }
621  else
622  {
623  //The length of the payload must be a multiple of the block size
624  status = CSEQ_ERC_GENERAL_ERROR;
625  }
626  }
627  else
628  {
629  size_t i;
630  uint8_t t[16];
631 
632  //CBC mode operates in a block-by-block fashion
633  while(length >= cipher->blockSize)
634  {
635  //Save input block
636  osMemcpy(t, c, cipher->blockSize);
637 
638  //Decrypt the current block
639  cipher->decryptBlock(context, c, p);
640 
641  //XOR output block with IV contents
642  for(i = 0; i < cipher->blockSize; i++)
643  {
644  p[i] ^= iv[i];
645  }
646 
647  //Update IV with input block contents
648  osMemcpy(iv, t, cipher->blockSize);
649 
650  //Next block
651  c += cipher->blockSize;
652  p += cipher->blockSize;
653  length -= cipher->blockSize;
654  }
655 
656  //The length of the payload must be a multiple of the block size
657  if(length != 0)
658  {
659  status = CSEQ_ERC_GENERAL_ERROR;
660  }
661  }
662 
663  //Return status code
664  return (status == CSEQ_ERC_NO_ERROR) ? NO_ERROR : ERROR_FAILURE;
665 }
666 
667 #endif
668 #endif
#define AES_CIPHER_ALGO
Definition: aes.h:45
#define AES_BLOCK_SIZE
Definition: aes.h:43
Collection of AEAD algorithms.
#define LOAD32BE(p)
Definition: cpu_endian.h:210
#define STORE32BE(a, p)
Definition: cpu_endian.h:286
#define htobe32(value)
Definition: cpu_endian.h:446
General definitions for cryptographic algorithms.
Debugging facilities.
uint8_t n
error_t
Error codes.
Definition: error.h:43
@ NO_ERROR
Success.
Definition: error.h:44
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
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 p
Definition: ndp.h:300
#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 s32k1CryptoMutex
Definition: s32k1_crypto.c:41
S32K1 hardware cryptographic accelerator (CSEq)
#define CSEQ_CALL_SEQ_FIRST
Definition: s32k1_crypto.h:63
#define CSEQ_CMD_LOAD_PLAIN_KEY
Definition: s32k1_crypto.h:45
#define CSEQ_ERC_GENERAL_ERROR
Definition: s32k1_crypto.h:106
#define CSEQ_CMD_DEC_CBC
Definition: s32k1_crypto.h:41
#define CSEQ_CMD_ENC_ECB
Definition: s32k1_crypto.h:38
#define CSEQ_ERC_KEY_INVALID
Definition: s32k1_crypto.h:98
#define CSEQ_RAM_KEY
Definition: s32k1_crypto.h:81
#define CSEQ_ERC_NO_ERROR
Definition: s32k1_crypto.h:95
#define CSEQ_FORMAT_COPY
Definition: s32k1_crypto.h:59
#define CSEQ_CALL_SEQ_SUBSEQUENT
Definition: s32k1_crypto.h:64
#define CSEQ_CMD_DEC_ECB
Definition: s32k1_crypto.h:40
#define CSEQ_CMD_ENC_CBC
Definition: s32k1_crypto.h:39
uint32_t aesProcessData(uint32_t command, size_t offset, const uint8_t *input, uint8_t *output, size_t length)
Perform AES 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.
uint32_t aesLoadKey(const uint32_t *key)
Load AES key.
error_t cbcDecrypt(const CipherAlgo *cipher, void *context, uint8_t *iv, const uint8_t *c, uint8_t *p, size_t length)
CBC decryption.
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.
S32K1 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
uint8_t length
Definition: tcp.h:368
uint16_t block
Definition: tftp_common.h:115