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