1 /*
2  * Copyright (c) 2016, Freescale Semiconductor, Inc.
3  * Copyright 2016-2017, 2020 NXP
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_aes.h"
10 #include "string.h"
11 
12 /*******************************************************************************
13  * Definitions
14  *******************************************************************************/
15 
16 /* Component ID definition, used by tools. */
17 #ifndef FSL_COMPONENT_ID
18 #define FSL_COMPONENT_ID "platform.drivers.aes"
19 #endif
20 
21 /*!< Use standard C library memcpy  */
22 #define aes_memcpy memcpy
23 
24 /*! @brief Definitions used for writing to the AES module CFG register. */
25 typedef enum _aes_configuration
26 {
27     kAES_CfgEncryptEcb            = 0x001u, /*!< OUTTEXT_SEL, HOLD_SEL and INBLK_SEL = Encrypt Ecb */
28     kAES_CfgDecryptEcb            = 0x001u, /*!< OUTTEXT_SEL, HOLD_SEL and INBLK_SEL = Decrypt Ecb */
29     kAES_CfgEncryptCbc            = 0x023u, /*!< OUTTEXT_SEL, HOLD_SEL and INBLK_SEL = Encrypt Cbc */
30     kAES_CfgDecryptCbc            = 0x211u, /*!< OUTTEXT_SEL, HOLD_SEL and INBLK_SEL = Decrypt Cbc */
31     kAES_CfgEncryptCfb            = 0x132u, /*!< OUTTEXT_SEL, HOLD_SEL and INBLK_SEL = Encrypt Cfb */
32     kAES_CfgDecryptCfb            = 0x112u, /*!< OUTTEXT_SEL, HOLD_SEL and INBLK_SEL = Decrypt Cfb */
33     kAES_CfgCryptOfb              = 0x122u, /*!< OUTTEXT_SEL, HOLD_SEL and INBLK_SEL = Ofb */
34     kAES_CfgCryptCtr              = 0x102u, /*!< OUTTEXT_SEL, HOLD_SEL and INBLK_SEL = Ctr */
35     kAES_CfgCryptGcmTag           = 0x102u, /*!< OUTTEXT_SEL, HOLD_SEL and INBLK_SEL = Gcm */
36     kAES_CfgSwap                  = 0x51u,  /*!< INTEXT swap bytes, OUTTEXT swap bytes, PROC_EN = Encrypt/Decrypt */
37     kAES_CfgIntextSwap            = 0x11u,  /*!< INTEXT swap bytes, PROC_EN = Encrypt/Decrypt */
38     kAES_CfgSwapIntextHashIn      = 0x12u,  /*!< Swap INTEXT only, Hash INTEXT */
39     kAES_CfgSwapIntextHashOut     = 0x16u,  /*!< Swap INTEXT only, Hash OUTTEXT */
40     kAES_CfgSwapEnDecHashIn       = 0x53u,  /*!< Swap INTEXT and OUTTEXT, Encrypt/Decrypt and Hash, Hash INTEXT */
41     kAES_CfgSwapEnDecHashOut      = 0x57u,  /*!< Swap INTEXT and OUTTEXT, Encrypt/Decrypt and Hash, Hash OUTTEXT */
42     kAES_CfgSwapIntextEnDecHashIn = 0x13u,  /*!< Swap INTEXT, Encrypt/Decrypt and Hash, Hash INTEXT */
43 } aes_configuration_t;
44 
45 /*! @brief Actual operation with AES. */
46 typedef enum _aes_encryption_decryption_mode
47 {
48     kAES_ModeEncrypt = 0U, /*!< Encryption */
49     kAES_ModeDecrypt = 1U, /*!< Decryption */
50 } aes_encryption_decryption_mode_t;
51 
52 /*******************************************************************************
53  * Prototypes
54  ******************************************************************************/
55 
56 static void aes_gcm_dec32(uint8_t *input);
57 
58 /*******************************************************************************
59  * Code
60  ******************************************************************************/
61 
62 /*!
63  * @brief Reads an unaligned word.
64  *
65  * This function creates a 32-bit word from an input array of four bytes.
66  *
67  * @param src Input array of four bytes. The array can start at any address in memory.
68  * @return 32-bit unsigned int created from the input byte array.
69  */
aes_get_word_from_unaligned(const uint8_t * srcAddr)70 static inline uint32_t aes_get_word_from_unaligned(const uint8_t *srcAddr)
71 {
72 #if (!(defined(__CORTEX_M)) || (defined(__CORTEX_M) && (__CORTEX_M == 0)))
73     register const uint8_t *src = srcAddr;
74     /* Cortex M0 does not support misaligned loads */
75     if ((uint32_t)src & 0x3u)
76     {
77         union _align_bytes_t
78         {
79             uint32_t word;
80             uint8_t byte[sizeof(uint32_t)];
81         } my_bytes;
82 
83         my_bytes.byte[0] = *src;
84         my_bytes.byte[1] = *(src + 1);
85         my_bytes.byte[2] = *(src + 2);
86         my_bytes.byte[3] = *(src + 3);
87         return my_bytes.word;
88     }
89     else
90     {
91         /* addr aligned to 0-modulo-4 so it is safe to type cast */
92         return *((const uint32_t *)src);
93     }
94 #elif defined(__CC_ARM) || defined(__ARMCC_VERSION)
95     /* -O3 optimization in Keil uses LDM instruction here (LDM r4!, {r0})
96      *    which is wrong, because srcAddr might be unaligned.
97      *    LDM on unaligned address causes hard-fault. so use memcpy() */
98     uint32_t ret;
99     memcpy(&ret, srcAddr, sizeof(uint32_t));
100     return ret;
101 #else
102     return *((const uint32_t *)(uint32_t)srcAddr);
103 #endif
104 }
105 
106 /*!
107  * @brief Converts a 32-bit word into a byte array.
108  *
109  * This function creates an output array of four bytes from an input 32-bit word.
110  *
111  * @param srcWord Input 32-bit unsigned integer.
112  * @param[out] dst Output array of four bytes. The array can start at any address in memory.
113  */
aes_set_unaligned_from_word(uint32_t srcWord,uint8_t * dstAddr)114 static inline void aes_set_unaligned_from_word(uint32_t srcWord, uint8_t *dstAddr)
115 {
116 #if (!(defined(__CORTEX_M)) || (defined(__CORTEX_M) && (__CORTEX_M == 0)))
117     register uint8_t *dst = dstAddr;
118     /* Cortex M0 does not support misaligned stores */
119     if ((uint32_t)dst & 0x3u)
120     {
121         *dst++ = (srcWord & 0x000000FFU);
122         *dst++ = (srcWord & 0x0000FF00U) >> 8;
123         *dst++ = (srcWord & 0x00FF0000U) >> 16;
124         *dst++ = (srcWord & 0xFF000000U) >> 24;
125     }
126     else
127     {
128         *((uint32_t *)dstAddr) = srcWord; /* addr aligned to 0-modulo-4 so it is safe to type cast */
129     }
130 #elif defined(__CC_ARM) || defined(__ARMCC_VERSION)
131     uint32_t ret;
132     ret = srcWord;
133     memcpy(dstAddr, &ret, sizeof(uint32_t));
134     return;
135 #else
136     *((uint32_t *)(uint32_t)dstAddr) = srcWord;
137 #endif
138 }
139 
140 /*!
141  * @brief Swap bytes withing 32-bit word.
142  *
143  * This function changes endianess of a 32-bit word.
144  *
145  * @param in 32-bit unsigned integer
146  * @return 32-bit unsigned integer with different endianess (big endian to little endian and vice versa).
147  */
swap_bytes(uint32_t in)148 static uint32_t swap_bytes(uint32_t in)
149 {
150     return (((in & 0x000000ffu) << 24) | ((in & 0x0000ff00u) << 8) | ((in & 0x00ff0000u) >> 8) |
151             ((in & 0xff000000u) >> 24));
152 }
153 
154 /*!
155  * @brief Loads key into key registers.
156  *
157  * This function loads the key into the AES key registers.
158  *
159  * @param base AES peripheral base address.
160  * @param key Input key in big endian format.
161  * @param keySize Size of the input key in bytes. Must be 16, 24 or 32.
162  * @return Status of the load key operation.
163  */
aes_load_key(AES_Type * base,const uint8_t * key,size_t keySize)164 static status_t aes_load_key(AES_Type *base, const uint8_t *key, size_t keySize)
165 {
166     uint32_t aesCfgKeyCfg;
167     uint32_t aesCfg;
168     int index;
169     int keyWords;
170 
171     switch (keySize)
172     {
173         case 16u:
174             aesCfgKeyCfg = 0u;
175             keyWords     = 4;
176             break;
177 
178         case 24u:
179             aesCfgKeyCfg = 1u;
180             keyWords     = 6;
181             break;
182 
183         case 32u:
184             aesCfgKeyCfg = 2u;
185             keyWords     = 8;
186             break;
187 
188         default:
189             keyWords = 0;
190             break;
191     }
192 
193     if (0 == keyWords)
194     {
195         /* invalidate a possibly valid key. user attempted to set a key but gives incorrect size. */
196         base->CMD = AES_CMD_WIPE(1);
197         /* wait for Idle */
198         while (0U == (base->STAT & AES_STAT_IDLE_MASK))
199         {
200         }
201         base->CMD = AES_CMD_WIPE(0u);
202         return kStatus_InvalidArgument;
203     }
204 
205     aesCfg = base->CFG;
206     aesCfg &= ~AES_CFG_KEY_CFG_MASK;
207     aesCfg |= AES_CFG_KEY_CFG(aesCfgKeyCfg);
208     base->CFG = aesCfg;
209 
210     for (index = 0; index < keyWords; index++)
211     {
212         base->KEY[index] = swap_bytes(aes_get_word_from_unaligned(key));
213         key += sizeof(uint32_t);
214     }
215 
216     return kStatus_Success;
217 }
218 
219 /*!
220  * @brief AES process one 16-byte block.
221  *
222  * This function pushes 16 bytes of data to INTEXT and pops 16 bytes of data from OUTTEXT.
223  *
224  * @param base AES peripheral base address.
225  * @param[out] output 16-byte block read from the OUTTEXT registers.
226  * @param input 16-byte block written to the INTEXT registers.
227  */
aes_one_block(AES_Type * base,uint8_t * output,const uint8_t * input)228 static void aes_one_block(AES_Type *base, uint8_t *output, const uint8_t *input)
229 {
230     int index;
231     uint32_t aesStat;
232 
233     /* If defined FLS_FEATURE_AES_IRQ_DISABLE, disable IRQs during computing AES block, */
234     /* please note that this can affect IRQs latency */
235 #if defined(FLS_FEATURE_AES_IRQ_DISABLE) && (FLS_FEATURE_AES_IRQ_DISABLE > 0)
236     uint32_t currPriMask;
237     /* disable global interrupt */
238     currPriMask = DisableGlobalIRQ();
239 #endif /* FLS_FEATURE_AES_IRQ_DISABLE */
240 
241     /* If the IN_READY bit in STAT register is 1, write the input text in the INTEXT [3:0]
242        registers. */
243     aesStat = base->STAT;
244 
245     /* Wait until input text can be written. */
246     while (0U == (aesStat & AES_STAT_IN_READY_MASK))
247     {
248         aesStat = base->STAT;
249     }
250 
251     /* Write input data into INTEXT regs */
252     for (index = 0; index < 4; index++)
253     {
254         base->INTEXT[index] = aes_get_word_from_unaligned(input);
255         input += sizeof(uint32_t);
256     }
257 
258     /* Wait until output text is ready to be read */
259     while (0U == (aesStat & AES_STAT_OUT_READY_MASK))
260     {
261         aesStat = base->STAT;
262     }
263 
264     /* Read output data from OUTTEXT regs */
265     for (index = 0; index < 4; index++)
266     {
267         aes_set_unaligned_from_word(base->OUTTEXT[index], output);
268         output += sizeof(uint32_t);
269     }
270 
271 #if defined(FLS_FEATURE_AES_IRQ_DISABLE) && (FLS_FEATURE_AES_IRQ_DISABLE > 0)
272     /* global interrupt enable */
273     EnableGlobalIRQ(currPriMask);
274 #endif /* FLS_FEATURE_AES_IRQ_DISABLE */
275 }
276 
277 /*!
278  * @brief AES switch to forward mode.
279  *
280  * This function sets the AES to forward mode if it is in reverse mode.
281  *
282  * @param base AES peripheral base address.
283  */
aes_set_forward(AES_Type * base)284 static void aes_set_forward(AES_Type *base)
285 {
286     if (AES_STAT_REVERSE_MASK == (base->STAT & AES_STAT_REVERSE_MASK))
287     {
288         /* currently in reverse, switch to forward */
289         base->CMD = AES_CMD_SWITCH_MODE(1u);
290 
291         /* wait for Idle */
292         while (0U == (base->STAT & AES_STAT_IDLE_MASK))
293         {
294         }
295 
296         base->CMD = AES_CMD_SWITCH_MODE(0u);
297     }
298 }
299 
300 /*!
301  * @brief AES switch to reverse mode.
302  *
303  * This function sets the AES to reverse mode if it is in forward mode.
304  *
305  * @param base AES peripheral base address.
306  */
aes_set_reverse(AES_Type * base)307 static void aes_set_reverse(AES_Type *base)
308 {
309     if (0U == (base->STAT & AES_STAT_REVERSE_MASK))
310     {
311         /* currently in forward, switch to reverse */
312         base->CMD = AES_CMD_SWITCH_MODE(1u);
313 
314         /* wait for Idle */
315         while (0U == (base->STAT & AES_STAT_IDLE_MASK))
316         {
317         }
318 
319         base->CMD = AES_CMD_SWITCH_MODE(0u);
320     }
321 }
322 
323 /*!
324  * @brief AES write HOLDING registers.
325  *
326  * This function writes input 16-byte data to AES HOLDING registers.
327  *
328  * @param base AES peripheral base address.
329  * @param input 16-byte input data.
330  */
aes_set_holding(AES_Type * base,const uint8_t * input)331 static void aes_set_holding(AES_Type *base, const uint8_t *input)
332 {
333     int index;
334 
335     for (index = 0; index < 4; index++)
336     {
337         base->HOLDING[index] = swap_bytes(aes_get_word_from_unaligned(input));
338         input += sizeof(uint32_t);
339     }
340 }
341 
342 /*!
343  * @brief AES check KEY_VALID.
344  *
345  * This function check the KEY_VALID bit in AES status register.
346  *
347  * @param base AES peripheral base address.
348  * @return kStatus_Success if the key is valid.
349  * @return kStatus_InvalidArgument if the key is invalid.
350  */
aes_check_key_valid(AES_Type * base)351 static status_t aes_check_key_valid(AES_Type *base)
352 {
353     status_t status;
354 
355     /* Check the key is valid */
356     status =
357         (AES_STAT_KEY_VALID_MASK == (base->STAT & AES_STAT_KEY_VALID_MASK)) ? kStatus_Success : kStatus_InvalidArgument;
358 
359     return status;
360 }
361 
362 /*!
363  * brief Sets AES key.
364  *
365  * Sets AES key.
366  *
367  * param base AES peripheral base address
368  * param key Input key to use for encryption or decryption
369  * param keySize Size of the input key, in bytes. Must be 16, 24, or 32.
370  * return Status from Set Key operation
371  */
AES_SetKey(AES_Type * base,const uint8_t * key,size_t keySize)372 status_t AES_SetKey(AES_Type *base, const uint8_t *key, size_t keySize)
373 {
374     return aes_load_key(base, key, keySize);
375 }
376 
377 /*!
378  * brief Encrypts AES using the ECB block mode.
379  *
380  * Encrypts AES using the ECB block mode.
381  *
382  * param base AES peripheral base address
383  * param plaintext Input plain text to encrypt
384  * param[out] ciphertext Output cipher text
385  * param size Size of input and output data in bytes. Must be multiple of 16 bytes.
386  * return Status from encrypt operation
387  */
AES_EncryptEcb(AES_Type * base,const uint8_t * plaintext,uint8_t * ciphertext,size_t size)388 status_t AES_EncryptEcb(AES_Type *base, const uint8_t *plaintext, uint8_t *ciphertext, size_t size)
389 {
390     status_t status;
391 
392     /* ECB mode, size must be 16-byte multiple */
393     if (0U != (size % 16u))
394     {
395         return kStatus_InvalidArgument;
396     }
397 
398     /*5. Select the required crypto operation (encryption/decryption/hash) and AES mode in the CFG register.*/
399     *(volatile uint8_t *)((uint32_t)base)         = (uint8_t)kAES_CfgSwap;
400     *(volatile uint16_t *)(((uint32_t)base + 2u)) = (uint16_t)kAES_CfgEncryptEcb;
401 
402     status = aes_check_key_valid(base);
403     if (status != kStatus_Success)
404     {
405         return status;
406     }
407 
408     /* make sure AES is set to forward mode */
409     aes_set_forward(base);
410 
411     while (size != 0U)
412     {
413         aes_one_block(base, ciphertext, plaintext);
414         ciphertext += 16;
415         plaintext += 16;
416         size -= 16u;
417     }
418 
419     return status;
420 }
421 
422 /*!
423  * brief Decrypts AES using the ECB block mode.
424  *
425  * Decrypts AES using the ECB block mode.
426  *
427  * param base AES peripheral base address
428  * param ciphertext Input ciphertext to decrypt
429  * param[out] plaintext Output plain text
430  * param size Size of input and output data in bytes. Must be multiple of 16 bytes.
431  * return Status from decrypt operation
432  */
AES_DecryptEcb(AES_Type * base,const uint8_t * ciphertext,uint8_t * plaintext,size_t size)433 status_t AES_DecryptEcb(AES_Type *base, const uint8_t *ciphertext, uint8_t *plaintext, size_t size)
434 {
435     status_t status;
436 
437     /* ECB mode, size must be 16-byte multiple */
438     if (0U != (size % 16u))
439     {
440         return kStatus_InvalidArgument;
441     }
442 
443     status = aes_check_key_valid(base);
444     if (status != kStatus_Success)
445     {
446         return status;
447     }
448 
449     /*5. Select the required crypto operation (encryption/decryption/hash) and AES mode in the CFG register.*/
450     *(volatile uint8_t *)((uint32_t)base)         = (uint8_t)kAES_CfgSwap;
451     *(volatile uint16_t *)(((uint32_t)base + 2u)) = (uint16_t)kAES_CfgDecryptEcb;
452 
453     /* make sure AES is set to reverse mode */
454     aes_set_reverse(base);
455 
456     while (size != 0U)
457     {
458         aes_one_block(base, plaintext, ciphertext);
459         ciphertext += 16;
460         plaintext += 16;
461         size -= 16u;
462     }
463 
464     return status;
465 }
466 
467 /*!
468  * @brief Main function for CBC, CFB and OFB modes.
469  *
470  * @param base AES peripheral base address
471  * @param input Input plaintext for encryption, input ciphertext for decryption.
472  * @param[out] output Output ciphertext for encryption, output plaintext for decryption.
473  * @param size Size of input and output data in bytes. For CBC and CFB it must be multiple of 16-bytes.
474  * @param iv Input initial vector to combine with the first input block.
475  * @return Status from the operation.
476  */
aes_block_mode(AES_Type * base,const uint8_t * input,uint8_t * output,size_t size,const uint8_t iv[AES_IV_SIZE],aes_configuration_t configuration)477 static status_t aes_block_mode(AES_Type *base,
478                                const uint8_t *input,
479                                uint8_t *output,
480                                size_t size,
481                                const uint8_t iv[AES_IV_SIZE],
482                                aes_configuration_t configuration)
483 {
484     status_t status;
485 
486     /* CBC and CFB128 mode, size must be 16-byte multiple */
487     switch (configuration)
488     {
489         case kAES_CfgEncryptCfb:
490         case kAES_CfgDecryptCfb:
491         case kAES_CfgEncryptCbc:
492         case kAES_CfgDecryptCbc:
493             if (0U != (size % 16u))
494             {
495                 status = kStatus_InvalidArgument;
496             }
497             else
498             {
499                 status = kStatus_Success;
500             }
501             break;
502 
503         case kAES_CfgCryptOfb:
504             status = kStatus_Success;
505             break;
506 
507         default:
508             status = kStatus_InvalidArgument;
509             break;
510     }
511     if (status != kStatus_Success)
512     {
513         return status;
514     }
515 
516     /* Check the key is valid */
517     status = aes_check_key_valid(base);
518     if (status != kStatus_Success)
519     {
520         return status;
521     }
522 
523     /*5. Select the required crypto operation (encryption/decryption/hash) and AES mode in the CFG register.*/
524     *(volatile uint8_t *)((uint32_t)base)         = (uint8_t)kAES_CfgSwap;
525     *(volatile uint16_t *)(((uint32_t)base + 2u)) = (uint16_t)configuration;
526 
527     /* CBC decrypt use reverse AES cipher. */
528     switch (configuration)
529     {
530         case kAES_CfgDecryptCbc:
531             aes_set_reverse(base);
532             break;
533 
534         default:
535             aes_set_forward(base);
536             break;
537     }
538 
539     /* For CBC, CFB and OFB modes write the Initialization Vector (IV) in the HOLDING
540        [3:0] registers. For CTR mode write the initial counter value in the HOLDING [3:0]
541        registers. */
542     aes_set_holding(base, iv);
543 
544     while (size >= 16u)
545     {
546         aes_one_block(base, output, input);
547         size -= 16u;
548         output += 16;
549         input += 16;
550     }
551 
552     /* OFB can have non-block multiple size. CBC and CFB128 have size zero at this moment. */
553     if (0U != (size % 16u))
554     {
555         uint8_t blkTemp[16] = {0};
556 
557         (void)aes_memcpy(blkTemp, input, size);
558         aes_one_block(base, blkTemp, blkTemp);
559         (void)aes_memcpy(output, blkTemp, size);
560     }
561 
562     return status;
563 }
564 
565 /*!
566  * brief Encrypts AES using CBC block mode.
567  *
568  * param base AES peripheral base address
569  * param plaintext Input plain text to encrypt
570  * param[out] ciphertext Output cipher text
571  * param size Size of input and output data in bytes. Must be multiple of 16 bytes.
572  * param iv Input initial vector to combine with the first input block.
573  * return Status from encrypt operation
574  */
AES_EncryptCbc(AES_Type * base,const uint8_t * plaintext,uint8_t * ciphertext,size_t size,const uint8_t iv[AES_IV_SIZE])575 status_t AES_EncryptCbc(
576     AES_Type *base, const uint8_t *plaintext, uint8_t *ciphertext, size_t size, const uint8_t iv[AES_IV_SIZE])
577 {
578     return aes_block_mode(base, plaintext, ciphertext, size, iv, kAES_CfgEncryptCbc);
579 }
580 
581 /*!
582  * brief Decrypts AES using CBC block mode.
583  *
584  * param base AES peripheral base address
585  * param ciphertext Input cipher text to decrypt
586  * param[out] plaintext Output plain text
587  * param size Size of input and output data in bytes. Must be multiple of 16 bytes.
588  * param iv Input initial vector to combine with the first input block.
589  * return Status from decrypt operation
590  */
AES_DecryptCbc(AES_Type * base,const uint8_t * ciphertext,uint8_t * plaintext,size_t size,const uint8_t iv[AES_IV_SIZE])591 status_t AES_DecryptCbc(
592     AES_Type *base, const uint8_t *ciphertext, uint8_t *plaintext, size_t size, const uint8_t iv[AES_IV_SIZE])
593 {
594     return aes_block_mode(base, ciphertext, plaintext, size, iv, kAES_CfgDecryptCbc);
595 }
596 
597 /*!
598  * brief Encrypts AES using CFB block mode.
599  *
600  * param base AES peripheral base address
601  * param plaintext Input plain text to encrypt
602  * param[out] ciphertext Output cipher text
603  * param size Size of input and output data in bytes. Must be multiple of 16 bytes.
604  * param iv Input Initial vector to be used as the first input block.
605  * return Status from encrypt operation
606  */
AES_EncryptCfb(AES_Type * base,const uint8_t * plaintext,uint8_t * ciphertext,size_t size,const uint8_t iv[AES_IV_SIZE])607 status_t AES_EncryptCfb(
608     AES_Type *base, const uint8_t *plaintext, uint8_t *ciphertext, size_t size, const uint8_t iv[AES_IV_SIZE])
609 {
610     return aes_block_mode(base, plaintext, ciphertext, size, iv, kAES_CfgEncryptCfb);
611 }
612 
613 /*!
614  * brief Decrypts AES using CFB block mode.
615  *
616  * param base AES peripheral base address
617  * param ciphertext Input cipher text to decrypt
618  * param[out] plaintext Output plain text
619  * param size Size of input and output data in bytes. Must be multiple of 16 bytes.
620  * param iv Input Initial vector to be used as the first input block.
621  * return Status from decrypt operation
622  */
AES_DecryptCfb(AES_Type * base,const uint8_t * ciphertext,uint8_t * plaintext,size_t size,const uint8_t iv[AES_IV_SIZE])623 status_t AES_DecryptCfb(
624     AES_Type *base, const uint8_t *ciphertext, uint8_t *plaintext, size_t size, const uint8_t iv[AES_IV_SIZE])
625 {
626     return aes_block_mode(base, ciphertext, plaintext, size, iv, kAES_CfgDecryptCfb);
627 }
628 
629 /*!
630  * brief Encrypts AES using OFB block mode.
631  *
632  * param base AES peripheral base address
633  * param plaintext Input plain text to encrypt
634  * param[out] ciphertext Output cipher text
635  * param size Size of input and output data in bytes.
636  * param iv Input Initial vector to be used as the first input block.
637  * return Status from encrypt operation
638  */
AES_EncryptOfb(AES_Type * base,const uint8_t * plaintext,uint8_t * ciphertext,size_t size,const uint8_t iv[AES_IV_SIZE])639 status_t AES_EncryptOfb(
640     AES_Type *base, const uint8_t *plaintext, uint8_t *ciphertext, size_t size, const uint8_t iv[AES_IV_SIZE])
641 {
642     return aes_block_mode(base, plaintext, ciphertext, size, iv, kAES_CfgCryptOfb);
643 }
644 
645 /*!
646  * brief Decrypts AES using OFB block mode.
647  *
648  * param base AES peripheral base address
649  * param ciphertext Input cipher text to decrypt
650  * param[out] plaintext Output plain text
651  * param size Size of input and output data in bytes.
652  * param iv Input Initial vector to be used as the first input block.
653  * return Status from decrypt operation
654  */
AES_DecryptOfb(AES_Type * base,const uint8_t * ciphertext,uint8_t * plaintext,size_t size,const uint8_t iv[AES_IV_SIZE])655 status_t AES_DecryptOfb(
656     AES_Type *base, const uint8_t *ciphertext, uint8_t *plaintext, size_t size, const uint8_t iv[AES_IV_SIZE])
657 {
658     return aes_block_mode(base, ciphertext, plaintext, size, iv, kAES_CfgCryptOfb);
659 }
660 
661 /*!
662  * brief Encrypts or decrypts AES using CTR block mode.
663  *
664  * Encrypts or decrypts AES using CTR block mode.
665  * AES CTR mode uses only forward AES cipher and same algorithm for encryption and decryption.
666  * The only difference between encryption and decryption is that, for encryption, the input argument
667  * is plain text and the output argument is cipher text. For decryption, the input argument is cipher text
668  * and the output argument is plain text.
669  *
670  * param base AES peripheral base address
671  * param input Input data for CTR block mode
672  * param[out] output Output data for CTR block mode
673  * param size Size of input and output data in bytes
674  * param[in,out] counter Input counter (updates on return)
675  * param[out] counterlast Output cipher of last counter, for chained CTR calls. NULL can be passed if chained calls are
676  * not used.
677  * param[out] szLeft Output number of bytes in left unused in counterlast block. NULL can be passed if chained calls
678  * are not used.
679  * return Status from crypt operation
680  */
AES_CryptCtr(AES_Type * base,const uint8_t * input,uint8_t * output,size_t size,uint8_t counter[AES_BLOCK_SIZE],uint8_t counterlast[AES_BLOCK_SIZE],size_t * szLeft)681 status_t AES_CryptCtr(AES_Type *base,
682                       const uint8_t *input,
683                       uint8_t *output,
684                       size_t size,
685                       uint8_t counter[AES_BLOCK_SIZE],
686                       uint8_t counterlast[AES_BLOCK_SIZE],
687                       size_t *szLeft)
688 {
689     status_t status;
690     uint32_t lastSize;
691     uint8_t lastBlock[AES_BLOCK_SIZE] = {0};
692     uint8_t *lastEncryptedCounter;
693 
694     /* Check the key is valid */
695     status = aes_check_key_valid(base);
696     if (status != kStatus_Success)
697     {
698         return status;
699     }
700 
701     /*5. Select the required crypto operation (encryption/decryption/hash) and AES mode in the CFG register.*/
702     *(volatile uint8_t *)((uint32_t)base)         = (uint8_t)kAES_CfgSwap;
703     *(volatile uint16_t *)(((uint32_t)base + 2u)) = (uint16_t)kAES_CfgCryptCtr;
704     aes_set_forward(base);
705 
706     /* For CBC, CFB and OFB modes write the Initialization Vector (IV) in the HOLDING
707        [3:0] registers. For CTR mode write the initial counter value in the HOLDING [3:0]
708        registers. */
709     aes_set_holding(base, counter);
710 
711     /* set counter increment by one */
712     base->CTR_INCR = 0x1U;
713 
714     /* Split the size into full 16-byte chunks and last incomplete block */
715     lastSize = 0U;
716     if (size <= 16U)
717     {
718         lastSize = size;
719         size     = 0U;
720     }
721     else
722     {
723         /* Process all 16-byte data chunks. */
724         lastSize = size % 16U;
725         if (lastSize == 0U)
726         {
727             lastSize = 16U;
728             size -= 16U;
729         }
730         else
731         {
732             size -= lastSize; /* size will be rounded down to 16 byte boundary. remaining bytes in lastSize */
733         }
734     }
735 
736     /* full 16-byte blocks */
737     while (size != 0U)
738     {
739         aes_one_block(base, output, input);
740         size -= 16u;
741         input += 16;
742         output += 16;
743     }
744 
745     /* last block */
746     if (counterlast != NULL)
747     {
748         lastEncryptedCounter = counterlast;
749     }
750     else
751     {
752         lastEncryptedCounter = lastBlock;
753     }
754     aes_one_block(base, lastEncryptedCounter, lastBlock); /* lastBlock is all zeroes, so I get directly ECB of the last
755                                                              counter, as the XOR with zeroes doesn't change */
756 
757     /* remain output = input XOR counterlast */
758     for (uint32_t i = 0; i < lastSize; i++)
759     {
760         output[i] = input[i] ^ lastEncryptedCounter[i];
761     }
762 
763     /* read counter value after last encryption */
764     aes_set_unaligned_from_word(swap_bytes(base->HOLDING[3]), &counter[12]);
765     aes_gcm_dec32(&counter[0]); /* TODO HW problem? (first time it increments HOLDING3 twice) */
766 
767     if (szLeft != NULL)
768     {
769         *szLeft = 16U - lastSize;
770     }
771 
772     return status;
773 }
774 
775 /*!
776  * @brief AES write input to INTEXT registers.
777  *
778  * This function writes input 16-byte data to AES INTEXT registers
779  * and wait for the engine Idle.
780  *
781  * @param base AES peripheral base address.
782  * @param input 16-byte input data.
783  */
aes_gcm_one_block_input_only(AES_Type * base,const uint8_t * input)784 static void aes_gcm_one_block_input_only(AES_Type *base, const uint8_t *input)
785 {
786     int index;
787     uint32_t aesStat;
788 
789     /* If the IN_READY bit in STAT register is 1, write the input text in the INTEXT [3:0]
790        registers. */
791     index = 0;
792     while (index < 4)
793     {
794         aesStat = base->STAT;
795 
796         if (0U != (aesStat & AES_STAT_IN_READY_MASK))
797         {
798             base->INTEXT[index] = aes_get_word_from_unaligned(input);
799             input += sizeof(uint32_t);
800             index++;
801         }
802     }
803 
804     while (0U == (base->STAT & AES_STAT_IDLE_MASK))
805     {
806     }
807 }
808 
809 /*!
810  * @brief AES execute command.
811  *
812  * This function issues command to AES CMD register.
813  *
814  * @param base AES peripheral base address.
815  * @param cmdMask Bit mask for the command to be issued.
816  */
aes_command(AES_Type * base,uint32_t cmdMask)817 static void aes_command(AES_Type *base, uint32_t cmdMask)
818 {
819     base->CMD = cmdMask;
820     /* wait for Idle */
821     while (0U == (base->STAT & AES_STAT_IDLE_MASK))
822     {
823     }
824     base->CMD = 0;
825 }
826 
827 /*!
828  * @brief AES read GCM_TAG.
829  *
830  * This function reads data from GCM_TAG registers.
831  *
832  * @param base AES peripheral base address.
833  * @param output 16 byte memory to write the GCM_TAG to.
834  */
aes_gcm_get_tag(AES_Type * base,uint8_t * output)835 static void aes_gcm_get_tag(AES_Type *base, uint8_t *output)
836 {
837     int index;
838 
839     for (index = 0; index < 4; index++)
840     {
841         aes_set_unaligned_from_word(swap_bytes(base->GCM_TAG[index]), output);
842         output += sizeof(uint32_t);
843     }
844 }
845 
846 /*!
847  * @brief AES GCM check validity of input arguments.
848  *
849  * This function checks the validity of input arguments.
850  *
851  * @param base AES peripheral base address.
852  * @param src Source address (plaintext or ciphertext).
853  * @param iv Initialization vector address.
854  * @param aad Additional authenticated data address.
855  * @param dst Destination address (plaintext or ciphertext).
856  * @param inputSize Size of input (same size as output) data in bytes.
857  * @param ivSize Size of Initialization vector in bytes.
858  * @param aadSize Size of additional data in bytes.
859  * @param tagSize Size of the GCM tag in bytes.
860  */
aes_gcm_check_input_args(AES_Type * base,const uint8_t * src,const uint8_t * iv,const uint8_t * aad,uint8_t * dst,size_t inputSize,size_t ivSize,size_t aadSize,size_t tagSize)861 static status_t aes_gcm_check_input_args(AES_Type *base,
862                                          const uint8_t *src,
863                                          const uint8_t *iv,
864                                          const uint8_t *aad,
865                                          uint8_t *dst,
866                                          size_t inputSize,
867                                          size_t ivSize,
868                                          size_t aadSize,
869                                          size_t tagSize)
870 {
871     if (base == NULL)
872     {
873         return kStatus_InvalidArgument;
874     }
875 
876     /* tag can be NULL to skip tag processing */
877     if (((ivSize != 0U) && (NULL == iv)) || ((aadSize != 0U) && (NULL == aad)) ||
878         ((inputSize != 0U) && ((NULL == src) || (NULL == dst))))
879     {
880         return kStatus_InvalidArgument;
881     }
882 
883     /* octet length of tag (tagSize) must be element of 4,8,12,13,14,15,16 */
884     if (((tagSize > 16u) || (tagSize < 12u)) && (tagSize != 4u) && (tagSize != 8u))
885     {
886         return kStatus_InvalidArgument;
887     }
888 
889     /* no IV AAD DATA makes no sense */
890     if (0U == (inputSize + ivSize + aadSize))
891     {
892         return kStatus_InvalidArgument;
893     }
894 
895     /* check length of input strings. This is more strict than the GCM specificaiton due to 32-bit architecture.
896      * The API interface would work on 64-bit architecture as well, but as it has not been tested, let it limit to
897      * 32-bits.
898      */
899     if (!((ivSize >= 1u) && (sizeof(size_t) <= 4u)))
900     {
901         return kStatus_InvalidArgument;
902     }
903 
904     return kStatus_Success;
905 }
906 
907 /*!
908  * @brief Increment a 16 byte integer.
909  *
910  * This function increments by one a 16 byte integer.
911  *
912  * @param input Pointer to a 16 byte integer to be incremented by one.
913  */
aes_gcm_incr32(uint8_t * input)914 static void aes_gcm_incr32(uint8_t *input)
915 {
916     int i = 15;
917     while (input[i] == (uint8_t)0xFFu)
918     {
919         input[i] = (uint8_t)0x00u;
920         i--;
921         if (i < 0)
922         {
923             return;
924         }
925     }
926 
927     if (i >= 0)
928     {
929         input[i] += (uint8_t)1u;
930     }
931 }
932 
933 /*!
934  * @brief Decrement a 16 byte integer.
935  *
936  * This function decrements by one a 16 byte integer.
937  *
938  * @param input Pointer to a 16 byte integer to be decremented by one.
939  */
aes_gcm_dec32(uint8_t * input)940 static void aes_gcm_dec32(uint8_t *input)
941 {
942     int i = 15;
943     while (input[i] == (uint8_t)0x00u)
944     {
945         input[i] = (uint8_t)0xFFu;
946         i--;
947         if (i < 0)
948         {
949             return;
950         }
951     }
952 
953     if (i >= 0)
954     {
955         input[i] -= (uint8_t)1u;
956     }
957 }
958 
959 /*!
960  * @brief AES read GF128_Z registers.
961  *
962  * This function reads AES module GF128_Z registers.
963  *
964  * @param base AES peripheral base address.
965  * @param input Pointer to a 16 byte integer to write the GF128_Z value to.
966  */
aes_get_gf128(AES_Type * base,uint8_t * output)967 static void aes_get_gf128(AES_Type *base, uint8_t *output)
968 {
969     int i;
970     for (i = 0; i < 4; i++)
971     {
972         aes_set_unaligned_from_word(swap_bytes(base->GF128_Z[i]), output);
973         output += sizeof(uint32_t);
974     }
975 }
976 
977 /*!
978  * @brief GCM process.
979  *
980  * This function is the main function for AES GCM encryption/decryption and tag generation/comparison.
981  *
982  * @param base AES peripheral base address.
983  * @param encryptMode Whether the actual operation is an encryption or a decryption.
984  * @param src Input plaintext for encryption or ciphertext for decryption.
985  * @param inputSize Size of input and output in bytes.
986  * @param iv Input initial vector.
987  * @param ivSize Size of initial vector in bytes.
988  * @param aad Additional authenticated data.
989  * @param aadSize Size of additional authenticated data in bytes.
990  * @param dst Output ciphertext for encryption or plaintext for decryption.
991  * @param tag For encryption, GCM tag output. For decryption, GCM tag input for comparison.
992  * @param tagSize Size of the GCM tag in bytes.
993  */
aes_gcm_process(AES_Type * base,aes_encryption_decryption_mode_t encryptMode,const uint8_t * src,size_t inputSize,const uint8_t * iv,size_t ivSize,const uint8_t * aad,size_t aadSize,uint8_t * dst,uint8_t * tag,size_t tagSize)994 static status_t aes_gcm_process(AES_Type *base,
995                                 aes_encryption_decryption_mode_t encryptMode,
996                                 const uint8_t *src,
997                                 size_t inputSize,
998                                 const uint8_t *iv,
999                                 size_t ivSize,
1000                                 const uint8_t *aad,
1001                                 size_t aadSize,
1002                                 uint8_t *dst,
1003                                 uint8_t *tag,
1004                                 size_t tagSize)
1005 {
1006     status_t status;
1007     uint8_t blkZero[16] = {0};
1008     uint8_t blkJ0[16]   = {0};
1009     uint8_t blkTag[16]  = {0};
1010     uint32_t saveSize;
1011     uint32_t saveAadSize;
1012     uint32_t saveIvSize;
1013     uint8_t lastBlock[AES_BLOCK_SIZE] = {0};
1014 
1015     status = aes_gcm_check_input_args(base, src, iv, aad, dst, inputSize, ivSize, aadSize, tagSize);
1016     if (status != kStatus_Success)
1017     {
1018         return status;
1019     }
1020 
1021     status = aes_check_key_valid(base);
1022     if (status != kStatus_Success)
1023     {
1024         return status;
1025     }
1026 
1027     saveSize    = inputSize;
1028     saveAadSize = aadSize;
1029     saveIvSize  = ivSize;
1030 
1031     /* 1. Let H = CIPHK(0_128). */
1032     *(volatile uint8_t *)((uint32_t)base) = (uint8_t)
1033         kAES_CfgIntextSwap; /* do not swap OUTTEXT, as OUTTEXT is copied for further use into GF128_Y register */
1034     *(volatile uint16_t *)(((uint32_t)base + 2u)) = (uint16_t)kAES_CfgEncryptEcb;
1035 
1036     /* make sure AES is set to forward mode */
1037     aes_set_forward(base);
1038 
1039     /* move 128-bit zeroes to INTEXT */
1040     aes_gcm_one_block_input_only(base, blkZero);
1041 
1042     /* set COPY_TO_Y command */
1043     aes_command(base, AES_CMD_COPY_TO_Y(1));
1044 
1045     if (ivSize != 12u)
1046     {
1047         /* if ivSize is not 12 bytes, we have to compute GF128 hash to get the initial counter J0 */
1048         uint8_t ivBlkZero[16] = {0};
1049 
1050         *(volatile uint8_t *)((uint32_t)base) = (uint8_t)kAES_CfgSwapIntextHashIn;
1051         while (ivSize >= 16u)
1052         {
1053             aes_gcm_one_block_input_only(base, iv);
1054             iv += 16;
1055             ivSize -= 16u;
1056         }
1057         if (ivSize != 0U)
1058         {
1059             (void)aes_memcpy(ivBlkZero, iv, ivSize);
1060             aes_gcm_one_block_input_only(base, ivBlkZero);
1061         }
1062 
1063         (void)aes_memcpy(ivBlkZero, blkZero, 16);
1064         aes_set_unaligned_from_word(swap_bytes(8U * saveIvSize), &ivBlkZero[12]);
1065         aes_gcm_one_block_input_only(base, ivBlkZero);
1066 
1067         aes_get_gf128(base, blkJ0);
1068         aes_gcm_incr32(blkJ0);
1069 
1070         /* put back the hash sub-key. this will abort running GF128, because we have to start new GF128 again for AAD
1071          * and C */
1072         *(volatile uint8_t *)((uint32_t)base) = (uint8_t)
1073             kAES_CfgIntextSwap; /* do not swap OUTTEXT, as OUTTEXT is copied for further use into GF128_Y register */
1074         *(volatile uint16_t *)(((uint32_t)base + 2u)) = (uint16_t)kAES_CfgEncryptEcb;
1075         aes_gcm_one_block_input_only(base, blkZero);
1076         aes_command(base, AES_CMD_COPY_TO_Y(1));
1077     }
1078     else
1079     {
1080         (void)aes_memcpy(blkJ0, iv, 12);
1081         blkJ0[15] = 0x02U; /* add one to Counter for the first encryption with plaintext - see GCM specification */
1082     }
1083 
1084     /* process all AAD as GF128 of INTEXT, pad to full 16-bytes block with zeroes */
1085     if (aadSize != 0U)
1086     {
1087         *(volatile uint8_t *)((uint32_t)base) = (uint8_t)kAES_CfgSwapIntextHashIn;
1088         while (aadSize >= 16u)
1089         {
1090             aes_gcm_one_block_input_only(base, aad);
1091             aad += 16;
1092             aadSize -= 16u;
1093         }
1094         if (aadSize != 0U)
1095         {
1096             uint8_t aadBlkZero[16] = {0};
1097             (void)aes_memcpy(aadBlkZero, aad, aadSize);
1098             aes_gcm_one_block_input_only(base, aadBlkZero);
1099         }
1100     }
1101 
1102     /* switch to EnryptDecryptHash, Hash of OUTTEXT, EncryptDecrypt in GCM mode */
1103     /* Process all plaintext, pad to full 16-bytes block with zeroes */
1104     if (encryptMode == kAES_ModeEncrypt)
1105     {
1106         *(volatile uint8_t *)((uint32_t)base) =
1107             (uint8_t)kAES_CfgSwapEnDecHashOut; /* Encrypt operation adds output to hash */
1108     }
1109     else
1110     {
1111         *(volatile uint8_t *)((uint32_t)base) =
1112             (uint8_t)kAES_CfgSwapEnDecHashIn; /* Decrypt operation adds input to hash */
1113     }
1114 
1115     *(volatile uint16_t *)(((uint32_t)base + 2u)) = (uint16_t) /*kAES_CfgCryptGcmTag*/ kAES_CfgCryptCtr;
1116 
1117     aes_set_holding(base, blkJ0);
1118 
1119     /* set counter increment by one */
1120     base->CTR_INCR = 0x1U;
1121 
1122     if (inputSize != 0U)
1123     {
1124         /* full 16-byte blocks */
1125         while (inputSize >= 16u)
1126         {
1127             aes_one_block(base, dst, src);
1128             inputSize -= 16u;
1129             src += 16;
1130             dst += 16;
1131         }
1132         /* last incomplete block. output shall be padded. */
1133         if (inputSize != 0U)
1134         {
1135             if (encryptMode == kAES_ModeEncrypt)
1136             {
1137                 uint8_t outputBlkZero[16] = {0};
1138 
1139                 /* I need to pad ciphertext, so I turn off the hash, and after I have ciphertext, I pad it with zeroes
1140                  * and hash manually */
1141                 *(volatile uint8_t *)((uint32_t)base) = (uint8_t)kAES_CfgSwap;
1142                 (void)aes_memcpy(lastBlock, src, inputSize);
1143                 aes_one_block(base, lastBlock, lastBlock);
1144                 (void)aes_memcpy(dst, lastBlock, inputSize);
1145                 /* pad the last output block with zeroes and add it to GF128 hash */
1146                 (void)aes_memcpy(outputBlkZero, lastBlock, inputSize);
1147                 *(volatile uint8_t *)((uint32_t)base) = (uint8_t)kAES_CfgSwapIntextHashIn;
1148                 aes_gcm_one_block_input_only(base, outputBlkZero);
1149             }
1150             else
1151             {
1152                 (void)aes_memcpy(lastBlock, src, inputSize);
1153                 aes_one_block(base, lastBlock, lastBlock);
1154                 (void)aes_memcpy(dst, lastBlock, inputSize);
1155             }
1156         }
1157     }
1158 
1159     /* Process AAD len plus Ciphertext len */
1160     *(volatile uint8_t *)((uint32_t)base)         = (uint8_t)kAES_CfgIntextSwap;
1161     *(volatile uint16_t *)(((uint32_t)base + 2u)) = (uint16_t)kAES_CfgEncryptEcb;
1162     aes_gcm_dec32(blkJ0);
1163     aes_gcm_one_block_input_only(base, blkJ0);
1164     *(volatile uint8_t *)((uint32_t)base) = (uint8_t)kAES_CfgSwapIntextHashIn;
1165     if (saveSize != 0U)
1166     {
1167         aes_set_unaligned_from_word(swap_bytes(saveSize * 8u), &blkZero[12]);
1168     }
1169     if (saveAadSize != 0U)
1170     {
1171         aes_set_unaligned_from_word(swap_bytes(saveAadSize * 8u), &blkZero[4]);
1172     }
1173     aes_gcm_one_block_input_only(base, blkZero); /* len(A) || len(C) */
1174     aes_gcm_get_tag(base, blkTag);
1175 
1176     if ((tag != NULL) && (tagSize != 0U))
1177     {
1178         if (encryptMode == kAES_ModeEncrypt)
1179         {
1180             (void)aes_memcpy(tag, blkTag, tagSize);
1181         }
1182         else
1183         {
1184             size_t i       = 0;
1185             uint32_t equal = 0;
1186             uint32_t chXor;
1187 
1188             while (i < tagSize)
1189             {
1190                 chXor = ((uint32_t)tag[i] ^ (uint32_t)blkTag[i]);
1191                 equal |= chXor;
1192                 i++;
1193             }
1194 
1195             if (equal != 0U)
1196             {
1197                 status = kStatus_Fail;
1198             }
1199         }
1200     }
1201 
1202     return status;
1203 }
1204 
1205 /*!
1206  * brief Encrypts AES and tags using GCM block mode.
1207  *
1208  * Encrypts AES and optionally tags using GCM block mode. If plaintext is NULL, only the GHASH is calculated and output
1209  * in the 'tag' field.
1210  *
1211  * param base AES peripheral base address
1212  * param plaintext Input plain text to encrypt
1213  * param[out] ciphertext Output cipher text.
1214  * param size Size of input and output data in bytes
1215  * param iv Input initial vector
1216  * param ivSize Size of the IV
1217  * param aad Input additional authentication data
1218  * param aadSize Input size in bytes of AAD
1219  * param[out] tag Output hash tag. Set to NULL to skip tag processing.
1220  * param tagSize Input size of the tag to generate, in bytes. Must be 4,8,12,13,14,15 or 16.
1221  * return Status from encrypt operation
1222  */
AES_EncryptTagGcm(AES_Type * base,const uint8_t * plaintext,uint8_t * ciphertext,size_t size,const uint8_t * iv,size_t ivSize,const uint8_t * aad,size_t aadSize,uint8_t * tag,size_t tagSize)1223 status_t AES_EncryptTagGcm(AES_Type *base,
1224                            const uint8_t *plaintext,
1225                            uint8_t *ciphertext,
1226                            size_t size,
1227                            const uint8_t *iv,
1228                            size_t ivSize,
1229                            const uint8_t *aad,
1230                            size_t aadSize,
1231                            uint8_t *tag,
1232                            size_t tagSize)
1233 {
1234     status_t status;
1235     status =
1236         aes_gcm_process(base, kAES_ModeEncrypt, plaintext, size, iv, ivSize, aad, aadSize, ciphertext, tag, tagSize);
1237     return status;
1238 }
1239 
1240 /*!
1241  * brief Decrypts AES and authenticates using GCM block mode.
1242  *
1243  * Decrypts AES and optionally authenticates using GCM block mode. If ciphertext is NULL, only the GHASH is calculated
1244  * and compared with the received GHASH in 'tag' field.
1245  *
1246  * param base AES peripheral base address
1247  * param ciphertext Input cipher text to decrypt
1248  * param[out] plaintext Output plain text.
1249  * param size Size of input and output data in bytes
1250  * param iv Input initial vector
1251  * param ivSize Size of the IV
1252  * param aad Input additional authentication data
1253  * param aadSize Input size in bytes of AAD
1254  * param tag Input hash tag to compare. Set to NULL to skip tag processing.
1255  * param tagSize Input size of the tag, in bytes. Must be 4, 8, 12, 13, 14, 15, or 16.
1256  * return Status from decrypt operation
1257  */
AES_DecryptTagGcm(AES_Type * base,const uint8_t * ciphertext,uint8_t * plaintext,size_t size,const uint8_t * iv,size_t ivSize,const uint8_t * aad,size_t aadSize,const uint8_t * tag,size_t tagSize)1258 status_t AES_DecryptTagGcm(AES_Type *base,
1259                            const uint8_t *ciphertext,
1260                            uint8_t *plaintext,
1261                            size_t size,
1262                            const uint8_t *iv,
1263                            size_t ivSize,
1264                            const uint8_t *aad,
1265                            size_t aadSize,
1266                            const uint8_t *tag,
1267                            size_t tagSize)
1268 {
1269     uint8_t temp_tag[16] = {0}; /* max. octet length of MAC (tag) is 16 */
1270     uint8_t *tag_ptr;
1271     status_t status;
1272 
1273     tag_ptr = NULL;
1274     if (tag != NULL)
1275     {
1276         (void)aes_memcpy(temp_tag, tag, tagSize);
1277         tag_ptr = &temp_tag[0];
1278     }
1279 
1280     status = aes_gcm_process(base, kAES_ModeDecrypt, ciphertext, size, iv, ivSize, aad, aadSize, plaintext, tag_ptr,
1281                              tagSize);
1282     return status;
1283 }
1284