stm32l0xx_crypto_cipher.c
Go to the documentation of this file.
1 /**
2  * @file stm32l0xx_crypto_cipher.c
3  * @brief STM32L0 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 "stm32l0xx.h"
36 #include "stm32l0xx_hal.h"
37 #include "core/crypto.h"
42 #include "aead/aead_algorithms.h"
43 #include "debug.h"
44 
45 //Check crypto library configuration
46 #if (STM32L0XX_CRYPTO_CIPHER_SUPPORT == ENABLED && AES_SUPPORT == ENABLED)
47 
48 
49 /**
50  * @brief CRYP module initialization
51  * @return Error code
52  **/
53 
55 {
56  //Enable AES peripheral clock
57  __HAL_RCC_AES_CLK_ENABLE();
58 
59  //Successful processing
60  return NO_ERROR;
61 }
62 
63 
64 /**
65  * @brief Perform AES encryption or decryption
66  * @param[in] context AES algorithm context
67  * @param[in,out] iv Initialization vector
68  * @param[in] input Data to be encrypted/decrypted
69  * @param[out] output Data resulting from the encryption/decryption process
70  * @param[in] length Total number of data bytes to be processed
71  * @param[in] mode Operation mode
72  **/
73 
74 void aesProcessData(AesContext *context, uint8_t *iv, const uint8_t *input,
75  uint8_t *output, size_t length, uint32_t mode)
76 {
77  uint32_t temp;
78 
79  //Acquire exclusive access to the CRYP module
81 
82  //Disable the AES peripheral and clear the CCF flag
83  AES->CR = AES_CR_CCFC;
84 
85  //Set encryption key
86  AES->KEYR3 = context->ek[0];
87  AES->KEYR2 = context->ek[1];
88  AES->KEYR1 = context->ek[2];
89  AES->KEYR0 = context->ek[3];
90 
91  //Decryption operation?
92  if((mode & AES_CR_MODE) == AES_CR_MODE_DECRYPTION)
93  {
94  //Select mode 2 by setting to '01' the MODE bitfield of the AES_CR
95  temp = AES->CR & ~AES_CR_CHMOD;
96  AES->CR = temp | AES_CR_MODE_KEY_DERIVATION;
97 
98  //Enable the AES peripheral, by setting the EN bit of the AES_CR register
99  AES->CR |= AES_CR_EN;
100 
101  //Wait until the CCF flag is set in the AES_SR register
102  while((AES->SR & AES_SR_CCF) == 0)
103  {
104  }
105 
106  //Clear the CCF flag, by setting the CCFC bit of the AES_CR register
107  AES->CR |= AES_CR_CCFC;
108  }
109 
110  //Select the chaining mode
111  temp = AES->CR & ~(AES_CR_CHMOD | AES_CR_MODE);
112  AES->CR = temp | mode;
113 
114  //Configure the data type
115  temp = AES->CR & ~AES_CR_DATATYPE;
116  AES->CR = temp | AES_CR_DATATYPE_8B;
117 
118  //Valid initialization vector?
119  if(iv != NULL)
120  {
121  //Set initialization vector
122  AES->IVR3 = LOAD32BE(iv);
123  AES->IVR2 = LOAD32BE(iv + 4);
124  AES->IVR1 = LOAD32BE(iv + 8);
125  AES->IVR0 = LOAD32BE(iv + 12);
126  }
127 
128  //Enable the AES by setting the EN bit in the AES_CR register
129  AES->CR |= AES_CR_EN;
130 
131  //Process data
132  while(length >= AES_BLOCK_SIZE)
133  {
134  //Write four input data words into the AES_DINR register
135  AES->DINR = __UNALIGNED_UINT32_READ(input);
136  AES->DINR = __UNALIGNED_UINT32_READ(input + 4);
137  AES->DINR = __UNALIGNED_UINT32_READ(input + 8);
138  AES->DINR = __UNALIGNED_UINT32_READ(input + 12);
139 
140  //Wait until the CCF flag is set in the AES_SR register
141  while((AES->SR & AES_SR_CCF) == 0)
142  {
143  }
144 
145  //Read four data words from the AES_DOUTR register
146  temp = AES->DOUTR;
147  __UNALIGNED_UINT32_WRITE(output, temp);
148  temp = AES->DOUTR;
149  __UNALIGNED_UINT32_WRITE(output + 4, temp);
150  temp = AES->DOUTR;
151  __UNALIGNED_UINT32_WRITE(output + 8, temp);
152  temp = AES->DOUTR;
153  __UNALIGNED_UINT32_WRITE(output + 12, temp);
154 
155  //Clear the CCF flag, by setting the CCFC bit of the AES_CR register
156  AES->CR |= AES_CR_CCFC;
157 
158  //Next block
159  input += AES_BLOCK_SIZE;
160  output += AES_BLOCK_SIZE;
162  }
163 
164  //Process final block of data
165  if(length > 0)
166  {
167  uint32_t buffer[4];
168 
169  //Copy partial block
170  osMemset(buffer, 0, AES_BLOCK_SIZE);
171  osMemcpy(buffer, input, length);
172 
173  //Write four input data words into the AES_DINR register
174  AES->DINR = buffer[0];
175  AES->DINR = buffer[1];
176  AES->DINR = buffer[2];
177  AES->DINR = buffer[3];
178 
179  //Wait until the CCF flag is set in the AES_SR register
180  while((AES->SR & AES_SR_CCF) == 0)
181  {
182  }
183 
184  //Read four data words from the AES_DOUTR register
185  buffer[0] = AES->DOUTR;
186  buffer[1] = AES->DOUTR;
187  buffer[2] = AES->DOUTR;
188  buffer[3] = AES->DOUTR;
189 
190  //Clear the CCF flag, by setting the CCFC bit of the AES_CR register
191  AES->CR |= AES_CR_CCFC;
192 
193  //Discard the data that is not part of the payload
194  osMemcpy(output, buffer, length);
195  }
196 
197  //Valid initialization vector?
198  if(iv != NULL)
199  {
200  //Update the value of the initialization vector
201  temp = AES->IVR3;
202  STORE32BE(temp, iv);
203  temp = AES->IVR2;
204  STORE32BE(temp, iv + 4);
205  temp = AES->IVR1;
206  STORE32BE(temp, iv + 8);
207  temp = AES->IVR0;
208  STORE32BE(temp, iv + 12);
209  }
210 
211  //Disable the AES peripheral by clearing the EN bit of the AES_CR register
212  AES->CR = 0;
213 
214  //Release exclusive access to the CRYP module
216 }
217 
218 
219 /**
220  * @brief Key expansion
221  * @param[in] context Pointer to the AES context to initialize
222  * @param[in] key Pointer to the key
223  * @param[in] keyLen Length of the key
224  * @return Error code
225  **/
226 
227 error_t aesInit(AesContext *context, const uint8_t *key, size_t keyLen)
228 {
229  //Check parameters
230  if(context == NULL || key == NULL)
232 
233  //Check the length of the key
234  if(keyLen != 16)
236 
237  //10 rounds are required for 128-bit key
238  context->nr = 10;
239 
240  //Copy the original key
241  context->ek[0] = LOAD32BE(key);
242  context->ek[1] = LOAD32BE(key + 4);
243  context->ek[2] = LOAD32BE(key + 8);
244  context->ek[3] = LOAD32BE(key + 12);
245 
246  //No error to report
247  return NO_ERROR;
248 }
249 
250 
251 /**
252  * @brief Encrypt a 16-byte block using AES algorithm
253  * @param[in] context Pointer to the AES context
254  * @param[in] input Plaintext block to encrypt
255  * @param[out] output Ciphertext block resulting from encryption
256  **/
257 
258 void aesEncryptBlock(AesContext *context, const uint8_t *input, uint8_t *output)
259 {
260  //Perform AES encryption
261  aesProcessData(context, NULL, input, output, AES_BLOCK_SIZE,
263 }
264 
265 
266 /**
267  * @brief Decrypt a 16-byte block using AES algorithm
268  * @param[in] context Pointer to the AES context
269  * @param[in] input Ciphertext block to decrypt
270  * @param[out] output Plaintext block resulting from decryption
271  **/
272 
273 void aesDecryptBlock(AesContext *context, const uint8_t *input, uint8_t *output)
274 {
275  //Perform AES decryption
276  aesProcessData(context, NULL, input, output, AES_BLOCK_SIZE,
278 }
279 
280 
281 #if (ECB_SUPPORT == ENABLED)
282 
283 /**
284  * @brief ECB encryption
285  * @param[in] cipher Cipher algorithm
286  * @param[in] context Cipher algorithm context
287  * @param[in] p Plaintext to be encrypted
288  * @param[out] c Ciphertext resulting from the encryption
289  * @param[in] length Total number of data bytes to be encrypted
290  * @return Error code
291  **/
292 
293 error_t ecbEncrypt(const CipherAlgo *cipher, void *context,
294  const uint8_t *p, uint8_t *c, size_t length)
295 {
296  error_t error;
297 
298  //Initialize status code
299  error = NO_ERROR;
300 
301  //AES cipher algorithm?
302  if(cipher == AES_CIPHER_ALGO)
303  {
304  //Check the length of the payload
305  if(length == 0)
306  {
307  //No data to process
308  }
309  else if((length % AES_BLOCK_SIZE) == 0)
310  {
311  //Encrypt payload data
312  aesProcessData(context, NULL, p, c, length, AES_CR_CHMOD_ECB |
314  }
315  else
316  {
317  //The length of the payload must be a multiple of the block size
318  error = ERROR_INVALID_LENGTH;
319  }
320  }
321  else
322  {
323  //ECB mode operates in a block-by-block fashion
324  while(length >= cipher->blockSize)
325  {
326  //Encrypt current block
327  cipher->encryptBlock(context, p, c);
328 
329  //Next block
330  p += cipher->blockSize;
331  c += cipher->blockSize;
332  length -= cipher->blockSize;
333  }
334 
335  //The length of the payload must be a multiple of the block size
336  if(length != 0)
337  {
338  error = ERROR_INVALID_LENGTH;
339  }
340  }
341 
342  //Return status code
343  return error;
344 }
345 
346 
347 /**
348  * @brief ECB decryption
349  * @param[in] cipher Cipher algorithm
350  * @param[in] context Cipher algorithm context
351  * @param[in] c Ciphertext to be decrypted
352  * @param[out] p Plaintext resulting from the decryption
353  * @param[in] length Total number of data bytes to be decrypted
354  * @return Error code
355  **/
356 
357 error_t ecbDecrypt(const CipherAlgo *cipher, void *context,
358  const uint8_t *c, uint8_t *p, size_t length)
359 {
360  error_t error;
361 
362  //Initialize status code
363  error = NO_ERROR;
364 
365  //AES cipher algorithm?
366  if(cipher == AES_CIPHER_ALGO)
367  {
368  //Check the length of the payload
369  if(length == 0)
370  {
371  //No data to process
372  }
373  else if((length % AES_BLOCK_SIZE) == 0)
374  {
375  //Decrypt payload data
376  aesProcessData(context, NULL, c, p, length, AES_CR_CHMOD_ECB |
378  }
379  else
380  {
381  //The length of the payload must be a multiple of the block size
382  error = ERROR_INVALID_LENGTH;
383  }
384  }
385  else
386  {
387  //ECB mode operates in a block-by-block fashion
388  while(length >= cipher->blockSize)
389  {
390  //Decrypt current block
391  cipher->decryptBlock(context, c, p);
392 
393  //Next block
394  c += cipher->blockSize;
395  p += cipher->blockSize;
396  length -= cipher->blockSize;
397  }
398 
399  //The length of the payload must be a multiple of the block size
400  if(length != 0)
401  {
402  error = ERROR_INVALID_LENGTH;
403  }
404  }
405 
406  //Return status code
407  return error;
408 }
409 
410 #endif
411 #if (CBC_SUPPORT == ENABLED)
412 
413 /**
414  * @brief CBC encryption
415  * @param[in] cipher Cipher algorithm
416  * @param[in] context Cipher algorithm context
417  * @param[in,out] iv Initialization vector
418  * @param[in] p Plaintext to be encrypted
419  * @param[out] c Ciphertext resulting from the encryption
420  * @param[in] length Total number of data bytes to be encrypted
421  * @return Error code
422  **/
423 
424 error_t cbcEncrypt(const CipherAlgo *cipher, void *context,
425  uint8_t *iv, const uint8_t *p, uint8_t *c, size_t length)
426 {
427  error_t error;
428 
429  //Initialize status code
430  error = NO_ERROR;
431 
432  //AES cipher algorithm?
433  if(cipher == AES_CIPHER_ALGO)
434  {
435  //Check the length of the payload
436  if(length == 0)
437  {
438  //No data to process
439  }
440  else if((length % AES_BLOCK_SIZE) == 0)
441  {
442  //Encrypt payload data
443  aesProcessData(context, iv, p, c, length, AES_CR_CHMOD_CBC |
445  }
446  else
447  {
448  //The length of the payload must be a multiple of the block size
449  error = ERROR_INVALID_LENGTH;
450  }
451  }
452  else
453  {
454  size_t i;
455 
456  //CBC mode operates in a block-by-block fashion
457  while(length >= cipher->blockSize)
458  {
459  //XOR input block with IV contents
460  for(i = 0; i < cipher->blockSize; i++)
461  {
462  c[i] = p[i] ^ iv[i];
463  }
464 
465  //Encrypt the current block based upon the output of the previous
466  //encryption
467  cipher->encryptBlock(context, c, c);
468 
469  //Update IV with output block contents
470  osMemcpy(iv, c, cipher->blockSize);
471 
472  //Next block
473  p += cipher->blockSize;
474  c += cipher->blockSize;
475  length -= cipher->blockSize;
476  }
477 
478  //The length of the payload must be a multiple of the block size
479  if(length != 0)
480  {
481  error = ERROR_INVALID_LENGTH;
482  }
483  }
484 
485  //Return status code
486  return error;
487 }
488 
489 
490 /**
491  * @brief CBC decryption
492  * @param[in] cipher Cipher algorithm
493  * @param[in] context Cipher algorithm context
494  * @param[in,out] iv Initialization vector
495  * @param[in] c Ciphertext to be decrypted
496  * @param[out] p Plaintext resulting from the decryption
497  * @param[in] length Total number of data bytes to be decrypted
498  * @return Error code
499  **/
500 
501 error_t cbcDecrypt(const CipherAlgo *cipher, void *context,
502  uint8_t *iv, const uint8_t *c, uint8_t *p, size_t length)
503 {
504  error_t error;
505 
506  //Initialize status code
507  error = NO_ERROR;
508 
509  //AES cipher algorithm?
510  if(cipher == AES_CIPHER_ALGO)
511  {
512  //Check the length of the payload
513  if(length == 0)
514  {
515  //No data to process
516  }
517  else if((length % AES_BLOCK_SIZE) == 0)
518  {
519  //Decrypt payload data
520  aesProcessData(context, iv, c, p, length, AES_CR_CHMOD_CBC |
522  }
523  else
524  {
525  //The length of the payload must be a multiple of the block size
526  error = ERROR_INVALID_LENGTH;
527  }
528  }
529  else
530  {
531  size_t i;
532  uint8_t t[16];
533 
534  //CBC mode operates in a block-by-block fashion
535  while(length >= cipher->blockSize)
536  {
537  //Save input block
538  osMemcpy(t, c, cipher->blockSize);
539 
540  //Decrypt the current block
541  cipher->decryptBlock(context, c, p);
542 
543  //XOR output block with IV contents
544  for(i = 0; i < cipher->blockSize; i++)
545  {
546  p[i] ^= iv[i];
547  }
548 
549  //Update IV with input block contents
550  osMemcpy(iv, t, cipher->blockSize);
551 
552  //Next block
553  c += cipher->blockSize;
554  p += cipher->blockSize;
555  length -= cipher->blockSize;
556  }
557 
558  //The length of the payload must be a multiple of the block size
559  if(length != 0)
560  {
561  error = ERROR_INVALID_LENGTH;
562  }
563  }
564 
565  //Return status code
566  return error;
567 }
568 
569 #endif
570 #if (CTR_SUPPORT == ENABLED)
571 
572 /**
573  * @brief CTR encryption
574  * @param[in] cipher Cipher algorithm
575  * @param[in] context Cipher algorithm context
576  * @param[in] m Size in bits of the specific part of the block to be incremented
577  * @param[in,out] t Initial counter block
578  * @param[in] p Plaintext to be encrypted
579  * @param[out] c Ciphertext resulting from the encryption
580  * @param[in] length Total number of data bytes to be encrypted
581  * @return Error code
582  **/
583 
584 error_t ctrEncrypt(const CipherAlgo *cipher, void *context, uint_t m,
585  uint8_t *t, const uint8_t *p, uint8_t *c, size_t length)
586 {
587  error_t error;
588 
589  //Initialize status code
590  error = NO_ERROR;
591 
592  //AES cipher algorithm?
593  if(cipher == AES_CIPHER_ALGO)
594  {
595  //Check the value of the parameter
596  if(m == (AES_BLOCK_SIZE * 8))
597  {
598  //Check the length of the payload
599  if(length > 0)
600  {
601  //Encrypt payload data
602  aesProcessData(context, t, p, c, length, AES_CR_CHMOD_CTR |
604  }
605  else
606  {
607  //No data to process
608  }
609  }
610  else
611  {
612  //The value of the parameter is not valid
613  error = ERROR_INVALID_PARAMETER;
614  }
615  }
616  else
617  {
618  //Check the value of the parameter
619  if((m % 8) == 0 && m <= (cipher->blockSize * 8))
620  {
621  size_t i;
622  size_t n;
623  uint16_t temp;
624  uint8_t o[16];
625 
626  //Determine the size, in bytes, of the specific part of the block
627  //to be incremented
628  m = m / 8;
629 
630  //Process plaintext
631  while(length > 0)
632  {
633  //CTR mode operates in a block-by-block fashion
634  n = MIN(length, cipher->blockSize);
635 
636  //Compute O(j) = CIPH(T(j))
637  cipher->encryptBlock(context, t, o);
638 
639  //Compute C(j) = P(j) XOR T(j)
640  for(i = 0; i < n; i++)
641  {
642  c[i] = p[i] ^ o[i];
643  }
644 
645  //Standard incrementing function
646  for(temp = 1, i = 1; i <= m; i++)
647  {
648  //Increment the current byte and propagate the carry
649  temp += t[cipher->blockSize - i];
650  t[cipher->blockSize - i] = temp & 0xFF;
651  temp >>= 8;
652  }
653 
654  //Next block
655  p += n;
656  c += n;
657  length -= n;
658  }
659  }
660  else
661  {
662  //The value of the parameter is not valid
663  error = ERROR_INVALID_PARAMETER;
664  }
665  }
666 
667  //Return status code
668  return error;
669 }
670 
671 #endif
672 #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 STORE32BE(a, p)
Definition: cpu_endian.h:286
General definitions for cryptographic algorithms.
Debugging facilities.
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_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 p
Definition: ndp.h:300
uint8_t m
Definition: ndp.h:304
#define osMemset(p, value, length)
Definition: os_port.h:135
#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.
#define AES_CR_MODE_ENCRYPTION
#define AES_CR_DATATYPE_8B
#define AES_CR_CHMOD_CTR
#define AES_CR_MODE_DECRYPTION
#define AES_CR_MODE_KEY_DERIVATION
#define AES_CR_CHMOD_ECB
#define AES_CR_CHMOD_CBC
OsMutex stm32l0xxCryptoMutex
STM32L0 hardware cryptographic accelerator.
error_t aesInit(AesContext *context, const uint8_t *key, size_t keyLen)
Key expansion.
error_t ctrEncrypt(const CipherAlgo *cipher, void *context, uint_t m, uint8_t *t, const uint8_t *p, uint8_t *c, size_t length)
CTR encryption.
void aesProcessData(AesContext *context, uint8_t *iv, const uint8_t *input, uint8_t *output, size_t length, uint32_t mode)
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.
error_t crypInit(void)
CRYP module initialization.
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.
void aesEncryptBlock(AesContext *context, const uint8_t *input, uint8_t *output)
Encrypt a 16-byte block using AES algorithm.
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.
STM32L0 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