/* * Copyright 2017-2023 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include "fsl_hashcrypt.h" /* Component ID definition, used by tools. */ #ifndef FSL_COMPONENT_ID #define FSL_COMPONENT_ID "platform.drivers.hashcrypt" #endif /******************************************************************************* * Definitions *******************************************************************************/ /*!< SHA-1 and SHA-256 block size */ #define SHA_BLOCK_SIZE 64U /*!< max number of blocks that can be proccessed in one run (master mode) */ #define SHA_MASTER_MAX_BLOCKS 2048U /*!< max number of blocks the SHA engine can copy, starting at MEMADDR */ #define SHA_MAX_BLOCK_COUNT 2047U /*!< Use standard C library memcpy */ #define hashcrypt_memcpy memcpy /*! Internal states of the HASH creation process */ typedef enum _hashcrypt_sha_algo_state { kHASHCRYPT_HashInit = 1u, /*!< Init state, the NEW bit in SHA Control register has not been written yet. */ kHASHCRYPT_HashUpdate, /*!< Update state, DIGEST registers contain running hash, NEW bit in SHA control register has been written. */ } hashcrypt_sha_algo_state_t; /*! 64-byte block represented as byte array of 16 32-bit words */ typedef union _sha_hash_block { uint32_t w[SHA_BLOCK_SIZE / 4]; /*!< array of 32-bit words */ uint8_t b[SHA_BLOCK_SIZE]; /*!< byte array */ } hashcrypt_sha_block_t; /*! internal sha context structure */ typedef struct _hashcrypt_sha_ctx_internal { hashcrypt_sha_block_t blk; /*!< memory buffer. only full 64-byte blocks are written to SHA during hash updates */ size_t blksz; /*!< number of valid bytes in memory buffer */ hashcrypt_algo_t algo; /*!< selected algorithm from the set of supported algorithms */ hashcrypt_sha_algo_state_t state; /*!< finite machine state of the hash software process */ size_t fullMessageSize; /*!< track message size during SHA_Update(). The value is used for padding. */ uint32_t remainingBlcks; /*!< number of remaining blocks to process in AHB master mode */ hashcrypt_callback_t hashCallback; /*!< pointer to HASH callback function */ void *userData; /*!< user data to be passed as an argument to callback function, once callback is invoked from isr */ #if defined(FSL_FEATURE_HASHCRYPT_HAS_RELOAD_FEATURE) && (FSL_FEATURE_HASHCRYPT_HAS_RELOAD_FEATURE > 0) uint32_t runningHash[8]; /*!< running hash. up to SHA-256, that is 32 bytes. */ #endif } hashcrypt_sha_ctx_internal_t; #if defined(FSL_FEATURE_HASHCRYPT_HAS_RELOAD_FEATURE) && (FSL_FEATURE_HASHCRYPT_HAS_RELOAD_FEATURE > 0) #define SHA1_LEN 5u #define SHA256_LEN 8u #endif /*!< SHA-1 and SHA-256 digest length in bytes */ enum _hashcrypt_sha_digest_len { kHASHCRYPT_OutLenSha1 = 20u, kHASHCRYPT_OutLenSha256 = 32u, }; /*!< pointer to hash context structure used by isr */ static hashcrypt_hash_ctx_t *s_ctx; /*!< macro for checking build time condition. It is used to assure the hashcrypt_sha_ctx_internal_t can fit into * hashcrypt_hash_ctx_t */ #define BUILD_ASSERT(condition, msg) extern int msg[1 - 2 * (!(condition))] __attribute__((unused)) /******************************************************************************* * Code ******************************************************************************/ /*! * @brief Swap bytes withing 32-bit word. * * This function changes endianess of a 32-bit word. * * @param in 32-bit unsigned integer * @return 32-bit unsigned integer with different endianess (big endian to little endian and vice versa). */ #define swap_bytes(in) __REV(in) /*! * @brief Increment a 16 byte integer. * * This function increments by one a 16 byte integer. * * @param input Pointer to a 16 byte integer to be incremented by one. */ static void ctrIncrement(uint8_t *input) { int i = 15; while (input[i] == (uint8_t)0xFFu) { input[i] = (uint8_t)0x00u; i--; if (i < 0) { return; } } if (i >= 0) { input[i] += (uint8_t)1u; } } /*! * @brief Reads an unaligned word. * * This function creates a 32-bit word from an input array of four bytes. * * @param src Input array of four bytes. The array can start at any address in memory. * @return 32-bit unsigned int created from the input byte array. */ /* Force lower optimization for Keil, otherwise it replaces inline LDR with LDM */ #if defined(__CC_ARM) #pragma push #pragma O0 #endif static inline uint32_t hashcrypt_get_word_from_unaligned(const uint8_t *srcAddr) { #if (!(defined(__CORTEX_M)) || (defined(__CORTEX_M) && (__CORTEX_M == 0))) register const uint8_t *src = srcAddr; /* Cortex M0 does not support misaligned loads */ if (0U != ((uint32_t)src & 0x3u)) { union _align_bytes_t { uint32_t word; uint8_t byte[sizeof(uint32_t)]; } my_bytes; my_bytes.byte[0] = *src; my_bytes.byte[1] = src[1]; my_bytes.byte[2] = src[2]; my_bytes.byte[3] = src[3]; return my_bytes.word; } else { /* addr aligned to 0-modulo-4 so it is safe to type cast */ return *((const uint32_t *)(uint32_t)src); } #elif defined(__CC_ARM) /* -O3 optimization in Keil 5.15 and 5.16a uses LDM instruction here (LDM r4!, {r0}) * which is wrong, because srcAddr might be unaligned. * LDM on unaligned address causes hard-fault. in contrary, * LDR supports unaligned address on Cortex M4 */ register uint32_t retVal; __asm { LDR retVal, [srcAddr] } return retVal; #else return *((const uint32_t *)(uintptr_t)srcAddr); #endif } /* End lower optimization */ #if defined(__CC_ARM) #pragma pop #endif static status_t hashcrypt_get_key_from_unaligned_src(uint8_t *dest, const uint8_t *src, size_t size) { status_t retVal = kStatus_InvalidArgument; uint32_t i; /* destination is SDK driver internal workspace and it must be aligned */ assert(0x0u == ((uint32_t)dest & 0x1u)); if (0U != ((uint32_t)dest & 0x1u)) { return retVal; } for (i = 0; i < ((uint32_t)size / 4u); i++) { ((uint32_t *)(uintptr_t)dest)[i] = hashcrypt_get_word_from_unaligned(&src[i * sizeof(uint32_t)]); } return kStatus_Success; } /*! * @brief LDM to SHA engine INDATA and ALIAS registers. * * This function writes 16 words starting from the src address (must be word aligned) * to the dst address. Dst address does not increment (destination is peripheral module register INDATA). * Src address increments to load 16 consecutive words. * * @param dst peripheral register address (word aligned) * @param src address of the input 512-bit block (16 words) (word aligned) * */ __STATIC_FORCEINLINE void hashcrypt_sha_ldm_stm_16_words(HASHCRYPT_Type *base, const uint32_t *src) { /* Data Synchronization Barrier */ __DSB(); /* typedef struct _one_block { uint32_t a[8]; } one_block_t; volatile one_block_t *ldst = (void *)(uintptr_t)(&base->INDATA); one_block_t *lsrc = (void *)(uintptr_t)src; *ldst = lsrc[0]; *ldst = lsrc[1]; */ /* Data Synchronization Barrier prevent compiler from reordering memory write when -O2 or higher is used. */ /* The address is passed to the crypto engine for hashing below, therefore out */ /* of order memory write due to compiler optimization must be prevented. */ __DSB(); base->MEMADDR = HASHCRYPT_MEMADDR_BASE(src); base->MEMCTRL = HASHCRYPT_MEMCTRL_MASTER(1) | HASHCRYPT_MEMCTRL_COUNT(1); __DSB(); } /*! * @brief Loads data to Hashcrypt engine INDATA register. * * This function writes desired number of bytes starting from the src address * to the dst address. Dst address does not increment (destination is peripheral module register INDATA). * Src address increments to load consecutive words. * * @param src address of the input block * @param size number of bytes to write * */ __STATIC_INLINE void hashcrypt_load_data(HASHCRYPT_Type *base, uint32_t *src, size_t size) { /* 16 bytes aligned input block */ uint32_t __attribute__((aligned(4))) inAlign[HASHCRYPT_AES_BLOCK_SIZE / sizeof(uint32_t)]; uint32_t *in; uint8_t i; in = src; /* Check if address of src data is aligned */ if ((0U != ((uint32_t)in & 3U))) { for (i = 0; i < ((uint32_t)size / 4U); i++) { inAlign[i] = hashcrypt_get_word_from_unaligned((uint8_t *)&src[i]); } in = &inAlign[0]; } if (size >= sizeof(uint32_t)) { base->INDATA = in[0]; size -= sizeof(uint32_t); } for (uint32_t j = 0; j < size / 4U; j++) { base->ALIAS[j] = in[j + 1U]; } } /*! * @brief Checks availability of HW AES key. * * This function checks if the AES key is present at dedicated hardware bus * and can be used at actual security level. * * @param base HASHCRYPT peripheral base address * @param handle Handle used for this request. * @return kStatus_Success if available, kStatus_Fail otherwise. * */ static status_t hashcrypt_check_need_key(HASHCRYPT_Type *base, hashcrypt_handle_t *handle) { if (handle->keyType == kHASHCRYPT_SecretKey) { volatile uint32_t wait = 50u; /* wait until STATUS register is non-zero */ while ((wait > 0U) && (base->STATUS == 0U)) { wait--; } /* if NEEDKEY bit is not set, HW key is available */ if (0U == (base->STATUS & HASHCRYPT_STATUS_NEEDKEY_MASK)) { return kStatus_Success; } /* NEEDKEY is set, HW key is not available */ return kStatus_Fail; } else { /* in case user key is used, return success */ return kStatus_Success; } } /*! * @brief Read OUTDATA registers. * * This function copies OUTDATA to output buffer. * * @param base Hachcrypt peripheral base address. * @param[out] output Output buffer. * @param Number of bytes to copy. * @return kStatus_Success if no hashing error, kStatus_Fail otherwise. */ static status_t hashcrypt_get_data(HASHCRYPT_Type *base, uint8_t *output, size_t outputSize) { status_t status = kStatus_Fail; uint32_t digest[8]; while ((0U == (base->STATUS & HASHCRYPT_STATUS_DIGEST_MASK)) && (0U == (base->STATUS & HASHCRYPT_STATUS_ERROR_MASK))) { } if (0U == (base->STATUS & HASHCRYPT_STATUS_ERROR_MASK)) { status = kStatus_Success; } /* Data Synchronization Barrier */ __DSB(); for (int i = 0; i < 8; i++) { digest[i] = swap_bytes(base->DIGEST0[i]); } if (outputSize > sizeof(digest)) { outputSize = sizeof(digest); } (void)hashcrypt_memcpy(output, (const uint8_t *)(uintptr_t)digest, outputSize); return status; } /*! * @brief Initialize the Hashcrypt engine for new operation. * * This function sets NEW and MODE fields in Hashcrypt Control register to start new operation. * * @param base Hashcrypt peripheral base address. * @param hashcrypt_algo_t Internal context. */ static void hashcrypt_engine_init(HASHCRYPT_Type *base, hashcrypt_algo_t algo) { /* NEW bit must be set before we switch from previous mode otherwise new mode will not work correctly */ base->CTRL = HASHCRYPT_CTRL_NEW_HASH(1); base->CTRL = HASHCRYPT_CTRL_MODE(algo) | HASHCRYPT_CTRL_NEW_HASH(1); } /*! * @brief Deinitialization of the Hashcrypt engine. * * This function sets MODE field in Hashcrypt Control register to zero - disabled. * This reduces power consumption of HASHCRYPT. * * @param base Hashcrypt peripheral base address. */ static inline void hashcrypt_engine_deinit(HASHCRYPT_Type *base) { base->CTRL &= ~(HASHCRYPT_CTRL_MODE_MASK); } /*! * @brief Loads user key to INDATA register. * * This function writes user key stored in handle into HashCrypt INDATA register. * * @param base Hashcrypt peripheral base address. * @param handle Handle used for this request. */ static void hashcrypt_aes_load_userKey(HASHCRYPT_Type *base, hashcrypt_handle_t *handle) { size_t keySize = 0; switch (handle->keySize) { case kHASHCRYPT_Aes128: keySize = 16; break; case kHASHCRYPT_Aes192: keySize = 24; break; case kHASHCRYPT_Aes256: keySize = 32; break; default: /* All the cases have been listed above, the default clause should not be reached. */ break; } if (keySize == 0U) { return; } hashcrypt_load_data(base, &handle->keyWord[0], keySize); } /*! * @brief Performs AES encryption/decryption of one data block. * * This function encrypts/decrypts one block of data with specified size. * * @param base Hashcrypt peripheral base address. * @param input input data * @param output output data * @param size size of data block to process in bytes (must be 16bytes multiple). */ static status_t hashcrypt_aes_one_block_aligned(HASHCRYPT_Type *base, const uint8_t *input, uint8_t *output, size_t size) { status_t status = kStatus_Fail; uint32_t idx = 0; base->MEMADDR = HASHCRYPT_MEMADDR_BASE(input); base->MEMCTRL = HASHCRYPT_MEMCTRL_MASTER(1) | HASHCRYPT_MEMCTRL_COUNT(size / 16U); while (size >= HASHCRYPT_AES_BLOCK_SIZE) { /* Get result */ while ((0U == (base->STATUS & HASHCRYPT_STATUS_DIGEST_MASK)) && (0U == (base->STATUS & HASHCRYPT_STATUS_ERROR_MASK))) { } for (int i = 0; i < 4; i++) { ((uint32_t *)(uintptr_t)output + idx)[i] = swap_bytes(base->DIGEST0[i]); } idx += HASHCRYPT_AES_BLOCK_SIZE / 4U; size -= HASHCRYPT_AES_BLOCK_SIZE; } if (0U == (base->STATUS & HASHCRYPT_STATUS_ERROR_MASK)) { status = kStatus_Success; } return status; } /*! * @brief Performs AES encryption/decryption of one data block. * * This function encrypts/decrypts one block of data with specified size. * * @param base Hashcrypt peripheral base address. * @param input input data * @param output output data * @param size size of data block to process in bytes (must be 16bytes multiple). */ static status_t hashcrypt_aes_one_block_unaligned(HASHCRYPT_Type *base, const uint8_t *input, uint8_t *output, size_t size) { status_t status = kStatus_Fail; /* we use AHB master mode as much as possible */ /* however, it can work only with aligned input data */ /* so, if unaligned, we do memcpy to temp buffer on stack, which is aligned, and use AHB mode to read data in */ /* then we read data back to it and do memcpy to the output buffer */ uint32_t temp[256 / sizeof(uint32_t)]; int cnt = 0; while (size != 0U) { size_t actSz = size >= 256u ? 256u : size; size_t actSzOrig = actSz; /* Memcpy input not typecast; see memcpy *important* note in hashcrypt_sha_one_block() */ (void)hashcrypt_memcpy(temp, (input + 256 * cnt), actSz); size -= actSz; base->MEMADDR = HASHCRYPT_MEMADDR_BASE(temp); base->MEMCTRL = HASHCRYPT_MEMCTRL_MASTER(1) | HASHCRYPT_MEMCTRL_COUNT(actSz / 16U); uint32_t outidx = 0; while (actSz != 0U) { while ((0U == (base->STATUS & HASHCRYPT_STATUS_DIGEST_MASK)) && (0U == (base->STATUS & HASHCRYPT_STATUS_ERROR_MASK))) { } for (int i = 0; i < 4; i++) { (temp + outidx)[i] = swap_bytes(base->DIGEST0[i]); } outidx += HASHCRYPT_AES_BLOCK_SIZE / 4U; actSz -= HASHCRYPT_AES_BLOCK_SIZE; } (void)hashcrypt_memcpy(output + 256 * cnt, (const uint8_t *)(uintptr_t)temp, actSzOrig); cnt++; } if (0U == (base->STATUS & HASHCRYPT_STATUS_ERROR_MASK)) { status = kStatus_Success; } return status; } /*! * @brief Performs AES encryption/decryption of one data block. * * This function encrypts/decrypts one block of data with specified size. * * @param base Hashcrypt peripheral base address. * @param input input data * @param output output data * @param size size of data block to process in bytes (must be 16bytes multiple). */ static status_t hashcrypt_aes_one_block(HASHCRYPT_Type *base, const uint8_t *input, uint8_t *output, size_t size) { status_t status = kStatus_Fail; /*MEMCTRL bitfield for COUNT is 11 bits, and this limits the number of blocks to process in one Master run to 2047 (2^11 -1) blocks . Each block is 16bytes long, so biggest data size which can we do in one Master run is (2047 blocks *16 bytes) = 32752 So, when size is overflowing HASHCRYPT_MEMCTRL_COUNT field of MEMCTRL register, we split our data into more smaller chunks */ if (size > 32752U) { size_t numBlock = size / 32752U; /* number of blocks, each block is processed in one run*/ size_t remainingSize = size - (numBlock * 32752U); /* size of last block */ if ((0U != ((uint32_t)input & 0x3u)) || (0U != ((uint32_t)output & 0x3u))) /* If data is unaligned*/ { for (uint32_t i = 0; i < numBlock; i++) { status = hashcrypt_aes_one_block_unaligned(base, input, output, 32752U); input += 32752U; output += 32752U; } status = hashcrypt_aes_one_block_unaligned(base, input, output, remainingSize); } else /* If data is aligned*/ { for (uint32_t i = 0; i < numBlock; i++) { status = hashcrypt_aes_one_block_aligned(base, input, output, 32752U); input += 32752U; output += 32752U; } status = hashcrypt_aes_one_block_aligned(base, input, output, remainingSize); } } else /* size is less than COUNT field of MEMCTRL register so we can process all data at once */ { /* we use AHB master mode as much as possible */ /* however, it can work only with aligned input data */ /* so, if unaligned, we do memcpy to temp buffer on stack, which is aligned, and use AHB mode to read data in */ /* then we read data back to it and do memcpy to the output buffer */ if ((0U != ((uint32_t)input & 0x3u)) || (0U != ((uint32_t)output & 0x3u))) { status = hashcrypt_aes_one_block_unaligned(base, input, output, size); } else { status = hashcrypt_aes_one_block_aligned(base, input, output, size); } } return status; } /*! * @brief Check validity of algoritm. * * This function checks the validity of input argument. * * @param algo Tested algorithm value. * @return kStatus_Success if valid, kStatus_InvalidArgument otherwise. */ static status_t hashcrypt_sha_check_input_alg(HASHCRYPT_Type *base, hashcrypt_algo_t algo) { if ((algo == kHASHCRYPT_Sha1) || (algo == kHASHCRYPT_Sha256)) { return kStatus_Success; } return kStatus_InvalidArgument; } /*! * @brief Check validity of input arguments. * * This function checks the validity of input arguments. * * @param base SHA peripheral base address. * @param ctx Memory buffer given by user application where the SHA_Init/SHA_Update/SHA_Finish store context. * @param algo Tested algorithm value. * @return kStatus_Success if valid, kStatus_InvalidArgument otherwise. */ static status_t hashcrypt_sha_check_input_args(HASHCRYPT_Type *base, hashcrypt_hash_ctx_t *ctx, hashcrypt_algo_t algo) { /* Check validity of input algorithm */ if (kStatus_Success != hashcrypt_sha_check_input_alg(base, algo)) { return kStatus_InvalidArgument; } if ((NULL == ctx) || (NULL == base)) { return kStatus_InvalidArgument; } return kStatus_Success; } /*! * @brief Check validity of internal software context. * * This function checks if the internal context structure looks correct. * * @param ctxInternal Internal context. * @return kStatus_Success if valid, kStatus_InvalidArgument otherwise. */ static status_t hashcrypt_sha_check_context(HASHCRYPT_Type *base, hashcrypt_sha_ctx_internal_t *ctxInternal) { if ((NULL == ctxInternal) || (kStatus_Success != hashcrypt_sha_check_input_alg(base, ctxInternal->algo))) { return kStatus_InvalidArgument; } return kStatus_Success; } /*! * @brief Load 512-bit block (16 words) into SHA engine. * * This function aligns the input block and moves it into SHA engine INDATA. * CPU polls the WAITING bit and then moves data by using LDM and STM instructions. * * @param base SHA peripheral base address. * @param blk 512-bit block */ static void hashcrypt_sha_one_block(HASHCRYPT_Type *base, const uint8_t *blk) { uint32_t temp[SHA_BLOCK_SIZE / sizeof(uint32_t)]; const uint32_t *actBlk; /* make sure the 512-bit block is word aligned */ if (0U != ((uintptr_t)blk & 0x3u)) { (void)hashcrypt_memcpy(temp, blk, SHA_BLOCK_SIZE); /* Important: do not cast blk to any other type then uint8_t. Depending on the compiler and optimization level, * compiler might decide to use a mempy implementation that does not work on non aligned addresses, resulting in * a hard fault */ actBlk = (const uint32_t *)(uintptr_t)temp; } else { actBlk = (const uint32_t *)(uintptr_t)blk; } /* poll waiting. */ while (0U == (base->STATUS & HASHCRYPT_STATUS_WAITING_MASK)) { } /* feed INDATA (and ALIASes). use STM instruction. */ hashcrypt_sha_ldm_stm_16_words(base, actBlk); } /*! * @brief Adds message to current hash. * * This function merges the message to fill the internal buffer, empties the internal buffer if * it becomes full, then process all remaining message data. * * * @param base SHA peripheral base address. * @param ctxInternal Internal context. * @param message Input message. * @param messageSize Size of input message in bytes. * @return kStatus_Success if message hashed, kStatus_Fail otherwise. */ static status_t hashcrypt_sha_process_message_data(HASHCRYPT_Type *base, hashcrypt_sha_ctx_internal_t *ctxInternal, const uint8_t *message, size_t messageSize) { status_t status = kStatus_Fail; /* first fill the internal buffer to full block */ if (ctxInternal->blksz != 0U) { size_t toCopy = SHA_BLOCK_SIZE - ctxInternal->blksz; (void)hashcrypt_memcpy(&ctxInternal->blk.b[ctxInternal->blksz], message, toCopy); message += toCopy; messageSize -= toCopy; /* process full internal block */ hashcrypt_sha_one_block(base, &ctxInternal->blk.b[0]); } /* process all full blocks in message[] */ if (messageSize >= SHA_BLOCK_SIZE) { if (0U != ((uintptr_t)message & 0x3u)) { while (messageSize >= SHA_BLOCK_SIZE) { hashcrypt_sha_one_block(base, message); message += SHA_BLOCK_SIZE; messageSize -= SHA_BLOCK_SIZE; } } else { /* number of blocks and number of rounds needed to compute hash */ uint32_t blkNum = (messageSize >> 6); /* div by 64 bytes */ uint32_t blkFullRounds = blkNum / SHA_MAX_BLOCK_COUNT; /* feed the SHA engine with the maximum possible number of blocks */ while (blkFullRounds >= 1U) { /* poll waiting. */ while (0U == (base->STATUS & HASHCRYPT_STATUS_WAITING_MASK)) { } uint32_t blkBytes = SHA_MAX_BLOCK_COUNT * 64u; /* number of bytes in maximum block count */ __DSB(); base->MEMADDR = HASHCRYPT_MEMADDR_BASE(message); base->MEMCTRL = HASHCRYPT_MEMCTRL_MASTER(1) | HASHCRYPT_MEMCTRL_COUNT(SHA_MAX_BLOCK_COUNT); __DSB(); while ((0U == (base->STATUS & HASHCRYPT_STATUS_DIGEST_MASK)) && (0U == (base->STATUS & HASHCRYPT_STATUS_ERROR_MASK))) { } message += blkBytes; messageSize -= blkBytes; blkFullRounds -= 1U; blkNum -= SHA_MAX_BLOCK_COUNT; } if (blkNum != 0U) { /* same as above, but only for the remaining number of blocks < SHA_MAX_BLOCK_COUNT */ while (0U == (base->STATUS & HASHCRYPT_STATUS_WAITING_MASK)) { } uint32_t blkBytes = blkNum * 64u; /* number of bytes in 64 bytes blocks */ __DSB(); base->MEMADDR = HASHCRYPT_MEMADDR_BASE(message); base->MEMCTRL = HASHCRYPT_MEMCTRL_MASTER(1) | HASHCRYPT_MEMCTRL_COUNT(blkNum); __DSB(); while ((0U == (base->STATUS & HASHCRYPT_STATUS_DIGEST_MASK)) && (0U == (base->STATUS & HASHCRYPT_STATUS_ERROR_MASK))) { } message += blkBytes; messageSize -= blkBytes; } } } if (0U == (base->STATUS & HASHCRYPT_STATUS_ERROR_MASK)) { status = kStatus_Success; } /* copy last incomplete message bytes into internal block */ (void)hashcrypt_memcpy(&ctxInternal->blk.b[0], message, messageSize); ctxInternal->blksz = messageSize; return status; } /*! * @brief Finalize the running hash to make digest. * * This function empties the internal buffer, adds padding bits, and generates final digest. * * @param base SHA peripheral base address. * @param ctxInternal Internal context. * @return kStatus_Success if finalized, kStatus_Fail otherwise. */ static status_t hashcrypt_sha_finalize(HASHCRYPT_Type *base, hashcrypt_sha_ctx_internal_t *ctxInternal) { status_t status = kStatus_Fail; hashcrypt_sha_block_t lastBlock; (void)memset(&lastBlock, 0, sizeof(hashcrypt_sha_block_t)); /* this is last call, so need to flush buffered message bytes along with padding */ if (ctxInternal->blksz <= 55u) { /* last data is 440 bits or less. */ (void)hashcrypt_memcpy(&lastBlock.b[0], &ctxInternal->blk.b[0], ctxInternal->blksz); lastBlock.b[ctxInternal->blksz] = (uint8_t)0x80U; lastBlock.w[SHA_BLOCK_SIZE / 4U - 1U] = swap_bytes(8u * ctxInternal->fullMessageSize); hashcrypt_sha_one_block(base, &lastBlock.b[0]); } else { if (ctxInternal->blksz < SHA_BLOCK_SIZE) { ctxInternal->blk.b[ctxInternal->blksz] = (uint8_t)0x80U; for (uint32_t i = ctxInternal->blksz + 1u; i < SHA_BLOCK_SIZE; i++) { ctxInternal->blk.b[i] = 0; } } else { lastBlock.b[0] = (uint8_t)0x80U; } hashcrypt_sha_one_block(base, &ctxInternal->blk.b[0]); lastBlock.w[SHA_BLOCK_SIZE / 4U - 1U] = swap_bytes(8u * ctxInternal->fullMessageSize); hashcrypt_sha_one_block(base, &lastBlock.b[0]); } /* poll wait for final digest */ while ((0U == (base->STATUS & HASHCRYPT_STATUS_DIGEST_MASK)) && (0U == (base->STATUS & HASHCRYPT_STATUS_ERROR_MASK))) { } if (0U == (base->STATUS & HASHCRYPT_STATUS_ERROR_MASK)) { status = kStatus_Success; } return status; } static status_t hashcrypt_save_running_hash(HASHCRYPT_Type *base, hashcrypt_sha_ctx_internal_t *ctxInternal) { #if defined(FSL_FEATURE_HASHCRYPT_HAS_RELOAD_FEATURE) && (FSL_FEATURE_HASHCRYPT_HAS_RELOAD_FEATURE > 0) status_t status = kStatus_Fail; size_t len = (ctxInternal->algo == kHASHCRYPT_Sha1) ? SHA1_LEN : SHA256_LEN; /* Wait until digest is ready */ while ((0U == (base->STATUS & HASHCRYPT_STATUS_DIGEST_MASK)) && (0U == (base->STATUS & HASHCRYPT_STATUS_ERROR_MASK))) { } /* Store partial digest to context */ for (uint32_t i = 0; i < len; i++) { ctxInternal->runningHash[i] = base->DIGEST0[i]; } if (0U == (base->STATUS & HASHCRYPT_STATUS_ERROR_MASK)) { status = kStatus_Success; } return status; #else return kStatus_Success; #endif } static void hashcrypt_restore_running_hash(HASHCRYPT_Type *base, hashcrypt_sha_ctx_internal_t *ctxInternal) { #if defined(FSL_FEATURE_HASHCRYPT_HAS_RELOAD_FEATURE) && (FSL_FEATURE_HASHCRYPT_HAS_RELOAD_FEATURE > 0) size_t len = (ctxInternal->algo == kHASHCRYPT_Sha1) ? SHA1_LEN : SHA256_LEN; /* When switching from different mode, need to set NEW bit to work properly */ if ((base->CTRL & HASHCRYPT_CTRL_MODE_MASK) != HASHCRYPT_CTRL_MODE(ctxInternal->algo)) { base->CTRL = HASHCRYPT_CTRL_NEW_HASH(1); base->CTRL = HASHCRYPT_CTRL_MODE(ctxInternal->algo) | HASHCRYPT_CTRL_NEW_HASH(1); } /* Set RELOAD bit to allow registers to be used */ base->CTRL |= HASHCRYPT_CTRL_RELOAD_MASK; /* Reload partial hash digest */ for (uint32_t i = 0; i < len; i++) { base->RELOAD[i] = ctxInternal->runningHash[i]; } /* Clear RELOAD register before continuing */ base->CTRL &= ~HASHCRYPT_CTRL_RELOAD_MASK; #endif } /* Load random number into PRNG_SEED register */ /* Used in AES operations for SCA protection */ static void hashcrypt_seed_prng(HASHCRYPT_Type *base) { #if defined(FSL_FEATURE_HASHCRYPT_HAS_RELOAD_FEATURE) && (FSL_FEATURE_HASHCRYPT_HAS_RELOAD_FEATURE > 0) #if defined(FSL_FEATURE_SOC_LPC_RNG1_COUNT) && (FSL_FEATURE_SOC_LPC_RNG1_COUNT > 0) base->PRNG_SEED = RNG->RANDOM_NUMBER; #endif /* defined(FSL_FEATURE_SOC_LPC_RNG1_COUNT) && (FSL_FEATURE_SOC_LPC_RNG1_COUNT > 0) */ #if defined(FSL_FEATURE_SOC_TRNG_COUNT) && (FSL_FEATURE_SOC_TRNG_COUNT > 0) base->PRNG_SEED = TRNG->ENT[15]; #endif /* defined(FSL_FEATURE_SOC_TRNG_COUNT) && (FSL_FEATURE_SOC_TRNG_COUNT > 0) */ #endif /* defined(FSL_FEATURE_HASHCRYPT_HAS_RELOAD_FEATURE) && (FSL_FEATURE_HASHCRYPT_HAS_RELOAD_FEATURE > 0) */ } status_t HASHCRYPT_SHA(HASHCRYPT_Type *base, hashcrypt_algo_t algo, const uint8_t *input, size_t inputSize, uint8_t *output, size_t *outputSize) { hashcrypt_hash_ctx_t hashCtx; status_t status; status = HASHCRYPT_SHA_Init(base, &hashCtx, algo); if (status != kStatus_Success) { return status; } status = HASHCRYPT_SHA_Update(base, &hashCtx, input, inputSize); if (status != kStatus_Success) { return status; } status = HASHCRYPT_SHA_Finish(base, &hashCtx, output, outputSize); return status; } status_t HASHCRYPT_SHA_Init(HASHCRYPT_Type *base, hashcrypt_hash_ctx_t *ctx, hashcrypt_algo_t algo) { status_t status; hashcrypt_sha_ctx_internal_t *ctxInternal; /* compile time check for the correct structure size */ BUILD_ASSERT(sizeof(hashcrypt_hash_ctx_t) >= sizeof(hashcrypt_sha_ctx_internal_t), hashcrypt_hash_ctx_t_size); status = hashcrypt_sha_check_input_args(base, ctx, algo); if (status != kStatus_Success) { return status; } /* set algorithm in context struct for later use */ ctxInternal = (hashcrypt_sha_ctx_internal_t *)(uint32_t)ctx; ctxInternal->algo = algo; ctxInternal->blksz = 0u; #ifdef HASHCRYPT_SHA_DO_WIPE_CONTEXT for (int i = 0; i < sizeof(ctxInternal->blk.w) / sizeof(ctxInternal->blk.w[0]); i++) { ctxInternal->blk.w[i] = 0u; } #endif /* HASHCRYPT_SHA_DO_WIPE_CONTEXT */ ctxInternal->state = kHASHCRYPT_HashInit; ctxInternal->fullMessageSize = 0; return kStatus_Success; } status_t HASHCRYPT_SHA_Update(HASHCRYPT_Type *base, hashcrypt_hash_ctx_t *ctx, const uint8_t *input, size_t inputSize) { bool isUpdateState; status_t status; hashcrypt_sha_ctx_internal_t *ctxInternal; size_t blockSize; if (inputSize == 0U) { return kStatus_Success; } ctxInternal = (hashcrypt_sha_ctx_internal_t *)(uint32_t)ctx; #ifdef HASHCRYPT_SHA_DO_CHECK_CONTEXT status = hashcrypt_sha_check_context(base, ctxInternal); if (kStatus_Success != status) { return status; } #endif /* HASHCRYPT_SHA_DO_CHECK_CONTEXT */ ctxInternal->fullMessageSize += inputSize; blockSize = SHA_BLOCK_SIZE; /* if we are still less than 64 bytes, keep only in context */ if ((ctxInternal->blksz + inputSize) <= blockSize) { (void)hashcrypt_memcpy((&ctxInternal->blk.b[0]) + ctxInternal->blksz, input, inputSize); ctxInternal->blksz += inputSize; return kStatus_Success; } else { isUpdateState = ctxInternal->state == kHASHCRYPT_HashUpdate; if (!isUpdateState) { /* start NEW hash */ hashcrypt_engine_init(base, ctxInternal->algo); ctxInternal->state = kHASHCRYPT_HashUpdate; } else { hashcrypt_restore_running_hash(base, ctxInternal); } } /* process message data */ /* Data Synchronization Barrier */ __DSB(); status = hashcrypt_sha_process_message_data(base, ctxInternal, input, inputSize); if (kStatus_Success != status) { return status; } __DSB(); status = hashcrypt_save_running_hash(base, ctxInternal); return status; } status_t HASHCRYPT_SHA_Finish(HASHCRYPT_Type *base, hashcrypt_hash_ctx_t *ctx, uint8_t *output, size_t *outputSize) { size_t algOutSize = 0; status_t status; hashcrypt_sha_ctx_internal_t *ctxInternal; #ifdef HASHCRYPT_SHA_DO_CHECK_CONTEXT uint32_t *ctxW; uint32_t i; #endif /* HASHCRYPT_SHA_DO_CHECK_CONTEXT */ if (output == NULL) { return kStatus_InvalidArgument; } ctxInternal = (hashcrypt_sha_ctx_internal_t *)(uint32_t)ctx; #ifdef HASHCRYPT_SHA_DO_CHECK_CONTEXT status = hashcrypt_sha_check_context(base, ctxInternal); if (kStatus_Success != status) { return status; } #endif /* HASHCRYPT_SHA_DO_CHECK_CONTEXT */ if (ctxInternal->state == kHASHCRYPT_HashInit) { hashcrypt_engine_init(base, ctxInternal->algo); } else { hashcrypt_restore_running_hash(base, ctxInternal); } size_t outSize = 0u; /* compute algorithm output length */ switch (ctxInternal->algo) { case kHASHCRYPT_Sha1: outSize = (size_t)kHASHCRYPT_OutLenSha1; break; case kHASHCRYPT_Sha256: outSize = (size_t)kHASHCRYPT_OutLenSha256; break; default: /* All the cases have been listed above, the default clause should not be reached. */ break; } algOutSize = outSize; /* flush message last incomplete block, if there is any, and add padding bits */ status = hashcrypt_sha_finalize(base, ctxInternal); if (kStatus_Success != status) { return status; } if (outputSize != NULL) { if (algOutSize < *outputSize) { *outputSize = algOutSize; } else { algOutSize = *outputSize; } } status = hashcrypt_get_data(base, output, algOutSize); if (kStatus_Success != status) { return status; } #ifdef HASHCRYPT_SHA_DO_WIPE_CONTEXT ctxW = (uint32_t *)ctx; for (i = 0; i < HASHCRYPT_HASH_CTX_SIZE; i++) { ctxW[i] = 0u; } #endif /* HASHCRYPT_SHA_DO_WIPE_CONTEXT */ return status; } void HASHCRYPT_SHA_SetCallback(HASHCRYPT_Type *base, hashcrypt_hash_ctx_t *ctx, hashcrypt_callback_t callback, void *userData) { hashcrypt_sha_ctx_internal_t *ctxInternal; s_ctx = ctx; ctxInternal = (hashcrypt_sha_ctx_internal_t *)(uint32_t)ctx; ctxInternal->hashCallback = callback; ctxInternal->userData = userData; (void)EnableIRQ(HASHCRYPT_IRQn); } status_t HASHCRYPT_SHA_UpdateNonBlocking(HASHCRYPT_Type *base, hashcrypt_hash_ctx_t *ctx, const uint8_t *input, size_t inputSize) { hashcrypt_sha_ctx_internal_t *ctxInternal; uint32_t numBlocks; status_t status; if (inputSize == 0U) { return kStatus_Success; } if (0U != ((uintptr_t)input & 0x3U)) { return kStatus_Fail; } ctxInternal = (hashcrypt_sha_ctx_internal_t *)(uint32_t)ctx; status = hashcrypt_sha_check_context(base, ctxInternal); if (kStatus_Success != status) { return status; } ctxInternal->fullMessageSize = inputSize; ctxInternal->remainingBlcks = inputSize / SHA_BLOCK_SIZE; ctxInternal->blksz = inputSize % SHA_BLOCK_SIZE; /* copy last incomplete block to context */ if ((ctxInternal->blksz > 0U) && (ctxInternal->blksz <= SHA_BLOCK_SIZE)) { (void)hashcrypt_memcpy((&ctxInternal->blk.b[0]), input + SHA_BLOCK_SIZE * ctxInternal->remainingBlcks, ctxInternal->blksz); } if (ctxInternal->remainingBlcks >= SHA_MASTER_MAX_BLOCKS) { numBlocks = SHA_MASTER_MAX_BLOCKS - 1U; } else { numBlocks = ctxInternal->remainingBlcks; } /* update remainingBlks so that ISR can run another hash if necessary */ ctxInternal->remainingBlcks -= numBlocks; /* compute hash using AHB Master mode for full blocks */ if (numBlocks > 0U) { ctxInternal->state = kHASHCRYPT_HashUpdate; hashcrypt_engine_init(base, ctxInternal->algo); /* Enable digest and error interrupts and start hash */ base->INTENSET = HASHCRYPT_INTENCLR_DIGEST_MASK | HASHCRYPT_INTENCLR_ERROR_MASK; base->MEMADDR = HASHCRYPT_MEMADDR_BASE(input); base->MEMCTRL = HASHCRYPT_MEMCTRL_MASTER(1) | HASHCRYPT_MEMCTRL_COUNT(numBlocks); } /* no full blocks, invoke callback directly */ else { ctxInternal->hashCallback(HASHCRYPT, ctx, status, ctxInternal->userData); } return status; } status_t HASHCRYPT_AES_SetKey(HASHCRYPT_Type *base, hashcrypt_handle_t *handle, const uint8_t *key, size_t keySize) { status_t retVal = kStatus_InvalidArgument; switch (keySize) { case 16: handle->keySize = kHASHCRYPT_Aes128; break; case 24: handle->keySize = kHASHCRYPT_Aes192; break; case 32: handle->keySize = kHASHCRYPT_Aes256; break; default: handle->keySize = kHASHCRYPT_InvalidKey; break; } if (handle->keySize == kHASHCRYPT_InvalidKey) { return retVal; } if (handle->keyType == kHASHCRYPT_SecretKey) { /* for kHASHCRYPT_SecretKey just return Success */ retVal = kStatus_Success; } else if (handle->keyType == kHASHCRYPT_UserKey) { retVal = hashcrypt_get_key_from_unaligned_src((uint8_t *)&handle->keyWord[0], key, keySize); } else { retVal = kStatus_InvalidArgument; } return retVal; } status_t HASHCRYPT_AES_EncryptEcb( HASHCRYPT_Type *base, hashcrypt_handle_t *handle, const uint8_t *plaintext, uint8_t *ciphertext, size_t size) { status_t status = kStatus_Fail; if ((0U != (size % 16u)) || (handle->keySize == kHASHCRYPT_InvalidKey)) { return kStatus_InvalidArgument; } hashcrypt_seed_prng(base); uint32_t keyType = (handle->keyType == kHASHCRYPT_UserKey) ? 0U : 1u; base->CRYPTCFG = HASHCRYPT_CRYPTCFG_AESMODE(kHASHCRYPT_AesEcb) | HASHCRYPT_CRYPTCFG_AESDECRYPT(AES_ENCRYPT) | HASHCRYPT_CRYPTCFG_AESSECRET(keyType) | HASHCRYPT_CRYPTCFG_AESKEYSZ(handle->keySize) | HASHCRYPT_CRYPTCFG_MSW1ST_OUT(1) | HASHCRYPT_CRYPTCFG_SWAPKEY(1) | HASHCRYPT_CRYPTCFG_SWAPDAT(1) | HASHCRYPT_CRYPTCFG_MSW1ST(1); hashcrypt_engine_init(base, kHASHCRYPT_Aes); /* in case of HW AES key, check if it is available */ if (hashcrypt_check_need_key(base, handle) != kStatus_Success) { hashcrypt_engine_deinit(base); return kStatus_Fail; } /* load key if kHASHCRYPT_UserKey is selected */ if (handle->keyType == kHASHCRYPT_UserKey) { hashcrypt_aes_load_userKey(base, handle); } /* load message and get result */ status = hashcrypt_aes_one_block(base, plaintext, ciphertext, size); /* After processing all data, hashcrypt engine is set to disabled to lower power consumption */ hashcrypt_engine_deinit(base); return status; } status_t HASHCRYPT_AES_DecryptEcb( HASHCRYPT_Type *base, hashcrypt_handle_t *handle, const uint8_t *ciphertext, uint8_t *plaintext, size_t size) { status_t status = kStatus_Fail; if ((0U != (size % 16u)) || (handle->keySize == kHASHCRYPT_InvalidKey)) { return kStatus_InvalidArgument; } hashcrypt_seed_prng(base); uint32_t keyType = (handle->keyType == kHASHCRYPT_UserKey) ? 0U : 1u; base->CRYPTCFG = HASHCRYPT_CRYPTCFG_AESMODE(kHASHCRYPT_AesEcb) | HASHCRYPT_CRYPTCFG_AESDECRYPT(AES_DECRYPT) | HASHCRYPT_CRYPTCFG_AESSECRET(keyType) | HASHCRYPT_CRYPTCFG_AESKEYSZ(handle->keySize) | HASHCRYPT_CRYPTCFG_MSW1ST_OUT(1) | HASHCRYPT_CRYPTCFG_SWAPKEY(1) | HASHCRYPT_CRYPTCFG_SWAPDAT(1) | HASHCRYPT_CRYPTCFG_MSW1ST(1); hashcrypt_engine_init(base, kHASHCRYPT_Aes); /* in case of HW AES key, check if it is available */ if (hashcrypt_check_need_key(base, handle) != kStatus_Success) { hashcrypt_engine_deinit(base); return kStatus_Fail; } /* load key if kHASHCRYPT_UserKey is selected */ if (handle->keyType == kHASHCRYPT_UserKey) { hashcrypt_aes_load_userKey(base, handle); } /* load message and get result */ status = hashcrypt_aes_one_block(base, ciphertext, plaintext, size); /* After processing all data, hashcrypt engine is set to disabled to lower power consumption */ hashcrypt_engine_deinit(base); return status; } status_t HASHCRYPT_AES_EncryptCbc(HASHCRYPT_Type *base, hashcrypt_handle_t *handle, const uint8_t *plaintext, uint8_t *ciphertext, size_t size, const uint8_t iv[16]) { status_t status = kStatus_Fail; if (0U != ((size % 16u)) || (handle->keySize == kHASHCRYPT_InvalidKey)) { return kStatus_InvalidArgument; } hashcrypt_seed_prng(base); uint32_t keyType = (handle->keyType == kHASHCRYPT_UserKey) ? 0U : 1u; base->CRYPTCFG = HASHCRYPT_CRYPTCFG_AESMODE(kHASHCRYPT_AesCbc) | HASHCRYPT_CRYPTCFG_AESDECRYPT(AES_ENCRYPT) | HASHCRYPT_CRYPTCFG_AESSECRET(keyType) | HASHCRYPT_CRYPTCFG_AESKEYSZ(handle->keySize) | HASHCRYPT_CRYPTCFG_MSW1ST_OUT(1) | HASHCRYPT_CRYPTCFG_SWAPKEY(1) | HASHCRYPT_CRYPTCFG_SWAPDAT(1) | HASHCRYPT_CRYPTCFG_MSW1ST(1); hashcrypt_engine_init(base, kHASHCRYPT_Aes); /* in case of HW AES key, check if it is available */ if (hashcrypt_check_need_key(base, handle) != kStatus_Success) { hashcrypt_engine_deinit(base); return kStatus_Fail; } /* load key if kHASHCRYPT_UserKey is selected */ if (handle->keyType == kHASHCRYPT_UserKey) { hashcrypt_aes_load_userKey(base, handle); } /* load 16b iv */ hashcrypt_load_data(base, (uint32_t *)(uintptr_t)iv, 16); /* load message and get result */ status = hashcrypt_aes_one_block(base, plaintext, ciphertext, size); /* After processing all data, hashcrypt engine is set to disabled to lower power consumption */ hashcrypt_engine_deinit(base); return status; } status_t HASHCRYPT_AES_DecryptCbc(HASHCRYPT_Type *base, hashcrypt_handle_t *handle, const uint8_t *ciphertext, uint8_t *plaintext, size_t size, const uint8_t iv[16]) { status_t status = kStatus_Fail; if ((0U != (size % 16u)) || (handle->keySize == kHASHCRYPT_InvalidKey)) { return kStatus_InvalidArgument; } hashcrypt_seed_prng(base); uint32_t keyType = (handle->keyType == kHASHCRYPT_UserKey) ? 0U : 1u; base->CRYPTCFG = HASHCRYPT_CRYPTCFG_AESMODE(kHASHCRYPT_AesCbc) | HASHCRYPT_CRYPTCFG_AESDECRYPT(AES_DECRYPT) | HASHCRYPT_CRYPTCFG_AESSECRET(keyType) | HASHCRYPT_CRYPTCFG_AESKEYSZ(handle->keySize) | HASHCRYPT_CRYPTCFG_MSW1ST_OUT(1) | HASHCRYPT_CRYPTCFG_SWAPKEY(1) | HASHCRYPT_CRYPTCFG_SWAPDAT(1) | HASHCRYPT_CRYPTCFG_MSW1ST(1); hashcrypt_engine_init(base, kHASHCRYPT_Aes); /* in case of HW AES key, check if it is available */ if (hashcrypt_check_need_key(base, handle) != kStatus_Success) { hashcrypt_engine_deinit(base); return kStatus_Fail; } /* load key if kHASHCRYPT_UserKey is selected */ if (handle->keyType == kHASHCRYPT_UserKey) { hashcrypt_aes_load_userKey(base, handle); } /* load iv */ hashcrypt_load_data(base, (uint32_t *)(uintptr_t)iv, 16); /* load message and get result */ status = hashcrypt_aes_one_block(base, ciphertext, plaintext, size); /* After processing all data, hashcrypt engine is set to disabled to lower power consumption */ hashcrypt_engine_deinit(base); return status; } status_t HASHCRYPT_AES_CryptCtr(HASHCRYPT_Type *base, hashcrypt_handle_t *handle, const uint8_t *input, uint8_t *output, size_t size, uint8_t counter[HASHCRYPT_AES_BLOCK_SIZE], uint8_t counterlast[HASHCRYPT_AES_BLOCK_SIZE], size_t *szLeft) { uint32_t lastSize; uint8_t lastBlock[HASHCRYPT_AES_BLOCK_SIZE] = {0}; uint8_t *lastEncryptedCounter; status_t status = kStatus_Fail; if (handle->keySize == kHASHCRYPT_InvalidKey) { return kStatus_InvalidArgument; } hashcrypt_seed_prng(base); uint32_t keyType = (handle->keyType == kHASHCRYPT_UserKey) ? 0U : 1u; base->CRYPTCFG = HASHCRYPT_CRYPTCFG_AESMODE(kHASHCRYPT_AesCtr) | HASHCRYPT_CRYPTCFG_AESDECRYPT(AES_ENCRYPT) | HASHCRYPT_CRYPTCFG_AESSECRET(keyType) | HASHCRYPT_CRYPTCFG_AESKEYSZ(handle->keySize) | HASHCRYPT_CRYPTCFG_MSW1ST_OUT(1) | HASHCRYPT_CRYPTCFG_SWAPKEY(1) | HASHCRYPT_CRYPTCFG_SWAPDAT(1) | HASHCRYPT_CRYPTCFG_MSW1ST(1); hashcrypt_engine_init(base, kHASHCRYPT_Aes); /* in case of HW AES key, check if it is available */ if (hashcrypt_check_need_key(base, handle) != kStatus_Success) { hashcrypt_engine_deinit(base); return kStatus_Fail; } /* load key if kHASHCRYPT_UserKey is selected */ if (handle->keyType == kHASHCRYPT_UserKey) { hashcrypt_aes_load_userKey(base, handle); } /* load nonce */ hashcrypt_load_data(base, (uint32_t *)(uintptr_t)counter, 16); lastSize = size % HASHCRYPT_AES_BLOCK_SIZE; size -= lastSize; /* encrypt full 16byte blocks */ status = hashcrypt_aes_one_block(base, input, output, size); if (status != kStatus_Success) { hashcrypt_engine_deinit(base); return status; } while (size != 0U) { ctrIncrement(counter); size -= 16u; input += 16; output += 16; } if (lastSize != 0U) { if (counterlast != NULL) { lastEncryptedCounter = counterlast; } else { lastEncryptedCounter = lastBlock; } /* Perform encryption with all zeros to get last counter. XOR with zeros doesn't change. */ status = hashcrypt_aes_one_block(base, lastBlock, lastEncryptedCounter, HASHCRYPT_AES_BLOCK_SIZE); if (status != kStatus_Success) { hashcrypt_engine_deinit(base); return status; } /* remain output = input XOR counterlast */ for (uint32_t i = 0; i < lastSize; i++) { output[i] = input[i] ^ lastEncryptedCounter[i]; } /* Increment counter parameter */ ctrIncrement(counter); } else { lastSize = HASHCRYPT_AES_BLOCK_SIZE; /* no remaining bytes in couterlast so clearing it */ if (counterlast != NULL) { (void)memset(counterlast, 0, HASHCRYPT_AES_BLOCK_SIZE); } } if (szLeft != NULL) { *szLeft = HASHCRYPT_AES_BLOCK_SIZE - lastSize; } /* After processing all data, hashcrypt engine is set to disabled to lower power consumption */ hashcrypt_engine_deinit(base); return kStatus_Success; } status_t HASHCRYPT_AES_CryptOfb(HASHCRYPT_Type *base, hashcrypt_handle_t *handle, const uint8_t *input, uint8_t *output, size_t size, const uint8_t iv[HASHCRYPT_AES_BLOCK_SIZE]) { status_t status = kStatus_Fail; uint8_t zeroes[HASHCRYPT_AES_BLOCK_SIZE] = {0}; uint8_t blockOutput[HASHCRYPT_AES_BLOCK_SIZE] = {0}; if (handle->keySize == kHASHCRYPT_InvalidKey) { return kStatus_InvalidArgument; } uint32_t keyType = (handle->keyType == kHASHCRYPT_UserKey) ? 0U : 1u; hashcrypt_seed_prng(base); base->CRYPTCFG = HASHCRYPT_CRYPTCFG_AESMODE(kHASHCRYPT_AesCbc) | HASHCRYPT_CRYPTCFG_AESDECRYPT(AES_ENCRYPT) | HASHCRYPT_CRYPTCFG_AESSECRET(keyType) | HASHCRYPT_CRYPTCFG_AESKEYSZ(handle->keySize) | HASHCRYPT_CRYPTCFG_MSW1ST_OUT(1) | HASHCRYPT_CRYPTCFG_SWAPKEY(1) | HASHCRYPT_CRYPTCFG_SWAPDAT(1) | HASHCRYPT_CRYPTCFG_MSW1ST(1); hashcrypt_engine_init(base, kHASHCRYPT_Aes); /* in case of HW AES key, check if it is available */ if (hashcrypt_check_need_key(base, handle) != kStatus_Success) { hashcrypt_engine_deinit(base); return kStatus_Fail; } /* load key if kHASHCRYPT_UserKey is selected */ if (handle->keyType == kHASHCRYPT_UserKey) { hashcrypt_aes_load_userKey(base, handle); } /* load iv */ hashcrypt_load_data(base, (uint32_t *)(uintptr_t)iv, HASHCRYPT_AES_BLOCK_SIZE); /*Use AES CBC mode and feed input with zeroes as input*/ /*Output block is then XORed with input*/ while (size >= 16u) { status = hashcrypt_aes_one_block(base, zeroes, blockOutput, HASHCRYPT_AES_BLOCK_SIZE); if (status != kStatus_Success) { hashcrypt_engine_deinit(base); return status; } /* XOR input with output block to get output*/ for (uint32_t i = 0; i < HASHCRYPT_AES_BLOCK_SIZE; i++) { output[i] = input[i] ^ blockOutput[i]; } size -= 16u; output += 16; input += 16; } /* OFB can have non-block multiple size.*/ if (size != 0U) { status = hashcrypt_aes_one_block(base, zeroes, blockOutput, HASHCRYPT_AES_BLOCK_SIZE); if (status != kStatus_Success) { hashcrypt_engine_deinit(base); return status; } /* XOR input with output block to get output*/ for (uint32_t i = 0; i < size; i++) { output[i] = input[i] ^ blockOutput[i]; } } /* After processing all data, hashcrypt engine is set to disabled to lower power consumption */ hashcrypt_engine_deinit(base); return status; } status_t HASHCRYPT_AES_EncryptCfb(HASHCRYPT_Type *base, hashcrypt_handle_t *handle, const uint8_t *plaintext, uint8_t *ciphertext, size_t size, const uint8_t iv[HASHCRYPT_AES_BLOCK_SIZE]) { status_t status = kStatus_Fail; uint8_t zeroes[HASHCRYPT_AES_BLOCK_SIZE] = {0}; uint8_t blockOutput[HASHCRYPT_AES_BLOCK_SIZE] = {0}; /* For CFB mode size must be 16-byte multiple */ if ((0U != (size % 16u)) || (handle->keySize == kHASHCRYPT_InvalidKey)) { return kStatus_InvalidArgument; } uint32_t keyType = (handle->keyType == kHASHCRYPT_UserKey) ? 0U : 1u; hashcrypt_seed_prng(base); base->CRYPTCFG = HASHCRYPT_CRYPTCFG_AESMODE(kHASHCRYPT_AesCbc) | HASHCRYPT_CRYPTCFG_AESDECRYPT(AES_ENCRYPT) | HASHCRYPT_CRYPTCFG_AESSECRET(keyType) | HASHCRYPT_CRYPTCFG_AESKEYSZ(handle->keySize) | HASHCRYPT_CRYPTCFG_MSW1ST_OUT(1) | HASHCRYPT_CRYPTCFG_SWAPKEY(1) | HASHCRYPT_CRYPTCFG_SWAPDAT(1) | HASHCRYPT_CRYPTCFG_MSW1ST(1); hashcrypt_engine_init(base, kHASHCRYPT_Aes); /* in case of HW AES key, check if it is available */ if (hashcrypt_check_need_key(base, handle) != kStatus_Success) { hashcrypt_engine_deinit(base); return kStatus_Fail; } /* load key if kHASHCRYPT_UserKey is selected */ if (handle->keyType == kHASHCRYPT_UserKey) { hashcrypt_aes_load_userKey(base, handle); } /* load iv */ hashcrypt_load_data(base, (uint32_t *)(uintptr_t)iv, HASHCRYPT_AES_BLOCK_SIZE); /*Use AES CBC mode and feed input with zeroes for first block */ /*Output block is then XORed with plaintext to get ciphertext*/ status = hashcrypt_aes_one_block(base, zeroes, blockOutput, HASHCRYPT_AES_BLOCK_SIZE); if (status != kStatus_Success) { hashcrypt_engine_deinit(base); return status; } /* XOR plaintext with output block to get ciphertext*/ for (uint32_t i = 0; i < HASHCRYPT_AES_BLOCK_SIZE; i++) { ciphertext[i] = plaintext[i] ^ blockOutput[i]; } size -= 16u; /*Remaining blocks use previous plaintext as input for aes block function */ while (size >= 16u) { status = hashcrypt_aes_one_block(base, plaintext, blockOutput, HASHCRYPT_AES_BLOCK_SIZE); ciphertext += 16; plaintext += 16; if (status != kStatus_Success) { hashcrypt_engine_deinit(base); return status; } /* XOR plaintext with output block to get ciphertext*/ for (uint32_t i = 0; i < HASHCRYPT_AES_BLOCK_SIZE; i++) { ciphertext[i] = plaintext[i] ^ blockOutput[i]; } size -= 16u; } /* After processing all data, hashcrypt engine is set to disabled to lower power consumption */ hashcrypt_engine_deinit(base); return status; } status_t HASHCRYPT_AES_DecryptCfb(HASHCRYPT_Type *base, hashcrypt_handle_t *handle, const uint8_t *ciphertext, uint8_t *plaintext, size_t size, const uint8_t iv[HASHCRYPT_AES_BLOCK_SIZE]) { status_t status = kStatus_Fail; uint8_t zeroes[HASHCRYPT_AES_BLOCK_SIZE] = {0}; uint8_t blockOutput[HASHCRYPT_AES_BLOCK_SIZE] = {0}; /* For CFB mode size must be 16-byte multiple */ if ((0U != (size % 16u)) || (handle->keySize == kHASHCRYPT_InvalidKey)) { return kStatus_InvalidArgument; } uint32_t keyType = (handle->keyType == kHASHCRYPT_UserKey) ? 0U : 1u; hashcrypt_seed_prng(base); base->CRYPTCFG = HASHCRYPT_CRYPTCFG_AESMODE(kHASHCRYPT_AesCbc) | HASHCRYPT_CRYPTCFG_AESDECRYPT(AES_ENCRYPT) | HASHCRYPT_CRYPTCFG_AESSECRET(keyType) | HASHCRYPT_CRYPTCFG_AESKEYSZ(handle->keySize) | HASHCRYPT_CRYPTCFG_MSW1ST_OUT(1) | HASHCRYPT_CRYPTCFG_SWAPKEY(1) | HASHCRYPT_CRYPTCFG_SWAPDAT(1) | HASHCRYPT_CRYPTCFG_MSW1ST(1); hashcrypt_engine_init(base, kHASHCRYPT_Aes); /* in case of HW AES key, check if it is available */ if (hashcrypt_check_need_key(base, handle) != kStatus_Success) { hashcrypt_engine_deinit(base); return kStatus_Fail; } /* load key if kHASHCRYPT_UserKey is selected */ if (handle->keyType == kHASHCRYPT_UserKey) { hashcrypt_aes_load_userKey(base, handle); } /* load iv */ hashcrypt_load_data(base, (uint32_t *)(uintptr_t)iv, HASHCRYPT_AES_BLOCK_SIZE); /*Use AES CBC mode and feed input with zeroes for first block */ /*Output block is then XORed with ciphertext to get plaintext*/ status = hashcrypt_aes_one_block(base, zeroes, blockOutput, HASHCRYPT_AES_BLOCK_SIZE); if (status != kStatus_Success) { hashcrypt_engine_deinit(base); return status; } /* XOR ciphertext with output block to get plaintext*/ for (uint32_t i = 0; i < HASHCRYPT_AES_BLOCK_SIZE; i++) { plaintext[i] = ciphertext[i] ^ blockOutput[i]; } size -= 16u; /*Remaining blocks use previous plaintext as input for aes block function */ while (size >= 16u) { status = hashcrypt_aes_one_block(base, plaintext, blockOutput, HASHCRYPT_AES_BLOCK_SIZE); ciphertext += 16; plaintext += 16; if (status != kStatus_Success) { hashcrypt_engine_deinit(base); return status; } /* XOR plaintext with ciphertext block to get plaintext*/ for (uint32_t i = 0; i < HASHCRYPT_AES_BLOCK_SIZE; i++) { plaintext[i] = ciphertext[i] ^ blockOutput[i]; } size -= 16u; } /* After processing all data, hashcrypt engine is set to disabled to lower power consumption */ hashcrypt_engine_deinit(base); return status; } void HASHCRYPT_DriverIRQHandler(void); void HASHCRYPT_DriverIRQHandler(void) { hashcrypt_sha_ctx_internal_t *ctxInternal; HASHCRYPT_Type *base = HASHCRYPT; uint32_t numBlocks; status_t status; ctxInternal = (hashcrypt_sha_ctx_internal_t *)(uint32_t)s_ctx; if (0U == (base->STATUS & HASHCRYPT_STATUS_ERROR_MASK)) { if (ctxInternal->remainingBlcks > 0U) { if (ctxInternal->remainingBlcks >= SHA_MASTER_MAX_BLOCKS) { numBlocks = SHA_MASTER_MAX_BLOCKS - 1U; } else { numBlocks = ctxInternal->remainingBlcks; } /* some blocks still remaining, update remainingBlcks for next ISR and start another hash */ ctxInternal->remainingBlcks -= numBlocks; base->MEMCTRL = HASHCRYPT_MEMCTRL_MASTER(1) | HASHCRYPT_MEMCTRL_COUNT(numBlocks); return; } /* no full blocks left, disable interrupts and AHB master mode */ base->INTENCLR = HASHCRYPT_INTENCLR_DIGEST_MASK | HASHCRYPT_INTENCLR_ERROR_MASK; base->MEMCTRL = HASHCRYPT_MEMCTRL_MASTER(0); status = hashcrypt_save_running_hash(base, ctxInternal); } else { status = kStatus_Fail; } /* Invoke callback if there is one */ if (NULL != ctxInternal->hashCallback) { ctxInternal->hashCallback(HASHCRYPT, s_ctx, status, ctxInternal->userData); } } void HASHCRYPT_Init(HASHCRYPT_Type *base) { #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) CLOCK_EnableClock(kCLOCK_HashCrypt); #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ RESET_PeripheralReset(kHASHCRYPT_RST_SHIFT_RSTn); } void HASHCRYPT_Deinit(HASHCRYPT_Type *base) { RESET_SetPeripheralReset(kHASHCRYPT_RST_SHIFT_RSTn); #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) CLOCK_DisableClock(kCLOCK_HashCrypt); #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ }