1 /*
2  * Copyright 2017-2019 NXP
3  * All rights reserved.
4  *
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_dcp.h"
10 #if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
11 #include "fsl_cache.h"
12 #endif
13 
14 /*******************************************************************************
15  * Definitions
16  ******************************************************************************/
17 
18 /* Component ID definition, used by tools. */
19 #ifndef FSL_COMPONENT_ID
20 #define FSL_COMPONENT_ID "platform.drivers.dcp"
21 #endif
22 
23 /*! Compile time sizeof() check */
24 #define BUILD_ASSURE(condition, msg) extern int msg[1 - 2 * (!(condition))] __attribute__((unused))
25 
26 #define dcp_memcpy memcpy
27 
28 /*! Internal states of the HASH creation process */
29 typedef enum _dcp_hash_algo_state
30 {
31     kDCP_StateHashInit = 1u, /*!< Init state. */
32     kDCP_StateHashUpdate,    /*!< Update state. */
33 } dcp_hash_algo_state_t;
34 
35 /*! multiple of 64-byte block represented as byte array of 32-bit words */
36 typedef union _dcp_hash_block
37 {
38     uint32_t w[DCP_HASH_BLOCK_SIZE / 4]; /*!< array of 32-bit words */
39     uint8_t b[DCP_HASH_BLOCK_SIZE];      /*!< byte array */
40 } dcp_hash_block_t;
41 
42 /*! internal dcp_hash context structure */
43 typedef struct _dcp_hash_ctx_internal
44 {
45     dcp_hash_block_t blk;            /*!< memory buffer. only full blocks are written to DCP during hash updates */
46     size_t blksz;                    /*!< number of valid bytes in memory buffer */
47     dcp_hash_algo_t algo;            /*!< selected algorithm from the set of supported algorithms */
48     dcp_hash_algo_state_t fsm_state; /*!< finite machine state of the hash software process */
49     uint32_t fullMessageSize;        /*!< track message size */
50     uint32_t ctrl0;                  /*!< HASH_INIT and HASH_TERM flags */
51     uint32_t runningHash[9];         /*!< running hash. up to SHA-256 plus size, that is 36 bytes. */
52     dcp_handle_t *handle;
53 } dcp_hash_ctx_internal_t;
54 
55 /*!< SHA-1/SHA-2 digest length in bytes  */
56 enum _dcp_hash_digest_len
57 {
58     kDCP_OutLenSha1   = 20u,
59     kDCP_OutLenSha256 = 32u,
60     kDCP_OutLenCrc32  = 4u,
61 };
62 
63 enum _dcp_work_packet_bit_definitions
64 {
65     kDCP_CONTROL0_DECR_SEMAPHOR      = 1u << 1,  /* DECR_SEMAPHOR */
66     kDCP_CONTROL0_ENABLE_HASH        = 1u << 6,  /* ENABLE_HASH */
67     kDCP_CONTROL0_HASH_INIT          = 1u << 12, /* HASH_INIT */
68     kDCP_CONTROL0_HASH_TERM          = 1u << 13, /* HASH_TERM */
69     kDCP_CONTROL1_HASH_SELECT_SHA256 = 2u << 16,
70     kDCP_CONTROL1_HASH_SELECT_SHA1   = 0u << 16,
71     kDCP_CONTROL1_HASH_SELECT_CRC32  = 1u << 16,
72 };
73 
74 /*! 64-byte block represented as byte array of 16 32-bit words */
75 typedef union _dcp_sha_block
76 {
77     uint32_t w[64 / 4]; /*!< array of 32-bit words */
78     uint8_t b[64];      /*!< byte array */
79 } dcp_sha_block_t;
80 
81 #if defined(DCP_HASH_CAVP_COMPATIBLE)
82 /* result of sha1 hash for message with zero size */
83 static uint8_t s_nullSha1[] = {0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55,
84                                0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09};
85 /* result of sha256 hash for message with zero size */
86 static uint8_t s_nullSha256[] = {0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4,
87                                  0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b,
88                                  0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55};
89 #endif /* DCP_HASH_CAVP_COMPATIBLE */
90 
91 /*******************************************************************************
92  * Variables
93  ******************************************************************************/
94 AT_NONCACHEABLE_SECTION_INIT(static dcp_context_t s_dcpContextSwitchingBuffer);
95 
96 /*******************************************************************************
97  * Code
98  ******************************************************************************/
99 #if defined(__GNUC__)
100 /* Disable optimizations for GCC to prevent instruction reordering */
101 #pragma GCC push_options
102 #pragma GCC optimize("-O0")
103 #endif
104 
dcp_reverse_and_copy(uint8_t * src,uint8_t * dest,size_t src_len)105 static void dcp_reverse_and_copy(uint8_t *src, uint8_t *dest, size_t src_len)
106 {
107     for (uint32_t i = 0; i < src_len; i++)
108     {
109         dest[i] = src[src_len - 1U - i];
110     }
111 }
112 
113 #if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
DCP_FindCacheLine(uint8_t * dcpWorkExt)114 static inline uint32_t *DCP_FindCacheLine(uint8_t *dcpWorkExt)
115 {
116     while (0U != ((uint32_t)dcpWorkExt & ((uint32_t)FSL_FEATURE_L1DCACHE_LINESIZE_BYTE - 1U)))
117     {
118         dcpWorkExt++;
119     }
120     return (uint32_t *)(uint32_t)dcpWorkExt;
121 }
122 #endif
123 
dcp_get_channel_status(DCP_Type * base,dcp_channel_t channel)124 static status_t dcp_get_channel_status(DCP_Type *base, dcp_channel_t channel)
125 {
126     uint32_t statReg = 0;
127     uint32_t semaReg = 0;
128     status_t status  = kStatus_Fail;
129 
130     switch (channel)
131     {
132         case kDCP_Channel0:
133             statReg = base->CH0STAT;
134             semaReg = base->CH0SEMA;
135             break;
136 
137         case kDCP_Channel1:
138             statReg = base->CH1STAT;
139             semaReg = base->CH1SEMA;
140             break;
141 
142         case kDCP_Channel2:
143             statReg = base->CH2STAT;
144             semaReg = base->CH2SEMA;
145             break;
146 
147         case kDCP_Channel3:
148             statReg = base->CH3STAT;
149             semaReg = base->CH3SEMA;
150             break;
151 
152         default:
153             /* All the cases have been listed above, the default clause should not be reached. */
154             break;
155     }
156 
157     if (!((0U != (semaReg & DCP_CH0SEMA_VALUE_MASK)) || (0U != (statReg & DCP_CH0STAT_ERROR_CODE_MASK))))
158     {
159         status = kStatus_Success;
160     }
161 
162     return status;
163 }
164 
dcp_clear_status(DCP_Type * base)165 static void dcp_clear_status(DCP_Type *base)
166 {
167     volatile uint32_t *dcpStatClrPtr = (volatile uint32_t *)&base->STAT + 2u;
168     *dcpStatClrPtr                   = 0xFFu;
169 
170     while ((base->STAT & 0xffu) != 0U)
171     {
172     }
173 }
174 
dcp_clear_channel_status(DCP_Type * base,uint32_t mask)175 static void dcp_clear_channel_status(DCP_Type *base, uint32_t mask)
176 {
177     volatile uint32_t *chStatClrPtr;
178 
179     if (0U != (mask & (uint32_t)kDCP_Channel0))
180     {
181         chStatClrPtr  = &base->CH0STAT_CLR;
182         *chStatClrPtr = 0xFFu;
183     }
184     if (0U != (mask & (uint32_t)kDCP_Channel1))
185     {
186         chStatClrPtr  = &base->CH1STAT_CLR;
187         *chStatClrPtr = 0xFFu;
188     }
189     if (0U != (mask & (uint32_t)kDCP_Channel2))
190     {
191         chStatClrPtr  = &base->CH2STAT_CLR;
192         *chStatClrPtr = 0xFFu;
193     }
194     if (0U != (mask & (uint32_t)kDCP_Channel3))
195     {
196         chStatClrPtr  = &base->CH3STAT_CLR;
197         *chStatClrPtr = 0xFFu;
198     }
199 }
200 
dcp_aes_set_sram_based_key(DCP_Type * base,dcp_handle_t * handle,const uint8_t * key)201 static status_t dcp_aes_set_sram_based_key(DCP_Type *base, dcp_handle_t *handle, const uint8_t *key)
202 {
203     base->KEY = DCP_KEY_INDEX(handle->keySlot) | DCP_KEY_SUBWORD(0);
204     /* move the key by 32-bit words */
205     int i          = 0;
206     size_t keySize = 16u;
207     while (keySize != 0U)
208     {
209         keySize -= sizeof(uint32_t);
210         base->KEYDATA = ((uint32_t *)(uintptr_t)key)[i];
211         i++;
212     }
213     return kStatus_Success;
214 }
215 
dcp_schedule_work(DCP_Type * base,dcp_handle_t * handle,dcp_work_packet_t * dcpPacket)216 static status_t dcp_schedule_work(DCP_Type *base, dcp_handle_t *handle, dcp_work_packet_t *dcpPacket)
217 {
218     status_t status;
219 
220     /* check if our channel is active */
221     if ((base->STAT & (uint32_t)handle->channel) != (uint32_t)handle->channel)
222     {
223         /* disable global interrupt */
224         uint32_t currPriMask = DisableGlobalIRQ();
225 
226         /* re-check if our channel is still available */
227         if ((base->STAT & (uint32_t)handle->channel) == 0U)
228         {
229             volatile uint32_t *cmdptr = NULL;
230             volatile uint32_t *chsema = NULL;
231 
232             switch (handle->channel)
233             {
234                 case kDCP_Channel0:
235                     cmdptr = &base->CH0CMDPTR;
236                     chsema = &base->CH0SEMA;
237                     break;
238 
239                 case kDCP_Channel1:
240                     cmdptr = &base->CH1CMDPTR;
241                     chsema = &base->CH1SEMA;
242                     break;
243 
244                 case kDCP_Channel2:
245                     cmdptr = &base->CH2CMDPTR;
246                     chsema = &base->CH2SEMA;
247                     break;
248 
249                 case kDCP_Channel3:
250                     cmdptr = &base->CH3CMDPTR;
251                     chsema = &base->CH3SEMA;
252                     break;
253 
254                 default:
255                     /* All the cases have been listed above, the default clause should not be reached. */
256                     break;
257             }
258 
259             if ((NULL != cmdptr) && (NULL != chsema))
260             {
261                 /* set out packet to DCP CMDPTR */
262                 *cmdptr = (uint32_t)dcpPacket;
263 
264 #if defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
265                 /* Clean DCACHE before sending DCP packet to engine */
266                 DCACHE_CleanByRange((uint32_t)dcpPacket, sizeof(dcp_work_packet_t));
267 #endif
268                 /* Make sure that all data memory accesses are completed before starting of the job */
269                 __DSB();
270                 __ISB();
271 
272                 /* set the channel semaphore to start the job */
273                 *chsema = 1u;
274             }
275 
276             status = kStatus_Success;
277         }
278 
279         else
280         {
281             status = (int32_t)kStatus_DCP_Again;
282         }
283         /* global interrupt enable */
284         EnableGlobalIRQ(currPriMask);
285     }
286 
287     else
288     {
289         return (int32_t)kStatus_DCP_Again;
290     }
291 
292     return status;
293 }
294 #if defined(__GNUC__)
295 #pragma GCC pop_options
296 #endif
297 
298 /*!
299  * brief Set AES key to dcp_handle_t struct and optionally to DCP.
300  *
301  * Sets the AES key for encryption/decryption with the dcp_handle_t structure.
302  * The dcp_handle_t input argument specifies keySlot.
303  * If the keySlot is kDCP_OtpKey, the function will check the OTP_KEY_READY bit and will return it's ready to use
304  * status.
305  * For other keySlot selections, the function will copy and hold the key in dcp_handle_t struct.
306  * If the keySlot is one of the four DCP SRAM-based keys (one of kDCP_KeySlot0, kDCP_KeySlot1, kDCP_KeySlot2,
307  * kDCP_KeySlot3),
308  * this function will also load the supplied key to the specified keySlot in DCP.
309  *
310  * param   base DCP peripheral base address.
311  * param   handle Handle used for the request.
312  * param   key 0-mod-4 aligned pointer to AES key.
313  * param   keySize AES key size in bytes. Shall equal 16.
314  * return  status from set key operation
315  */
DCP_AES_SetKey(DCP_Type * base,dcp_handle_t * handle,const uint8_t * key,size_t keySize)316 status_t DCP_AES_SetKey(DCP_Type *base, dcp_handle_t *handle, const uint8_t *key, size_t keySize)
317 {
318     status_t status = kStatus_Fail;
319 
320     if ((kDCP_OtpKey == handle->keySlot) || (kDCP_OtpUniqueKey == handle->keySlot))
321     {
322         /* for AES OTP and unique key, check and return read from fuses status */
323         if ((base->STAT & DCP_STAT_OTP_KEY_READY_MASK) == DCP_STAT_OTP_KEY_READY_MASK)
324         {
325             status = kStatus_Success;
326         }
327     }
328     else
329     {
330         /* only work with aligned key[] */
331         if ((0x3U & (uintptr_t)key) != 0U)
332         {
333             return kStatus_InvalidArgument;
334         }
335 
336         /* keySize must be 16. */
337         if (keySize != 16U)
338         {
339             return kStatus_InvalidArgument;
340         }
341 
342         /* move the key by 32-bit words */
343         int i = 0;
344         while (keySize != 0U)
345         {
346             keySize -= sizeof(uint32_t);
347             handle->keyWord[i] = ((uint32_t *)(uintptr_t)key)[i];
348             i++;
349         }
350 
351         if (kDCP_PayloadKey != handle->keySlot)
352         {
353             /* move the key by 32-bit words to DCP SRAM-based key storage */
354             status = dcp_aes_set_sram_based_key(base, handle, key);
355         }
356         else
357         {
358             /* for PAYLOAD_KEY, just return Ok status now */
359             status = kStatus_Success;
360         }
361     }
362 
363     return status;
364 }
365 
366 /*!
367  * brief Encrypts AES on one or multiple 128-bit block(s).
368  *
369  * Encrypts AES.
370  * The source plaintext and destination ciphertext can overlap in system memory.
371  *
372  * param base DCP peripheral base address
373  * param handle Handle used for this request.
374  * param plaintext Input plain text to encrypt
375  * param[out] ciphertext Output cipher text
376  * param size Size of input and output data in bytes. Must be multiple of 16 bytes.
377  * return Status from encrypt operation
378  */
DCP_AES_EncryptEcb(DCP_Type * base,dcp_handle_t * handle,const uint8_t * plaintext,uint8_t * ciphertext,size_t size)379 status_t DCP_AES_EncryptEcb(
380     DCP_Type *base, dcp_handle_t *handle, const uint8_t *plaintext, uint8_t *ciphertext, size_t size)
381 {
382     status_t completionStatus = kStatus_Fail;
383 
384     /* Use extended  DCACHE line size aligned structure */
385 #if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
386     dcp_work_packet_t *dcpWork;
387     uint8_t dcpWorkExt[sizeof(dcp_work_packet_t) + FSL_FEATURE_L1DCACHE_LINESIZE_BYTE] = {0U};
388     dcpWork = (dcp_work_packet_t *)(uint32_t)DCP_FindCacheLine(dcpWorkExt);
389 #else
390     dcp_work_packet_t dcpWorkPacket = {0};
391     dcp_work_packet_t *dcpWork      = &dcpWorkPacket;
392 #endif
393 
394     do
395     {
396         completionStatus = DCP_AES_EncryptEcbNonBlocking(base, handle, dcpWork, plaintext, ciphertext, size);
397     } while (completionStatus == (int32_t)kStatus_DCP_Again);
398 
399     if (completionStatus != kStatus_Success)
400     {
401         return completionStatus;
402     }
403 
404     return DCP_WaitForChannelComplete(base, handle);
405 }
406 
407 /*!
408  * brief Encrypts AES using the ECB block mode.
409  *
410  * Puts AES ECB encrypt work packet to DCP channel.
411  *
412  * param base DCP peripheral base address
413  * param handle Handle used for this request.
414  * param[out] dcpPacket Memory for the DCP work packet.
415  * param plaintext Input plain text to encrypt.
416  * param[out] ciphertext Output cipher text
417  * param size Size of input and output data in bytes. Must be multiple of 16 bytes.
418  * return kStatus_Success The work packet has been scheduled at DCP channel.
419  * return kStatus_DCP_Again The DCP channel is busy processing previous request.
420  */
DCP_AES_EncryptEcbNonBlocking(DCP_Type * base,dcp_handle_t * handle,dcp_work_packet_t * dcpPacket,const uint8_t * plaintext,uint8_t * ciphertext,size_t size)421 status_t DCP_AES_EncryptEcbNonBlocking(DCP_Type *base,
422                                        dcp_handle_t *handle,
423                                        dcp_work_packet_t *dcpPacket,
424                                        const uint8_t *plaintext,
425                                        uint8_t *ciphertext,
426                                        size_t size)
427 {
428     /* Size must be 16-byte multiple */
429     if ((size < 16u) || (0U != (size % 16u)))
430     {
431         return kStatus_InvalidArgument;
432     }
433 
434     dcpPacket->control0 =
435         0x122u | (handle->swapConfig & 0xFC0000u); /* CIPHER_ENCRYPT | ENABLE_CIPHER | DECR_SEMAPHORE */
436     dcpPacket->sourceBufferAddress      = (uint32_t)plaintext;
437     dcpPacket->destinationBufferAddress = (uint32_t)ciphertext;
438     dcpPacket->bufferSize               = (uint32_t)size;
439 
440     if (handle->keySlot == kDCP_OtpKey)
441     {
442         dcpPacket->control0 |= ((uint32_t)1u << 10);  /* OTP_KEY */
443         dcpPacket->control1 = ((uint32_t)0xFFu << 8); /* KEY_SELECT = OTP_KEY */
444     }
445     else if (handle->keySlot == kDCP_OtpUniqueKey)
446     {
447         dcpPacket->control0 |= ((uint32_t)1u << 10);  /* OTP_KEY */
448         dcpPacket->control1 = ((uint32_t)0xFEu << 8); /* KEY_SELECT = UNIQUE_KEY */
449     }
450     else if (handle->keySlot == kDCP_PayloadKey)
451     {
452         /* ECB does not have IV, so we can point payload directly to keyWord[] stored in handle. */
453         dcpPacket->payloadPointer = (uint32_t)&handle->keyWord[0];
454         dcpPacket->control0 |= ((uint32_t)1u << 11); /* PAYLOAD_KEY */
455     }
456     else
457     {
458         dcpPacket->control1 = ((uint32_t)handle->keySlot << 8); /* KEY_SELECT = keySlot */
459     }
460 
461     return dcp_schedule_work(base, handle, dcpPacket);
462 }
463 
464 /*!
465  * brief Decrypts AES on one or multiple 128-bit block(s).
466  *
467  * Decrypts AES.
468  * The source ciphertext and destination plaintext can overlap in system memory.
469  *
470  * param base DCP peripheral base address
471  * param handle Handle used for this request.
472  * param ciphertext Input plain text to encrypt
473  * param[out] plaintext Output cipher text
474  * param size Size of input and output data in bytes. Must be multiple of 16 bytes.
475  * return Status from decrypt operation
476  */
DCP_AES_DecryptEcb(DCP_Type * base,dcp_handle_t * handle,const uint8_t * ciphertext,uint8_t * plaintext,size_t size)477 status_t DCP_AES_DecryptEcb(
478     DCP_Type *base, dcp_handle_t *handle, const uint8_t *ciphertext, uint8_t *plaintext, size_t size)
479 {
480     status_t completionStatus = kStatus_Fail;
481 
482     /* Use extended  DCACHE line size aligned structure */
483 #if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
484     dcp_work_packet_t *dcpWork;
485     uint8_t dcpWorkExt[sizeof(dcp_work_packet_t) + FSL_FEATURE_L1DCACHE_LINESIZE_BYTE] = {0U};
486     dcpWork = (dcp_work_packet_t *)(uint32_t)DCP_FindCacheLine(dcpWorkExt);
487 #else
488     dcp_work_packet_t dcpWorkPacket = {0};
489     dcp_work_packet_t *dcpWork      = &dcpWorkPacket;
490 #endif
491 
492     do
493     {
494         completionStatus = DCP_AES_DecryptEcbNonBlocking(base, handle, dcpWork, ciphertext, plaintext, size);
495     } while (completionStatus == (int32_t)(kStatus_DCP_Again));
496 
497     if (completionStatus != kStatus_Success)
498     {
499         return completionStatus;
500     }
501 
502     return DCP_WaitForChannelComplete(base, handle);
503 }
504 
505 /*!
506  * brief Decrypts AES using ECB block mode.
507  *
508  * Puts AES ECB decrypt dcpPacket to DCP input job ring.
509  *
510  * param base DCP peripheral base address
511  * param handle Handle used for this request.
512  * param[out] dcpPacket Memory for the DCP work packet.
513  * param ciphertext Input cipher text to decrypt
514  * param[out] plaintext Output plain text
515  * param size Size of input and output data in bytes. Must be multiple of 16 bytes.
516  * return kStatus_Success The work packet has been scheduled at DCP channel.
517  * return kStatus_DCP_Again The DCP channel is busy processing previous request.
518  */
DCP_AES_DecryptEcbNonBlocking(DCP_Type * base,dcp_handle_t * handle,dcp_work_packet_t * dcpPacket,const uint8_t * ciphertext,uint8_t * plaintext,size_t size)519 status_t DCP_AES_DecryptEcbNonBlocking(DCP_Type *base,
520                                        dcp_handle_t *handle,
521                                        dcp_work_packet_t *dcpPacket,
522                                        const uint8_t *ciphertext,
523                                        uint8_t *plaintext,
524                                        size_t size)
525 {
526     /* Size must be 16-byte multiple */
527     if ((size < 16u) || (0U != (size % 16u)))
528     {
529         return kStatus_InvalidArgument;
530     }
531 
532     dcpPacket->control0                 = 0x22u | (handle->swapConfig & 0xFC0000u); /* ENABLE_CIPHER | DECR_SEMAPHORE */
533     dcpPacket->sourceBufferAddress      = (uint32_t)ciphertext;
534     dcpPacket->destinationBufferAddress = (uint32_t)plaintext;
535     dcpPacket->bufferSize               = (uint32_t)size;
536 
537     if (handle->keySlot == kDCP_OtpKey)
538     {
539         dcpPacket->control0 |= ((uint32_t)1u << 10);  /* OTP_KEY */
540         dcpPacket->control1 = ((uint32_t)0xFFu << 8); /* KEY_SELECT = OTP_KEY */
541     }
542     else if (handle->keySlot == kDCP_OtpUniqueKey)
543     {
544         dcpPacket->control0 |= ((uint32_t)1u << 10);  /* OTP_KEY */
545         dcpPacket->control1 = ((uint32_t)0xFEu << 8); /* KEY_SELECT = UNIQUE_KEY */
546     }
547     else if (handle->keySlot == kDCP_PayloadKey)
548     {
549         /* ECB does not have IV, so we can point payload directly to keyWord[] stored in handle. */
550         dcpPacket->payloadPointer = (uint32_t)&handle->keyWord[0];
551         dcpPacket->control0 |= ((uint32_t)1u << 11); /* PAYLOAD_KEY */
552     }
553     else
554     {
555         dcpPacket->control1 = ((uint32_t)handle->keySlot << 8); /* KEY_SELECT = keySlot */
556     }
557 
558     return dcp_schedule_work(base, handle, dcpPacket);
559 }
560 
561 /*!
562  * brief Encrypts AES using CBC block mode.
563  *
564  * Encrypts AES using CBC block mode.
565  * The source plaintext and destination ciphertext can overlap in system memory.
566  *
567  * param base DCP peripheral base address
568  * param handle Handle used for this request.
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  */
DCP_AES_EncryptCbc(DCP_Type * base,dcp_handle_t * handle,const uint8_t * plaintext,uint8_t * ciphertext,size_t size,const uint8_t iv[16])575 status_t DCP_AES_EncryptCbc(DCP_Type *base,
576                             dcp_handle_t *handle,
577                             const uint8_t *plaintext,
578                             uint8_t *ciphertext,
579                             size_t size,
580                             const uint8_t iv[16])
581 {
582     status_t completionStatus = kStatus_Fail;
583 
584     /* Use extended  DCACHE line size aligned structure */
585 #if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
586     dcp_work_packet_t *dcpWork;
587     uint8_t dcpWorkExt[sizeof(dcp_work_packet_t) + FSL_FEATURE_L1DCACHE_LINESIZE_BYTE] = {0U};
588     dcpWork = (dcp_work_packet_t *)(uint32_t)DCP_FindCacheLine(dcpWorkExt);
589 #else
590     dcp_work_packet_t dcpWorkPacket = {0};
591     dcp_work_packet_t *dcpWork      = &dcpWorkPacket;
592 #endif
593 
594     do
595     {
596         completionStatus = DCP_AES_EncryptCbcNonBlocking(base, handle, dcpWork, plaintext, ciphertext, size, iv);
597     } while (completionStatus == (int32_t)kStatus_DCP_Again);
598 
599     if (completionStatus != kStatus_Success)
600     {
601         return completionStatus;
602     }
603 
604     return DCP_WaitForChannelComplete(base, handle);
605 }
606 
607 /*!
608  * brief Encrypts AES using CBC block mode.
609  *
610  * Puts AES CBC encrypt dcpPacket to DCP input job ring.
611  *
612  * param base DCP peripheral base address
613  * param handle Handle used for this request. Specifies jobRing.
614  * param[out] dcpPacket Memory for the DCP work packet.
615  * param plaintext Input plain text to encrypt
616  * param[out] ciphertext Output cipher text
617  * param size Size of input and output data in bytes. Must be multiple of 16 bytes.
618  * param iv Input initial vector to combine with the first input block.
619  * return kStatus_Success The work packet has been scheduled at DCP channel.
620  * return kStatus_DCP_Again The DCP channel is busy processing previous request.
621  */
DCP_AES_EncryptCbcNonBlocking(DCP_Type * base,dcp_handle_t * handle,dcp_work_packet_t * dcpPacket,const uint8_t * plaintext,uint8_t * ciphertext,size_t size,const uint8_t * iv)622 status_t DCP_AES_EncryptCbcNonBlocking(DCP_Type *base,
623                                        dcp_handle_t *handle,
624                                        dcp_work_packet_t *dcpPacket,
625                                        const uint8_t *plaintext,
626                                        uint8_t *ciphertext,
627                                        size_t size,
628                                        const uint8_t *iv)
629 {
630     /* Size must be 16-byte multiple */
631     if ((size < 16u) || (0U != (size % 16u)))
632     {
633         return kStatus_InvalidArgument;
634     }
635 
636     dcpPacket->control0 =
637         0x322u | (handle->swapConfig & 0xFC0000u); /* CIPHER_INIT | CIPHER_ENCRYPT | ENABLE_CIPHER | DECR_SEMAPHORE */
638     dcpPacket->control1                 = 0x10u;   /* CBC */
639     dcpPacket->sourceBufferAddress      = (uint32_t)plaintext;
640     dcpPacket->destinationBufferAddress = (uint32_t)ciphertext;
641     dcpPacket->bufferSize               = (uint32_t)size;
642 
643     if (handle->keySlot == kDCP_OtpKey)
644     {
645         dcpPacket->payloadPointer = (uint32_t)iv;
646         dcpPacket->control0 |= ((uint32_t)1u << 10);   /* OTP_KEY */
647         dcpPacket->control1 |= ((uint32_t)0xFFu << 8); /* KEY_SELECT = OTP_KEY */
648     }
649     else if (handle->keySlot == kDCP_OtpUniqueKey)
650     {
651         dcpPacket->payloadPointer = (uint32_t)iv;
652         dcpPacket->control0 |= ((uint32_t)1u << 10);   /* OTP_KEY */
653         dcpPacket->control1 |= ((uint32_t)0xFEu << 8); /* KEY_SELECT = UNIQUE_KEY */
654     }
655     else if (handle->keySlot == kDCP_PayloadKey)
656     {
657         /* In this case payload must contain key & iv in one array. */
658         /* Copy iv into handle right behind the keyWord[] so we can point payload to keyWord[]. */
659         (void)dcp_memcpy(handle->iv, (const uint32_t *)(uintptr_t)iv, 16);
660         dcpPacket->payloadPointer = (uint32_t)&handle->keyWord[0];
661         dcpPacket->control0 |= ((uint32_t)1u << 11); /* PAYLOAD_KEY */
662     }
663     else
664     {
665         dcpPacket->payloadPointer = (uint32_t)iv;
666         dcpPacket->control1 |= ((uint32_t)handle->keySlot << 8); /* KEY_SELECT = keySlot */
667     }
668 
669     return dcp_schedule_work(base, handle, dcpPacket);
670 }
671 
672 /*!
673  * brief Decrypts AES using CBC block mode.
674  *
675  * Decrypts AES using CBC block mode.
676  * The source ciphertext and destination plaintext can overlap in system memory.
677  *
678  * param base DCP peripheral base address
679  * param handle Handle used for this request.
680  * param ciphertext Input cipher text to decrypt
681  * param[out] plaintext Output plain text
682  * param size Size of input and output data in bytes. Must be multiple of 16 bytes.
683  * param iv Input initial vector to combine with the first input block.
684  * return Status from decrypt operation
685  */
DCP_AES_DecryptCbc(DCP_Type * base,dcp_handle_t * handle,const uint8_t * ciphertext,uint8_t * plaintext,size_t size,const uint8_t iv[16])686 status_t DCP_AES_DecryptCbc(DCP_Type *base,
687                             dcp_handle_t *handle,
688                             const uint8_t *ciphertext,
689                             uint8_t *plaintext,
690                             size_t size,
691                             const uint8_t iv[16])
692 {
693     status_t completionStatus = kStatus_Fail;
694 
695     /* Use extended  DCACHE line size aligned structure */
696 #if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
697     dcp_work_packet_t *dcpWork;
698     uint8_t dcpWorkExt[sizeof(dcp_work_packet_t) + FSL_FEATURE_L1DCACHE_LINESIZE_BYTE] = {0U};
699     dcpWork = (dcp_work_packet_t *)(uint32_t)DCP_FindCacheLine(dcpWorkExt);
700 #else
701     dcp_work_packet_t dcpWorkPacket = {0};
702     dcp_work_packet_t *dcpWork      = &dcpWorkPacket;
703 #endif
704 
705     do
706     {
707         completionStatus = DCP_AES_DecryptCbcNonBlocking(base, handle, dcpWork, ciphertext, plaintext, size, iv);
708     } while (completionStatus == (int32_t)kStatus_DCP_Again);
709 
710     if (completionStatus != (int32_t)kStatus_Success)
711     {
712         return completionStatus;
713     }
714 
715     return DCP_WaitForChannelComplete(base, handle);
716 }
717 
718 /*!
719  * brief Decrypts AES using CBC block mode.
720  *
721  * Puts AES CBC decrypt dcpPacket to DCP input job ring.
722  *
723  * param base DCP peripheral base address
724  * param handle Handle used for this request. Specifies jobRing.
725  * param[out] dcpPacket Memory for the DCP work packet.
726  * param ciphertext Input cipher text to decrypt
727  * param[out] plaintext Output plain text
728  * param size Size of input and output data in bytes. Must be multiple of 16 bytes.
729  * param iv Input initial vector to combine with the first input block.
730  * return kStatus_Success The work packet has been scheduled at DCP channel.
731  * return kStatus_DCP_Again The DCP channel is busy processing previous request.
732  */
DCP_AES_DecryptCbcNonBlocking(DCP_Type * base,dcp_handle_t * handle,dcp_work_packet_t * dcpPacket,const uint8_t * ciphertext,uint8_t * plaintext,size_t size,const uint8_t * iv)733 status_t DCP_AES_DecryptCbcNonBlocking(DCP_Type *base,
734                                        dcp_handle_t *handle,
735                                        dcp_work_packet_t *dcpPacket,
736                                        const uint8_t *ciphertext,
737                                        uint8_t *plaintext,
738                                        size_t size,
739                                        const uint8_t *iv)
740 {
741     /* Size must be 16-byte multiple */
742     if ((size < 16u) || (0U != (size % 16u)))
743     {
744         return kStatus_InvalidArgument;
745     }
746 
747     dcpPacket->control0 = 0x222u | (handle->swapConfig & 0xFC0000u); /* CIPHER_INIT | ENABLE_CIPHER | DECR_SEMAPHORE */
748     dcpPacket->control1 = 0x10u;                                     /* CBC */
749     dcpPacket->sourceBufferAddress      = (uint32_t)ciphertext;
750     dcpPacket->destinationBufferAddress = (uint32_t)plaintext;
751     dcpPacket->bufferSize               = (uint32_t)size;
752 
753     if (handle->keySlot == kDCP_OtpKey)
754     {
755         dcpPacket->payloadPointer = (uint32_t)iv;
756         dcpPacket->control0 |= ((uint32_t)1u << 10);   /* OTP_KEY */
757         dcpPacket->control1 |= ((uint32_t)0xFFu << 8); /* OTP_KEY */
758     }
759     else if (handle->keySlot == kDCP_OtpUniqueKey)
760     {
761         dcpPacket->payloadPointer = (uint32_t)iv;
762         dcpPacket->control0 |= ((uint32_t)1u << 10);   /* OTP_KEY */
763         dcpPacket->control1 |= ((uint32_t)0xFEu << 8); /* UNIQUE_KEY */
764     }
765     else if (handle->keySlot == kDCP_PayloadKey)
766     {
767         /* in this case payload must contain KEY + IV together */
768         /* copy iv into handle struct so we can point payload directly to keyWord[]. */
769         (void)dcp_memcpy(handle->iv, (const uint32_t *)(uintptr_t)iv, 16);
770         dcpPacket->payloadPointer = (uint32_t)&handle->keyWord[0];
771         dcpPacket->control0 |= ((uint32_t)1u << 11); /* PAYLOAD_KEY */
772     }
773     else
774     {
775         dcpPacket->payloadPointer = (uint32_t)iv;
776         dcpPacket->control1 |= ((uint32_t)handle->keySlot << 8); /* KEY_SELECT */
777     }
778 
779     return dcp_schedule_work(base, handle, dcpPacket);
780 }
781 
782 /*!
783  * brief Gets the default configuration structure.
784  *
785  * This function initializes the DCP configuration structure to a default value. The default
786  * values are as follows.
787  *   dcpConfig->gatherResidualWrites = true;
788  *   dcpConfig->enableContextCaching = true;
789  *   dcpConfig->enableContextSwitching = true;
790  *   dcpConfig->enableChannnel = kDCP_chEnableAll;
791  *   dcpConfig->enableChannelInterrupt = kDCP_chIntDisable;
792  *
793  * param[out] config Pointer to configuration structure.
794  */
DCP_GetDefaultConfig(dcp_config_t * config)795 void DCP_GetDefaultConfig(dcp_config_t *config)
796 {
797     /* ENABLE_CONTEXT_CACHING is disabled by default as the DCP Hash driver uses
798      * dcp_hash_save_running_hash() and dcp_hash_restore_running_hash() to support
799      * Hash context switch (different messages interleaved) on the same channel.
800      */
801 
802     /* Initializes the configure structure to zero. */
803     (void)memset(config, 0, sizeof(*config));
804 
805     dcp_config_t userConfig = {
806         true, false, true, (uint8_t)kDCP_chEnableAll, (uint8_t)kDCP_chIntDisable,
807     };
808 
809     *config = userConfig;
810 }
811 
812 /*!
813  * brief   Enables clock to and enables DCP
814  *
815  * Enable DCP clock and configure DCP.
816  *
817  * param base DCP base address
818  * param config Pointer to configuration structure.
819  */
DCP_Init(DCP_Type * base,const dcp_config_t * config)820 void DCP_Init(DCP_Type *base, const dcp_config_t *config)
821 {
822 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
823     CLOCK_EnableClock(kCLOCK_Dcp);
824 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
825 
826     base->CTRL = 0xF0800000u; /* reset value */
827     base->CTRL = 0x30800000u; /* default value */
828 
829     dcp_clear_status(base);
830     dcp_clear_channel_status(
831         base, (uint32_t)kDCP_Channel0 | (uint32_t)kDCP_Channel1 | (uint32_t)kDCP_Channel2 | (uint32_t)kDCP_Channel3);
832 
833     base->CTRL = DCP_CTRL_GATHER_RESIDUAL_WRITES(config->gatherResidualWrites) |
834                  DCP_CTRL_ENABLE_CONTEXT_CACHING(config->enableContextCaching) |
835                  DCP_CTRL_ENABLE_CONTEXT_SWITCHING(config->enableContextSwitching) |
836                  DCP_CTRL_CHANNEL_INTERRUPT_ENABLE(config->enableChannelInterrupt);
837 
838     /* enable DCP channels */
839     base->CHANNELCTRL = DCP_CHANNELCTRL_ENABLE_CHANNEL(config->enableChannel);
840 
841     /* use context switching buffer */
842     base->CONTEXT = (uint32_t)&s_dcpContextSwitchingBuffer;
843 }
844 
845 /*!
846  * brief   Disable DCP clock
847  *
848  * Reset DCP and Disable DCP clock.
849  *
850  * param base DCP base address
851  */
DCP_Deinit(DCP_Type * base)852 void DCP_Deinit(DCP_Type *base)
853 {
854     base->CTRL = 0xF0800000u; /* reset value */
855     (void)memset(&s_dcpContextSwitchingBuffer, 0, sizeof(s_dcpContextSwitchingBuffer));
856 
857 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
858     CLOCK_DisableClock(kCLOCK_Dcp);
859 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
860 }
861 
862 /*!
863  * brief Poll and wait on DCP channel.
864  *
865  * Polls the specified DCP channel until current it completes activity.
866  *
867  * param   base DCP peripheral base address.
868  * param   handle Specifies DCP channel.
869  * return  kStatus_Success When data processing completes without error.
870  * return  kStatus_Fail When error occurs.
871  */
DCP_WaitForChannelComplete(DCP_Type * base,dcp_handle_t * handle)872 status_t DCP_WaitForChannelComplete(DCP_Type *base, dcp_handle_t *handle)
873 {
874     /* wait if our channel is still active */
875     while ((base->STAT & (uint32_t)handle->channel) == (uint32_t)handle->channel)
876     {
877     }
878 
879     if (dcp_get_channel_status(base, handle->channel) != kStatus_Success)
880     {
881         dcp_clear_status(base);
882         dcp_clear_channel_status(base, (uint32_t)handle->channel);
883         return kStatus_Fail;
884     }
885 
886     dcp_clear_status(base);
887     return kStatus_Success;
888 }
889 
890 /*!
891  * @brief Check validity of algoritm.
892  *
893  * This function checks the validity of input argument.
894  *
895  * @param algo Tested algorithm value.
896  * @return kStatus_Success if valid, kStatus_InvalidArgument otherwise.
897  */
dcp_hash_check_input_alg(dcp_hash_algo_t algo)898 static status_t dcp_hash_check_input_alg(dcp_hash_algo_t algo)
899 {
900     if ((algo != kDCP_Sha256) && (algo != kDCP_Sha1) && (algo != kDCP_Crc32))
901     {
902         return kStatus_InvalidArgument;
903     }
904     return kStatus_Success;
905 }
906 
907 /*!
908  * @brief Check validity of input arguments.
909  *
910  * This function checks the validity of input arguments.
911  *
912  * @param base DCP peripheral base address.
913  * @param ctx Memory buffer given by user application where the DCP_HASH_Init/DCP_HASH_Update/DCP_HASH_Finish store
914  * context.
915  * @param algo Tested algorithm value.
916  * @return kStatus_Success if valid, kStatus_InvalidArgument otherwise.
917  */
dcp_hash_check_input_args(DCP_Type * base,dcp_hash_ctx_t * ctx,dcp_hash_algo_t algo)918 static status_t dcp_hash_check_input_args(DCP_Type *base, dcp_hash_ctx_t *ctx, dcp_hash_algo_t algo)
919 {
920     /* Check validity of input algorithm */
921     if (kStatus_Success != dcp_hash_check_input_alg(algo))
922     {
923         return kStatus_InvalidArgument;
924     }
925 
926     if ((NULL == ctx) || (NULL == base))
927     {
928         return kStatus_InvalidArgument;
929     }
930 
931     return kStatus_Success;
932 }
933 
934 /*!
935  * @brief Check validity of internal software context.
936  *
937  * This function checks if the internal context structure looks correct.
938  *
939  * @param ctxInternal Internal context.
940  * @param message Input message address.
941  * @return kStatus_Success if valid, kStatus_InvalidArgument otherwise.
942  */
dcp_hash_check_context(dcp_hash_ctx_internal_t * ctxInternal,const uint8_t * message)943 static status_t dcp_hash_check_context(dcp_hash_ctx_internal_t *ctxInternal, const uint8_t *message)
944 {
945     if ((NULL == message) || (NULL == ctxInternal) || (kStatus_Success != dcp_hash_check_input_alg(ctxInternal->algo)))
946     {
947         return kStatus_InvalidArgument;
948     }
949 
950     return kStatus_Success;
951 }
952 
953 /*!
954  * @brief Initialize the SHA engine for new hash.
955  *
956  * This function sets kDCP_CONTROL0_HASH_INIT for control0 in work packet to start a new hash.
957  *
958  * @param base SHA peripheral base address.
959  * @param ctxInternal Internal context.
960  */
dcp_hash_engine_init(DCP_Type * base,dcp_hash_ctx_internal_t * ctxInternal)961 static status_t dcp_hash_engine_init(DCP_Type *base, dcp_hash_ctx_internal_t *ctxInternal)
962 {
963     status_t status;
964 
965     status = kStatus_InvalidArgument;
966 
967     if ((kDCP_Sha256 == ctxInternal->algo) || (kDCP_Sha1 == ctxInternal->algo) || (kDCP_Crc32 == ctxInternal->algo))
968     {
969         ctxInternal->ctrl0 = (uint32_t)kDCP_CONTROL0_HASH_INIT;
970         status             = kStatus_Success;
971     }
972 
973     return status;
974 }
975 
dcp_hash_update_non_blocking(DCP_Type * base,dcp_hash_ctx_internal_t * ctxInternal,dcp_work_packet_t * dcpPacket,const uint8_t * msg,size_t size)976 static status_t dcp_hash_update_non_blocking(
977     DCP_Type *base, dcp_hash_ctx_internal_t *ctxInternal, dcp_work_packet_t *dcpPacket, const uint8_t *msg, size_t size)
978 {
979     dcpPacket->control0 = ctxInternal->ctrl0 | (ctxInternal->handle->swapConfig & 0xFC0000u) |
980                           (uint32_t)kDCP_CONTROL0_ENABLE_HASH | (uint32_t)kDCP_CONTROL0_DECR_SEMAPHOR;
981     if (ctxInternal->algo == kDCP_Sha256)
982     {
983         dcpPacket->control1 = (uint32_t)kDCP_CONTROL1_HASH_SELECT_SHA256;
984     }
985     else if (ctxInternal->algo == kDCP_Sha1)
986     {
987         dcpPacket->control1 = (uint32_t)kDCP_CONTROL1_HASH_SELECT_SHA1;
988     }
989     else if (ctxInternal->algo == kDCP_Crc32)
990     {
991         /* In CRC-32 case if size is zero, do not schedule other computing */
992         if (size == 0U)
993         {
994 #if defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
995             /* Clear DCACHE memory before starting the engine */
996             DCACHE_CleanByRange((uint32_t)ctxInternal, sizeof(dcp_hash_ctx_internal_t));
997 #endif
998             /* Make sure that all data memory accesses are completed before starting of the job */
999             __DSB();
1000             __ISB();
1001             return kStatus_Success;
1002         }
1003         dcpPacket->control1 = (uint32_t)kDCP_CONTROL1_HASH_SELECT_CRC32;
1004     }
1005     else
1006     {
1007         return kStatus_Fail;
1008     }
1009     dcpPacket->sourceBufferAddress      = (uint32_t)msg;
1010     dcpPacket->destinationBufferAddress = 0;
1011     dcpPacket->bufferSize               = size;
1012     dcpPacket->payloadPointer           = (uint32_t)ctxInternal->runningHash;
1013 
1014 #if defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
1015     /* Clear DCACHE memory before starting the engine */
1016     DCACHE_CleanByRange((uint32_t)ctxInternal, sizeof(dcp_hash_ctx_internal_t));
1017 #endif
1018     /* Make sure that all data memory accesses are completed before starting of the job */
1019     __DSB();
1020     __ISB();
1021 
1022     return dcp_schedule_work(base, ctxInternal->handle, dcpPacket);
1023 }
1024 
dcp_hash_update(DCP_Type * base,dcp_hash_ctx_internal_t * ctxInternal,const uint8_t * msg,size_t size)1025 static status_t dcp_hash_update(DCP_Type *base, dcp_hash_ctx_internal_t *ctxInternal, const uint8_t *msg, size_t size)
1026 {
1027     status_t completionStatus = kStatus_Fail;
1028 
1029     /* Use extended  DCACHE line size aligned structure */
1030 #if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
1031     dcp_work_packet_t *dcpWork;
1032     uint8_t dcpWorkExt[sizeof(dcp_work_packet_t) + FSL_FEATURE_L1DCACHE_LINESIZE_BYTE] = {0U};
1033     dcpWork = (dcp_work_packet_t *)(uint32_t)DCP_FindCacheLine(dcpWorkExt);
1034 #else
1035     dcp_work_packet_t dcpWorkPacket = {0};
1036     dcp_work_packet_t *dcpWork      = &dcpWorkPacket;
1037 #endif
1038 
1039     do
1040     {
1041         completionStatus = dcp_hash_update_non_blocking(base, ctxInternal, dcpWork, msg, size);
1042     } while (completionStatus == (int32_t)kStatus_DCP_Again);
1043 
1044     completionStatus = DCP_WaitForChannelComplete(base, ctxInternal->handle);
1045 
1046     ctxInternal->ctrl0 = 0; /* clear kDCP_CONTROL0_HASH_INIT and kDCP_CONTROL0_HASH_TERM flags */
1047     return (completionStatus);
1048 }
1049 
1050 /*!
1051  * @brief Adds message to current hash.
1052  *
1053  * This function merges the message to fill the internal buffer, empties the internal buffer if
1054  * it becomes full, then process all remaining message data.
1055  *
1056  *
1057  * @param base DCP peripheral base address.
1058  * @param ctxInternal Internal context.
1059  * @param message Input message.
1060  * @param messageSize Size of input message in bytes.
1061  * @return kStatus_Success.
1062  */
dcp_hash_process_message_data(DCP_Type * base,dcp_hash_ctx_internal_t * ctxInternal,const uint8_t * message,size_t messageSize)1063 static status_t dcp_hash_process_message_data(DCP_Type *base,
1064                                               dcp_hash_ctx_internal_t *ctxInternal,
1065                                               const uint8_t *message,
1066                                               size_t messageSize)
1067 {
1068     status_t status = kStatus_Fail;
1069 
1070     /* if there is partially filled internal buffer, fill it to full block */
1071     if (ctxInternal->blksz > 0U)
1072     {
1073         size_t toCopy = DCP_HASH_BLOCK_SIZE - ctxInternal->blksz;
1074         (void)dcp_memcpy(&ctxInternal->blk.b[ctxInternal->blksz], message, toCopy);
1075         message += toCopy;
1076         messageSize -= toCopy;
1077 
1078         /* process full internal block */
1079         status = dcp_hash_update(base, ctxInternal, &ctxInternal->blk.b[0], DCP_HASH_BLOCK_SIZE);
1080         if (kStatus_Success != status)
1081         {
1082             return status;
1083         }
1084     }
1085 
1086     /* process all full blocks in message[] */
1087     uint32_t fullBlocksSize = ((messageSize >> 6) << 6); /* (X / 64) * 64 */
1088     if (fullBlocksSize > 0U)
1089     {
1090         status = dcp_hash_update(base, ctxInternal, message, fullBlocksSize);
1091         if (kStatus_Success != status)
1092         {
1093             return status;
1094         }
1095         message += fullBlocksSize;
1096         messageSize -= fullBlocksSize;
1097     }
1098 
1099     /* copy last incomplete message bytes into internal block */
1100     (void)dcp_memcpy(&ctxInternal->blk.b[0], message, messageSize);
1101     ctxInternal->blksz = messageSize;
1102 
1103     return status;
1104 }
1105 
1106 /*!
1107  * @brief Finalize the running hash to make digest.
1108  *
1109  * This function empties the internal buffer, adds padding bits, and generates final digest.
1110  *
1111  * @param base SHA peripheral base address.
1112  * @param ctxInternal Internal context.
1113  * @return kStatus_Success.
1114  */
dcp_hash_finalize(DCP_Type * base,dcp_hash_ctx_internal_t * ctxInternal)1115 static status_t dcp_hash_finalize(DCP_Type *base, dcp_hash_ctx_internal_t *ctxInternal)
1116 {
1117     status_t status;
1118 
1119     ctxInternal->ctrl0 |= (uint32_t)kDCP_CONTROL0_HASH_TERM;
1120     status = dcp_hash_update(base, ctxInternal, &ctxInternal->blk.b[0], ctxInternal->blksz);
1121 
1122     return status;
1123 }
1124 
dcp_hash_save_running_hash(dcp_hash_ctx_internal_t * ctxInternal)1125 static void dcp_hash_save_running_hash(dcp_hash_ctx_internal_t *ctxInternal)
1126 {
1127     uint32_t *srcAddr = NULL;
1128 
1129     switch (ctxInternal->handle->channel)
1130     {
1131         case kDCP_Channel0:
1132             srcAddr = &s_dcpContextSwitchingBuffer.x[43];
1133             break;
1134 
1135         case kDCP_Channel1:
1136             srcAddr = &s_dcpContextSwitchingBuffer.x[30];
1137             break;
1138 
1139         case kDCP_Channel2:
1140             srcAddr = &s_dcpContextSwitchingBuffer.x[17];
1141             break;
1142 
1143         case kDCP_Channel3:
1144             srcAddr = &s_dcpContextSwitchingBuffer.x[4];
1145             break;
1146 
1147         default:
1148             /* All the cases have been listed above, the default clause should not be reached. */
1149             break;
1150     }
1151     if (srcAddr != NULL)
1152     {
1153         DCACHE_InvalidateByRange((uint32_t)srcAddr, sizeof(ctxInternal->runningHash));
1154         (void)dcp_memcpy(ctxInternal->runningHash, srcAddr, sizeof(ctxInternal->runningHash));
1155     }
1156 }
1157 
dcp_hash_restore_running_hash(dcp_hash_ctx_internal_t * ctxInternal)1158 static void dcp_hash_restore_running_hash(dcp_hash_ctx_internal_t *ctxInternal)
1159 {
1160     uint32_t *destAddr = NULL;
1161 
1162     switch (ctxInternal->handle->channel)
1163     {
1164         case kDCP_Channel0:
1165             destAddr = &s_dcpContextSwitchingBuffer.x[43];
1166             break;
1167 
1168         case kDCP_Channel1:
1169             destAddr = &s_dcpContextSwitchingBuffer.x[30];
1170             break;
1171 
1172         case kDCP_Channel2:
1173             destAddr = &s_dcpContextSwitchingBuffer.x[17];
1174             break;
1175 
1176         case kDCP_Channel3:
1177             destAddr = &s_dcpContextSwitchingBuffer.x[4];
1178             break;
1179 
1180         default:
1181             /* No valid channel */
1182             break;
1183     }
1184     if (destAddr != NULL)
1185     {
1186         (void)dcp_memcpy(destAddr, ctxInternal->runningHash, sizeof(ctxInternal->runningHash));
1187     }
1188 }
1189 
1190 /*!
1191  * brief Initialize HASH context
1192  *
1193  * This function initializes the HASH.
1194  *
1195  * param base DCP peripheral base address
1196  * param handle Specifies the DCP channel used for hashing.
1197  * param[out] ctx Output hash context
1198  * param algo Underlaying algorithm to use for hash computation.
1199  * return Status of initialization
1200  */
DCP_HASH_Init(DCP_Type * base,dcp_handle_t * handle,dcp_hash_ctx_t * ctx,dcp_hash_algo_t algo)1201 status_t DCP_HASH_Init(DCP_Type *base, dcp_handle_t *handle, dcp_hash_ctx_t *ctx, dcp_hash_algo_t algo)
1202 {
1203     status_t status;
1204 
1205     dcp_hash_ctx_internal_t *ctxInternal;
1206     /* Align structure on DCACHE line*/
1207 #if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
1208     ctxInternal = (dcp_hash_ctx_internal_t *)(uint32_t)((uint8_t *)ctx + FSL_FEATURE_L1DCACHE_LINESIZE_BYTE);
1209 #else
1210     ctxInternal                     = (dcp_hash_ctx_internal_t *)(uint32_t)ctx;
1211 #endif
1212 
1213     /* compile time check for the correct structure size */
1214     BUILD_ASSURE(sizeof(dcp_hash_ctx_t) >= sizeof(dcp_hash_ctx_internal_t), dcp_hash_ctx_t_size);
1215     uint32_t i;
1216 
1217     status = dcp_hash_check_input_args(base, ctx, algo);
1218     if (status != kStatus_Success)
1219     {
1220         return status;
1221     }
1222 
1223     /* set algorithm in context struct for later use */
1224     ctxInternal->algo  = algo;
1225     ctxInternal->blksz = 0u;
1226 
1227     const uint32_t j = sizeof(ctxInternal->blk.w) / sizeof(ctxInternal->blk.w[0]);
1228     for (i = 0; i < j; i++)
1229     {
1230         ctxInternal->blk.w[i] = 0u;
1231     }
1232     ctxInternal->fsm_state       = kDCP_StateHashInit;
1233     ctxInternal->fullMessageSize = 0;
1234     ctxInternal->handle          = handle;
1235     return status;
1236 }
1237 
1238 /*!
1239  * brief Add data to current HASH
1240  *
1241  * Add data to current HASH. This can be called repeatedly with an arbitrary amount of data to be
1242  * hashed. The functions blocks. If it returns kStatus_Success, the running hash
1243  * has been updated (DCP has processed the input data), so the memory at ref input pointer
1244  * can be released back to system. The DCP context buffer is updated with the running hash
1245  * and with all necessary information to support possible context switch.
1246  *
1247  * param base DCP peripheral base address
1248  * param[in,out] ctx HASH context
1249  * param input Input data
1250  * param inputSize Size of input data in bytes
1251  * return Status of the hash update operation
1252  */
DCP_HASH_Update(DCP_Type * base,dcp_hash_ctx_t * ctx,const uint8_t * input,size_t inputSize)1253 status_t DCP_HASH_Update(DCP_Type *base, dcp_hash_ctx_t *ctx, const uint8_t *input, size_t inputSize)
1254 {
1255     bool isUpdateState;
1256     status_t status;
1257     dcp_hash_ctx_internal_t *ctxInternal;
1258     size_t blockSize;
1259 
1260     /* Align structure on DCACHE line*/
1261 #if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
1262     ctxInternal = (dcp_hash_ctx_internal_t *)(uint32_t)((uint8_t *)ctx + FSL_FEATURE_L1DCACHE_LINESIZE_BYTE);
1263 #else
1264     ctxInternal                     = (dcp_hash_ctx_internal_t *)(uint32_t)ctx;
1265 #endif
1266 
1267     if (inputSize == 0U)
1268     {
1269         return kStatus_Success;
1270     }
1271 
1272     status = dcp_hash_check_context(ctxInternal, input);
1273     if (kStatus_Success != status)
1274     {
1275         return status;
1276     }
1277 
1278     ctxInternal->fullMessageSize += inputSize;
1279     blockSize = DCP_HASH_BLOCK_SIZE;
1280     /* if we are still less than DCP_HASH_BLOCK_SIZE bytes, keep only in context */
1281     if ((ctxInternal->blksz + inputSize) <= blockSize)
1282     {
1283         (void)dcp_memcpy((&ctxInternal->blk.b[0]) + ctxInternal->blksz, input, inputSize);
1284         ctxInternal->blksz += inputSize;
1285         return status;
1286     }
1287     else
1288     {
1289         isUpdateState = ctxInternal->fsm_state == kDCP_StateHashUpdate;
1290         if (!isUpdateState)
1291         {
1292             /* start NEW hash */
1293             status = dcp_hash_engine_init(base, ctxInternal);
1294             if (status != kStatus_Success)
1295             {
1296                 return status;
1297             }
1298             ctxInternal->fsm_state = kDCP_StateHashUpdate;
1299         }
1300         else
1301         {
1302             dcp_hash_restore_running_hash(ctxInternal);
1303         }
1304     }
1305 
1306     /* process input data */
1307     status = dcp_hash_process_message_data(base, ctxInternal, input, inputSize);
1308     dcp_hash_save_running_hash(ctxInternal);
1309     return status;
1310 }
1311 
1312 /*!
1313  * brief Finalize hashing
1314  *
1315  * Outputs the final hash (computed by DCP_HASH_Update()) and erases the context.
1316  *
1317  * param[in,out] ctx Input hash context
1318  * param[out] output Output hash data
1319  * param[in,out] outputSize Optional parameter (can be passed as NULL). On function entry, it specifies the size of
1320  * output[] buffer. On function return, it stores the number of updated output bytes.
1321  * return Status of the hash finish operation
1322  */
DCP_HASH_Finish(DCP_Type * base,dcp_hash_ctx_t * ctx,uint8_t * output,size_t * outputSize)1323 status_t DCP_HASH_Finish(DCP_Type *base, dcp_hash_ctx_t *ctx, uint8_t *output, size_t *outputSize)
1324 {
1325     size_t algOutSize = 0;
1326     status_t status;
1327     dcp_hash_ctx_internal_t *ctxInternal;
1328 
1329     /* Align structure on DCACHE line*/
1330 #if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
1331     ctxInternal = (dcp_hash_ctx_internal_t *)(uint32_t)((uint8_t *)ctx + FSL_FEATURE_L1DCACHE_LINESIZE_BYTE);
1332 #else
1333     ctxInternal                     = (dcp_hash_ctx_internal_t *)(uint32_t)ctx;
1334 #endif
1335 
1336     status = dcp_hash_check_context(ctxInternal, output);
1337 
1338     if (kStatus_Success != status)
1339     {
1340         return status;
1341     }
1342 
1343     if (ctxInternal->fsm_state == kDCP_StateHashInit)
1344     {
1345         status = dcp_hash_engine_init(base, ctxInternal);
1346         if (status != kStatus_Success)
1347         {
1348             return status;
1349         }
1350     }
1351     else
1352     {
1353         dcp_hash_restore_running_hash(ctxInternal);
1354     }
1355 
1356     size_t outSize = 0u;
1357 
1358     /* compute algorithm output length */
1359     switch (ctxInternal->algo)
1360     {
1361         case kDCP_Sha256:
1362             outSize = (uint32_t)kDCP_OutLenSha256;
1363             break;
1364         case kDCP_Sha1:
1365             outSize = (uint32_t)kDCP_OutLenSha1;
1366             break;
1367         case kDCP_Crc32:
1368             outSize = (uint32_t)kDCP_OutLenCrc32;
1369             break;
1370         default:
1371             /* All the cases have been listed above, the default clause should not be reached. */
1372             break;
1373     }
1374     algOutSize = outSize;
1375 
1376 #if defined(DCP_HASH_CAVP_COMPATIBLE)
1377     if (ctxInternal->fullMessageSize == 0U)
1378     {
1379         switch (ctxInternal->algo)
1380         {
1381             case kDCP_Sha256:
1382                 (void)dcp_memcpy(&output[0], &s_nullSha256, 32);
1383                 break;
1384             case kDCP_Sha1:
1385                 (void)dcp_memcpy(&output[0], &s_nullSha1, 20);
1386                 break;
1387             default:
1388                 /* All the cases have been listed above, the default clause should not be reached. */
1389                 break;
1390         }
1391 
1392         return kStatus_Success;
1393     }
1394 #endif /* DCP_HASH_CAVP_COMPATIBLE */
1395 
1396     /* flush message last incomplete block, if there is any, and add padding bits */
1397     status = dcp_hash_finalize(base, ctxInternal);
1398 
1399     if (outputSize != NULL)
1400     {
1401         if (algOutSize < *outputSize)
1402         {
1403             *outputSize = algOutSize;
1404         }
1405         else
1406         {
1407             algOutSize = *outputSize;
1408         }
1409     }
1410 
1411 #if defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
1412     DCACHE_InvalidateByRange((uint32_t)ctxInternal->runningHash, sizeof(ctxInternal->runningHash));
1413 #endif
1414     /* Reverse and copy result to output[] */
1415     dcp_reverse_and_copy((uint8_t *)ctxInternal->runningHash, &output[0], algOutSize);
1416 
1417     (void)memset(ctx, 0, sizeof(dcp_hash_ctx_t));
1418     return status;
1419 }
1420 
1421 /*!
1422  * brief Create HASH on given data
1423  *
1424  * Perform the full SHA or CRC32 in one function call. The function is blocking.
1425  *
1426  * param base DCP peripheral base address
1427  * param handle Handle used for the request.
1428  * param algo Underlaying algorithm to use for hash computation.
1429  * param input Input data
1430  * param inputSize Size of input data in bytes
1431  * param[out] output Output hash data
1432  * param[out] outputSize Output parameter storing the size of the output hash in bytes
1433  * return Status of the one call hash operation.
1434  */
DCP_HASH(DCP_Type * base,dcp_handle_t * handle,dcp_hash_algo_t algo,const uint8_t * input,size_t inputSize,uint8_t * output,size_t * outputSize)1435 status_t DCP_HASH(DCP_Type *base,
1436                   dcp_handle_t *handle,
1437                   dcp_hash_algo_t algo,
1438                   const uint8_t *input,
1439                   size_t inputSize,
1440                   uint8_t *output,
1441                   size_t *outputSize)
1442 {
1443     dcp_hash_ctx_t hashCtx = {0};
1444     status_t status;
1445 
1446     status = DCP_HASH_Init(base, handle, &hashCtx, algo);
1447     if (status != kStatus_Success)
1448     {
1449         return status;
1450     }
1451 
1452     status = DCP_HASH_Update(base, &hashCtx, input, inputSize);
1453     if (status != kStatus_Success)
1454     {
1455         return status;
1456     }
1457 
1458     status = DCP_HASH_Finish(base, &hashCtx, output, outputSize);
1459 
1460     return status;
1461 }
1462