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