1 /*
2 * Copyright (c) 2016, Freescale Semiconductor, Inc.
3 * Copyright 2016-2022 NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8 #include "fsl_sha.h"
9
10 /*******************************************************************************
11 * Definitions
12 *******************************************************************************/
13
14 /* Component ID definition, used by tools. */
15 #ifndef FSL_COMPONENT_ID
16 #define FSL_COMPONENT_ID "platform.drivers.sha"
17 #endif
18
19 /*!< SHA-1 and SHA-256 block size */
20 #define SHA_BLOCK_SIZE 64U
21 #define MAX_HASH_CHUNK (2048U - 1U)
22
23 /*!< Use standard C library memcpy */
24 #define sha_memcpy memcpy
25
26 /*! Internal states of the HASH creation process */
27 typedef enum _sha_algo_state
28 {
29 kSHA_HashInit = 1u, /*!< Init state, the NEW bit in SHA Control register has not been written yet. */
30 kSHA_HashUpdate, /*!< Update state, DIGEST registers contain running hash, NEW bit in SHA control register has been
31 written. */
32 kSHA_HashDone, /*!< Done state, computing of hash has been completed */
33 kSHA_HashError, /*!< Error state*/
34 } sha_algo_state_t;
35
36 /*! 64-byte block represented as byte array of 16 32-bit words */
37 typedef union _sha_hash_block
38 {
39 uint32_t w[SHA_BLOCK_SIZE / 4]; /*!< array of 32-bit words */
40 uint8_t b[SHA_BLOCK_SIZE]; /*!< byte array */
41 } sha_block_t;
42
43 /*! internal sha context structure */
44 typedef struct _sha_ctx_internal
45 {
46 sha_block_t blk; /*!< memory buffer. only full 64-byte blocks are written to SHA during hash updates */
47 size_t blksz; /*!< number of valid bytes in memory buffer */
48 sha_algo_t algo; /*!< selected algorithm from the set of supported algorithms */
49 sha_algo_state_t state; /*!< finite machine state of the hash software process */
50 size_t fullMessageSize; /*!< track message size during SHA_Update(). The value is used for padding. */
51 uint32_t remainingBlcks; /*!< number of remaining blocks to process in AHB master mode */
52 sha_callback_t hashCallback; /*!< pointer to HASH callback function */
53 void
54 *userData; /*!< user data to be passed as an argument to callback function, once callback is invoked from isr */
55 } sha_ctx_internal_t;
56
57 /*!< SHA-1 and SHA-256 digest length in bytes */
58 enum _sha_digest_len
59 {
60 kSHA_OutLenSha1 = 20u,
61 kSHA_OutLenSha256 = 32u,
62 };
63
64 /*! pointer to hash context structure used by isr */
65 static sha_ctx_t *s_shaCtx = NULL;
66
67 /*!< macro for checking build time condition. It is used to assure the sha_ctx_internal_t can fit into sha_ctx_t */
68 #define BUILD_ASSERT(condition, msg) extern int msg[1 - 2 * (!(condition))] __attribute__((unused))
69
70 /*******************************************************************************
71 * Code
72 ******************************************************************************/
73
74 /*!
75 * @brief LDM to SHA engine INDATA and ALIAS registers.
76 *
77 * This function writes 16 words starting from the src address (must be word aligned)
78 * to the dst address. Dst address does not increment (destination is peripheral module register INDATA).
79 * Src address increments to load 16 consecutive words.
80 *
81 * @param dst peripheral register address (word aligned)
82 * @param src address of the input 512-bit block (16 words) (word aligned)
83 *
84 */
85 #if defined(SHA_ALIAS_DATA_MASK)
sha_ldm_stm_16_words(SHA_Type * base,const uint32_t * src)86 __STATIC_INLINE void sha_ldm_stm_16_words(SHA_Type *base, const uint32_t *src)
87 {
88 base->INDATA = src[0];
89 for (int i = 0; i < 7; i++)
90 {
91 base->ALIAS[i] = src[i + 1];
92 }
93 src += 8u;
94 base->INDATA = src[0];
95 for (int i = 0; i < 7; i++)
96 {
97 base->ALIAS[i] = src[i + 1];
98 }
99 }
100 #else
sha_ldm_stm_16_words(volatile uint32_t * dst,const uint32_t * src)101 __STATIC_INLINE void sha_ldm_stm_16_words(volatile uint32_t *dst, const uint32_t *src)
102 {
103 for (int i = 0; i < 8; i++)
104 {
105 dst[i] = src[i];
106 }
107 src += 8u;
108 for (int i = 0; i < 8; i++)
109 {
110 dst[i] = src[i];
111 }
112 }
113 #endif
114 /*!
115 * @brief Swap bytes withing 32-bit word.
116 *
117 * This function changes endianess of a 32-bit word.
118 *
119 * @param in 32-bit unsigned integer
120 * @return 32-bit unsigned integer with different endianess (big endian to little endian and vice versa).
121 */
swap_bytes(uint32_t in)122 static uint32_t swap_bytes(uint32_t in)
123 {
124 return (((in & 0x000000ffu) << 24) | ((in & 0x0000ff00u) << 8) | ((in & 0x00ff0000u) >> 8) |
125 ((in & 0xff000000u) >> 24));
126 }
127
128 /*!
129 * @brief Check validity of algoritm.
130 *
131 * This function checks the validity of input argument.
132 *
133 * @param algo Tested algorithm value.
134 * @return kStatus_Success if valid, kStatus_InvalidArgument otherwise.
135 */
sha_check_input_alg(sha_algo_t algo)136 static status_t sha_check_input_alg(sha_algo_t algo)
137 {
138 if ((algo != kSHA_Sha1) && (algo != kSHA_Sha256))
139 {
140 return kStatus_InvalidArgument;
141 }
142 return kStatus_Success;
143 }
144
145 #if defined(FSL_FEATURE_SHA_HAS_MEMADDR_DMA) && (FSL_FEATURE_SHA_HAS_MEMADDR_DMA > 0)
146 /*!
147 * @brief Check if input data are stored in SRAMX/0.
148 *
149 * This function checks if input data are stored in SRAMX or SRAM0.
150 * The requirements for MEMADDR (pseudo DMA) are that the data are on a x4 boundary
151 * and only SRAMX and SRAM0 addresses can be used. SRAM1-SRAM3 are illegal.
152 *
153 * @param message Pointer to input data
154 * @param messageSize Message size in bytes
155 * @return kStatus_Success if valid, kStatus_InvalidArgument otherwise.
156 */
sha_check_memory_boundry(const uint8_t * message,size_t messageSize)157 static status_t sha_check_memory_boundry(const uint8_t *message, size_t messageSize)
158 {
159 #if defined(SRAMX_BASE) && defined(SRAM0_BASE) && defined(SRAMX_SIZE) && defined(SRAM0_SIZE)
160 /* Message is not in SRAMX and SRAM0*/
161 if ((((uint32_t)message + messageSize) > (SRAMX_BASE + SRAMX_SIZE)) && ((uint32_t)message < SRAM0_BASE))
162 {
163 return kStatus_Fail;
164 }
165 /* Message is in SRAM1 or higher */
166 else if (((uint32_t)message + messageSize) > (SRAM0_BASE + SRAM0_SIZE))
167 {
168 return kStatus_Fail;
169 }
170 /* Message is not 4-byte aligned */
171 else if (((uint32_t)message & 0x3U) != 0U)
172 {
173 return kStatus_Fail;
174 }
175 else
176 {
177 return kStatus_Success;
178 }
179 #else
180 return kStatus_Fail;
181 #endif /* defined(SRAMX_BASE) && defined(SRAM0_BASE) && defined(SRAMX_SIZE) && defined(SRAM0_SIZE) */
182 }
183 #endif /* defined(FSL_FEATURE_SHA_HAS_MEMADDR_DMA) && (FSL_FEATURE_SHA_HAS_MEMADDR_DMA > 0) */
184
185 /*!
186 * @brief Check validity of input arguments.
187 *
188 * This function checks the validity of input arguments.
189 *
190 * @param base SHA peripheral base address.
191 * @param ctx Memory buffer given by user application where the SHA_Init/SHA_Update/SHA_Finish store context.
192 * @param algo Tested algorithm value.
193 * @return kStatus_Success if valid, kStatus_InvalidArgument otherwise.
194 */
sha_check_input_args(SHA_Type * base,sha_ctx_t * ctx,sha_algo_t algo)195 static status_t sha_check_input_args(SHA_Type *base, sha_ctx_t *ctx, sha_algo_t algo)
196 {
197 /* Check validity of input algorithm */
198 if (kStatus_Success != sha_check_input_alg(algo))
199 {
200 return kStatus_InvalidArgument;
201 }
202
203 if ((NULL == ctx) || (NULL == base))
204 {
205 return kStatus_InvalidArgument;
206 }
207
208 return kStatus_Success;
209 }
210
211 /*!
212 * @brief Check validity of internal software context.
213 *
214 * This function checks if the internal context structure looks correct.
215 *
216 * @param ctxInternal Internal context.
217 * @param message Input message address.
218 * @return kStatus_Success if valid, kStatus_InvalidArgument otherwise.
219 */
sha_check_context(sha_ctx_internal_t * ctxInternal,const uint8_t * message)220 static status_t sha_check_context(sha_ctx_internal_t *ctxInternal, const uint8_t *message)
221 {
222 if ((NULL == message) || (NULL == ctxInternal) || (kStatus_Success != sha_check_input_alg(ctxInternal->algo)))
223 {
224 return kStatus_InvalidArgument;
225 }
226 return kStatus_Success;
227 }
228
229 /*!
230 * @brief Initialize the SHA engine for new hash.
231 *
232 * This function sets NEW and MODE fields in SHA Control register to start new hash.
233 *
234 * @param base SHA peripheral base address.
235 * @param ctxInternal Internal context.
236 */
sha_engine_init(SHA_Type * base,sha_ctx_internal_t * ctxInternal)237 static void sha_engine_init(SHA_Type *base, sha_ctx_internal_t *ctxInternal)
238 {
239 uint32_t shaCtrl;
240
241 if (kSHA_Sha1 == ctxInternal->algo)
242 {
243 shaCtrl = SHA_CTRL_MODE(1) | SHA_CTRL_NEW(1);
244 }
245 else
246 {
247 shaCtrl = SHA_CTRL_MODE(2) | SHA_CTRL_NEW(1);
248 }
249 base->CTRL = shaCtrl;
250 }
251
252 /*!
253 * @brief Load 512-bit block (16 words) into SHA engine.
254 *
255 * This function aligns the input block and moves it into SHA engine INDATA.
256 * CPU polls the WAITING bit and then moves data by using LDM and STM instructions.
257 *
258 * @param base SHA peripheral base address.
259 * @param blk 512-bit block
260 */
sha_one_block(SHA_Type * base,const uint8_t * blk)261 static void sha_one_block(SHA_Type *base, const uint8_t *blk)
262 {
263 uint32_t temp[SHA_BLOCK_SIZE / sizeof(uint32_t)];
264 const uint32_t *actBlk;
265
266 /* make sure the 512-bit block is word aligned */
267 if (((uintptr_t)blk & 0x3u) != 0U)
268 {
269 (void)sha_memcpy(temp, (const uint32_t *)(uintptr_t)blk, SHA_BLOCK_SIZE);
270 actBlk = (const uint32_t *)(uintptr_t)temp;
271 }
272 else
273 {
274 actBlk = (const uint32_t *)(uintptr_t)blk;
275 }
276
277 /* poll waiting. */
278 while (0U == (base->STATUS & SHA_STATUS_WAITING_MASK))
279 {
280 }
281 /* feed INDATA (and ALIASes). use STM instruction. */
282 #if defined(SHA_ALIAS_DATA_MASK)
283 sha_ldm_stm_16_words(base, actBlk);
284 #else
285 sha_ldm_stm_16_words(&base->INDATA[0], actBlk);
286 #endif
287 }
288
289 /*!
290 * @brief Adds message to current hash.
291 *
292 * This function merges the message to fill the internal buffer, empties the internal buffer if
293 * it becomes full, then process all remaining message data.
294 *
295 *
296 * @param base SHA peripheral base address.
297 * @param ctxInternal Internal context.
298 * @param message Input message.
299 * @param messageSize Size of input message in bytes.
300 * @return kStatus_Success.
301 */
sha_process_message_data(SHA_Type * base,sha_ctx_internal_t * ctxInternal,const uint8_t * message,size_t messageSize)302 static status_t sha_process_message_data(SHA_Type *base,
303 sha_ctx_internal_t *ctxInternal,
304 const uint8_t *message,
305 size_t messageSize)
306 {
307 /* first fill the internal buffer to full block */
308 if (ctxInternal->blksz != 0U)
309 {
310 size_t toCopy = SHA_BLOCK_SIZE - ctxInternal->blksz;
311 (void)sha_memcpy(&ctxInternal->blk.b[ctxInternal->blksz], message, toCopy);
312 message += toCopy;
313 messageSize -= toCopy;
314
315 /* process full internal block */
316 sha_one_block(base, &ctxInternal->blk.b[0]);
317 }
318
319 /* process all full blocks in message[] */
320 while (messageSize >= SHA_BLOCK_SIZE)
321 {
322 sha_one_block(base, message);
323 message += SHA_BLOCK_SIZE;
324 messageSize -= SHA_BLOCK_SIZE;
325 }
326
327 /* copy last incomplete message bytes into internal block */
328 (void)sha_memcpy(&ctxInternal->blk.b[0], message, messageSize);
329 ctxInternal->blksz = messageSize;
330 ctxInternal->state = kSHA_HashDone;
331 return kStatus_Success;
332 }
333
334 #if defined(FSL_FEATURE_SHA_HAS_MEMADDR_DMA) && (FSL_FEATURE_SHA_HAS_MEMADDR_DMA > 0)
335 #if defined(__GNUC__)
336 /* Enable optimizations for GCC - workaround for when this function hangs with -O0 */
337 #pragma GCC push_options
338 #pragma GCC optimize("-O2")
339 #endif
340 /*!
341 * @brief Adds message to current hash.
342 *
343 * This function merges the message to fill the internal buffer, empties the internal buffer if
344 * it becomes full, then process all remaining message data using AHB master mode.
345 *
346 *
347 * @param base SHA peripheral base address.
348 * @param ctxInternal Internal context.
349 * @param message Input message.
350 * @param messageSize Size of input message in bytes.
351 * @return kStatus_Success.
352 */
sha_process_message_data_master(SHA_Type * base,sha_ctx_internal_t * ctxInternal,const uint8_t * message,size_t messageSize)353 static status_t sha_process_message_data_master(SHA_Type *base,
354 sha_ctx_internal_t *ctxInternal,
355 const uint8_t *message,
356 size_t messageSize)
357 {
358 /* first fill the internal buffer to full block */
359 if (ctxInternal->blksz != 0U)
360 {
361 size_t toCopy = SHA_BLOCK_SIZE - ctxInternal->blksz;
362 (void)sha_memcpy(&ctxInternal->blk.b[ctxInternal->blksz], message, toCopy);
363 message += toCopy;
364 messageSize -= toCopy;
365
366 /* process full internal block */
367 sha_one_block(base, &ctxInternal->blk.b[0]);
368 }
369
370 /* process all full blocks in message[] */
371 if (messageSize >= SHA_BLOCK_SIZE)
372 {
373 /* poll waiting. */
374 while (0U == (base->STATUS & SHA_STATUS_WAITING_MASK))
375 {
376 }
377 /* transfer one 512-bit block manually first to workaround the silicon bug */
378 /* Disabling interrupts to ensure that MEMADDR is written within 64 cycles of writing last word to INDATA as is
379 * mentioned in errata */
380 /* disable global interrupt */
381 uint32_t currPriMask = DisableGlobalIRQ();
382 sha_one_block(base, message);
383 message += SHA_BLOCK_SIZE;
384 messageSize -= SHA_BLOCK_SIZE;
385
386 uint32_t blkNum = (messageSize >> 6); /* div by 64 bytes */
387 uint32_t blkBytes = blkNum * 64u; /* number of bytes in 64 bytes blocks */
388 base->MEMADDR = SHA_MEMADDR_BASEADDR(message);
389 base->MEMCTRL = SHA_MEMCTRL_MASTER(1) | SHA_MEMCTRL_COUNT(blkNum);
390
391 /* global interrupt enable */
392 EnableGlobalIRQ(currPriMask);
393
394 message += blkBytes;
395 messageSize -= blkBytes;
396 while (0U == (base->STATUS & SHA_STATUS_DIGEST_MASK))
397 {
398 }
399 }
400
401 /* copy last incomplete message bytes into internal block */
402 (void)sha_memcpy(&ctxInternal->blk.b[0], message, messageSize);
403 ctxInternal->blksz = messageSize;
404 ctxInternal->state = kSHA_HashDone;
405 return kStatus_Success;
406 }
407 #if defined(__GNUC__)
408 /* Disable optimizations */
409 #pragma GCC pop_options
410 #endif
411 #endif /* defined(FSL_FEATURE_SHA_HAS_MEMADDR_DMA) && (FSL_FEATURE_SHA_HAS_MEMADDR_DMA > 0) */
412
413 /*!
414 * @brief Finalize the running hash to make digest.
415 *
416 * This function empties the internal buffer, adds padding bits, and generates final digest.
417 *
418 * @param base SHA peripheral base address.
419 * @param ctxInternal Internal context.
420 * @return kStatus_Success.
421 */
sha_finalize(SHA_Type * base,sha_ctx_internal_t * ctxInternal)422 static status_t sha_finalize(SHA_Type *base, sha_ctx_internal_t *ctxInternal)
423 {
424 sha_block_t lastBlock;
425
426 (void)memset(&lastBlock, 0, sizeof(sha_block_t));
427
428 /* this is last call, so need to flush buffered message bytes along with padding */
429 if (ctxInternal->blksz <= 55u)
430 {
431 /* last data is 440 bits or less. */
432 (void)sha_memcpy(&lastBlock.b[0], &ctxInternal->blk.b[0], ctxInternal->blksz);
433 lastBlock.b[ctxInternal->blksz] = (uint8_t)0x80U;
434 lastBlock.w[SHA_BLOCK_SIZE / 4U - 1U] = swap_bytes(8u * ctxInternal->fullMessageSize);
435 sha_one_block(base, &lastBlock.b[0]);
436 }
437 else
438 {
439 if (ctxInternal->blksz < SHA_BLOCK_SIZE)
440 {
441 ctxInternal->blk.b[ctxInternal->blksz] = (uint8_t)0x80U;
442 for (uint32_t i = ctxInternal->blksz + 1u; i < SHA_BLOCK_SIZE; i++)
443 {
444 ctxInternal->blk.b[i] = 0;
445 }
446 }
447 else
448 {
449 lastBlock.b[0] = (uint8_t)0x80U;
450 }
451
452 sha_one_block(base, &ctxInternal->blk.b[0]);
453 lastBlock.w[SHA_BLOCK_SIZE / 4U - 1U] = swap_bytes(8u * ctxInternal->fullMessageSize);
454 sha_one_block(base, &lastBlock.b[0]);
455 }
456 /* poll wait for final digest */
457 while (0U == (base->STATUS & SHA_STATUS_DIGEST_MASK))
458 {
459 }
460 return kStatus_Success;
461 }
462
463 /*!
464 * @brief Read DIGEST registers.
465 *
466 * This function copies DIGEST to output buffer.
467 *
468 * @param base SHA peripheral base address.
469 * @param[out] output Output buffer.
470 * @param Number of bytes to copy.
471 * @return kStatus_Success.
472 */
sha_get_digest(SHA_Type * base,uint8_t * output,size_t outputSize)473 static void sha_get_digest(SHA_Type *base, uint8_t *output, size_t outputSize)
474 {
475 uint32_t digest[8];
476
477 for (int i = 0; i < 8; i++)
478 {
479 digest[i] = swap_bytes(base->DIGEST[i]);
480 }
481
482 if (outputSize > sizeof(digest))
483 {
484 outputSize = sizeof(digest);
485 }
486 (void)sha_memcpy(output, (const uint8_t *)digest, outputSize);
487 }
488
489 /*!
490 * brief Initialize HASH context
491 *
492 * This function initializes new hash context.
493 *
494 * param base SHA peripheral base address
495 * param[out] ctx Output hash context
496 * param algo Underlaying algorithm to use for hash computation. Either SHA-1 or SHA-256.
497 * return Status of initialization
498 */
SHA_Init(SHA_Type * base,sha_ctx_t * ctx,sha_algo_t algo)499 status_t SHA_Init(SHA_Type *base, sha_ctx_t *ctx, sha_algo_t algo)
500 {
501 status_t status;
502
503 sha_ctx_internal_t *ctxInternal;
504 /* compile time check for the correct structure size */
505 BUILD_ASSERT(sizeof(sha_ctx_t) >= sizeof(sha_ctx_internal_t), sha_ctx_t_size);
506 uint32_t i;
507
508 status = sha_check_input_args(base, ctx, algo);
509 if (status != kStatus_Success)
510 {
511 return status;
512 }
513
514 /* set algorithm in context struct for later use */
515 ctxInternal = (sha_ctx_internal_t *)(uint32_t)ctx;
516 ctxInternal->algo = algo;
517 ctxInternal->blksz = 0u;
518 size_t j;
519 j = (sizeof(ctxInternal->blk.w) / sizeof(ctxInternal->blk.w[0]));
520 for (i = 0; i < j; i++)
521 {
522 ctxInternal->blk.w[0] = 0u;
523 }
524 ctxInternal->state = kSHA_HashInit;
525 ctxInternal->fullMessageSize = 0;
526 return status;
527 }
528
529 /*!
530 * brief Add data to current HASH
531 *
532 * Add data to current HASH. This can be called repeatedly with an arbitrary amount of data to be
533 * hashed.
534 *
535 * param base SHA peripheral base address
536 * param[in,out] ctx HASH context
537 * param message Input message
538 * param messageSize Size of input message in bytes
539 * return Status of the hash update operation
540 */
SHA_Update(SHA_Type * base,sha_ctx_t * ctx,const uint8_t * message,size_t messageSize)541 status_t SHA_Update(SHA_Type *base, sha_ctx_t *ctx, const uint8_t *message, size_t messageSize)
542 {
543 bool isInitState;
544 status_t status;
545 sha_ctx_internal_t *ctxInternal;
546 size_t blockSize;
547
548 if (messageSize == 0U)
549 {
550 return kStatus_Success;
551 }
552
553 ctxInternal = (sha_ctx_internal_t *)(uint32_t)ctx;
554 status = sha_check_context(ctxInternal, message);
555 if (kStatus_Success != status)
556 {
557 ctxInternal->state = kSHA_HashError;
558 return status;
559 }
560
561 ctxInternal->fullMessageSize += messageSize;
562 blockSize = SHA_BLOCK_SIZE;
563 /* if we are still less than 64 bytes, keep only in context */
564 if ((ctxInternal->blksz + messageSize) <= blockSize)
565 {
566 (void)sha_memcpy((&ctxInternal->blk.b[0]) + ctxInternal->blksz, message, messageSize);
567 ctxInternal->blksz += messageSize;
568 return status;
569 }
570 else
571 {
572 isInitState = ctxInternal->state == kSHA_HashInit;
573 if (isInitState)
574 {
575 /* start NEW hash */
576 sha_engine_init(base, ctxInternal);
577 ctxInternal->state = kSHA_HashUpdate;
578 }
579 }
580
581 #if defined(FSL_FEATURE_SHA_HAS_MEMADDR_DMA) && (FSL_FEATURE_SHA_HAS_MEMADDR_DMA > 0)
582 /* Check if address is outisde of SRAMX or SRAM0, thus data must be loaded manually */
583 if (kStatus_Success != sha_check_memory_boundry(message, messageSize))
584 {
585 /* process message data */
586 status = sha_process_message_data(base, ctxInternal, message, messageSize);
587 }
588 /* If entirely contained in SRAMX or SRAM0, SHA engine will be set up as AHB bus master automatically
589 load blocks of memory for hashing. */
590 else
591 {
592 status = sha_process_message_data_master(base, ctxInternal, message, messageSize);
593 }
594 #else /* SHA engine does not have MEMADDR DMA, so data are processed manually */
595 status = sha_process_message_data(base, ctxInternal, message, messageSize);
596 #endif /* defined(FSL_FEATURE_SHA_HAS_MEMADDR_DMA) && (FSL_FEATURE_SHA_HAS_MEMADDR_DMA > 0) */
597 return status;
598 }
599
600 /*!
601 * brief Finalize hashing
602 *
603 * Outputs the final hash and erases the context. SHA-1 or SHA-256 padding bits are automatically added by this
604 * function.
605 *
606 * param base SHA peripheral base address
607 * param[in,out] ctx HASH context
608 * param[out] output Output hash data
609 * param[in,out] outputSize On input, determines the size of bytes of the output array. On output, tells how many bytes
610 * have been written to output.
611 * return Status of the hash finish operation
612 */
SHA_Finish(SHA_Type * base,sha_ctx_t * ctx,uint8_t * output,size_t * outputSize)613 status_t SHA_Finish(SHA_Type *base, sha_ctx_t *ctx, uint8_t *output, size_t *outputSize)
614 {
615 size_t algOutSize = 0;
616 status_t status;
617 sha_ctx_internal_t *ctxInternal;
618 uint32_t *ctxW;
619 uint32_t i;
620 volatile sha_algo_state_t tempState;
621
622 ctxInternal = (sha_ctx_internal_t *)(uint32_t)ctx;
623 status = sha_check_context(ctxInternal, output);
624 if (kStatus_Success != status)
625 {
626 return status;
627 }
628
629 tempState = ctxInternal->state;
630 if (tempState == kSHA_HashInit)
631 {
632 sha_engine_init(base, ctxInternal);
633 }
634 else
635 {
636 /* Wait for the hash to complete */
637 tempState = ctxInternal->state;
638 while (tempState != kSHA_HashDone)
639 {
640 if (tempState == kSHA_HashError)
641 {
642 return kStatus_Fail;
643 }
644 tempState = ctxInternal->state;
645 __NOP();
646 }
647 }
648
649 size_t outSize = 0u;
650
651 /* compute algorithm output length */
652 switch (ctxInternal->algo)
653 {
654 case kSHA_Sha1:
655 outSize = (uint32_t)kSHA_OutLenSha1;
656 break;
657 case kSHA_Sha256:
658 outSize = (uint32_t)kSHA_OutLenSha256;
659 break;
660 default:
661 /* No valid length*/
662 break;
663 }
664 algOutSize = outSize;
665
666 /* flush message last incomplete block, if there is any, and add padding bits */
667 status = sha_finalize(base, ctxInternal);
668
669 if (outputSize != NULL)
670 {
671 if (algOutSize < *outputSize)
672 {
673 *outputSize = algOutSize;
674 }
675 else
676 {
677 algOutSize = *outputSize;
678 }
679 }
680
681 sha_get_digest(base, &output[0], algOutSize);
682
683 ctxW = (uint32_t *)(uint32_t)ctx;
684 for (i = 0; i < SHA_CTX_SIZE; i++)
685 {
686 ctxW[i] = 0u;
687 }
688 return status;
689 }
690
691 #if defined(FSL_FEATURE_SHA_HAS_MEMADDR_DMA) && (FSL_FEATURE_SHA_HAS_MEMADDR_DMA > 0)
SHA_SetCallback(SHA_Type * base,sha_ctx_t * ctx,sha_callback_t callback,void * userData)692 void SHA_SetCallback(SHA_Type *base, sha_ctx_t *ctx, sha_callback_t callback, void *userData)
693 {
694 sha_ctx_internal_t *ctxInternal;
695
696 s_shaCtx = ctx;
697 ctxInternal = (sha_ctx_internal_t *)(uint32_t)ctx;
698 ctxInternal->hashCallback = callback;
699 ctxInternal->userData = userData;
700
701 (void)EnableIRQ(SHA_IRQn);
702 }
703
SHA_UpdateNonBlocking(SHA_Type * base,sha_ctx_t * ctx,const uint8_t * input,size_t inputSize)704 status_t SHA_UpdateNonBlocking(SHA_Type *base, sha_ctx_t *ctx, const uint8_t *input, size_t inputSize)
705 {
706 sha_ctx_internal_t *ctxInternal;
707 uint32_t numBlocks;
708 status_t status;
709
710 if (inputSize == 0U)
711 {
712 return kStatus_Success;
713 }
714
715 if (0U != ((uintptr_t)input & 0x3U))
716 {
717 return kStatus_Fail;
718 }
719
720 ctxInternal = (sha_ctx_internal_t *)(uint32_t)ctx;
721 status = sha_check_context(ctxInternal, input);
722 if (kStatus_Success != status)
723 {
724 return status;
725 }
726
727 ctxInternal->fullMessageSize = inputSize;
728 ctxInternal->remainingBlcks = inputSize / SHA_BLOCK_SIZE;
729 ctxInternal->blksz = inputSize % SHA_BLOCK_SIZE;
730
731 /* copy last incomplete block to context */
732 if ((ctxInternal->blksz > 0U) && (ctxInternal->blksz <= SHA_BLOCK_SIZE))
733 {
734 (void)sha_memcpy((&ctxInternal->blk.b[0]), input + SHA_BLOCK_SIZE * ctxInternal->remainingBlcks,
735 ctxInternal->blksz);
736 }
737
738 if (ctxInternal->remainingBlcks >= MAX_HASH_CHUNK)
739 {
740 numBlocks = MAX_HASH_CHUNK - 1U;
741 }
742 else
743 {
744 numBlocks = ctxInternal->remainingBlcks;
745 }
746 /* update remainingBlks so that ISR can run another hash if necessary */
747 ctxInternal->remainingBlcks -= numBlocks;
748
749 /* compute hash using AHB Master mode for full blocks */
750 if (numBlocks > 0U)
751 {
752 ctxInternal->state = kSHA_HashUpdate;
753 sha_engine_init(base, ctxInternal);
754
755 /* Enable digest and error interrupts and start hash */
756 base->INTENSET = SHA_STATUS_DIGEST_MASK | SHA_STATUS_ERROR_MASK;
757 base->MEMADDR = SHA_MEMADDR_BASEADDR(input);
758 base->MEMCTRL = SHA_MEMCTRL_MASTER(1) | SHA_MEMCTRL_COUNT(numBlocks);
759 }
760 /* no full blocks, invoke callback directly */
761 else
762 {
763 ctxInternal->hashCallback(base, ctx, status, ctxInternal->userData);
764 }
765
766 return status;
767 }
768 #endif /* defined(FSL_FEATURE_SHA_HAS_MEMADDR_DMA) && (FSL_FEATURE_SHA_HAS_MEMADDR_DMA > 0) */
769
SHA_ClkInit(SHA_Type * base)770 void SHA_ClkInit(SHA_Type *base)
771 {
772 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
773 /* ungate clock */
774 CLOCK_EnableClock(kCLOCK_Sha0);
775 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
776 RESET_PeripheralReset(kSHA_RST_SHIFT_RSTn);
777 }
778
SHA_ClkDeinit(SHA_Type * base)779 void SHA_ClkDeinit(SHA_Type *base)
780 {
781 RESET_PeripheralReset(kSHA_RST_SHIFT_RSTn);
782 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
783 /* gate clock */
784 CLOCK_DisableClock(kCLOCK_Sha0);
785 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
786 }
787
788 void SHA_DriverIRQHandler(void);
SHA_DriverIRQHandler(void)789 void SHA_DriverIRQHandler(void)
790 {
791 sha_ctx_internal_t *ctxInternal;
792 SHA_Type *base = SHA0;
793 uint32_t numBlocks;
794 status_t status;
795
796 ctxInternal = (sha_ctx_internal_t *)(uint32_t)s_shaCtx;
797
798 if (0U == (base->STATUS & SHA_STATUS_ERROR_MASK))
799 {
800 if (ctxInternal->remainingBlcks > 0U)
801 {
802 if (ctxInternal->remainingBlcks >= MAX_HASH_CHUNK)
803 {
804 numBlocks = MAX_HASH_CHUNK - 1U;
805 }
806 else
807 {
808 numBlocks = ctxInternal->remainingBlcks;
809 }
810 /* some blocks still remaining, update remainingBlcks for next ISR and start another hash */
811 ctxInternal->remainingBlcks -= numBlocks;
812 base->MEMCTRL = SHA_MEMCTRL_MASTER(1) | SHA_MEMCTRL_COUNT(numBlocks);
813 return;
814 }
815 /* no full blocks left, disable interrupts and AHB master mode */
816 base->INTENCLR = SHA_INTENCLR_DIGEST_MASK | SHA_INTENCLR_ERROR_MASK;
817 base->MEMCTRL = SHA_MEMCTRL_MASTER(0);
818 status = kStatus_Success;
819 }
820 else
821 {
822 status = kStatus_Fail;
823 }
824
825 /* Invoke callback if there is one */
826 if (NULL != ctxInternal->hashCallback)
827 {
828 ctxInternal->hashCallback(SHA0, s_shaCtx, status, ctxInternal->userData);
829 }
830
831 SDK_ISR_EXIT_BARRIER;
832 }
833