| /* |
| * Copyright (c) 2015-2016, Freescale Semiconductor, Inc. |
| * Copyright 2016-2017 NXP |
| * |
| * Redistribution and use in source and binary forms, with or without modification, |
| * are permitted provided that the following conditions are met: |
| * |
| * o Redistributions of source code must retain the above copyright notice, this list |
| * of conditions and the following disclaimer. |
| * |
| * o Redistributions in binary form must reproduce the above copyright notice, this |
| * list of conditions and the following disclaimer in the documentation and/or |
| * other materials provided with the distribution. |
| * |
| * o Neither the name of the copyright holder nor the names of its |
| * contributors may be used to endorse or promote products derived from this |
| * software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR |
| * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
| * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "fsl_ltc.h" |
| |
| /******************************************************************************* |
| * Definitions |
| ******************************************************************************/ |
| /*! Full word representing the actual bit values for the LTC mode register. */ |
| typedef uint32_t ltc_mode_t; |
| |
| #define LTC_FIFO_SZ_MAX_DOWN_ALGN (0xff0u) |
| #define LTC_MD_ALG_AES (0x10U) /*!< Bit field value for LTC_MD_ALG: AES */ |
| #define LTC_MD_ALG_DES (0x20U) /*!< Bit field value for LTC_MD_ALG: DES */ |
| #define LTC_MD_ALG_TRIPLE_DES (0x21U) /*!< Bit field value for LTC_MD_ALG: 3DES */ |
| #define LTC_MD_ALG_SHA1 (0x41U) /*!< Bit field value for LTC_MD_ALG: SHA-1 */ |
| #define LTC_MD_ALG_SHA224 (0x42U) /*!< Bit field value for LTC_MD_ALG: SHA-224 */ |
| #define LTC_MD_ALG_SHA256 (0x43U) /*!< Bit field value for LTC_MD_ALG: SHA-256 */ |
| #define LTC_MDPK_ALG_PKHA (0x80U) /*!< Bit field value for LTC_MDPK_ALG: PKHA */ |
| #define LTC_MD_ENC_DECRYPT (0U) /*!< Bit field value for LTC_MD_ENC: Decrypt. */ |
| #define LTC_MD_ENC_ENCRYPT (0x1U) /*!< Bit field value for LTC_MD_ENC: Encrypt. */ |
| #define LTC_MD_AS_UPDATE (0U) /*!< Bit field value for LTC_MD_AS: Update */ |
| #define LTC_MD_AS_INITIALIZE (0x1U) /*!< Bit field value for LTC_MD_AS: Initialize */ |
| #define LTC_MD_AS_FINALIZE (0x2U) /*!< Bit field value for LTC_MD_AS: Finalize */ |
| #define LTC_MD_AS_INIT_FINAL (0x3U) /*!< Bit field value for LTC_MD_AS: Initialize/Finalize */ |
| |
| #define LTC_AES_GCM_TYPE_AAD 55 |
| #define LTC_AES_GCM_TYPE_IV 0 |
| |
| #define LTC_CCM_TAG_IDX 8 /*! For CCM encryption, the encrypted final MAC is written to the context word 8-11 */ |
| #define LTC_GCM_TAG_IDX 0 /*! For GCM encryption, the encrypted final MAC is written to the context word 0-3 */ |
| |
| enum _ltc_md_dk_bit_shift |
| { |
| kLTC_ModeRegBitShiftDK = 12U, |
| }; |
| |
| typedef enum _ltc_algorithm |
| { |
| #if defined(FSL_FEATURE_LTC_HAS_PKHA) && FSL_FEATURE_LTC_HAS_PKHA |
| kLTC_AlgorithmPKHA = LTC_MDPK_ALG_PKHA << LTC_MD_ALG_SHIFT, |
| #endif /* FSL_FEATURE_LTC_HAS_PKHA */ |
| kLTC_AlgorithmAES = LTC_MD_ALG_AES << LTC_MD_ALG_SHIFT, |
| #if defined(FSL_FEATURE_LTC_HAS_DES) && FSL_FEATURE_LTC_HAS_DES |
| kLTC_AlgorithmDES = LTC_MD_ALG_DES << LTC_MD_ALG_SHIFT, |
| kLTC_Algorithm3DES = LTC_MD_ALG_TRIPLE_DES << LTC_MD_ALG_SHIFT, |
| #endif /* FSL_FEATURE_LTC_HAS_DES */ |
| #if defined(FSL_FEATURE_LTC_HAS_SHA) && FSL_FEATURE_LTC_HAS_SHA |
| kLTC_AlgorithmSHA1 = LTC_MD_ALG_SHA1 << LTC_MD_ALG_SHIFT, |
| kLTC_AlgorithmSHA224 = LTC_MD_ALG_SHA224 << LTC_MD_ALG_SHIFT, |
| kLTC_AlgorithmSHA256 = LTC_MD_ALG_SHA256 << LTC_MD_ALG_SHIFT, |
| #endif /* FSL_FEATURE_LTC_HAS_SHA */ |
| } ltc_algorithm_t; |
| |
| typedef enum _ltc_mode_symmetric_alg |
| { |
| kLTC_ModeCTR = 0x00U << LTC_MD_AAI_SHIFT, |
| kLTC_ModeCBC = 0x10U << LTC_MD_AAI_SHIFT, |
| kLTC_ModeECB = 0x20U << LTC_MD_AAI_SHIFT, |
| kLTC_ModeCFB = 0x30U << LTC_MD_AAI_SHIFT, |
| kLTC_ModeOFB = 0x40U << LTC_MD_AAI_SHIFT, |
| kLTC_ModeCMAC = 0x60U << LTC_MD_AAI_SHIFT, |
| kLTC_ModeXCBCMAC = 0x70U << LTC_MD_AAI_SHIFT, |
| kLTC_ModeCCM = 0x80U << LTC_MD_AAI_SHIFT, |
| kLTC_ModeGCM = 0x90U << LTC_MD_AAI_SHIFT, |
| } ltc_mode_symmetric_alg_t; |
| |
| typedef enum _ltc_mode_encrypt |
| { |
| kLTC_ModeDecrypt = LTC_MD_ENC_DECRYPT << LTC_MD_ENC_SHIFT, |
| kLTC_ModeEncrypt = LTC_MD_ENC_ENCRYPT << LTC_MD_ENC_SHIFT, |
| } ltc_mode_encrypt_t; |
| |
| typedef enum _ltc_mode_algorithm_state |
| { |
| kLTC_ModeUpdate = LTC_MD_AS_UPDATE << LTC_MD_AS_SHIFT, |
| kLTC_ModeInit = LTC_MD_AS_INITIALIZE << LTC_MD_AS_SHIFT, |
| kLTC_ModeFinalize = LTC_MD_AS_FINALIZE << LTC_MD_AS_SHIFT, |
| kLTC_ModeInitFinal = LTC_MD_AS_INIT_FINAL << LTC_MD_AS_SHIFT |
| } ltc_mode_algorithm_state_t; |
| |
| /*! @brief LTC status flags */ |
| enum _ltc_status_flag |
| { |
| kLTC_StatusAesBusy = 1U << LTC_STA_AB_SHIFT, |
| #if defined(FSL_FEATURE_LTC_HAS_DES) && FSL_FEATURE_LTC_HAS_DES |
| kLTC_StatusDesBusy = 1U << LTC_STA_DB_SHIFT, |
| #endif /* FSL_FEATURE_LTC_HAS_DES */ |
| #if defined(FSL_FEATURE_LTC_HAS_PKHA) && FSL_FEATURE_LTC_HAS_PKHA |
| kLTC_StatusPkhaBusy = 1U << LTC_STA_PB_SHIFT, |
| #endif /* FSL_FEATURE_LTC_HAS_PKHA */ |
| #if defined(FSL_FEATURE_LTC_HAS_SHA) && FSL_FEATURE_LTC_HAS_SHA |
| kLTC_StatusMdhaBusy = 1U << LTC_STA_MB_SHIFT, |
| #endif /* FSL_FEATURE_LTC_HAS_SHA */ |
| kLTC_StatusDoneIsr = 1U << LTC_STA_DI_SHIFT, |
| kLTC_StatusErrorIsr = 1U << LTC_STA_EI_SHIFT, |
| #if defined(FSL_FEATURE_LTC_HAS_PKHA) && FSL_FEATURE_LTC_HAS_PKHA |
| kLTC_StatusPublicKeyPrime = 1U << LTC_STA_PKP_SHIFT, |
| kLTC_StatusPublicKeyOpOne = 1U << LTC_STA_PKO_SHIFT, |
| kLTC_StatusPublicKeyOpZero = 1U << LTC_STA_PKZ_SHIFT, |
| #endif /* FSL_FEATURE_LTC_HAS_PKHA */ |
| kLTC_StatusAll = LTC_STA_AB_MASK | |
| #if defined(FSL_FEATURE_LTC_HAS_DES) && FSL_FEATURE_LTC_HAS_DES |
| LTC_STA_DB_MASK | |
| #endif /* FSL_FEATURE_LTC_HAS_DES */ |
| #if defined(FSL_FEATURE_LTC_HAS_SHA) && FSL_FEATURE_LTC_HAS_SHA |
| LTC_STA_MB_MASK | |
| #endif /* FSL_FEATURE_LTC_HAS_SHA */ |
| LTC_STA_DI_MASK | LTC_STA_EI_MASK |
| #if defined(FSL_FEATURE_LTC_HAS_PKHA) && FSL_FEATURE_LTC_HAS_PKHA |
| | |
| LTC_STA_PB_MASK | LTC_STA_PKP_MASK | LTC_STA_PKO_MASK | LTC_STA_PKZ_MASK |
| #endif /* FSL_FEATURE_LTC_HAS_PKHA */ |
| }; |
| |
| /*! @brief LTC clear register */ |
| typedef enum _ltc_clear_written |
| { |
| kLTC_ClearMode = 1U << LTC_CW_CM_SHIFT, |
| kLTC_ClearDataSize = 1U << LTC_CW_CDS_SHIFT, |
| kLTC_ClearIcvSize = 1U << LTC_CW_CICV_SHIFT, |
| kLTC_ClearContext = 1U << LTC_CW_CCR_SHIFT, |
| kLTC_ClearKey = 1U << LTC_CW_CKR_SHIFT, |
| #if defined(FSL_FEATURE_LTC_HAS_PKHA) && FSL_FEATURE_LTC_HAS_PKHA |
| kLTC_ClearPkhaSizeA = 1U << LTC_CW_CPKA_SHIFT, |
| kLTC_ClearPkhaSizeB = 1U << LTC_CW_CPKB_SHIFT, |
| kLTC_ClearPkhaSizeN = 1U << LTC_CW_CPKN_SHIFT, |
| kLTC_ClearPkhaSizeE = 1U << LTC_CW_CPKE_SHIFT, |
| kLTC_ClearAllSize = (int)kLTC_ClearPkhaSizeA | kLTC_ClearPkhaSizeB | kLTC_ClearPkhaSizeN | kLTC_ClearPkhaSizeE, |
| #endif /* FSL_FEATURE_LTC_HAS_PKHA */ |
| kLTC_ClearOutputFifo = 1U << LTC_CW_COF_SHIFT, |
| kLTC_ClearInputFifo = (int)(1U << LTC_CW_CIF_SHIFT), |
| kLTC_ClearAll = (int)(LTC_CW_CM_MASK | LTC_CW_CDS_MASK | LTC_CW_CICV_MASK | LTC_CW_CCR_MASK | LTC_CW_CKR_MASK | |
| #if defined(FSL_FEATURE_LTC_HAS_PKHA) && FSL_FEATURE_LTC_HAS_PKHA |
| LTC_CW_CPKA_MASK | LTC_CW_CPKB_MASK | LTC_CW_CPKN_MASK | LTC_CW_CPKE_MASK | |
| #endif /* FSL_FEATURE_LTC_HAS_PKHA */ |
| LTC_CW_COF_MASK | LTC_CW_CIF_MASK) |
| } ltc_clear_written_t; |
| |
| enum _ltc_ctrl_swap |
| { |
| kLTC_CtrlSwapAll = |
| LTC_CTL_IFS_MASK | LTC_CTL_OFS_MASK | LTC_CTL_KIS_MASK | LTC_CTL_KOS_MASK | LTC_CTL_CIS_MASK | LTC_CTL_COS_MASK, |
| }; |
| |
| /*! @brief Type used in GCM and CCM modes. |
| |
| Content of a block is established via individual bytes and moved to LTC |
| IFIFO by moving 32-bit words. |
| */ |
| typedef union _ltc_xcm_block_t |
| { |
| uint32_t w[4]; /*!< LTC context register is 16 bytes written as four 32-bit words */ |
| uint8_t b[16]; /*!< 16 octets block for CCM B0 and CTR0 and for GCM */ |
| } ltc_xcm_block_t; |
| |
| #if defined(FSL_FEATURE_LTC_HAS_PKHA) && FSL_FEATURE_LTC_HAS_PKHA |
| |
| /*! @brief PKHA functions - arithmetic, copy/clear memory. */ |
| typedef enum _ltc_pkha_func_t |
| { |
| kLTC_PKHA_ClearMem = 1U, |
| kLTC_PKHA_ArithModAdd = 2U, /*!< (A + B) mod N */ |
| kLTC_PKHA_ArithModSub1 = 3U, /*!< (A - B) mod N */ |
| kLTC_PKHA_ArithModSub2 = 4U, /*!< (B - A) mod N */ |
| kLTC_PKHA_ArithModMul = 5U, /*!< (A x B) mod N */ |
| kLTC_PKHA_ArithModExp = 6U, /*!< (A^E) mod N */ |
| kLTC_PKHA_ArithModRed = 7U, /*!< (A) mod N */ |
| kLTC_PKHA_ArithModInv = 8U, /*!< (A^-1) mod N */ |
| kLTC_PKHA_ArithEccAdd = 9U, /*!< (P1 + P2) */ |
| kLTC_PKHA_ArithEccDouble = 10U, /*!< (P2 + P2) */ |
| kLTC_PKHA_ArithEccMul = 11U, /*!< (E x P1) */ |
| kLTC_PKHA_ArithModR2 = 12U, /*!< (R^2 mod N) */ |
| kLTC_PKHA_ArithGcd = 14U, /*!< GCD (A, N) */ |
| kLTC_PKHA_ArithPrimalityTest = 15U, /*!< Miller-Rabin */ |
| kLTC_PKHA_CopyMemSizeN = 16U, |
| kLTC_PKHA_CopyMemSizeSrc = 17U, |
| } ltc_pkha_func_t; |
| |
| /*! @brief Register areas for PKHA clear memory operations. */ |
| typedef enum _ltc_pkha_reg_area |
| { |
| kLTC_PKHA_RegA = 8U, |
| kLTC_PKHA_RegB = 4U, |
| kLTC_PKHA_RegE = 2U, |
| kLTC_PKHA_RegN = 1U, |
| kLTC_PKHA_RegAll = kLTC_PKHA_RegA | kLTC_PKHA_RegB | kLTC_PKHA_RegE | kLTC_PKHA_RegN, |
| } ltc_pkha_reg_area_t; |
| |
| /*! @brief Quadrant areas for 2048-bit registers for PKHA copy memory |
| * operations. */ |
| typedef enum _ltc_pkha_quad_area_t |
| { |
| kLTC_PKHA_Quad0 = 0U, |
| kLTC_PKHA_Quad1 = 1U, |
| kLTC_PKHA_Quad2 = 2U, |
| kLTC_PKHA_Quad3 = 3U, |
| } ltc_pkha_quad_area_t; |
| |
| /*! @brief User-supplied (R^2 mod N) input or LTC should calculate. */ |
| typedef enum _ltc_pkha_r2_t |
| { |
| kLTC_PKHA_CalcR2 = 0U, /*!< Calculate (R^2 mod N) */ |
| kLTC_PKHA_InputR2 = 1U /*!< (R^2 mod N) supplied as input */ |
| } ltc_pkha_r2_t; |
| |
| /*! @brief LTC PKHA parameters */ |
| typedef struct _ltc_pkha_mode_params_t |
| { |
| ltc_pkha_func_t func; |
| ltc_pkha_f2m_t arithType; |
| ltc_pkha_montgomery_form_t montFormIn; |
| ltc_pkha_montgomery_form_t montFormOut; |
| ltc_pkha_reg_area_t srcReg; |
| ltc_pkha_quad_area_t srcQuad; |
| ltc_pkha_reg_area_t dstReg; |
| ltc_pkha_quad_area_t dstQuad; |
| ltc_pkha_timing_t equalTime; |
| ltc_pkha_r2_t r2modn; |
| } ltc_pkha_mode_params_t; |
| |
| #endif /* FSL_FEATURE_LTC_HAS_PKHA */ |
| |
| /******************************************************************************* |
| * Prototypes |
| ******************************************************************************/ |
| #if defined(FSL_FEATURE_LTC_HAS_PKHA) && FSL_FEATURE_LTC_HAS_PKHA |
| static status_t ltc_pkha_clear_regabne(LTC_Type *base, bool A, bool B, bool N, bool E); |
| #endif /* FSL_FEATURE_LTC_HAS_PKHA */ |
| |
| /******************************************************************************* |
| * Code |
| ******************************************************************************/ |
| |
| /******************************************************************************* |
| * LTC Common code static |
| ******************************************************************************/ |
| /*! |
| * @brief Tests the correct key size. |
| * |
| * This function tests the correct key size. |
| * @param keySize Input key length in bytes. |
| * @return True if the key length is supported, false if not. |
| */ |
| bool ltc_check_key_size(const uint32_t keySize) |
| { |
| return ((keySize == 16u) |
| #if defined(FSL_FEATURE_LTC_HAS_AES192) && FSL_FEATURE_LTC_HAS_AES192 |
| || ((keySize == 24u)) |
| #endif /* FSL_FEATURE_LTC_HAS_AES192 */ |
| #if defined(FSL_FEATURE_LTC_HAS_AES256) && FSL_FEATURE_LTC_HAS_AES256 |
| || ((keySize == 32u)) |
| #endif /* FSL_FEATURE_LTC_HAS_AES256 */ |
| ); |
| } |
| |
| /*! @brief LTC driver wait mechanism. */ |
| status_t ltc_wait(LTC_Type *base) |
| { |
| status_t status; |
| |
| bool error = false; |
| bool done = false; |
| |
| /* Wait for 'done' or 'error' flag. */ |
| while ((!error) && (!done)) |
| { |
| uint32_t temp32 = base->STA; |
| error = temp32 & LTC_STA_EI_MASK; |
| done = temp32 & LTC_STA_DI_MASK; |
| } |
| |
| if (error) |
| { |
| base->COM = LTC_COM_ALL_MASK; /* Reset all engine to clear the error flag */ |
| status = kStatus_Fail; |
| } |
| else /* 'done' */ |
| { |
| status = kStatus_Success; |
| |
| base->CW = kLTC_ClearDataSize; |
| /* Clear 'done' interrupt status. This also clears the mode register. */ |
| base->STA = kLTC_StatusDoneIsr; |
| } |
| |
| return status; |
| } |
| |
| /*! |
| * @brief Clears the LTC module. |
| * This function can be used to clear all sensitive data from theLTC module, such as private keys. It is called |
| * internally by the LTC driver in case of an error or operation complete. |
| * @param base LTC peripheral base address |
| * @param pkha Include LTC PKHA register clear. If there is no PKHA, the argument is ignored. |
| */ |
| void ltc_clear_all(LTC_Type *base, bool addPKHA) |
| { |
| base->CW = (uint32_t)kLTC_ClearAll; |
| #if defined(FSL_FEATURE_LTC_HAS_PKHA) && FSL_FEATURE_LTC_HAS_PKHA |
| if (addPKHA) |
| { |
| ltc_pkha_clear_regabne(base, true, true, true, true); |
| } |
| #endif /* FSL_FEATURE_LTC_HAS_PKHA */ |
| } |
| |
| void ltc_memcpy(void *dst, const void *src, size_t size) |
| { |
| #if defined(__cplusplus) |
| register uint8_t *to = (uint8_t *)dst; |
| register const uint8_t *from = (const uint8_t *)src; |
| #else |
| register uint8_t *to = dst; |
| register const uint8_t *from = src; |
| #endif |
| while (size) |
| { |
| *to = *from; |
| size--; |
| to++; |
| from++; |
| } |
| } |
| |
| /*! |
| * @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. |
| */ |
| static inline uint32_t ltc_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 ((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 *)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 *)srcAddr); |
| #endif |
| } |
| |
| /*! |
| * @brief Converts a 32-bit word into a byte array. |
| * |
| * This function creates an output array of four bytes from an input 32-bit word. |
| * |
| * @param srcWord Input 32-bit unsigned integer. |
| * @param dst Output array of four bytes. The array can start at any address in memory. |
| */ |
| static inline void ltc_set_unaligned_from_word(uint32_t srcWord, uint8_t *dstAddr) |
| { |
| #if (!(defined(__CORTEX_M)) || (defined(__CORTEX_M) && (__CORTEX_M == 0))) |
| register uint8_t *dst = dstAddr; |
| /* Cortex M0 does not support misaligned stores */ |
| if ((uint32_t)dst & 0x3u) |
| { |
| *dst++ = (srcWord & 0x000000FFU); |
| *dst++ = (srcWord & 0x0000FF00U) >> 8; |
| *dst++ = (srcWord & 0x00FF0000U) >> 16; |
| *dst++ = (srcWord & 0xFF000000U) >> 24; |
| } |
| else |
| { |
| *((uint32_t *)dstAddr) = srcWord; /* addr aligned to 0-modulo-4 so it is safe to type cast */ |
| } |
| #elif defined(__CC_ARM) |
| __asm |
| { |
| STR srcWord, [dstAddr] |
| } |
| return; |
| #else |
| *((uint32_t *)dstAddr) = srcWord; |
| #endif |
| } |
| |
| /*! |
| * @brief Sets the LTC keys. |
| * |
| * This function writes the LTC keys into the key register. The keys should |
| * be written before the key size. |
| * |
| * @param base LTC peripheral base address |
| * @param key Key |
| * @param keySize Number of bytes for all keys to be loaded (maximum 32, must be a |
| * multiple of 4). |
| * @returns Key set status |
| */ |
| static status_t ltc_set_key(LTC_Type *base, const uint8_t *key, uint8_t keySize) |
| { |
| int32_t i; |
| |
| for (i = 0; i < (keySize / 4); i++) |
| { |
| base->KEY[i] = ltc_get_word_from_unaligned(key + i * sizeof(uint32_t)); |
| } |
| |
| return kStatus_Success; |
| } |
| |
| /*! |
| * @brief Gets the LTC keys. |
| * |
| * This function retrieves the LTC keys from the key register. |
| * |
| * @param base LTC peripheral base address |
| * @param key Array of data to store keys |
| * @param keySize Number of bytes of keys to retrieve |
| * @returns Key set status |
| */ |
| static status_t ltc_get_key(LTC_Type *base, uint8_t *key, uint8_t keySize) |
| { |
| int32_t i; |
| |
| for (i = 0; i < (keySize / 4); i++) |
| { |
| ltc_set_unaligned_from_word(base->KEY[i], key + i * sizeof(uint32_t)); |
| } |
| |
| return kStatus_Success; |
| } |
| |
| /*! |
| * @brief Writes the LTC context register; |
| * |
| * The LTC context register is a 512 bit (64 byte) register that holds |
| * internal context for the crypto engine. The meaning varies based on the |
| * algorithm and operating state being used. This register is written by the |
| * driver/application to load state such as IV, counter, and so on. Then, it is |
| * updated by the internal crypto engine as needed. |
| * |
| * @param base LTC peripheral base address |
| * @param data Data to write |
| * @param dataSize Size of data to write in bytes |
| * @param startIndex Starting word (4-byte) index into the 16-word register. |
| * @return Status of write |
| */ |
| status_t ltc_set_context(LTC_Type *base, const uint8_t *data, uint8_t dataSize, uint8_t startIndex) |
| { |
| int32_t i; |
| int32_t j; |
| int32_t szLeft; |
| |
| /* Context register is 16 words in size (64 bytes). Ensure we are only |
| * writing a valid amount of data. */ |
| if (startIndex + (dataSize / 4) >= 16) |
| { |
| return kStatus_InvalidArgument; |
| } |
| |
| j = 0; |
| szLeft = dataSize % 4; |
| for (i = startIndex; i < (startIndex + dataSize / 4); i++) |
| { |
| base->CTX[i] = ltc_get_word_from_unaligned(data + j); |
| j += sizeof(uint32_t); |
| } |
| |
| if (szLeft) |
| { |
| uint32_t context_data = {0}; |
| ltc_memcpy(&context_data, data + j, szLeft); |
| base->CTX[i] = context_data; |
| } |
| return kStatus_Success; |
| } |
| |
| /*! |
| * @brief Reads the LTC context register. |
| * |
| * The LTC context register is a 512 bit (64 byte) register that holds |
| * internal context for the crypto engine. The meaning varies based on the |
| * algorithm and operating state being used. This register is written by the |
| * driver/application to load state such as IV, counter, and so on. Then, it is |
| * updated by the internal crypto engine as needed. |
| * |
| * @param base LTC peripheral base address |
| * @param data Destination of read data |
| * @param dataSize Size of data to read in bytes |
| * @param startIndex Starting word (4-byte) index into the 16-word register. |
| * @return Status of read |
| */ |
| status_t ltc_get_context(LTC_Type *base, uint8_t *dest, uint8_t dataSize, uint8_t startIndex) |
| { |
| int32_t i; |
| int32_t j; |
| int32_t szLeft; |
| uint32_t rdCtx; |
| |
| /* Context register is 16 words in size (64 bytes). Ensure we are only |
| * writing a valid amount of data. */ |
| if (startIndex + (dataSize / 4) >= 16) |
| { |
| return kStatus_InvalidArgument; |
| } |
| |
| j = 0; |
| szLeft = dataSize % 4; |
| for (i = startIndex; i < (startIndex + dataSize / 4); i++) |
| { |
| ltc_set_unaligned_from_word(base->CTX[i], dest + j); |
| j += sizeof(uint32_t); |
| } |
| |
| if (szLeft) |
| { |
| rdCtx = 0; |
| rdCtx = base->CTX[i]; |
| ltc_memcpy(dest + j, &rdCtx, szLeft); |
| } |
| return kStatus_Success; |
| } |
| |
| static status_t ltc_symmetric_alg_state(LTC_Type *base, |
| const uint8_t *key, |
| uint8_t keySize, |
| ltc_algorithm_t alg, |
| ltc_mode_symmetric_alg_t mode, |
| ltc_mode_encrypt_t enc, |
| ltc_mode_algorithm_state_t as) |
| { |
| ltc_mode_t modeReg; |
| |
| /* Clear internal register states. */ |
| base->CW = (uint32_t)kLTC_ClearAll; |
| |
| /* Set byte swap on for several registers we will be reading and writing |
| * user data to/from. */ |
| base->CTL |= kLTC_CtrlSwapAll; |
| |
| /* Write the key in place. */ |
| ltc_set_key(base, key, keySize); |
| |
| /* Write the key size. This must be done after writing the key, and this |
| * action locks the ability to modify the key registers. */ |
| base->KS = keySize; |
| |
| /* Clear the 'done' interrupt. */ |
| base->STA = kLTC_StatusDoneIsr; |
| |
| /* Set the proper block and algorithm mode. */ |
| modeReg = (uint32_t)alg | (uint32_t)enc | (uint32_t)as | (uint32_t)mode; |
| |
| /* Write the mode register to the hardware. */ |
| base->MD = modeReg; |
| |
| return kStatus_Success; |
| } |
| |
| /*! |
| * @brief Initializes the LTC for symmetric encrypt/decrypt operation. Mode is set to UPDATE. |
| * |
| * @param base LTC peripheral base address |
| * @param key Input key to use for encryption |
| * @param keySize Size of the input key, in bytes. Must be 8, 16, 24, or 32. |
| * @param alg Symmetric algorithm |
| * @param mode Symmetric block mode |
| * @param enc Encrypt/decrypt control |
| * @return Status |
| */ |
| status_t ltc_symmetric_update(LTC_Type *base, |
| const uint8_t *key, |
| uint8_t keySize, |
| ltc_algorithm_t alg, |
| ltc_mode_symmetric_alg_t mode, |
| ltc_mode_encrypt_t enc) |
| { |
| return ltc_symmetric_alg_state(base, key, keySize, alg, mode, enc, kLTC_ModeUpdate); |
| } |
| |
| #if defined(FSL_FEATURE_LTC_HAS_GCM) && FSL_FEATURE_LTC_HAS_GCM |
| /*! |
| * @brief Initializes the LTC for symmetric encrypt/decrypt operation. Mode is set to FINALIZE. |
| * |
| * @param base LTC peripheral base address |
| * @param key Input key to use for encryption |
| * @param keySize Size of the input key, in bytes. Must be 8, 16, 24, or 32. |
| * @param alg Symmetric algorithm |
| * @param mode Symmetric block mode |
| * @param enc Encrypt/decrypt control |
| * @return Status |
| */ |
| static status_t ltc_symmetric_final(LTC_Type *base, |
| const uint8_t *key, |
| uint8_t keySize, |
| ltc_algorithm_t alg, |
| ltc_mode_symmetric_alg_t mode, |
| ltc_mode_encrypt_t enc) |
| { |
| return ltc_symmetric_alg_state(base, key, keySize, alg, mode, enc, kLTC_ModeFinalize); |
| } |
| #endif /* FSL_FEATURE_LTC_HAS_GCM */ |
| |
| /*! |
| * @brief Initializes the LTC for symmetric encrypt/decrypt operation. Mode is set to INITIALIZE. |
| * |
| * @param base LTC peripheral base address |
| * @param key Input key to use for encryption |
| * @param keySize Size of the input key, in bytes. Must be 8, 16, 24, or 32. |
| * @param alg Symmetric algorithm |
| * @param mode Symmetric block mode |
| * @param enc Encrypt/decrypt control |
| * @return Status |
| */ |
| static status_t ltc_symmetric_init(LTC_Type *base, |
| const uint8_t *key, |
| uint8_t keySize, |
| ltc_algorithm_t alg, |
| ltc_mode_symmetric_alg_t mode, |
| ltc_mode_encrypt_t enc) |
| { |
| return ltc_symmetric_alg_state(base, key, keySize, alg, mode, enc, kLTC_ModeInit); |
| } |
| |
| /*! |
| * @brief Initializes the LTC for symmetric encrypt/decrypt operation. Mode is set to INITIALIZE/FINALIZE. |
| * |
| * @param base LTC peripheral base address |
| * @param key Input key to use for encryption |
| * @param keySize Size of the input key, in bytes. Must be 8, 16, 24, or 32. |
| * @param alg Symmetric algorithm |
| * @param mode Symmetric block mode |
| * @param enc Encrypt/decrypt control |
| * @return Status |
| */ |
| static status_t ltc_symmetric_init_final(LTC_Type *base, |
| const uint8_t *key, |
| uint8_t keySize, |
| ltc_algorithm_t alg, |
| ltc_mode_symmetric_alg_t mode, |
| ltc_mode_encrypt_t enc) |
| { |
| return ltc_symmetric_alg_state(base, key, keySize, alg, mode, enc, kLTC_ModeInitFinal); |
| } |
| |
| void ltc_symmetric_process(LTC_Type *base, uint32_t inSize, const uint8_t **inData, uint8_t **outData) |
| { |
| uint32_t outSize; |
| uint32_t fifoData; |
| uint32_t fifoStatus; |
| |
| register const uint8_t *in = *inData; |
| register uint8_t *out = *outData; |
| |
| outSize = inSize; |
| while ((outSize > 0) || (inSize > 0)) |
| { |
| fifoStatus = base->FIFOSTA; |
| |
| /* Check output FIFO level to make sure there is at least an entry |
| * ready to be read. */ |
| if (fifoStatus & LTC_FIFOSTA_OFL_MASK) |
| { |
| /* Read data from the output FIFO. */ |
| if (outSize > 0) |
| { |
| if (outSize >= sizeof(uint32_t)) |
| { |
| ltc_set_unaligned_from_word(base->OFIFO, out); |
| out += sizeof(uint32_t); |
| outSize -= sizeof(uint32_t); |
| } |
| else /* (outSize > 0) && (outSize < 4) */ |
| { |
| fifoData = base->OFIFO; |
| ltc_memcpy(out, &fifoData, outSize); |
| out += outSize; |
| outSize = 0; |
| } |
| } |
| } |
| |
| /* Check input FIFO status to see if it is full. We can |
| * only write more data when both input and output FIFOs are not at a full state. |
| * At the same time we are sure Output FIFO is not full because we have poped at least one entry |
| * by the while loop above. |
| */ |
| if (!(fifoStatus & LTC_FIFOSTA_IFF_MASK)) |
| { |
| /* Copy data to the input FIFO. |
| * Data can only be copied one word at a time, so pad the data |
| * appropriately if it is less than this size. */ |
| if (inSize > 0) |
| { |
| if (inSize >= sizeof(uint32_t)) |
| { |
| base->IFIFO = ltc_get_word_from_unaligned(in); |
| inSize -= sizeof(uint32_t); |
| in += sizeof(uint32_t); |
| } |
| else /* (inSize > 0) && (inSize < 4) */ |
| { |
| fifoData = 0; |
| ltc_memcpy(&fifoData, in, inSize); |
| base->IFIFO = fifoData; |
| in += inSize; |
| inSize = 0; |
| } |
| } |
| } |
| } |
| *inData = in; |
| *outData = out; |
| } |
| |
| /*! |
| * @brief Processes symmetric data through LTC AES and DES engines. |
| * |
| * @param base LTC peripheral base address |
| * @param inData Input data |
| * @param inSize Size of input data, in bytes |
| * @param outData Output data |
| * @return Status from encrypt/decrypt operation |
| */ |
| status_t ltc_symmetric_process_data(LTC_Type *base, const uint8_t *inData, uint32_t inSize, uint8_t *outData) |
| { |
| uint32_t lastSize; |
| |
| if ((!inData) || (!outData)) |
| { |
| return kStatus_InvalidArgument; |
| } |
| |
| /* Write the data size. */ |
| base->DS = inSize; |
| |
| /* Split the inSize into full 16-byte chunks and last incomplete block due to LTC AES OFIFO errata */ |
| if (inSize <= 16u) |
| { |
| lastSize = inSize; |
| inSize = 0; |
| } |
| else |
| { |
| /* Process all 16-byte data chunks. */ |
| lastSize = inSize % 16u; |
| if (lastSize == 0) |
| { |
| lastSize = 16; |
| inSize -= 16; |
| } |
| else |
| { |
| inSize -= lastSize; /* inSize will be rounded down to 16 byte boundary. remaining bytes in lastSize */ |
| } |
| } |
| |
| ltc_symmetric_process(base, inSize, &inData, &outData); |
| ltc_symmetric_process(base, lastSize, &inData, &outData); |
| return ltc_wait(base); |
| } |
| |
| /*! |
| * @brief Splits the LTC job into sessions. Used for CBC, CTR, CFB, OFB cipher block modes. |
| * |
| * @param base LTC peripheral base address |
| * @param inData Input data to process. |
| * @param inSize Input size of the input buffer. |
| * @param outData Output data buffer. |
| */ |
| static status_t ltc_process_message_in_sessions(LTC_Type *base, |
| const uint8_t *inData, |
| uint32_t inSize, |
| uint8_t *outData) |
| { |
| uint32_t sz; |
| status_t retval; |
| ltc_mode_t modeReg; /* read and write LTC mode register */ |
| |
| sz = LTC_FIFO_SZ_MAX_DOWN_ALGN; |
| modeReg = base->MD; |
| retval = kStatus_Success; |
| |
| while (inSize) |
| { |
| if (inSize <= sz) |
| { |
| retval = ltc_symmetric_process_data(base, inData, inSize, outData); |
| if (kStatus_Success != retval) |
| { |
| return retval; |
| } |
| inSize = 0; |
| } |
| else |
| { |
| retval = ltc_symmetric_process_data(base, inData, sz, outData); |
| if (kStatus_Success != retval) |
| { |
| return retval; |
| } |
| inData += sz; |
| inSize -= sz; |
| outData += sz; |
| base->MD = modeReg; |
| } |
| } |
| return retval; |
| } |
| |
| static void ltc_move_block_to_ififo(LTC_Type *base, const ltc_xcm_block_t *blk, uint32_t num_bytes) |
| { |
| uint32_t i = 0; |
| uint32_t words; |
| |
| words = num_bytes / 4u; |
| if (num_bytes % 4u) |
| { |
| words++; |
| } |
| |
| if (words > 4) |
| { |
| words = 4; |
| } |
| |
| while (i < words) |
| { |
| if (0U == (base->FIFOSTA & LTC_FIFOSTA_IFF_MASK)) |
| { |
| /* Copy data to the input FIFO. */ |
| base->IFIFO = blk->w[i++]; |
| } |
| } |
| } |
| |
| static void ltc_move_to_ififo(LTC_Type *base, const uint8_t *data, uint32_t dataSize) |
| { |
| ltc_xcm_block_t blk; |
| ltc_xcm_block_t blkZero = {{0x0u, 0x0u, 0x0u, 0x0u}}; |
| |
| while (dataSize) |
| { |
| if (dataSize > 16u) |
| { |
| ltc_memcpy(&blk, data, 16u); |
| dataSize -= 16u; |
| data += 16u; |
| } |
| else |
| { |
| ltc_memcpy(&blk, &blkZero, sizeof(ltc_xcm_block_t)); /* memset blk to zeroes */ |
| ltc_memcpy(&blk, data, dataSize); |
| dataSize = 0; |
| } |
| ltc_move_block_to_ififo(base, &blk, sizeof(ltc_xcm_block_t)); |
| } |
| } |
| |
| /*! |
| * @brief Processes symmetric data through LTC AES in multiple sessions. |
| * |
| * Specific for AES CCM and GCM modes as they need to update mode register. |
| * |
| * @param base LTC peripheral base address |
| * @param inData Input data |
| * @param inSize Size of input data, in bytes |
| * @param outData Output data |
| * @param lastAs The LTC Algorithm state to be set sup for last block during message processing in multiple sessions. |
| * For CCM it is kLTC_ModeFinalize. For GCM it is kLTC_ModeInitFinal. |
| * @return Status from encrypt/decrypt operation |
| */ |
| static status_t ltc_symmetric_process_data_multiple(LTC_Type *base, |
| const uint8_t *inData, |
| uint32_t inSize, |
| uint8_t *outData, |
| ltc_mode_t modeReg, |
| ltc_mode_algorithm_state_t lastAs) |
| { |
| uint32_t fifoConsumed; |
| uint32_t lastSize; |
| uint32_t sz; |
| uint32_t max_ltc_fifo_size; |
| ltc_mode_algorithm_state_t fsm; |
| status_t status; |
| |
| if ((!inData) || (!outData)) |
| { |
| return kStatus_InvalidArgument; |
| } |
| |
| if (!((kLTC_ModeFinalize == lastAs) || (kLTC_ModeInitFinal == lastAs))) |
| { |
| return kStatus_InvalidArgument; |
| } |
| |
| if (0 == inSize) |
| { |
| return kStatus_Success; |
| } |
| |
| if (inSize <= 16u) |
| { |
| fsm = lastAs; |
| lastSize = inSize; |
| } |
| else |
| { |
| fsm = (ltc_mode_algorithm_state_t)( |
| modeReg & |
| LTC_MD_AS_MASK); /* this will be either kLTC_ModeInit or kLTC_ModeUpdate, based on prior processing */ |
| |
| /* Process all 16-byte data chunks. */ |
| lastSize = inSize % 16u; |
| if (lastSize == 0u) |
| { |
| lastSize = 16u; |
| inSize -= 16u; |
| } |
| else |
| { |
| inSize -= lastSize; /* inSize will be rounded down to 16 byte boundary. remaining bytes in lastSize */ |
| } |
| } |
| |
| max_ltc_fifo_size = LTC_FIFO_SZ_MAX_DOWN_ALGN; |
| fifoConsumed = base->DS; |
| |
| while (lastSize) |
| { |
| switch (fsm) |
| { |
| case kLTC_ModeUpdate: |
| case kLTC_ModeInit: |
| while (inSize) |
| { |
| if (inSize > (max_ltc_fifo_size - fifoConsumed)) |
| { |
| sz = (max_ltc_fifo_size - fifoConsumed); |
| } |
| else |
| { |
| sz = inSize; |
| } |
| base->DS = sz; |
| ltc_symmetric_process(base, sz, &inData, &outData); |
| inSize -= sz; |
| fifoConsumed = 0; |
| |
| /* after we completed INITIALIZE job, are there still any data left? */ |
| if (inSize) |
| { |
| fsm = kLTC_ModeUpdate; |
| status = ltc_wait(base); |
| if (kStatus_Success != status) |
| { |
| return status; |
| } |
| modeReg &= ~LTC_MD_AS_MASK; |
| modeReg |= (uint32_t)fsm; |
| base->MD = modeReg; |
| } |
| else |
| { |
| fsm = lastAs; |
| } |
| } |
| break; |
| |
| case kLTC_ModeFinalize: |
| case kLTC_ModeInitFinal: |
| /* process last block in FINALIZE */ |
| |
| status = ltc_wait(base); |
| if (kStatus_Success != status) |
| { |
| return status; |
| } |
| |
| modeReg &= ~LTC_MD_AS_MASK; |
| modeReg |= (uint32_t)lastAs; |
| base->MD = modeReg; |
| |
| base->DS = lastSize; |
| ltc_symmetric_process(base, lastSize, &inData, &outData); |
| lastSize = 0; |
| break; |
| |
| default: |
| break; |
| } |
| } |
| |
| status = ltc_wait(base); |
| return status; |
| } |
| |
| /*! |
| * @brief Receives MAC compare. |
| * |
| * This function is a sub-process of CCM and GCM decryption. |
| * It compares received MAC with the MAC computed during decryption. |
| * |
| * @param base LTC peripheral base address |
| * @param tag Received MAC. |
| * @param tagSize Number of bytes in the received MAC. |
| * @param modeReg LTC Mode Register current value. It is modified and written to LTC Mode Register. |
| */ |
| static status_t ltc_aes_received_mac_compare(LTC_Type *base, const uint8_t *tag, uint32_t tagSize, ltc_mode_t modeReg) |
| { |
| ltc_xcm_block_t blk = {{0x0u, 0x0u, 0x0u, 0x0u}}; |
| |
| base->CW = kLTC_ClearDataSize; |
| base->STA = kLTC_StatusDoneIsr; |
| |
| modeReg &= ~LTC_MD_AS_MASK; |
| modeReg |= (uint32_t)kLTC_ModeUpdate | LTC_MD_ICV_TEST_MASK; |
| base->MD = modeReg; |
| |
| base->DS = 0u; |
| base->ICVS = tagSize; |
| ltc_memcpy(&blk.b[0], &tag[0], tagSize); |
| |
| ltc_move_block_to_ififo(base, &blk, tagSize); |
| return ltc_wait(base); |
| } |
| |
| /*! |
| * @brief Processes tag during AES GCM and CCM. |
| * |
| * This function is a sub-process of CCM and GCM encryption and decryption. |
| * For encryption, it writes computed MAC to the output tag. |
| * For decryption, it compares the received MAC with the computed MAC. |
| * |
| * @param base LTC peripheral base address |
| * @param[in,out] tag Output computed MAC during encryption or Input received MAC during decryption. |
| * @param tagSize Size of MAC buffer in bytes. |
| * @param modeReg LTC Mode Register current value. It is checked to read Enc/Dec bit. |
| * It is modified and written to LTC Mode Register during decryption. |
| * @param ctx Index to LTC context registers with computed MAC for encryption process. |
| */ |
| static status_t ltc_aes_process_tag(LTC_Type *base, uint8_t *tag, uint32_t tagSize, ltc_mode_t modeReg, uint32_t ctx) |
| { |
| status_t status = kStatus_Success; |
| if (tag) |
| { |
| /* For decrypt, compare received MAC with the computed MAC. */ |
| if (kLTC_ModeDecrypt == (modeReg & LTC_MD_ENC_MASK)) |
| { |
| status = ltc_aes_received_mac_compare(base, tag, tagSize, modeReg); |
| } |
| else /* FSL_AES_GCM_TYPE_ENCRYPT */ |
| { |
| /* For encryption, write the computed and encrypted MAC to user buffer */ |
| ltc_get_context(base, &tag[0], tagSize, ctx); |
| } |
| } |
| return status; |
| } |
| |
| /******************************************************************************* |
| * LTC Common code public |
| ******************************************************************************/ |
| void LTC_Init(LTC_Type *base) |
| { |
| #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) |
| /* ungate clock */ |
| CLOCK_EnableClock(kCLOCK_Ltc0); |
| #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ |
| } |
| |
| void LTC_Deinit(LTC_Type *base) |
| { |
| #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) |
| /* gate clock */ |
| CLOCK_DisableClock(kCLOCK_Ltc0); |
| #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ |
| } |
| |
| #if defined(FSL_FEATURE_LTC_HAS_DPAMS) && FSL_FEATURE_LTC_HAS_DPAMS |
| void LTC_SetDpaMaskSeed(LTC_Type *base, uint32_t mask) |
| { |
| base->DPAMS = mask; |
| /* second write as workaround for DPA mask re-seed errata */ |
| base->DPAMS = mask; |
| } |
| #endif /* FSL_FEATURE_LTC_HAS_DPAMS */ |
| |
| /******************************************************************************* |
| * AES Code static |
| ******************************************************************************/ |
| static status_t ltc_aes_decrypt_ecb(LTC_Type *base, |
| const uint8_t *ciphertext, |
| uint8_t *plaintext, |
| uint32_t size, |
| const uint8_t *key, |
| uint32_t keySize, |
| ltc_aes_key_t keyType) |
| { |
| status_t retval; |
| |
| /* Initialize algorithm state. */ |
| ltc_symmetric_update(base, key, keySize, kLTC_AlgorithmAES, kLTC_ModeECB, kLTC_ModeDecrypt); |
| |
| /* set DK bit in the LTC Mode Register AAI field for directly loaded decrypt keys */ |
| if (keyType == kLTC_DecryptKey) |
| { |
| base->MD |= (1U << kLTC_ModeRegBitShiftDK); |
| } |
| |
| /* Process data and return status. */ |
| retval = ltc_process_message_in_sessions(base, &ciphertext[0], size, &plaintext[0]); |
| return retval; |
| } |
| |
| /******************************************************************************* |
| * AES Code public |
| ******************************************************************************/ |
| status_t LTC_AES_GenerateDecryptKey(LTC_Type *base, const uint8_t *encryptKey, uint8_t *decryptKey, uint32_t keySize) |
| { |
| uint8_t plaintext[LTC_AES_BLOCK_SIZE]; |
| uint8_t ciphertext[LTC_AES_BLOCK_SIZE]; |
| status_t status; |
| |
| if (!ltc_check_key_size(keySize)) |
| { |
| return kStatus_InvalidArgument; |
| } |
| |
| /* ECB decrypt with encrypt key will convert the key in LTC context into decrypt form of the key */ |
| status = ltc_aes_decrypt_ecb(base, ciphertext, plaintext, LTC_AES_BLOCK_SIZE, encryptKey, keySize, kLTC_EncryptKey); |
| /* now there is decrypt form of the key in the LTC context, so take it */ |
| ltc_get_key(base, decryptKey, keySize); |
| |
| ltc_clear_all(base, false); |
| |
| return status; |
| } |
| |
| status_t LTC_AES_EncryptEcb( |
| LTC_Type *base, const uint8_t *plaintext, uint8_t *ciphertext, uint32_t size, const uint8_t *key, uint32_t keySize) |
| { |
| status_t retval; |
| |
| if (!ltc_check_key_size(keySize)) |
| { |
| return kStatus_InvalidArgument; |
| } |
| /* ECB mode, size must be 16-byte multiple */ |
| if ((size < 16u) || (size % 16u)) |
| { |
| return kStatus_InvalidArgument; |
| } |
| |
| /* Initialize algorithm state. */ |
| ltc_symmetric_update(base, key, keySize, kLTC_AlgorithmAES, kLTC_ModeECB, kLTC_ModeEncrypt); |
| |
| /* Process data and return status. */ |
| retval = ltc_process_message_in_sessions(base, &plaintext[0], size, &ciphertext[0]); |
| ltc_clear_all(base, false); |
| return retval; |
| } |
| |
| status_t LTC_AES_DecryptEcb(LTC_Type *base, |
| const uint8_t *ciphertext, |
| uint8_t *plaintext, |
| uint32_t size, |
| const uint8_t *key, |
| uint32_t keySize, |
| ltc_aes_key_t keyType) |
| { |
| status_t status; |
| |
| if (!ltc_check_key_size(keySize)) |
| { |
| return kStatus_InvalidArgument; |
| } |
| /* ECB mode, size must be 16-byte multiple */ |
| if ((size < 16u) || (size % 16u)) |
| { |
| return kStatus_InvalidArgument; |
| } |
| |
| status = ltc_aes_decrypt_ecb(base, ciphertext, plaintext, size, key, keySize, keyType); |
| ltc_clear_all(base, false); |
| return status; |
| } |
| |
| status_t LTC_AES_EncryptCbc(LTC_Type *base, |
| const uint8_t *plaintext, |
| uint8_t *ciphertext, |
| uint32_t size, |
| const uint8_t iv[LTC_AES_IV_SIZE], |
| const uint8_t *key, |
| uint32_t keySize) |
| { |
| status_t retval; |
| |
| if (!ltc_check_key_size(keySize)) |
| { |
| return kStatus_InvalidArgument; |
| } |
| |
| /* CBC mode, size must be 16-byte multiple */ |
| if ((size < 16u) || (size % 16u)) |
| { |
| return kStatus_InvalidArgument; |
| } |
| |
| /* Initialize algorithm state. */ |
| ltc_symmetric_update(base, key, keySize, kLTC_AlgorithmAES, kLTC_ModeCBC, kLTC_ModeEncrypt); |
| |
| /* Write IV data to the context register. */ |
| ltc_set_context(base, &iv[0], LTC_AES_IV_SIZE, 0); |
| |
| /* Process data and return status. */ |
| retval = ltc_process_message_in_sessions(base, &plaintext[0], size, &ciphertext[0]); |
| ltc_clear_all(base, false); |
| return retval; |
| } |
| |
| status_t LTC_AES_DecryptCbc(LTC_Type *base, |
| const uint8_t *ciphertext, |
| uint8_t *plaintext, |
| uint32_t size, |
| const uint8_t iv[LTC_AES_IV_SIZE], |
| const uint8_t *key, |
| uint32_t keySize, |
| ltc_aes_key_t keyType) |
| { |
| status_t retval; |
| |
| if (!ltc_check_key_size(keySize)) |
| { |
| return kStatus_InvalidArgument; |
| } |
| /* CBC mode, size must be 16-byte multiple */ |
| if ((size < 16u) || (size % 16u)) |
| { |
| return kStatus_InvalidArgument; |
| } |
| |
| /* set DK bit in the LTC Mode Register AAI field for directly loaded decrypt keys */ |
| if (keyType == kLTC_DecryptKey) |
| { |
| base->MD |= (1U << kLTC_ModeRegBitShiftDK); |
| } |
| |
| /* Initialize algorithm state. */ |
| ltc_symmetric_update(base, key, keySize, kLTC_AlgorithmAES, kLTC_ModeCBC, kLTC_ModeDecrypt); |
| |
| /* Write IV data to the context register. */ |
| ltc_set_context(base, &iv[0], LTC_AES_IV_SIZE, 0); |
| |
| /* Process data and return status. */ |
| retval = ltc_process_message_in_sessions(base, &ciphertext[0], size, &plaintext[0]); |
| ltc_clear_all(base, false); |
| return retval; |
| } |
| |
| status_t LTC_AES_CryptCtr(LTC_Type *base, |
| const uint8_t *input, |
| uint8_t *output, |
| uint32_t size, |
| uint8_t counter[LTC_AES_BLOCK_SIZE], |
| const uint8_t *key, |
| uint32_t keySize, |
| uint8_t counterlast[LTC_AES_BLOCK_SIZE], |
| uint32_t *szLeft) |
| { |
| status_t retval; |
| uint32_t lastSize; |
| |
| if (!ltc_check_key_size(keySize)) |
| { |
| return kStatus_InvalidArgument; |
| } |
| |
| lastSize = 0U; |
| if (counterlast != NULL) |
| { |
| /* Split the size into full 16-byte chunks and last incomplete block due to LTC AES OFIFO errata */ |
| if (size <= 16U) |
| { |
| lastSize = size; |
| size = 0U; |
| } |
| else |
| { |
| /* Process all 16-byte data chunks. */ |
| lastSize = size % 16U; |
| if (lastSize == 0U) |
| { |
| lastSize = 16U; |
| size -= 16U; |
| } |
| else |
| { |
| size -= lastSize; /* size will be rounded down to 16 byte boundary. remaining bytes in lastSize */ |
| } |
| } |
| } |
| |
| /* Initialize algorithm state. */ |
| ltc_symmetric_update(base, key, keySize, kLTC_AlgorithmAES, kLTC_ModeCTR, kLTC_ModeEncrypt); |
| |
| /* Write initial counter data to the context register. |
| * NOTE the counter values start at 4-bytes offset into the context. */ |
| ltc_set_context(base, &counter[0], 16U, 4U); |
| |
| /* Process data and return status. */ |
| retval = ltc_process_message_in_sessions(base, input, size, output); |
| if (kStatus_Success != retval) |
| { |
| return retval; |
| } |
| |
| input += size; |
| output += size; |
| |
| if ((counterlast != NULL) && lastSize) |
| { |
| uint8_t zeroes[16] = {0}; |
| ltc_mode_t modeReg; |
| |
| modeReg = (uint32_t)kLTC_AlgorithmAES | (uint32_t)kLTC_ModeCTR | (uint32_t)kLTC_ModeEncrypt; |
| /* Write the mode register to the hardware. */ |
| base->MD = modeReg | (uint32_t)kLTC_ModeFinalize; |
| |
| /* context is re-used (CTRi) */ |
| |
| /* Process data and return status. */ |
| retval = ltc_symmetric_process_data(base, input, lastSize, output); |
| if (kStatus_Success != retval) |
| { |
| return retval; |
| } |
| if (szLeft) |
| { |
| *szLeft = 16U - lastSize; |
| } |
| |
| /* Initialize algorithm state. */ |
| base->MD = modeReg | (uint32_t)kLTC_ModeUpdate; |
| |
| /* context is re-used (CTRi) */ |
| |
| /* Process data and return status. */ |
| retval = ltc_symmetric_process_data(base, zeroes, 16U, counterlast); |
| } |
| ltc_get_context(base, &counter[0], 16U, 4U); |
| ltc_clear_all(base, false); |
| return retval; |
| } |
| |
| #if defined(FSL_FEATURE_LTC_HAS_GCM) && FSL_FEATURE_LTC_HAS_GCM |
| /******************************************************************************* |
| * GCM Code static |
| ******************************************************************************/ |
| static status_t ltc_aes_gcm_check_input_args(LTC_Type *base, |
| const uint8_t *src, |
| const uint8_t *iv, |
| const uint8_t *aad, |
| const uint8_t *key, |
| uint8_t *dst, |
| uint32_t inputSize, |
| uint32_t ivSize, |
| uint32_t aadSize, |
| uint32_t keySize, |
| uint32_t tagSize) |
| { |
| if (!base) |
| { |
| return kStatus_InvalidArgument; |
| } |
| |
| /* tag can be NULL to skip tag processing */ |
| if ((!key) || (ivSize && (!iv)) || (aadSize && (!aad)) || (inputSize && ((!src) || (!dst)))) |
| { |
| return kStatus_InvalidArgument; |
| } |
| |
| /* octet length of tag (tagSize) must be element of 4,8,12,13,14,15,16 */ |
| if (((tagSize > 16u) || (tagSize < 12u)) && (tagSize != 4u) && (tagSize != 8u)) |
| { |
| return kStatus_InvalidArgument; |
| } |
| |
| /* check if keySize is supported */ |
| if (!ltc_check_key_size(keySize)) |
| { |
| return kStatus_InvalidArgument; |
| } |
| |
| /* no IV AAD DATA makes no sense */ |
| if (0 == (inputSize + ivSize + aadSize)) |
| { |
| return kStatus_InvalidArgument; |
| } |
| |
| return kStatus_Success; |
| } |
| |
| /*! |
| * @brief Process Wrapper for void (*pfunc)(LTC_Type*, uint32_t, bool). Sets IV Size register. |
| */ |
| static void ivsize_next(LTC_Type *base, uint32_t ivSize, bool iv_only) |
| { |
| base->IVSZ = LTC_IVSZ_IL(iv_only) | ((ivSize)<C_DS_DS_MASK); |
| } |
| |
| /*! |
| * @brief Process Wrapper for void (*pfunc)(LTC_Type*, uint32_t, bool). Sets AAD Size register. |
| */ |
| static void aadsize_next(LTC_Type *base, uint32_t aadSize, bool aad_only) |
| { |
| base->AADSZ = LTC_AADSZ_AL(aad_only) | ((aadSize)<C_DS_DS_MASK); |
| } |
| |
| /*! |
| * @brief Process IV or AAD string in multi-session. |
| * |
| * @param base LTC peripheral base address |
| * @param iv IV or AAD data |
| * @param ivSize Size in bytes of IV or AAD data |
| * @param modeReg LTC peripheral Mode register value |
| * @param iv_only IV only or AAD only flag |
| * @param type selects between IV or AAD |
| */ |
| static status_t ltc_aes_gcm_process_iv_aad( |
| LTC_Type *base, const uint8_t *iv, uint32_t ivSize, ltc_mode_t modeReg, bool iv_only, int type, ltc_mode_t modeLast) |
| { |
| uint32_t sz; |
| status_t retval; |
| void (*next_size_func)(LTC_Type *ltcBase, uint32_t nextSize, bool authOnly); |
| |
| if ((NULL == iv) || (ivSize == 0)) |
| { |
| return kStatus_InvalidArgument; |
| } |
| |
| sz = LTC_FIFO_SZ_MAX_DOWN_ALGN; |
| next_size_func = type == LTC_AES_GCM_TYPE_AAD ? aadsize_next : ivsize_next; |
| |
| while (ivSize) |
| { |
| if (ivSize < sz) |
| { |
| modeReg &= ~LTC_MD_AS_MASK; |
| modeReg |= modeLast; |
| base->MD = modeReg; |
| next_size_func(base, ivSize, iv_only); |
| ltc_move_to_ififo(base, iv, ivSize); |
| ivSize = 0; |
| } |
| else |
| { |
| /* set algorithm state to UPDATE */ |
| modeReg &= ~LTC_MD_AS_MASK; |
| modeReg |= kLTC_ModeUpdate; |
| base->MD = modeReg; |
| |
| next_size_func(base, (uint16_t)sz, true); |
| ltc_move_to_ififo(base, iv, sz); |
| ivSize -= sz; |
| iv += sz; |
| } |
| |
| retval = ltc_wait(base); |
| if (kStatus_Success != retval) |
| { |
| return retval; |
| } |
| } /* end while */ |
| return kStatus_Success; |
| } |
| |
| static status_t ltc_aes_gcm_process(LTC_Type *base, |
| ltc_mode_encrypt_t encryptMode, |
| const uint8_t *src, |
| uint32_t inputSize, |
| const uint8_t *iv, |
| uint32_t ivSize, |
| const uint8_t *aad, |
| uint32_t aadSize, |
| const uint8_t *key, |
| uint32_t keySize, |
| uint8_t *dst, |
| uint8_t *tag, |
| uint32_t tagSize) |
| { |
| status_t retval; /* return value */ |
| uint32_t max_ltc_fifo_sz; /* maximum data size that we can put to LTC FIFO in one session. 12-bit limit. */ |
| ltc_mode_t modeReg; /* read and write LTC mode register */ |
| |
| bool single_ses_proc_all; /* iv, aad and src data can be processed in one session */ |
| bool iv_only; |
| bool aad_only; |
| |
| retval = ltc_aes_gcm_check_input_args(base, src, iv, aad, key, dst, inputSize, ivSize, aadSize, keySize, tagSize); |
| |
| /* API input validation */ |
| if (kStatus_Success != retval) |
| { |
| return retval; |
| } |
| |
| max_ltc_fifo_sz = LTC_DS_DS_MASK; /* 12-bit field limit */ |
| |
| /* |
| * Write value to LTC AADSIZE (rounded up to next 16 byte boundary) |
| * plus the write value to LTC IV (rounded up to next 16 byte boundary) |
| * plus the inputSize. If the result is less than max_ltc_fifo_sz |
| * then all can be processed in one session FINALIZE. |
| * Otherwise, we have to split into multiple session, going through UPDATE(s), INITIALIZE, UPDATE(s) and FINALIZE. |
| */ |
| single_ses_proc_all = |
| (((aadSize + 15u) & 0xfffffff0u) + ((ivSize + 15u) & 0xfffffff0u) + inputSize) <= max_ltc_fifo_sz; |
| |
| /* setup key, algorithm and set the alg.state */ |
| if (single_ses_proc_all) |
| { |
| ltc_symmetric_final(base, key, keySize, kLTC_AlgorithmAES, kLTC_ModeGCM, encryptMode); |
| modeReg = base->MD; |
| |
| iv_only = (aadSize == 0) && (inputSize == 0); |
| aad_only = (inputSize == 0); |
| |
| /* DS_MASK here is not a bug. IV size field can be written with more than 4-bits, |
| * as the IVSZ write value, aligned to next 16 bytes boundary, is written also to the Data Size. |
| * For example, I can write 22 to IVSZ, 32 will be written to Data Size and IVSZ will have value 6, which is 22 |
| * mod 16. |
| */ |
| base->IVSZ = LTC_IVSZ_IL(iv_only) | ((ivSize)<C_DS_DS_MASK); |
| ltc_move_to_ififo(base, iv, ivSize); |
| if (iv_only && ivSize) |
| { |
| retval = ltc_wait(base); |
| if (kStatus_Success != retval) |
| { |
| return retval; |
| } |
| } |
| base->AADSZ = LTC_AADSZ_AL(aad_only) | ((aadSize)<C_DS_DS_MASK); |
| ltc_move_to_ififo(base, aad, aadSize); |
| if (aad_only && aadSize) |
| { |
| retval = ltc_wait(base); |
| if (kStatus_Success != retval) |
| { |
| return retval; |
| } |
| } |
| |
| if (inputSize) |
| { |
| /* Workaround for the LTC Data Size register update errata TKT261180 */ |
| while (16U < base->DS) |
| { |
| } |
| |
| ltc_symmetric_process_data(base, &src[0], inputSize, &dst[0]); |
| } |
| } |
| else |
| { |
| ltc_symmetric_init(base, key, keySize, kLTC_AlgorithmAES, kLTC_ModeGCM, encryptMode); |
| modeReg = base->MD; |
| |
| /* process IV */ |
| if (ivSize) |
| { |
| /* last chunk of IV is always INITIALIZE (for GHASH to occur) */ |
| retval = ltc_aes_gcm_process_iv_aad(base, iv, ivSize, modeReg, true, LTC_AES_GCM_TYPE_IV, kLTC_ModeInit); |
| if (kStatus_Success != retval) |
| { |
| return retval; |
| } |
| } |
| |
| /* process AAD */ |
| if (aadSize) |
| { |
| /* AS mode to process last chunk of AAD. it differs if we are in GMAC or GCM */ |
| ltc_mode_t lastModeReg; |
| if (0 == inputSize) |
| { |
| /* if there is no DATA, set mode to compute final MAC. this is GMAC mode */ |
| lastModeReg = kLTC_ModeInitFinal; |
| } |
| else |
| { |
| /* there are confidential DATA. so process last chunk of AAD in UPDATE mode */ |
| lastModeReg = kLTC_ModeUpdate; |
| } |
| retval = ltc_aes_gcm_process_iv_aad(base, aad, aadSize, modeReg, true, LTC_AES_GCM_TYPE_AAD, lastModeReg); |
| if (kStatus_Success != retval) |
| { |
| return retval; |
| } |
| } |
| |
| /* there are DATA. */ |
| if (inputSize) |
| { |
| /* set algorithm state to UPDATE */ |
| modeReg &= ~LTC_MD_AS_MASK; |
| modeReg |= kLTC_ModeUpdate; |
| base->MD = modeReg; |
| retval = |
| ltc_symmetric_process_data_multiple(base, &src[0], inputSize, &dst[0], modeReg, kLTC_ModeInitFinal); |
| } |
| } |
| if (kStatus_Success != retval) |
| { |
| return retval; |
| } |
| retval = ltc_aes_process_tag(base, tag, tagSize, modeReg, LTC_GCM_TAG_IDX); |
| return retval; |
| } |
| |
| /******************************************************************************* |
| * GCM Code public |
| ******************************************************************************/ |
| status_t LTC_AES_EncryptTagGcm(LTC_Type *base, |
| const uint8_t *plaintext, |
| uint8_t *ciphertext, |
| uint32_t size, |
| const uint8_t *iv, |
| uint32_t ivSize, |
| const uint8_t *aad, |
| uint32_t aadSize, |
| const uint8_t *key, |
| uint32_t keySize, |
| uint8_t *tag, |
| uint32_t tagSize) |
| { |
| status_t status; |
| |
| status = ltc_aes_gcm_process(base, kLTC_ModeEncrypt, plaintext, size, iv, ivSize, aad, aadSize, key, keySize, |
| ciphertext, tag, tagSize); |
| |
| ltc_clear_all(base, false); |
| return status; |
| } |
| |
| status_t LTC_AES_DecryptTagGcm(LTC_Type *base, |
| const uint8_t *ciphertext, |
| uint8_t *plaintext, |
| uint32_t size, |
| const uint8_t *iv, |
| uint32_t ivSize, |
| const uint8_t *aad, |
| uint32_t aadSize, |
| const uint8_t *key, |
| uint32_t keySize, |
| const uint8_t *tag, |
| uint32_t tagSize) |
| { |
| uint8_t temp_tag[16] = {0}; /* max. octet length of Integrity Check Value ICV (tag) is 16 */ |
| uint8_t *tag_ptr; |
| status_t status; |
| |
| tag_ptr = NULL; |
| if (tag) |
| { |
| ltc_memcpy(temp_tag, tag, tagSize); |
| tag_ptr = &temp_tag[0]; |
| } |
| status = ltc_aes_gcm_process(base, kLTC_ModeDecrypt, ciphertext, size, iv, ivSize, aad, aadSize, key, keySize, |
| plaintext, tag_ptr, tagSize); |
| |
| ltc_clear_all(base, false); |
| return status; |
| } |
| #endif /* FSL_FEATURE_LTC_HAS_GCM */ |
| |
| /******************************************************************************* |
| * CCM Code static |
| ******************************************************************************/ |
| static status_t ltc_aes_ccm_check_input_args(LTC_Type *base, |
| const uint8_t *src, |
| const uint8_t *iv, |
| const uint8_t *key, |
| uint8_t *dst, |
| uint32_t ivSize, |
| uint32_t aadSize, |
| uint32_t keySize, |
| uint32_t tagSize) |
| { |
| if (!base) |
| { |
| return kStatus_InvalidArgument; |
| } |
| |
| /* tag can be NULL to skip tag processing */ |
| if ((!src) || (!iv) || (!key) || (!dst)) |
| { |
| return kStatus_InvalidArgument; |
| } |
| |
| /* size of Nonce (ivSize) must be element of 7,8,9,10,11,12,13 */ |
| if ((ivSize < 7u) || (ivSize > 13u)) |
| { |
| return kStatus_InvalidArgument; |
| } |
| /* octet length of MAC (tagSize) must be element of 4,6,8,10,12,14,16 for tag processing or zero to skip tag |
| * processing */ |
| if (((tagSize > 0) && (tagSize < 4u)) || (tagSize > 16u) || (tagSize & 1u)) |
| { |
| return kStatus_InvalidArgument; |
| } |
| |
| /* check if keySize is supported */ |
| if (!ltc_check_key_size(keySize)) |
| { |
| return kStatus_InvalidArgument; |
| } |
| |
| /* LTC does not support more AAD than this */ |
| if (aadSize >= 65280u) |
| { |
| return kStatus_InvalidArgument; |
| } |
| return kStatus_Success; |
| } |
| |
| static uint32_t swap_bytes(uint32_t in) |
| { |
| return (((in & 0x000000ffu) << 24) | ((in & 0x0000ff00u) << 8) | ((in & 0x00ff0000u) >> 8) | |
| ((in & 0xff000000u) >> 24)); |
| } |
| |
| static void ltc_aes_ccm_context_init( |
| LTC_Type *base, uint32_t inputSize, const uint8_t *iv, uint32_t ivSize, uint32_t aadSize, uint32_t tagSize) |
| { |
| ltc_xcm_block_t blk; |
| ltc_xcm_block_t blkZero = {{0x0u, 0x0u, 0x0u, 0x0u}}; |
| |
| int q; /* octet length of binary representation of the octet length of the payload. computed as (15 - n), where n is |
| length of nonce(=ivSize) */ |
| uint8_t flags; /* flags field in B0 and CTR0 */ |
| |
| /* compute B0 */ |
| ltc_memcpy(&blk, &blkZero, sizeof(blk)); |
| /* tagSize - size of output MAC */ |
| q = 15 - ivSize; |
| flags = (uint8_t)(8 * ((tagSize - 2) / 2) + q - 1); /* 8*M' + L' */ |
| if (aadSize) |
| { |
| flags |= 0x40; /* Adata */ |
| } |
| blk.b[0] = flags; /* flags field */ |
| blk.w[3] = swap_bytes(inputSize); /* message size, most significant byte first */ |
| ltc_memcpy(&blk.b[1], iv, ivSize); /* nonce field */ |
| |
| /* Write B0 data to the context register. |
| */ |
| ltc_set_context(base, &blk.b[0], 16, 0); |
| |
| /* Write CTR0 to the context register. |
| */ |
| ltc_memcpy(&blk, &blkZero, sizeof(blk)); /* ctr(0) field = zero */ |
| blk.b[0] = q - 1; /* flags field */ |
| ltc_memcpy(&blk.b[1], iv, ivSize); /* nonce field */ |
| ltc_set_context(base, &blk.b[0], 16, 4); |
| } |
| |
| static status_t ltc_aes_ccm_process_aad( |
| LTC_Type *base, uint32_t inputSize, const uint8_t *aad, uint32_t aadSize, ltc_mode_t *modeReg) |
| { |
| ltc_xcm_block_t blk = {{0x0u, 0x0u, 0x0u, 0x0u}}; |
| uint32_t swapped; /* holds byte swap of uint32_t */ |
| status_t retval; |
| |
| if (aadSize) |
| { |
| bool aad_only; |
| bool aad_single_session; |
| |
| uint32_t sz = 0; |
| |
| aad_only = inputSize == 0u; |
| aad_single_session = (((aadSize + 2u) + 15u) & 0xfffffff0u) <= LTC_FIFO_SZ_MAX_DOWN_ALGN; |
| |
| /* limit by CCM spec: 2^16 - 2^8 = 65280 */ |
| |
| /* encoding is two octets, msbyte first */ |
| swapped = swap_bytes(aadSize); |
| ltc_memcpy(&blk.b[0], ((uint8_t *)&swapped) + sizeof(uint16_t), sizeof(uint16_t)); |
| |
| sz = aadSize > 14u ? 14u : aadSize; /* limit aad to the end of 16 bytes blk */ |
| ltc_memcpy(&blk.b[2], aad, sz); /* fill B1 with aad */ |
| |
| if (aad_single_session) |
| { |
| base->AADSZ = LTC_AADSZ_AL(aad_only) | ((aadSize + 2U) & LTC_DS_DS_MASK); |
| /* move first AAD block (16 bytes block B1) to FIFO */ |
| ltc_move_block_to_ififo(base, &blk, sizeof(blk)); |
| } |
| else |
| { |
| base->AADSZ = LTC_AADSZ_AL(true) | (16U); |
| /* move first AAD block (16 bytes block B1) to FIFO */ |
| ltc_move_block_to_ififo(base, &blk, sizeof(blk)); |
| } |
| |
| /* track consumed AAD. sz bytes have been moved to fifo. */ |
| aadSize -= sz; |
| aad += sz; |
| |
| if (aad_single_session) |
| { |
| /* move remaining AAD to FIFO, then return, to continue with MDATA */ |
| ltc_move_to_ififo(base, aad, aadSize); |
| } |
| else if (aadSize == 0u) |
| { |
| retval = ltc_wait(base); |
| if (kStatus_Success != retval) |
| { |
| return retval; |
| } |
| } |
| else |
| { |
| while (aadSize) |
| { |
| retval = ltc_wait(base); |
| if (kStatus_Success != retval) |
| { |
| return retval; |
| } |
| |
| *modeReg &= ~LTC_MD_AS_MASK; |
| *modeReg |= (uint32_t)kLTC_ModeUpdate; |
| base->MD = *modeReg; |
| |
| sz = LTC_FIFO_SZ_MAX_DOWN_ALGN; |
| if (aadSize < sz) |
| { |
| base->AADSZ = LTC_AADSZ_AL(aad_only) | (aadSize & LTC_DS_DS_MASK); |
| ltc_move_to_ififo(base, aad, aadSize); |
| aadSize = 0; |
| } |
| else |
| { |
| base->AADSZ = LTC_AADSZ_AL(true) | (sz & LTC_DS_DS_MASK); |
| ltc_move_to_ififo(base, aad, sz); |
| aadSize -= sz; |
| aad += sz; |
| } |
| } /* end while */ |
| } /* end else */ |
| } /* end if */ |
| return kStatus_Success; |
| } |
| |
| static status_t ltc_aes_ccm_process(LTC_Type *base, |
| ltc_mode_encrypt_t encryptMode, |
| const uint8_t *src, |
| uint32_t inputSize, |
| const uint8_t *iv, |
| uint32_t ivSize, |
| const uint8_t *aad, |
| uint32_t aadSize, |
| const uint8_t *key, |
| uint32_t keySize, |
| uint8_t *dst, |
| uint8_t *tag, |
| uint32_t tagSize) |
| { |
| status_t retval; /* return value */ |
| uint32_t max_ltc_fifo_sz; /* maximum data size that we can put to LTC FIFO in one session. 12-bit limit. */ |
| ltc_mode_t modeReg; /* read and write LTC mode register */ |
| |
| bool single_ses_proc_all; /* aad and src data can be processed in one session */ |
| |
| retval = ltc_aes_ccm_check_input_args(base, src, iv, key, dst, ivSize, aadSize, keySize, tagSize); |
| |
| /* API input validation */ |
| if (kStatus_Success != retval) |
| { |
| return retval; |
| } |
| |
| max_ltc_fifo_sz = LTC_DS_DS_MASK; /* 12-bit field limit */ |
| |
| /* Write value to LTC AADSIZE will be (aadSize+2) value. |
| * The value will be rounded up to next 16 byte boundary and added to Data Size register. |
| * We then add inputSize to Data Size register. If the resulting Data Size is less than max_ltc_fifo_sz |
| * then all can be processed in one session INITIALIZE/FINALIZE. |
| * Otherwise, we have to split into multiple session, going through INITIALIZE, UPDATE (if required) and FINALIZE. |
| */ |
| single_ses_proc_all = ((((aadSize + 2) + 15u) & 0xfffffff0u) + inputSize) <= max_ltc_fifo_sz; |
| |
| /* setup key, algorithm and set the alg.state to INITIALIZE */ |
| if (single_ses_proc_all) |
| { |
| ltc_symmetric_init_final(base, key, keySize, kLTC_AlgorithmAES, kLTC_ModeCCM, encryptMode); |
| } |
| else |
| { |
| ltc_symmetric_init(base, key, keySize, kLTC_AlgorithmAES, kLTC_ModeCCM, encryptMode); |
| } |
| modeReg = base->MD; |
| |
| /* Initialize LTC context for AES CCM: block B0 and initial counter CTR0 */ |
| ltc_aes_ccm_context_init(base, inputSize, iv, ivSize, aadSize, tagSize); |
| |
| /* Process additional authentication data, if there are any. |
| * Need to split the job into individual sessions of up to 4096 bytes, due to LTC IFIFO data size limit. |
| */ |
| retval = ltc_aes_ccm_process_aad(base, inputSize, aad, aadSize, &modeReg); |
| if (kStatus_Success != retval) |
| { |
| return retval; |
| } |
| |
| /* Workaround for the LTC Data Size register update errata TKT261180 */ |
| if (inputSize) |
| { |
| while (16u < base->DS) |
| { |
| } |
| } |
| |
| /* Process message */ |
| if (single_ses_proc_all) |
| { |
| retval = ltc_symmetric_process_data(base, &src[0], inputSize, &dst[0]); |
| } |
| else |
| { |
| retval = ltc_symmetric_process_data_multiple(base, &src[0], inputSize, &dst[0], modeReg, kLTC_ModeFinalize); |
| } |
| if (kStatus_Success != retval) |
| { |
| return retval; |
| } |
| retval = ltc_aes_process_tag(base, tag, tagSize, modeReg, LTC_CCM_TAG_IDX); |
| return retval; |
| } |
| |
| /******************************************************************************* |
| * CCM Code public |
| ******************************************************************************/ |
| status_t LTC_AES_EncryptTagCcm(LTC_Type *base, |
| const uint8_t *plaintext, |
| uint8_t *ciphertext, |
| uint32_t size, |
| const uint8_t *iv, |
| uint32_t ivSize, |
| const uint8_t *aad, |
| uint32_t aadSize, |
| const uint8_t *key, |
| uint32_t keySize, |
| uint8_t *tag, |
| uint32_t tagSize) |
| { |
| status_t status; |
| status = ltc_aes_ccm_process(base, kLTC_ModeEncrypt, plaintext, size, iv, ivSize, aad, aadSize, key, keySize, |
| ciphertext, tag, tagSize); |
| |
| ltc_clear_all(base, false); |
| return status; |
| } |
| |
| status_t LTC_AES_DecryptTagCcm(LTC_Type *base, |
| const uint8_t *ciphertext, |
| uint8_t *plaintext, |
| uint32_t size, |
| const uint8_t *iv, |
| uint32_t ivSize, |
| const uint8_t *aad, |
| uint32_t aadSize, |
| const uint8_t *key, |
| uint32_t keySize, |
| const uint8_t *tag, |
| uint32_t tagSize) |
| { |
| uint8_t temp_tag[16] = {0}; /* max. octet length of MAC (tag) is 16 */ |
| uint8_t *tag_ptr; |
| status_t status; |
| |
| tag_ptr = NULL; |
| if (tag) |
| { |
| ltc_memcpy(temp_tag, tag, tagSize); |
| tag_ptr = &temp_tag[0]; |
| } |
| |
| status = ltc_aes_ccm_process(base, kLTC_ModeDecrypt, ciphertext, size, iv, ivSize, aad, aadSize, key, keySize, |
| plaintext, tag_ptr, tagSize); |
| |
| ltc_clear_all(base, false); |
| return status; |
| } |
| |
| #if defined(FSL_FEATURE_LTC_HAS_DES) && FSL_FEATURE_LTC_HAS_DES |
| /******************************************************************************* |
| * DES / 3DES Code static |
| ******************************************************************************/ |
| static status_t ltc_des_process(LTC_Type *base, |
| const uint8_t *input, |
| uint8_t *output, |
| uint32_t size, |
| const uint8_t iv[LTC_DES_IV_SIZE], |
| const uint8_t key[LTC_DES_KEY_SIZE], |
| ltc_mode_symmetric_alg_t modeAs, |
| ltc_mode_encrypt_t modeEnc) |
| { |
| status_t retval; |
| |
| /* all but OFB, size must be 8-byte multiple */ |
| if ((modeAs != kLTC_ModeOFB) && ((size < 8u) || (size % 8u))) |
| { |
| return kStatus_InvalidArgument; |
| } |
| |
| /* Initialize algorithm state. */ |
| ltc_symmetric_update(base, &key[0], LTC_DES_KEY_SIZE, kLTC_AlgorithmDES, modeAs, modeEnc); |
| |
| if ((modeAs != kLTC_ModeECB)) |
| { |
| ltc_set_context(base, iv, LTC_DES_IV_SIZE, 0); |
| } |
| |
| /* Process data and return status. */ |
| retval = ltc_process_message_in_sessions(base, input, size, output); |
| ltc_clear_all(base, false); |
| return retval; |
| } |
| |
| status_t ltc_3des_check_input_args(ltc_mode_symmetric_alg_t modeAs, |
| uint32_t size, |
| const uint8_t *key1, |
| const uint8_t *key2) |
| { |
| /* all but OFB, size must be 8-byte multiple */ |
| if ((modeAs != kLTC_ModeOFB) && ((size < 8u) || (size % 8u))) |
| { |
| return kStatus_InvalidArgument; |
| } |
| |
| if ((key1 == NULL) || (key2 == NULL)) |
| { |
| return kStatus_InvalidArgument; |
| } |
| return kStatus_Success; |
| } |
| |
| static status_t ltc_3des_process(LTC_Type *base, |
| const uint8_t *input, |
| uint8_t *output, |
| uint32_t size, |
| const uint8_t iv[LTC_DES_IV_SIZE], |
| const uint8_t key1[LTC_DES_KEY_SIZE], |
| const uint8_t key2[LTC_DES_KEY_SIZE], |
| const uint8_t key3[LTC_DES_KEY_SIZE], |
| ltc_mode_symmetric_alg_t modeAs, |
| ltc_mode_encrypt_t modeEnc) |
| { |
| status_t retval; |
| uint8_t key[LTC_DES_KEY_SIZE * 3]; |
| uint8_t keySize = LTC_DES_KEY_SIZE * 2; |
| |
| retval = ltc_3des_check_input_args(modeAs, size, key1, key2); |
| if (kStatus_Success != retval) |
| { |
| return retval; |
| } |
| |
| ltc_memcpy(&key[0], &key1[0], LTC_DES_KEY_SIZE); |
| ltc_memcpy(&key[LTC_DES_KEY_SIZE], &key2[0], LTC_DES_KEY_SIZE); |
| if (key3) |
| { |
| ltc_memcpy(&key[LTC_DES_KEY_SIZE * 2], &key3[0], LTC_DES_KEY_SIZE); |
| keySize = sizeof(key); |
| } |
| |
| /* Initialize algorithm state. */ |
| ltc_symmetric_update(base, &key[0], keySize, kLTC_Algorithm3DES, modeAs, modeEnc); |
| |
| if ((modeAs != kLTC_ModeECB)) |
| { |
| ltc_set_context(base, iv, LTC_DES_IV_SIZE, 0); |
| } |
| |
| /* Process data and return status. */ |
| retval = ltc_process_message_in_sessions(base, input, size, output); |
| ltc_clear_all(base, false); |
| return retval; |
| } |
| /******************************************************************************* |
| * DES / 3DES Code public |
| ******************************************************************************/ |
| status_t LTC_DES_EncryptEcb( |
| LTC_Type *base, const uint8_t *plaintext, uint8_t *ciphertext, uint32_t size, const uint8_t key[LTC_DES_KEY_SIZE]) |
| { |
| return ltc_des_process(base, plaintext, ciphertext, size, NULL, key, kLTC_ModeECB, kLTC_ModeEncrypt); |
| } |
| |
| status_t LTC_DES_DecryptEcb( |
| LTC_Type *base, const uint8_t *ciphertext, uint8_t *plaintext, uint32_t size, const uint8_t key[LTC_DES_KEY_SIZE]) |
| { |
| return ltc_des_process(base, ciphertext, plaintext, size, NULL, key, kLTC_ModeECB, kLTC_ModeDecrypt); |
| } |
| |
| status_t LTC_DES_EncryptCbc(LTC_Type *base, |
| const uint8_t *plaintext, |
| uint8_t *ciphertext, |
| uint32_t size, |
| const uint8_t iv[LTC_DES_IV_SIZE], |
| const uint8_t key[LTC_DES_KEY_SIZE]) |
| { |
| return ltc_des_process(base, plaintext, ciphertext, size, iv, key, kLTC_ModeCBC, kLTC_ModeEncrypt); |
| } |
| |
| status_t LTC_DES_DecryptCbc(LTC_Type *base, |
| const uint8_t *ciphertext, |
| uint8_t *plaintext, |
| uint32_t size, |
| const uint8_t iv[LTC_DES_IV_SIZE], |
| const uint8_t key[LTC_DES_KEY_SIZE]) |
| { |
| return ltc_des_process(base, ciphertext, plaintext, size, iv, key, kLTC_ModeCBC, kLTC_ModeDecrypt); |
| } |
| |
| status_t LTC_DES_EncryptCfb(LTC_Type *base, |
| const uint8_t *plaintext, |
| uint8_t *ciphertext, |
| uint32_t size, |
| const uint8_t iv[LTC_DES_IV_SIZE], |
| const uint8_t key[LTC_DES_KEY_SIZE]) |
| { |
| return ltc_des_process(base, plaintext, ciphertext, size, iv, key, kLTC_ModeCFB, kLTC_ModeEncrypt); |
| } |
| |
| status_t LTC_DES_DecryptCfb(LTC_Type *base, |
| const uint8_t *ciphertext, |
| uint8_t *plaintext, |
| uint32_t size, |
| const uint8_t iv[LTC_DES_IV_SIZE], |
| const uint8_t key[LTC_DES_KEY_SIZE]) |
| { |
| return ltc_des_process(base, ciphertext, plaintext, size, iv, key, kLTC_ModeCFB, kLTC_ModeDecrypt); |
| } |
| |
| status_t LTC_DES_EncryptOfb(LTC_Type *base, |
| const uint8_t *plaintext, |
| uint8_t *ciphertext, |
| uint32_t size, |
| const uint8_t iv[LTC_DES_IV_SIZE], |
| const uint8_t key[LTC_DES_KEY_SIZE]) |
| { |
| return ltc_des_process(base, plaintext, ciphertext, size, iv, key, kLTC_ModeOFB, kLTC_ModeEncrypt); |
| } |
| |
| status_t LTC_DES_DecryptOfb(LTC_Type *base, |
| const uint8_t *ciphertext, |
| uint8_t *plaintext, |
| uint32_t size, |
| const uint8_t iv[LTC_DES_IV_SIZE], |
| const uint8_t key[LTC_DES_KEY_SIZE]) |
| { |
| return ltc_des_process(base, ciphertext, plaintext, size, iv, key, kLTC_ModeOFB, kLTC_ModeDecrypt); |
| } |
| |
| status_t LTC_DES2_EncryptEcb(LTC_Type *base, |
| const uint8_t *plaintext, |
| uint8_t *ciphertext, |
| uint32_t size, |
| const uint8_t key1[LTC_DES_KEY_SIZE], |
| const uint8_t key2[LTC_DES_KEY_SIZE]) |
| { |
| return ltc_3des_process(base, plaintext, ciphertext, size, NULL, key1, key2, NULL, kLTC_ModeECB, kLTC_ModeEncrypt); |
| } |
| |
| status_t LTC_DES3_EncryptEcb(LTC_Type *base, |
| const uint8_t *plaintext, |
| uint8_t *ciphertext, |
| uint32_t size, |
| const uint8_t key1[LTC_DES_KEY_SIZE], |
| const uint8_t key2[LTC_DES_KEY_SIZE], |
| const uint8_t key3[LTC_DES_KEY_SIZE]) |
| { |
| return ltc_3des_process(base, plaintext, ciphertext, size, NULL, key1, key2, key3, kLTC_ModeECB, kLTC_ModeEncrypt); |
| } |
| |
| status_t LTC_DES2_DecryptEcb(LTC_Type *base, |
| const uint8_t *ciphertext, |
| uint8_t *plaintext, |
| uint32_t size, |
| const uint8_t key1[LTC_DES_KEY_SIZE], |
| const uint8_t key2[LTC_DES_KEY_SIZE]) |
| { |
| return ltc_3des_process(base, ciphertext, plaintext, size, NULL, key1, key2, NULL, kLTC_ModeECB, kLTC_ModeDecrypt); |
| } |
| |
| status_t LTC_DES3_DecryptEcb(LTC_Type *base, |
| const uint8_t *ciphertext, |
| uint8_t *plaintext, |
| uint32_t size, |
| const uint8_t key1[LTC_DES_KEY_SIZE], |
| const uint8_t key2[LTC_DES_KEY_SIZE], |
| const uint8_t key3[LTC_DES_KEY_SIZE]) |
| { |
| return ltc_3des_process(base, ciphertext, plaintext, size, NULL, key1, key2, key3, kLTC_ModeECB, kLTC_ModeDecrypt); |
| } |
| |
| status_t LTC_DES2_EncryptCbc(LTC_Type *base, |
| const uint8_t *plaintext, |
| uint8_t *ciphertext, |
| uint32_t size, |
| const uint8_t iv[LTC_DES_IV_SIZE], |
| const uint8_t key1[LTC_DES_KEY_SIZE], |
| const uint8_t key2[LTC_DES_KEY_SIZE]) |
| { |
| return ltc_3des_process(base, plaintext, ciphertext, size, iv, key1, key2, NULL, kLTC_ModeCBC, kLTC_ModeEncrypt); |
| } |
| |
| status_t LTC_DES3_EncryptCbc(LTC_Type *base, |
| const uint8_t *plaintext, |
| uint8_t *ciphertext, |
| uint32_t size, |
| const uint8_t iv[LTC_DES_IV_SIZE], |
| const uint8_t key1[LTC_DES_KEY_SIZE], |
| const uint8_t key2[LTC_DES_KEY_SIZE], |
| const uint8_t key3[LTC_DES_KEY_SIZE]) |
| { |
| return ltc_3des_process(base, plaintext, ciphertext, size, iv, key1, key2, key3, kLTC_ModeCBC, kLTC_ModeEncrypt); |
| } |
| |
| status_t LTC_DES2_DecryptCbc(LTC_Type *base, |
| const uint8_t *ciphertext, |
| uint8_t *plaintext, |
| uint32_t size, |
| const uint8_t iv[LTC_DES_IV_SIZE], |
| const uint8_t key1[LTC_DES_KEY_SIZE], |
| const uint8_t key2[LTC_DES_KEY_SIZE]) |
| { |
| return ltc_3des_process(base, ciphertext, plaintext, size, iv, key1, key2, NULL, kLTC_ModeCBC, kLTC_ModeDecrypt); |
| } |
| |
| status_t LTC_DES3_DecryptCbc(LTC_Type *base, |
| const uint8_t *ciphertext, |
| uint8_t *plaintext, |
| uint32_t size, |
| const uint8_t iv[LTC_DES_IV_SIZE], |
| const uint8_t key1[LTC_DES_KEY_SIZE], |
| const uint8_t key2[LTC_DES_KEY_SIZE], |
| const uint8_t key3[LTC_DES_KEY_SIZE]) |
| { |
| return ltc_3des_process(base, ciphertext, plaintext, size, iv, key1, key2, key3, kLTC_ModeCBC, kLTC_ModeDecrypt); |
| } |
| |
| status_t LTC_DES2_EncryptCfb(LTC_Type *base, |
| const uint8_t *plaintext, |
| uint8_t *ciphertext, |
| uint32_t size, |
| const uint8_t iv[LTC_DES_IV_SIZE], |
| const uint8_t key1[LTC_DES_KEY_SIZE], |
| const uint8_t key2[LTC_DES_KEY_SIZE]) |
| { |
| return ltc_3des_process(base, plaintext, ciphertext, size, iv, key1, key2, NULL, kLTC_ModeCFB, kLTC_ModeEncrypt); |
| } |
| |
| status_t LTC_DES3_EncryptCfb(LTC_Type *base, |
| const uint8_t *plaintext, |
| uint8_t *ciphertext, |
| uint32_t size, |
| const uint8_t iv[LTC_DES_IV_SIZE], |
| const uint8_t key1[LTC_DES_KEY_SIZE], |
| const uint8_t key2[LTC_DES_KEY_SIZE], |
| const uint8_t key3[LTC_DES_KEY_SIZE]) |
| { |
| return ltc_3des_process(base, plaintext, ciphertext, size, iv, key1, key2, key3, kLTC_ModeCFB, kLTC_ModeEncrypt); |
| } |
| |
| status_t LTC_DES2_DecryptCfb(LTC_Type *base, |
| const uint8_t *ciphertext, |
| uint8_t *plaintext, |
| uint32_t size, |
| const uint8_t iv[LTC_DES_IV_SIZE], |
| const uint8_t key1[LTC_DES_KEY_SIZE], |
| const uint8_t key2[LTC_DES_KEY_SIZE]) |
| { |
| return ltc_3des_process(base, ciphertext, plaintext, size, iv, key1, key2, NULL, kLTC_ModeCFB, kLTC_ModeDecrypt); |
| } |
| |
| status_t LTC_DES3_DecryptCfb(LTC_Type *base, |
| const uint8_t *ciphertext, |
| uint8_t *plaintext, |
| uint32_t size, |
| const uint8_t iv[LTC_DES_IV_SIZE], |
| const uint8_t key1[LTC_DES_KEY_SIZE], |
| const uint8_t key2[LTC_DES_KEY_SIZE], |
| const uint8_t key3[LTC_DES_KEY_SIZE]) |
| { |
| return ltc_3des_process(base, ciphertext, plaintext, size, iv, key1, key2, key3, kLTC_ModeCFB, kLTC_ModeDecrypt); |
| } |
| |
| status_t LTC_DES2_EncryptOfb(LTC_Type *base, |
| const uint8_t *plaintext, |
| uint8_t *ciphertext, |
| uint32_t size, |
| const uint8_t iv[LTC_DES_IV_SIZE], |
| const uint8_t key1[LTC_DES_KEY_SIZE], |
| const uint8_t key2[LTC_DES_KEY_SIZE]) |
| { |
| return ltc_3des_process(base, plaintext, ciphertext, size, iv, key1, key2, NULL, kLTC_ModeOFB, kLTC_ModeEncrypt); |
| } |
| |
| status_t LTC_DES3_EncryptOfb(LTC_Type *base, |
| const uint8_t *plaintext, |
| uint8_t *ciphertext, |
| uint32_t size, |
| const uint8_t iv[LTC_DES_IV_SIZE], |
| const uint8_t key1[LTC_DES_KEY_SIZE], |
| const uint8_t key2[LTC_DES_KEY_SIZE], |
| const uint8_t key3[LTC_DES_KEY_SIZE]) |
| { |
| return ltc_3des_process(base, plaintext, ciphertext, size, iv, key1, key2, key3, kLTC_ModeOFB, kLTC_ModeEncrypt); |
| } |
| |
| status_t LTC_DES2_DecryptOfb(LTC_Type *base, |
| const uint8_t *ciphertext, |
| uint8_t *plaintext, |
| uint32_t size, |
| const uint8_t iv[LTC_DES_IV_SIZE], |
| const uint8_t key1[LTC_DES_KEY_SIZE], |
| const uint8_t key2[LTC_DES_KEY_SIZE]) |
| { |
| return ltc_3des_process(base, ciphertext, plaintext, size, iv, key1, key2, NULL, kLTC_ModeOFB, kLTC_ModeDecrypt); |
| } |
| |
| status_t LTC_DES3_DecryptOfb(LTC_Type *base, |
| const uint8_t *ciphertext, |
| uint8_t *plaintext, |
| uint32_t size, |
| const uint8_t iv[LTC_DES_IV_SIZE], |
| const uint8_t key1[LTC_DES_KEY_SIZE], |
| const uint8_t key2[LTC_DES_KEY_SIZE], |
| const uint8_t key3[LTC_DES_KEY_SIZE]) |
| { |
| return ltc_3des_process(base, ciphertext, plaintext, size, iv, key1, key2, key3, kLTC_ModeOFB, kLTC_ModeDecrypt); |
| } |
| #endif /* FSL_FEATURE_LTC_HAS_DES */ |
| |
| /******************************************************************************* |
| * HASH Definitions |
| ******************************************************************************/ |
| #if defined(FSL_FEATURE_LTC_HAS_SHA) && FSL_FEATURE_LTC_HAS_SHA |
| #define LTC_SHA_BLOCK_SIZE 64 /*!< SHA-1, SHA-224 & SHA-256 block size */ |
| #define LTC_HASH_BLOCK_SIZE LTC_SHA_BLOCK_SIZE /*!< LTC hash block size */ |
| |
| enum _ltc_sha_digest_len |
| { |
| kLTC_RunLenSha1 = 28u, |
| kLTC_OutLenSha1 = 20u, |
| kLTC_RunLenSha224 = 40u, |
| kLTC_OutLenSha224 = 28u, |
| kLTC_RunLenSha256 = 40u, |
| kLTC_OutLenSha256 = 32u, |
| }; |
| #else |
| #define LTC_HASH_BLOCK_SIZE LTC_AES_BLOCK_SIZE /*!< LTC hash block size */ |
| #endif /* FSL_FEATURE_LTC_HAS_SHA */ |
| |
| /*! Internal states of the HASH creation process */ |
| typedef enum _ltc_hash_algo_state |
| { |
| kLTC_HashInit = 1u, /*!< Key in the HASH context is the input key. */ |
| kLTC_HashUpdate, /*!< HASH context has algorithm specific context: MAC, K2 and K3 (XCBC-MAC), MAC and L (CMAC), |
| running digest (MDHA). Key in the HASH context is the derived key. */ |
| } ltc_hash_algo_state_t; |
| |
| /*! 16/64-byte block represented as byte array or 4/16 32-bit words */ |
| typedef union _ltc_hash_block |
| { |
| uint32_t w[LTC_HASH_BLOCK_SIZE / 4]; /*!< array of 32-bit words */ |
| uint8_t b[LTC_HASH_BLOCK_SIZE]; /*!< byte array */ |
| } ltc_hash_block_t; |
| |
| /*! Definitions of indexes into hash context array */ |
| typedef enum _ltc_hash_ctx_indexes |
| { |
| kLTC_HashCtxKeyStartIdx = 12, /*!< context word array index where key is stored */ |
| kLTC_HashCtxKeySize = 20, /*!< context word array index where key size is stored */ |
| kLTC_HashCtxNumWords = 21, /*!< number of context array 32-bit words */ |
| } ltc_hash_ctx_indexes; |
| |
| typedef struct _ltc_hash_ctx_internal |
| { |
| ltc_hash_block_t blk; /*!< memory buffer. only full 64/16-byte blocks are written to LTC during hash updates */ |
| uint32_t blksz; /*!< number of valid bytes in memory buffer */ |
| LTC_Type *base; /*!< LTC peripheral base address */ |
| ltc_hash_algo_t algo; /*!< selected algorithm from the set of supported algorithms in ltc_drv_hash_algo */ |
| ltc_hash_algo_state_t state; /*!< finite machine state of the hash software process */ |
| uint32_t word[kLTC_HashCtxNumWords]; /*!< LTC module context that needs to be saved/restored between LTC jobs */ |
| } ltc_hash_ctx_internal_t; |
| |
| /******************************************************************************* |
| * HASH Code static |
| ******************************************************************************/ |
| static status_t ltc_hash_check_input_alg(ltc_hash_algo_t algo) |
| { |
| if ((algo != kLTC_XcbcMac) && (algo != kLTC_Cmac) |
| #if defined(FSL_FEATURE_LTC_HAS_SHA) && FSL_FEATURE_LTC_HAS_SHA |
| && (algo != kLTC_Sha1) && (algo != kLTC_Sha224) && (algo != kLTC_Sha256) |
| #endif /* FSL_FEATURE_LTC_HAS_SHA */ |
| ) |
| { |
| return kStatus_InvalidArgument; |
| } |
| return kStatus_Success; |
| } |
| |
| static inline bool ltc_hash_alg_is_cmac(ltc_hash_algo_t algo) |
| { |
| return ((algo == kLTC_XcbcMac) || (algo == kLTC_Cmac)); |
| } |
| |
| #if defined(FSL_FEATURE_LTC_HAS_SHA) && FSL_FEATURE_LTC_HAS_SHA |
| static inline bool ltc_hash_alg_is_sha(ltc_hash_algo_t algo) |
| { |
| return ((algo == kLTC_Sha1) || (algo == kLTC_Sha224) || (algo == kLTC_Sha256)); |
| } |
| #endif /* FSL_FEATURE_LTC_HAS_SHA */ |
| |
| static status_t ltc_hash_check_input_args( |
| LTC_Type *base, ltc_hash_ctx_t *ctx, ltc_hash_algo_t algo, const uint8_t *key, uint32_t keySize) |
| { |
| /* Check validity of input algorithm */ |
| if (kStatus_Success != ltc_hash_check_input_alg(algo)) |
| { |
| return kStatus_InvalidArgument; |
| } |
| |
| if ((NULL == ctx) || (NULL == base)) |
| { |
| return kStatus_InvalidArgument; |
| } |
| |
| if (ltc_hash_alg_is_cmac(algo)) |
| { |
| if ((NULL == key) || (!ltc_check_key_size(keySize))) |
| { |
| return kStatus_InvalidArgument; |
| } |
| } |
| |
| return kStatus_Success; |
| } |
| |
| static status_t ltc_hash_check_context(ltc_hash_ctx_internal_t *ctxInternal, const uint8_t *data) |
| { |
| if ((NULL == data) || (NULL == ctxInternal) || (NULL == ctxInternal->base) || |
| (kStatus_Success != ltc_hash_check_input_alg(ctxInternal->algo))) |
| { |
| return kStatus_InvalidArgument; |
| } |
| return kStatus_Success; |
| } |
| |
| static uint32_t ltc_hash_algo2mode(ltc_hash_algo_t algo, ltc_mode_algorithm_state_t asMode, uint32_t *algOutSize) |
| { |
| uint32_t modeReg = 0u; |
| uint32_t outSize = 0u; |
| |
| /* Set LTC algorithm */ |
| switch (algo) |
| { |
| case kLTC_XcbcMac: |
| modeReg = (uint32_t)kLTC_AlgorithmAES | (uint32_t)kLTC_ModeXCBCMAC; |
| outSize = 16u; |
| break; |
| case kLTC_Cmac: |
| modeReg = (uint32_t)kLTC_AlgorithmAES | (uint32_t)kLTC_ModeCMAC; |
| outSize = 16u; |
| break; |
| #if defined(FSL_FEATURE_LTC_HAS_SHA) && FSL_FEATURE_LTC_HAS_SHA |
| case kLTC_Sha1: |
| modeReg = (uint32_t)kLTC_AlgorithmSHA1; |
| outSize = kLTC_OutLenSha1; |
| break; |
| case kLTC_Sha224: |
| modeReg = (uint32_t)kLTC_AlgorithmSHA224; |
| outSize = kLTC_OutLenSha224; |
| break; |
| case kLTC_Sha256: |
| modeReg = (uint32_t)kLTC_AlgorithmSHA256; |
| outSize = kLTC_OutLenSha256; |
| break; |
| #endif /* FSL_FEATURE_LTC_HAS_SHA */ |
| default: |
| break; |
| } |
| |
| modeReg |= (uint32_t)asMode; |
| if (algOutSize) |
| { |
| *algOutSize = outSize; |
| } |
| |
| return modeReg; |
| } |
| |
| static void ltc_hash_engine_init(ltc_hash_ctx_internal_t *ctx) |
| { |
| uint8_t *key; |
| uint32_t keySize; |
| LTC_Type *base; |
| ltc_mode_symmetric_alg_t algo; |
| |
| base = ctx->base; |
| #if defined(FSL_FEATURE_LTC_HAS_SHA) && FSL_FEATURE_LTC_HAS_SHA |
| if (ltc_hash_alg_is_cmac(ctx->algo)) |
| { |
| #endif /* FSL_FEATURE_LTC_HAS_SHA */ |
| /* |
| * word[kLtcCmacCtxKeySize] = key_length |
| * word[1-8] = key |
| */ |
| keySize = ctx->word[kLTC_HashCtxKeySize]; |
| key = (uint8_t *)&ctx->word[kLTC_HashCtxKeyStartIdx]; |
| |
| /* set LTC mode register to INITIALIZE */ |
| algo = (ctx->algo == kLTC_XcbcMac) ? kLTC_ModeXCBCMAC : kLTC_ModeCMAC; |
| ltc_symmetric_init(base, key, keySize, kLTC_AlgorithmAES, algo, kLTC_ModeEncrypt); |
| #if defined(FSL_FEATURE_LTC_HAS_SHA) && FSL_FEATURE_LTC_HAS_SHA |
| } |
| else if (ltc_hash_alg_is_sha(ctx->algo)) |
| { |
| /* Clear internal register states. */ |
| base->CW = (uint32_t)kLTC_ClearAll; |
| |
| /* Set byte swap on for several registers we will be reading and writing |
| * user data to/from. */ |
| base->CTL |= kLTC_CtrlSwapAll; |
| } |
| else |
| { |
| /* do nothing in this case */ |
| } |
| #endif /* FSL_FEATURE_LTC_HAS_SHA */ |
| } |
| |
| static void ltc_hash_save_context(ltc_hash_ctx_internal_t *ctx) |
| { |
| uint32_t sz; |
| LTC_Type *base; |
| |
| base = ctx->base; |
| /* Get context size */ |
| switch (ctx->algo) |
| { |
| case kLTC_XcbcMac: |
| /* |
| * word[0-3] = mac |
| * word[3-7] = k3 |
| * word[8-11] = k2 |
| * word[kLtcCmacCtxKeySize] = keySize |
| */ |
| sz = 12 * sizeof(uint32_t); |
| break; |
| case kLTC_Cmac: |
| /* |
| * word[0-3] = mac |
| * word[3-7] = L */ |
| sz = 8 * sizeof(uint32_t); |
| break; |
| #if defined(FSL_FEATURE_LTC_HAS_SHA) && FSL_FEATURE_LTC_HAS_SHA |
| case kLTC_Sha1: |
| sz = (kLTC_RunLenSha1); |
| break; |
| case kLTC_Sha224: |
| sz = (kLTC_RunLenSha224); |
| break; |
| case kLTC_Sha256: |
| sz = (kLTC_RunLenSha256); |
| break; |
| #endif /* FSL_FEATURE_LTC_HAS_SHA */ |
| default: |
| sz = 0; |
| break; |
| } |
| |
| ltc_get_context(base, (uint8_t *)&ctx->word[0], sz, 0); |
| |
| if (true == ltc_hash_alg_is_cmac(ctx->algo)) |
| { |
| /* word[12-19] = key */ |
| ltc_get_key(base, (uint8_t *)&ctx->word[kLTC_HashCtxKeyStartIdx], ctx->word[kLTC_HashCtxKeySize]); |
| } |
| } |
| |
| static void ltc_hash_restore_context(ltc_hash_ctx_internal_t *ctx) |
| { |
| uint32_t sz; |
| uint32_t keySize; |
| LTC_Type *base; |
| |
| base = ctx->base; |
| /* Get context size */ |
| switch (ctx->algo) |
| { |
| case kLTC_XcbcMac: |
| /* |
| * word[0-3] = mac |
| * word[3-7] = k3 |
| * word[8-11] = k2 |
| * word[kLtcCmacCtxKeySize] = keySize |
| */ |
| sz = 12 * sizeof(uint32_t); |
| break; |
| case kLTC_Cmac: |
| /* |
| * word[0-3] = mac |
| * word[3-7] = L */ |
| sz = 8 * sizeof(uint32_t); |
| break; |
| #if defined(FSL_FEATURE_LTC_HAS_SHA) && FSL_FEATURE_LTC_HAS_SHA |
| case kLTC_Sha1: |
| sz = (kLTC_RunLenSha1); |
| break; |
| case kLTC_Sha224: |
| sz = (kLTC_RunLenSha224); |
| break; |
| case kLTC_Sha256: |
| sz = (kLTC_RunLenSha256); |
| break; |
| #endif /* FSL_FEATURE_LTC_HAS_SHA */ |
| default: |
| sz = 0; |
| break; |
| } |
| |
| ltc_set_context(base, (const uint8_t *)&ctx->word[0], sz, 0); |
| |
| if (ltc_hash_alg_is_cmac(ctx->algo)) |
| { |
| /* |
| * word[12-19] = key |
| * word[kLtcCmacCtxKeySize] = keySize |
| */ |
| base->CW = kLTC_ClearKey; /* clear Key and Key Size registers */ |
| |
| keySize = ctx->word[kLTC_HashCtxKeySize]; |
| /* Write the key in place. */ |
| ltc_set_key(base, (const uint8_t *)&ctx->word[kLTC_HashCtxKeyStartIdx], keySize); |
| |
| /* Write the key size. This must be done after writing the key, and this |
| * action locks the ability to modify the key registers. */ |
| base->KS = keySize; |
| } |
| } |
| |
| static void ltc_hash_prepare_context_switch(LTC_Type *base) |
| { |
| base->CW = (uint32_t)kLTC_ClearDataSize | (uint32_t)kLTC_ClearMode; |
| base->STA = kLTC_StatusDoneIsr; |
| } |
| |
| static uint32_t ltc_hash_get_block_size(ltc_hash_algo_t algo) |
| { |
| if ((algo == kLTC_XcbcMac) || (algo == kLTC_Cmac)) |
| { |
| return (uint32_t)LTC_AES_BLOCK_SIZE; |
| } |
| #if defined(FSL_FEATURE_LTC_HAS_SHA) && FSL_FEATURE_LTC_HAS_SHA |
| else if ((algo == kLTC_Sha1) || (algo == kLTC_Sha224) || (algo == kLTC_Sha256)) |
| { |
| return (uint32_t)LTC_SHA_BLOCK_SIZE; |
| } |
| else |
| { |
| return 0; |
| } |
| #else |
| return 0; |
| #endif |
| } |
| |
| static void ltc_hash_block_to_ififo(LTC_Type *base, const ltc_hash_block_t *blk, uint32_t numBytes, uint32_t blockSize) |
| { |
| uint32_t i = 0; |
| uint32_t words; |
| |
| words = numBytes / 4u; |
| if (numBytes % 4u) |
| { |
| words++; |
| } |
| |
| if (words > blockSize / 4u) |
| { |
| words = blockSize / 4u; |
| } |
| |
| while (i < words) |
| { |
| if (0U == (base->FIFOSTA & LTC_FIFOSTA_IFF_MASK)) |
| { |
| /* Copy data to the input FIFO. */ |
| base->IFIFO = blk->w[i++]; |
| } |
| } |
| } |
| |
| static void ltc_hash_move_to_ififo(ltc_hash_ctx_internal_t *ctx, |
| const uint8_t *data, |
| uint32_t dataSize, |
| uint32_t blockSize) |
| { |
| ltc_hash_block_t blkZero; |
| uint32_t i; |
| |
| for (i = 0; i < ARRAY_SIZE(blkZero.w); i++) |
| { |
| blkZero.w[i] = 0; |
| } |
| |
| while (dataSize) |
| { |
| if (dataSize >= blockSize) |
| { |
| ltc_memcpy(&ctx->blk, data, blockSize); |
| ltc_hash_block_to_ififo(ctx->base, &ctx->blk, blockSize, blockSize); |
| dataSize -= blockSize; |
| data += blockSize; |
| } |
| else |
| { |
| /* last incomplete 16/64-bytes block of this message chunk */ |
| ltc_memcpy(&ctx->blk, &blkZero, sizeof(ctx->blk)); |
| ltc_memcpy(&ctx->blk, data, dataSize); |
| ctx->blksz = dataSize; |
| dataSize = 0; |
| } |
| } |
| } |
| |
| static status_t ltc_hash_merge_and_flush_buf(ltc_hash_ctx_internal_t *ctx, |
| const uint8_t *input, |
| uint32_t inputSize, |
| ltc_mode_t modeReg, |
| uint32_t blockSize, |
| uint32_t *consumedSize) |
| { |
| uint32_t sz; |
| LTC_Type *base; |
| status_t status = kStatus_Success; |
| |
| base = ctx->base; |
| sz = 0; |
| if (ctx->blksz) |
| { |
| sz = blockSize - ctx->blksz; |
| if (sz > inputSize) |
| { |
| sz = inputSize; |
| } |
| ltc_memcpy(ctx->blk.b + ctx->blksz, input, sz); |
| input += sz; |
| inputSize -= sz; |
| ctx->blksz += sz; |
| |
| if (ctx->blksz == blockSize) |
| { |
| base->DS = blockSize; |
| ltc_hash_block_to_ififo(base, &ctx->blk, blockSize, blockSize); |
| ctx->blksz = 0; |
| |
| status = ltc_wait(base); |
| if (kStatus_Success != status) |
| { |
| return status; |
| } |
| |
| /* if there is still inputSize left, make sure LTC alg.state is set to UPDATE and continue */ |
| if (inputSize) |
| { |
| /* set algorithm state to UPDATE */ |
| modeReg &= ~LTC_MD_AS_MASK; |
| modeReg |= kLTC_ModeUpdate; |
| base->MD = modeReg; |
| } |
| } |
| } |
| if (consumedSize) |
| { |
| *consumedSize = sz; |
| } |
| return status; |
| } |
| |
| static status_t ltc_hash_move_rest_to_context( |
| ltc_hash_ctx_internal_t *ctx, const uint8_t *data, uint32_t dataSize, ltc_mode_t modeReg, uint32_t blockSize) |
| { |
| status_t status = kStatus_Success; |
| ltc_hash_block_t blkZero; |
| uint32_t i; |
| |
| /* make blkZero clear */ |
| for (i = 0; i < ARRAY_SIZE(blkZero.w); i++) |
| { |
| blkZero.w[i] = 0; |
| } |
| |
| while (dataSize) |
| { |
| if (dataSize > blockSize) |
| { |
| dataSize -= blockSize; |
| data += blockSize; |
| } |
| else |
| { |
| if (dataSize + ctx->blksz > blockSize) |
| { |
| uint32_t sz; |
| status = ltc_hash_merge_and_flush_buf(ctx, data, dataSize, modeReg, blockSize, &sz); |
| if (kStatus_Success != status) |
| { |
| return status; |
| } |
| data += sz; |
| dataSize -= sz; |
| } |
| /* last incomplete 16/64-bytes block of this message chunk */ |
| ltc_memcpy(&ctx->blk, &blkZero, blockSize); |
| ltc_memcpy(&ctx->blk, data, dataSize); |
| ctx->blksz = dataSize; |
| dataSize = 0; |
| } |
| } |
| return status; |
| } |
| |
| static status_t ltc_hash_process_input_data(ltc_hash_ctx_internal_t *ctx, |
| const uint8_t *input, |
| uint32_t inputSize, |
| ltc_mode_t modeReg) |
| { |
| uint32_t sz = 0; |
| LTC_Type *base; |
| uint32_t blockSize = 0; |
| status_t status = kStatus_Success; |
| |
| blockSize = ltc_hash_get_block_size(ctx->algo); |
| base = ctx->base; |
| |
| /* fill context struct blk and flush to LTC ififo in case it is full block */ |
| status = ltc_hash_merge_and_flush_buf(ctx, input, inputSize, modeReg, blockSize, &sz); |
| if (kStatus_Success != status) |
| { |
| return status; |
| } |
| input += sz; |
| inputSize -= sz; |
| |
| /* if there is still more than or equal to 64 bytes, move each 64 bytes through LTC */ |
| sz = LTC_DS_DS_MASK + 1u - LTC_HASH_BLOCK_SIZE; |
| while (inputSize) |
| { |
| if (inputSize < sz) |
| { |
| uint32_t lastSize; |
| |
| lastSize = inputSize % blockSize; |
| if (lastSize == 0) |
| { |
| lastSize = blockSize; |
| } |
| inputSize -= lastSize; |
| if (inputSize) |
| { |
| /* move all complete blocks to ififo. */ |
| base->DS = inputSize; |
| ltc_hash_move_to_ififo(ctx, input, inputSize, blockSize); |
| |
| status = ltc_wait(base); |
| if (kStatus_Success != status) |
| { |
| return status; |
| } |
| |
| input += inputSize; |
| } |
| /* keep last (in)complete 16-bytes block in context struct. */ |
| /* when 3rd argument of cmac_move_to_ififo() is <= 16 bytes, it only stores the data to context struct */ |
| status = ltc_hash_move_rest_to_context(ctx, input, lastSize, modeReg, blockSize); |
| if (kStatus_Success != status) |
| { |
| return status; |
| } |
| inputSize = 0; |
| } |
| else |
| { |
| base->DS = sz; |
| ltc_hash_move_to_ififo(ctx, input, sz, blockSize); |
| inputSize -= sz; |
| input += sz; |
| |
| status = ltc_wait(base); |
| if (kStatus_Success != status) |
| { |
| return status; |
| } |
| |
| /* set algorithm state to UPDATE */ |
| modeReg &= ~LTC_MD_AS_MASK; |
| modeReg |= kLTC_ModeUpdate; |
| base->MD = modeReg; |
| } |
| } /* end while */ |
| |
| return status; |
| } |
| |
| /******************************************************************************* |
| * HASH Code public |
| ******************************************************************************/ |
| status_t LTC_HASH_Init(LTC_Type *base, ltc_hash_ctx_t *ctx, ltc_hash_algo_t algo, const uint8_t *key, uint32_t keySize) |
| { |
| status_t ret; |
| ltc_hash_ctx_internal_t *ctxInternal; |
| uint32_t i; |
| |
| ret = ltc_hash_check_input_args(base, ctx, algo, key, keySize); |
| if (ret != kStatus_Success) |
| { |
| return ret; |
| } |
| |
| /* set algorithm in context struct for later use */ |
| ctxInternal = (ltc_hash_ctx_internal_t *)ctx; |
| ctxInternal->algo = algo; |
| for (i = 0; i < kLTC_HashCtxNumWords; i++) |
| { |
| ctxInternal->word[i] = 0u; |
| } |
| |
| /* Steps required only using AES engine */ |
| if (ltc_hash_alg_is_cmac(algo)) |
| { |
| /* store input key and key length in context struct for later use */ |
| ctxInternal->word[kLTC_HashCtxKeySize] = keySize; |
| ltc_memcpy(&ctxInternal->word[kLTC_HashCtxKeyStartIdx], key, keySize); |
| } |
| ctxInternal->blksz = 0u; |
| for (i = 0; i < sizeof(ctxInternal->blk.w) / sizeof(ctxInternal->blk.w[0]); i++) |
| { |
| ctxInternal->blk.w[0] = 0u; |
| } |
| ctxInternal->state = kLTC_HashInit; |
| ctxInternal->base = base; |
| |
| return kStatus_Success; |
| } |
| |
| status_t LTC_HASH_Update(ltc_hash_ctx_t *ctx, const uint8_t *input, uint32_t inputSize) |
| { |
| bool isUpdateState; |
| ltc_mode_t modeReg = 0; /* read and write LTC mode register */ |
| LTC_Type *base; |
| status_t status; |
| ltc_hash_ctx_internal_t *ctxInternal; |
| uint32_t blockSize; |
| |
| ctxInternal = (ltc_hash_ctx_internal_t *)ctx; |
| status = ltc_hash_check_context(ctxInternal, input); |
| if (kStatus_Success != status) |
| { |
| return status; |
| } |
| |
| base = ctxInternal->base; |
| blockSize = ltc_hash_get_block_size(ctxInternal->algo); |
| /* if we are still less than 64 bytes, keep only in context */ |
| if ((ctxInternal->blksz + inputSize) <= blockSize) |
| { |
| ltc_memcpy((&ctxInternal->blk.b[0]) + ctxInternal->blksz, input, inputSize); |
| ctxInternal->blksz += inputSize; |
| return status; |
| } |
| else |
| { |
| isUpdateState = ctxInternal->state == kLTC_HashUpdate; |
| if (ctxInternal->state == kLTC_HashInit) |
| { |
| /* set LTC mode register to INITIALIZE job */ |
| ltc_hash_engine_init(ctxInternal); |
| |
| #if defined(FSL_FEATURE_LTC_HAS_SHA) && FSL_FEATURE_LTC_HAS_SHA |
| if (ltc_hash_alg_is_cmac(ctxInternal->algo)) |
| { |
| #endif /* FSL_FEATURE_LTC_HAS_SHA */ |
| ctxInternal->state = kLTC_HashUpdate; |
| isUpdateState = true; |
| base->DS = 0u; |
| status = ltc_wait(base); |
| #if defined(FSL_FEATURE_LTC_HAS_SHA) && FSL_FEATURE_LTC_HAS_SHA |
| } |
| else |
| { |
| /* Set the proper block and algorithm mode. */ |
| modeReg = ltc_hash_algo2mode(ctxInternal->algo, kLTC_ModeInit, NULL); |
| base->MD = modeReg; |
| |
| ctxInternal->state = kLTC_HashUpdate; |
| status = ltc_hash_process_input_data(ctxInternal, input, inputSize, modeReg); |
| ltc_hash_save_context(ctxInternal); |
| } |
| #endif /* FSL_FEATURE_LTC_HAS_SHA */ |
| } |
| else if (isUpdateState) |
| { |
| /* restore LTC context from context struct */ |
| ltc_hash_restore_context(ctxInternal); |
| } |
| else |
| { |
| /* nothing special at this place */ |
| } |
| } |
| |
| if (kStatus_Success != status) |
| { |
| return status; |
| } |
| |
| if (isUpdateState) |
| { |
| /* set LTC mode register to UPDATE job */ |
| ltc_hash_prepare_context_switch(base); |
| base->CW = kLTC_ClearDataSize; |
| modeReg = ltc_hash_algo2mode(ctxInternal->algo, kLTC_ModeUpdate, NULL); |
| base->MD = modeReg; |
| |
| /* process input data and save LTC context to context structure */ |
| status = ltc_hash_process_input_data(ctxInternal, input, inputSize, modeReg); |
| ltc_hash_save_context(ctxInternal); |
| } |
| ltc_clear_all(base, false); |
| return status; |
| } |
| |
| status_t LTC_HASH_Finish(ltc_hash_ctx_t *ctx, uint8_t *output, uint32_t *outputSize) |
| { |
| ltc_mode_t modeReg; /* read and write LTC mode register */ |
| LTC_Type *base; |
| uint32_t algOutSize = 0; |
| status_t status; |
| ltc_hash_ctx_internal_t *ctxInternal; |
| uint32_t *ctxW; |
| uint32_t i; |
| |
| ctxInternal = (ltc_hash_ctx_internal_t *)ctx; |
| status = ltc_hash_check_context(ctxInternal, output); |
| if (kStatus_Success != status) |
| { |
| return status; |
| } |
| |
| base = ctxInternal->base; |
| ltc_hash_prepare_context_switch(base); |
| |
| base->CW = kLTC_ClearDataSize; |
| if (ctxInternal->state == kLTC_HashInit) |
| { |
| ltc_hash_engine_init(ctxInternal); |
| #if defined(FSL_FEATURE_LTC_HAS_SHA) && FSL_FEATURE_LTC_HAS_SHA |
| if (ltc_hash_alg_is_cmac(ctxInternal->algo)) |
| { |
| #endif /* FSL_FEATURE_LTC_HAS_SHA */ |
| base->DS = 0u; |
| status = ltc_wait(base); |
| if (kStatus_Success != status) |
| { |
| return status; |
| } |
| modeReg = ltc_hash_algo2mode(ctxInternal->algo, kLTC_ModeFinalize, &algOutSize); |
| #if defined(FSL_FEATURE_LTC_HAS_SHA) && FSL_FEATURE_LTC_HAS_SHA |
| } |
| else |
| { |
| modeReg = ltc_hash_algo2mode(ctxInternal->algo, kLTC_ModeInitFinal, &algOutSize); |
| } |
| #endif /* FSL_FEATURE_LTC_HAS_SHA */ |
| base->MD = modeReg; |
| } |
| else |
| { |
| modeReg = ltc_hash_algo2mode(ctxInternal->algo, kLTC_ModeFinalize, &algOutSize); |
| base->MD = modeReg; |
| |
| /* restore LTC context from context struct */ |
| ltc_hash_restore_context(ctxInternal); |
| } |
| |
| /* flush message last incomplete block, if there is any, or write zero to data size register. */ |
| base->DS = ctxInternal->blksz; |
| ltc_hash_block_to_ififo(base, &ctxInternal->blk, ctxInternal->blksz, ltc_hash_get_block_size(ctxInternal->algo)); |
| /* Wait for finish of the encryption */ |
| status = ltc_wait(base); |
| |
| if (outputSize) |
| { |
| if (algOutSize < *outputSize) |
| { |
| *outputSize = algOutSize; |
| } |
| else |
| { |
| algOutSize = *outputSize; |
| } |
| } |
| |
| ltc_get_context(base, &output[0], algOutSize, 0u); |
| |
| ctxW = (uint32_t *)ctx; |
| for (i = 0; i < LTC_HASH_CTX_SIZE; i++) |
| { |
| ctxW[i] = 0u; |
| } |
| |
| ltc_clear_all(base, false); |
| return status; |
| } |
| |
| status_t LTC_HASH(LTC_Type *base, |
| ltc_hash_algo_t algo, |
| const uint8_t *input, |
| uint32_t inputSize, |
| const uint8_t *key, |
| uint32_t keySize, |
| uint8_t *output, |
| uint32_t *outputSize) |
| { |
| status_t status; |
| ltc_hash_ctx_t ctx; |
| |
| status = LTC_HASH_Init(base, &ctx, algo, key, keySize); |
| if (status != kStatus_Success) |
| { |
| return status; |
| } |
| status = LTC_HASH_Update(&ctx, input, inputSize); |
| if (status != kStatus_Success) |
| { |
| return status; |
| } |
| status = LTC_HASH_Finish(&ctx, output, outputSize); |
| return status; |
| } |
| |
| /******************************************************************************* |
| * PKHA Code static |
| ******************************************************************************/ |
| #if defined(FSL_FEATURE_LTC_HAS_PKHA) && FSL_FEATURE_LTC_HAS_PKHA |
| static status_t ltc_pkha_clear_regabne(LTC_Type *base, bool A, bool B, bool N, bool E) |
| { |
| ltc_mode_t mode; |
| |
| /* Set the PKHA algorithm and the appropriate function. */ |
| mode = (uint32_t)kLTC_AlgorithmPKHA | 1U; |
| |
| /* Set ram area to clear. Clear all. */ |
| if (A) |
| { |
| mode |= 1U << 19U; |
| } |
| if (B) |
| { |
| mode |= 1U << 18U; |
| } |
| if (N) |
| { |
| mode |= 1U << 16U; |
| } |
| if (E) |
| { |
| mode |= 1U << 17U; |
| } |
| |
| /* Write the mode register to the hardware. |
| * NOTE: This will begin the operation. */ |
| base->MDPK = mode; |
| |
| /* Wait for 'done' */ |
| return ltc_wait(base); |
| } |
| |
| static void ltc_pkha_default_parms(ltc_pkha_mode_params_t *params) |
| { |
| params->func = (ltc_pkha_func_t)0; |
| params->arithType = kLTC_PKHA_IntegerArith; |
| params->montFormIn = kLTC_PKHA_NormalValue; |
| params->montFormOut = kLTC_PKHA_NormalValue; |
| params->srcReg = kLTC_PKHA_RegAll; |
| params->srcQuad = kLTC_PKHA_Quad0; |
| params->dstReg = kLTC_PKHA_RegAll; |
| params->dstQuad = kLTC_PKHA_Quad0; |
| params->equalTime = kLTC_PKHA_NoTimingEqualized; |
| params->r2modn = kLTC_PKHA_CalcR2; |
| } |
| |
| static void ltc_pkha_write_word(LTC_Type *base, ltc_pkha_reg_area_t reg, uint8_t index, uint32_t data) |
| { |
| switch (reg) |
| { |
| case kLTC_PKHA_RegA: |
| base->PKA[index] = data; |
| break; |
| |
| case kLTC_PKHA_RegB: |
| base->PKB[index] = data; |
| break; |
| |
| case kLTC_PKHA_RegN: |
| base->PKN[index] = data; |
| break; |
| |
| case kLTC_PKHA_RegE: |
| base->PKE[index] = data; |
| break; |
| |
| default: |
| break; |
| } |
| } |
| |
| static uint32_t ltc_pkha_read_word(LTC_Type *base, ltc_pkha_reg_area_t reg, uint8_t index) |
| { |
| uint32_t retval; |
| |
| switch (reg) |
| { |
| case kLTC_PKHA_RegA: |
| retval = base->PKA[index]; |
| break; |
| |
| case kLTC_PKHA_RegB: |
| retval = base->PKB[index]; |
| break; |
| |
| case kLTC_PKHA_RegN: |
| retval = base->PKN[index]; |
| break; |
| |
| case kLTC_PKHA_RegE: |
| retval = base->PKE[index]; |
| break; |
| |
| default: |
| retval = 0; |
| break; |
| } |
| return retval; |
| } |
| |
| static status_t ltc_pkha_write_reg( |
| LTC_Type *base, ltc_pkha_reg_area_t reg, uint8_t quad, const uint8_t *data, uint16_t dataSize) |
| { |
| /* Select the word-based start index for each quadrant of 64 bytes. */ |
| uint8_t startIndex = (quad * 16u); |
| uint32_t outWord; |
| |
| while (dataSize > 0) |
| { |
| if (dataSize >= sizeof(uint32_t)) |
| { |
| ltc_pkha_write_word(base, reg, startIndex++, ltc_get_word_from_unaligned(data)); |
| dataSize -= sizeof(uint32_t); |
| data += sizeof(uint32_t); |
| } |
| else /* (dataSize > 0) && (dataSize < 4) */ |
| { |
| outWord = 0; |
| ltc_memcpy(&outWord, data, dataSize); |
| ltc_pkha_write_word(base, reg, startIndex, outWord); |
| dataSize = 0; |
| } |
| } |
| |
| return kStatus_Success; |
| } |
| |
| static void ltc_pkha_read_reg(LTC_Type *base, ltc_pkha_reg_area_t reg, uint8_t quad, uint8_t *data, uint16_t dataSize) |
| { |
| /* Select the word-based start index for each quadrant of 64 bytes. */ |
| uint8_t startIndex = (quad * 16u); |
| uint16_t calcSize; |
| uint32_t word; |
| |
| while (dataSize > 0) |
| { |
| word = ltc_pkha_read_word(base, reg, startIndex++); |
| |
| calcSize = (dataSize >= sizeof(uint32_t)) ? sizeof(uint32_t) : dataSize; |
| ltc_memcpy(data, &word, calcSize); |
| |
| data += calcSize; |
| dataSize -= calcSize; |
| } |
| } |
| |
| static void ltc_pkha_init_data(LTC_Type *base, |
| const uint8_t *A, |
| uint16_t sizeA, |
| const uint8_t *B, |
| uint16_t sizeB, |
| const uint8_t *N, |
| uint16_t sizeN, |
| const uint8_t *E, |
| uint16_t sizeE) |
| { |
| uint32_t clearMask = kLTC_ClearMode; /* clear Mode Register */ |
| |
| /* Clear internal register states. */ |
| if (sizeA) |
| { |
| clearMask |= kLTC_ClearPkhaSizeA; |
| } |
| if (sizeB) |
| { |
| clearMask |= kLTC_ClearPkhaSizeB; |
| } |
| if (sizeN) |
| { |
| clearMask |= kLTC_ClearPkhaSizeN; |
| } |
| if (sizeE) |
| { |
| clearMask |= kLTC_ClearPkhaSizeE; |
| } |
| |
| base->CW = clearMask; |
| base->STA = kLTC_StatusDoneIsr; |
| ltc_pkha_clear_regabne(base, A, B, N, E); |
| |
| /* Write register sizes. */ |
| /* Write modulus (N) and A and B register arguments. */ |
| if (sizeN) |
| { |
| base->PKNSZ = sizeN; |
| if (N) |
| { |
| ltc_pkha_write_reg(base, kLTC_PKHA_RegN, 0, N, sizeN); |
| } |
| } |
| |
| if (sizeA) |
| { |
| base->PKASZ = sizeA; |
| if (A) |
| { |
| ltc_pkha_write_reg(base, kLTC_PKHA_RegA, 0, A, sizeA); |
| } |
| } |
| |
| if (sizeB) |
| { |
| base->PKBSZ = sizeB; |
| if (B) |
| { |
| ltc_pkha_write_reg(base, kLTC_PKHA_RegB, 0, B, sizeB); |
| } |
| } |
| |
| if (sizeE) |
| { |
| base->PKESZ = sizeE; |
| if (E) |
| { |
| ltc_pkha_write_reg(base, kLTC_PKHA_RegE, 0, E, sizeE); |
| } |
| } |
| } |
| |
| static void ltc_pkha_mode_set_src_reg_copy(ltc_mode_t *outMode, ltc_pkha_reg_area_t reg) |
| { |
| int i = 0; |
| |
| do |
| { |
| reg = (ltc_pkha_reg_area_t)(((uint32_t)reg) >> 1u); |
| i++; |
| } while (reg); |
| |
| i = 4 - i; |
| /* Source register must not be E. */ |
| if (i != 2) |
| { |
| *outMode |= ((uint32_t)i << 17u); |
| } |
| } |
| |
| static void ltc_pkha_mode_set_dst_reg_copy(ltc_mode_t *outMode, ltc_pkha_reg_area_t reg) |
| { |
| int i = 0; |
| |
| do |
| { |
| reg = (ltc_pkha_reg_area_t)(((uint32_t)reg) >> 1u); |
| i++; |
| } while (reg); |
| |
| i = 4 - i; |
| *outMode |= ((uint32_t)i << 10u); |
| } |
| |
| static void ltc_pkha_mode_set_src_seg_copy(ltc_mode_t *outMode, const ltc_pkha_quad_area_t quad) |
| { |
| *outMode |= ((uint32_t)quad << 8u); |
| } |
| |
| static void ltc_pkha_mode_set_dst_seg_copy(ltc_mode_t *outMode, const ltc_pkha_quad_area_t quad) |
| { |
| *outMode |= ((uint32_t)quad << 6u); |
| } |
| |
| /*! |
| * @brief Starts the PKHA operation. |
| * |
| * This function starts an operation configured by the params parameter. |
| * |
| * @param base LTC peripheral base address |
| * @param params Configuration structure containing all settings required for PKHA operation. |
| */ |
| static status_t ltc_pkha_init_mode(LTC_Type *base, const ltc_pkha_mode_params_t *params) |
| { |
| ltc_mode_t modeReg; |
| status_t retval; |
| |
| /* Set the PKHA algorithm and the appropriate function. */ |
| modeReg = kLTC_AlgorithmPKHA; |
| modeReg |= (uint32_t)params->func; |
| |
| if ((params->func == kLTC_PKHA_CopyMemSizeN) || (params->func == kLTC_PKHA_CopyMemSizeSrc)) |
| { |
| /* Set source and destination registers and quads. */ |
| ltc_pkha_mode_set_src_reg_copy(&modeReg, params->srcReg); |
| ltc_pkha_mode_set_dst_reg_copy(&modeReg, params->dstReg); |
| ltc_pkha_mode_set_src_seg_copy(&modeReg, params->srcQuad); |
| ltc_pkha_mode_set_dst_seg_copy(&modeReg, params->dstQuad); |
| } |
| else |
| { |
| /* Set the arithmetic type - integer or binary polynomial (F2m). */ |
| modeReg |= ((uint32_t)params->arithType << 17u); |
| |
| /* Set to use Montgomery form of inputs and/or outputs. */ |
| modeReg |= ((uint32_t)params->montFormIn << 19u); |
| modeReg |= ((uint32_t)params->montFormOut << 18u); |
| |
| /* Set to use pre-computed R2modN */ |
| modeReg |= ((uint32_t)params->r2modn << 16u); |
| } |
| |
| modeReg |= ((uint32_t)params->equalTime << 10u); |
| |
| /* Write the mode register to the hardware. |
| * NOTE: This will begin the operation. */ |
| base->MDPK = modeReg; |
| |
| retval = ltc_wait(base); |
| return (retval); |
| } |
| |
| static status_t ltc_pkha_modR2( |
| LTC_Type *base, const uint8_t *N, uint16_t sizeN, uint8_t *result, uint16_t *resultSize, ltc_pkha_f2m_t arithType) |
| { |
| status_t status; |
| ltc_pkha_mode_params_t params; |
| |
| ltc_pkha_default_parms(¶ms); |
| params.func = kLTC_PKHA_ArithModR2; |
| params.arithType = arithType; |
| |
| ltc_pkha_init_data(base, NULL, 0, NULL, 0, N, sizeN, NULL, 0); |
| status = ltc_pkha_init_mode(base, ¶ms); |
| |
| if (status == kStatus_Success) |
| { |
| /* Read the result and size from register B0. */ |
| if (resultSize && result) |
| { |
| *resultSize = base->PKBSZ; |
| /* Read the data from the result register into place. */ |
| ltc_pkha_read_reg(base, kLTC_PKHA_RegB, 0, result, *resultSize); |
| } |
| } |
| |
| return status; |
| } |
| |
| static status_t ltc_pkha_modmul(LTC_Type *base, |
| const uint8_t *A, |
| uint16_t sizeA, |
| const uint8_t *B, |
| uint16_t sizeB, |
| const uint8_t *N, |
| uint16_t sizeN, |
| uint8_t *result, |
| uint16_t *resultSize, |
| ltc_pkha_f2m_t arithType, |
| ltc_pkha_montgomery_form_t montIn, |
| ltc_pkha_montgomery_form_t montOut, |
| ltc_pkha_timing_t equalTime) |
| { |
| ltc_pkha_mode_params_t params; |
| status_t status; |
| |
| if (arithType == kLTC_PKHA_IntegerArith) |
| { |
| if (LTC_PKHA_CompareBigNum(A, sizeA, N, sizeN) >= 0) |
| { |
| return (kStatus_InvalidArgument); |
| } |
| |
| if (LTC_PKHA_CompareBigNum(B, sizeB, N, sizeN) >= 0) |
| { |
| return (kStatus_InvalidArgument); |
| } |
| } |
| |
| ltc_pkha_default_parms(¶ms); |
| params.func = kLTC_PKHA_ArithModMul; |
| params.arithType = arithType; |
| params.montFormIn = montIn; |
| params.montFormOut = montOut; |
| params.equalTime = equalTime; |
| |
| ltc_pkha_init_data(base, A, sizeA, B, sizeB, N, sizeN, NULL, 0); |
| status = ltc_pkha_init_mode(base, ¶ms); |
| |
| if (status == kStatus_Success) |
| { |
| /* Read the result and size from register B0. */ |
| if (resultSize && result) |
| { |
| *resultSize = base->PKBSZ; |
| /* Read the data from the result register into place. */ |
| ltc_pkha_read_reg(base, kLTC_PKHA_RegB, 0, result, *resultSize); |
| } |
| } |
| |
| return status; |
| } |
| |
| /******************************************************************************* |
| * PKHA Code public |
| ******************************************************************************/ |
| int LTC_PKHA_CompareBigNum(const uint8_t *a, size_t sizeA, const uint8_t *b, size_t sizeB) |
| { |
| int retval = 0; |
| |
| /* skip zero msbytes - integer a */ |
| while ((sizeA) && (0u == a[sizeA - 1])) |
| { |
| sizeA--; |
| } |
| |
| /* skip zero msbytes - integer b */ |
| while ((sizeB) && (0u == b[sizeB - 1])) |
| { |
| sizeB--; |
| } |
| |
| if (sizeA > sizeB) |
| { |
| retval = 1; |
| } /* int a has more non-zero bytes, thus it is bigger than b */ |
| else if (sizeA < sizeB) |
| { |
| retval = -1; |
| } /* int b has more non-zero bytes, thus it is bigger than a */ |
| else if (sizeA == 0) |
| { |
| retval = 0; |
| } /* sizeA = sizeB = 0 */ |
| else |
| { |
| int n; |
| int i; |
| int val; |
| uint32_t equal; |
| |
| n = sizeA - 1; |
| i = 0; |
| equal = 0; |
| |
| while (n >= 0) |
| { |
| uint32_t chXor = a[i] ^ b[i]; |
| |
| equal |= chXor; |
| val = (int)chXor * (a[i] - b[i]); |
| |
| if (val < 0) |
| { |
| retval = -1; |
| } |
| |
| if (val > 0) |
| { |
| retval = 1; |
| } |
| |
| if (val == 0) |
| { |
| val = 1; |
| } |
| |
| if (val) |
| { |
| i++; |
| n--; |
| } |
| } |
| |
| if (0 == equal) |
| { |
| retval = 0; |
| } |
| } |
| return (retval); |
| } |
| |
| status_t LTC_PKHA_NormalToMontgomery(LTC_Type *base, |
| const uint8_t *N, |
| uint16_t sizeN, |
| uint8_t *A, |
| uint16_t *sizeA, |
| uint8_t *B, |
| uint16_t *sizeB, |
| uint8_t *R2, |
| uint16_t *sizeR2, |
| ltc_pkha_timing_t equalTime, |
| ltc_pkha_f2m_t arithType) |
| { |
| status_t status; |
| |
| /* need to convert our Integer inputs into Montgomery format */ |
| if (N && sizeN && R2 && sizeR2) |
| { |
| /* 1. R2 = MOD_R2(N) */ |
| status = ltc_pkha_modR2(base, N, sizeN, R2, sizeR2, arithType); |
| if (status != kStatus_Success) |
| { |
| return status; |
| } |
| |
| /* 2. A(Montgomery) = MOD_MUL_IM_OM(A, R2, N) */ |
| if (A && sizeA) |
| { |
| status = ltc_pkha_modmul(base, A, *sizeA, R2, *sizeR2, N, sizeN, A, sizeA, arithType, |
| kLTC_PKHA_MontgomeryFormat, kLTC_PKHA_MontgomeryFormat, equalTime); |
| if (status != kStatus_Success) |
| { |
| return status; |
| } |
| } |
| |
| /* 2. B(Montgomery) = MOD_MUL_IM_OM(B, R2, N) */ |
| if (B && sizeB) |
| { |
| status = ltc_pkha_modmul(base, B, *sizeB, R2, *sizeR2, N, sizeN, B, sizeB, arithType, |
| kLTC_PKHA_MontgomeryFormat, kLTC_PKHA_MontgomeryFormat, equalTime); |
| if (status != kStatus_Success) |
| { |
| return status; |
| } |
| } |
| |
| ltc_clear_all(base, true); |
| } |
| else |
| { |
| status = kStatus_InvalidArgument; |
| } |
| |
| return status; |
| } |
| |
| status_t LTC_PKHA_MontgomeryToNormal(LTC_Type *base, |
| const uint8_t *N, |
| uint16_t sizeN, |
| uint8_t *A, |
| uint16_t *sizeA, |
| uint8_t *B, |
| uint16_t *sizeB, |
| ltc_pkha_timing_t equalTime, |
| ltc_pkha_f2m_t arithType) |
| { |
| uint8_t one = 1; |
| status_t status = kStatus_InvalidArgument; |
| |
| /* A = MOD_MUL_IM_OM(A(Montgomery), 1, N) */ |
| if (A && sizeA) |
| { |
| status = ltc_pkha_modmul(base, A, *sizeA, &one, sizeof(one), N, sizeN, A, sizeA, arithType, |
| kLTC_PKHA_MontgomeryFormat, kLTC_PKHA_MontgomeryFormat, equalTime); |
| if (kStatus_Success != status) |
| { |
| return status; |
| } |
| } |
| |
| /* B = MOD_MUL_IM_OM(B(Montgomery), 1, N) */ |
| if (B && sizeB) |
| { |
| status = ltc_pkha_modmul(base, B, *sizeB, &one, sizeof(one), N, sizeN, B, sizeB, arithType, |
| kLTC_PKHA_MontgomeryFormat, kLTC_PKHA_MontgomeryFormat, equalTime); |
| if (kStatus_Success != status) |
| { |
| return status; |
| } |
| } |
| |
| ltc_clear_all(base, true); |
| return status; |
| } |
| |
| status_t LTC_PKHA_ModAdd(LTC_Type *base, |
| const uint8_t *A, |
| uint16_t sizeA, |
| const uint8_t *B, |
| uint16_t sizeB, |
| const uint8_t *N, |
| uint16_t sizeN, |
| uint8_t *result, |
| uint16_t *resultSize, |
| ltc_pkha_f2m_t arithType) |
| { |
| ltc_pkha_mode_params_t params; |
| status_t status; |
| |
| if (arithType == kLTC_PKHA_IntegerArith) |
| { |
| if (LTC_PKHA_CompareBigNum(A, sizeA, N, sizeN) >= 0) |
| { |
| return (kStatus_InvalidArgument); |
| } |
| |
| if (LTC_PKHA_CompareBigNum(B, sizeB, N, sizeN) >= 0) |
| { |
| return (kStatus_InvalidArgument); |
| } |
| } |
| |
| ltc_pkha_default_parms(¶ms); |
| params.func = kLTC_PKHA_ArithModAdd; |
| params.arithType = arithType; |
| |
| ltc_pkha_init_data(base, A, sizeA, B, sizeB, N, sizeN, NULL, 0); |
| status = ltc_pkha_init_mode(base, ¶ms); |
| |
| if (status == kStatus_Success) |
| { |
| /* Read the result and size from register B0. */ |
| if (resultSize && result) |
| { |
| *resultSize = base->PKBSZ; |
| /* Read the data from the result register into place. */ |
| ltc_pkha_read_reg(base, kLTC_PKHA_RegB, 0, result, *resultSize); |
| } |
| } |
| |
| ltc_clear_all(base, true); |
| return status; |
| } |
| |
| status_t LTC_PKHA_ModSub1(LTC_Type *base, |
| const uint8_t *A, |
| uint16_t sizeA, |
| const uint8_t *B, |
| uint16_t sizeB, |
| const uint8_t *N, |
| uint16_t sizeN, |
| uint8_t *result, |
| uint16_t *resultSize) |
| { |
| ltc_pkha_mode_params_t params; |
| status_t status; |
| |
| if (LTC_PKHA_CompareBigNum(A, sizeA, N, sizeN) >= 0) |
| { |
| return (kStatus_InvalidArgument); |
| } |
| |
| if (LTC_PKHA_CompareBigNum(B, sizeB, N, sizeN) >= 0) |
| { |
| return (kStatus_InvalidArgument); |
| } |
| |
| ltc_pkha_default_parms(¶ms); |
| params.func = kLTC_PKHA_ArithModSub1; |
| ltc_pkha_init_data(base, A, sizeA, B, sizeB, N, sizeN, NULL, 0); |
| |
| status = ltc_pkha_init_mode(base, ¶ms); |
| |
| if (status == kStatus_Success) |
| { |
| /* Read the result and size from register B0. */ |
| if (resultSize && result) |
| { |
| *resultSize = base->PKBSZ; |
| /* Read the data from the result register into place. */ |
| ltc_pkha_read_reg(base, kLTC_PKHA_RegB, 0, result, *resultSize); |
| } |
| } |
| |
| ltc_clear_all(base, true); |
| return status; |
| } |
| |
| status_t LTC_PKHA_ModSub2(LTC_Type *base, |
| const uint8_t *A, |
| uint16_t sizeA, |
| const uint8_t *B, |
| uint16_t sizeB, |
| const uint8_t *N, |
| uint16_t sizeN, |
| uint8_t *result, |
| uint16_t *resultSize) |
| { |
| ltc_pkha_mode_params_t params; |
| status_t status; |
| |
| ltc_pkha_default_parms(¶ms); |
| params.func = kLTC_PKHA_ArithModSub2; |
| |
| ltc_pkha_init_data(base, A, sizeA, B, sizeB, N, sizeN, NULL, 0); |
| status = ltc_pkha_init_mode(base, ¶ms); |
| |
| if (status == kStatus_Success) |
| { |
| /* Read the result and size from register B0. */ |
| if (resultSize && result) |
| { |
| *resultSize = base->PKBSZ; |
| /* Read the data from the result register into place. */ |
| ltc_pkha_read_reg(base, kLTC_PKHA_RegB, 0, result, *resultSize); |
| } |
| } |
| |
| ltc_clear_all(base, true); |
| return status; |
| } |
| |
| status_t LTC_PKHA_ModMul(LTC_Type *base, |
| const uint8_t *A, |
| uint16_t sizeA, |
| const uint8_t *B, |
| uint16_t sizeB, |
| const uint8_t *N, |
| uint16_t sizeN, |
| uint8_t *result, |
| uint16_t *resultSize, |
| ltc_pkha_f2m_t arithType, |
| ltc_pkha_montgomery_form_t montIn, |
| ltc_pkha_montgomery_form_t montOut, |
| ltc_pkha_timing_t equalTime) |
| { |
| status_t status; |
| |
| status = |
| ltc_pkha_modmul(base, A, sizeA, B, sizeB, N, sizeN, result, resultSize, arithType, montIn, montOut, equalTime); |
| |
| ltc_clear_all(base, true); |
| return status; |
| } |
| |
| status_t LTC_PKHA_ModExp(LTC_Type *base, |
| const uint8_t *A, |
| uint16_t sizeA, |
| const uint8_t *N, |
| uint16_t sizeN, |
| const uint8_t *E, |
| uint16_t sizeE, |
| uint8_t *result, |
| uint16_t *resultSize, |
| ltc_pkha_f2m_t arithType, |
| ltc_pkha_montgomery_form_t montIn, |
| ltc_pkha_timing_t equalTime) |
| { |
| ltc_pkha_mode_params_t params; |
| status_t status; |
| |
| if (arithType == kLTC_PKHA_IntegerArith) |
| { |
| if (LTC_PKHA_CompareBigNum(A, sizeA, N, sizeN) >= 0) |
| { |
| return (kStatus_InvalidArgument); |
| } |
| } |
| |
| ltc_pkha_default_parms(¶ms); |
| params.func = kLTC_PKHA_ArithModExp; |
| params.arithType = arithType; |
| params.montFormIn = montIn; |
| params.equalTime = equalTime; |
| |
| ltc_pkha_init_data(base, A, sizeA, NULL, 0, N, sizeN, E, sizeE); |
| status = ltc_pkha_init_mode(base, ¶ms); |
| |
| if (status == kStatus_Success) |
| { |
| /* Read the result and size from register B0. */ |
| if (resultSize && result) |
| { |
| *resultSize = base->PKBSZ; |
| /* Read the data from the result register into place. */ |
| ltc_pkha_read_reg(base, kLTC_PKHA_RegB, 0, result, *resultSize); |
| } |
| } |
| |
| ltc_clear_all(base, true); |
| return status; |
| } |
| |
| status_t LTC_PKHA_ModRed(LTC_Type *base, |
| const uint8_t *A, |
| uint16_t sizeA, |
| const uint8_t *N, |
| uint16_t sizeN, |
| uint8_t *result, |
| uint16_t *resultSize, |
| ltc_pkha_f2m_t arithType) |
| { |
| ltc_pkha_mode_params_t params; |
| status_t status; |
| |
| ltc_pkha_default_parms(¶ms); |
| params.func = kLTC_PKHA_ArithModRed; |
| params.arithType = arithType; |
| |
| ltc_pkha_init_data(base, A, sizeA, NULL, 0, N, sizeN, NULL, 0); |
| status = ltc_pkha_init_mode(base, ¶ms); |
| |
| if (status == kStatus_Success) |
| { |
| /* Read the result and size from register B0. */ |
| if (resultSize && result) |
| { |
| *resultSize = base->PKBSZ; |
| /* Read the data from the result register into place. */ |
| ltc_pkha_read_reg(base, kLTC_PKHA_RegB, 0, result, *resultSize); |
| } |
| } |
| |
| ltc_clear_all(base, true); |
| return status; |
| } |
| |
| status_t LTC_PKHA_ModInv(LTC_Type *base, |
| const uint8_t *A, |
| uint16_t sizeA, |
| const uint8_t *N, |
| uint16_t sizeN, |
| uint8_t *result, |
| uint16_t *resultSize, |
| ltc_pkha_f2m_t arithType) |
| { |
| ltc_pkha_mode_params_t params; |
| status_t status; |
| |
| /* A must be less than N -> LTC_PKHA_CompareBigNum() must return -1 */ |
| if (arithType == kLTC_PKHA_IntegerArith) |
| { |
| if (LTC_PKHA_CompareBigNum(A, sizeA, N, sizeN) >= 0) |
| { |
| return (kStatus_InvalidArgument); |
| } |
| } |
| |
| ltc_pkha_default_parms(¶ms); |
| params.func = kLTC_PKHA_ArithModInv; |
| params.arithType = arithType; |
| |
| ltc_pkha_init_data(base, A, sizeA, NULL, 0, N, sizeN, NULL, 0); |
| status = ltc_pkha_init_mode(base, ¶ms); |
| |
| if (status == kStatus_Success) |
| { |
| /* Read the result and size from register B0. */ |
| if (resultSize && result) |
| { |
| *resultSize = base->PKBSZ; |
| /* Read the data from the result register into place. */ |
| ltc_pkha_read_reg(base, kLTC_PKHA_RegB, 0, result, *resultSize); |
| } |
| } |
| |
| ltc_clear_all(base, true); |
| return status; |
| } |
| |
| status_t LTC_PKHA_ModR2( |
| LTC_Type *base, const uint8_t *N, uint16_t sizeN, uint8_t *result, uint16_t *resultSize, ltc_pkha_f2m_t arithType) |
| { |
| status_t status; |
| status = ltc_pkha_modR2(base, N, sizeN, result, resultSize, arithType); |
| ltc_clear_all(base, true); |
| return status; |
| } |
| |
| status_t LTC_PKHA_GCD(LTC_Type *base, |
| const uint8_t *A, |
| uint16_t sizeA, |
| const uint8_t *N, |
| uint16_t sizeN, |
| uint8_t *result, |
| uint16_t *resultSize, |
| ltc_pkha_f2m_t arithType) |
| { |
| ltc_pkha_mode_params_t params; |
| status_t status; |
| |
| ltc_pkha_default_parms(¶ms); |
| params.func = kLTC_PKHA_ArithGcd; |
| params.arithType = arithType; |
| |
| ltc_pkha_init_data(base, A, sizeA, NULL, 0, N, sizeN, NULL, 0); |
| status = ltc_pkha_init_mode(base, ¶ms); |
| |
| if (status == kStatus_Success) |
| { |
| /* Read the result and size from register B0. */ |
| if (resultSize && result) |
| { |
| *resultSize = base->PKBSZ; |
| /* Read the data from the result register into place. */ |
| ltc_pkha_read_reg(base, kLTC_PKHA_RegB, 0, result, *resultSize); |
| } |
| } |
| |
| ltc_clear_all(base, true); |
| return status; |
| } |
| |
| status_t LTC_PKHA_PrimalityTest(LTC_Type *base, |
| const uint8_t *A, |
| uint16_t sizeA, |
| const uint8_t *B, |
| uint16_t sizeB, |
| const uint8_t *N, |
| uint16_t sizeN, |
| bool *res) |
| { |
| uint8_t result; |
| ltc_pkha_mode_params_t params; |
| status_t status; |
| |
| ltc_pkha_default_parms(¶ms); |
| params.func = kLTC_PKHA_ArithPrimalityTest; |
| ltc_pkha_init_data(base, A, sizeA, B, sizeB, N, sizeN, NULL, 0); |
| status = ltc_pkha_init_mode(base, ¶ms); |
| |
| if (status == kStatus_Success) |
| { |
| /* Read the data from the result register into place. */ |
| ltc_pkha_read_reg(base, kLTC_PKHA_RegB, 0, &result, 1); |
| |
| *res = (bool)result; |
| } |
| |
| ltc_clear_all(base, true); |
| return status; |
| } |
| |
| status_t LTC_PKHA_ECC_PointAdd(LTC_Type *base, |
| const ltc_pkha_ecc_point_t *A, |
| const ltc_pkha_ecc_point_t *B, |
| const uint8_t *N, |
| const uint8_t *R2modN, |
| const uint8_t *aCurveParam, |
| const uint8_t *bCurveParam, |
| uint8_t size, |
| ltc_pkha_f2m_t arithType, |
| ltc_pkha_ecc_point_t *result) |
| { |
| ltc_pkha_mode_params_t params; |
| uint32_t clearMask; |
| status_t status; |
| |
| ltc_pkha_default_parms(¶ms); |
| params.func = kLTC_PKHA_ArithEccAdd; |
| params.arithType = arithType; |
| params.r2modn = R2modN ? kLTC_PKHA_InputR2 : kLTC_PKHA_CalcR2; |
| |
| clearMask = kLTC_ClearMode; |
| |
| /* Clear internal register states. */ |
| clearMask |= kLTC_ClearPkhaSizeA; |
| clearMask |= kLTC_ClearPkhaSizeB; |
| clearMask |= kLTC_ClearPkhaSizeN; |
| clearMask |= kLTC_ClearPkhaSizeE; |
| |
| base->CW = clearMask; |
| base->STA = kLTC_StatusDoneIsr; |
| ltc_pkha_clear_regabne(base, true, true, true, false); |
| |
| /* sizeN should be less than 64 bytes. */ |
| base->PKNSZ = size; |
| ltc_pkha_write_reg(base, kLTC_PKHA_RegN, 0, N, size); |
| |
| base->PKASZ = size; |
| ltc_pkha_write_reg(base, kLTC_PKHA_RegA, 0, A->X, size); |
| ltc_pkha_write_reg(base, kLTC_PKHA_RegA, 1, A->Y, size); |
| ltc_pkha_write_reg(base, kLTC_PKHA_RegA, 3, aCurveParam, size); |
| |
| base->PKBSZ = size; |
| ltc_pkha_write_reg(base, kLTC_PKHA_RegB, 0, bCurveParam, size); |
| ltc_pkha_write_reg(base, kLTC_PKHA_RegB, 1, B->X, size); |
| ltc_pkha_write_reg(base, kLTC_PKHA_RegB, 2, B->Y, size); |
| if (R2modN) |
| { |
| ltc_pkha_write_reg(base, kLTC_PKHA_RegB, 3, R2modN, size); |
| } |
| |
| status = ltc_pkha_init_mode(base, ¶ms); |
| |
| if (status == kStatus_Success) |
| { |
| /* Read the data from the result register into place. */ |
| ltc_pkha_read_reg(base, kLTC_PKHA_RegB, 1, result->X, size); |
| ltc_pkha_read_reg(base, kLTC_PKHA_RegB, 2, result->Y, size); |
| } |
| |
| ltc_clear_all(base, true); |
| return status; |
| } |
| |
| status_t LTC_PKHA_ECC_PointDouble(LTC_Type *base, |
| const ltc_pkha_ecc_point_t *B, |
| const uint8_t *N, |
| const uint8_t *aCurveParam, |
| const uint8_t *bCurveParam, |
| uint8_t size, |
| ltc_pkha_f2m_t arithType, |
| ltc_pkha_ecc_point_t *result) |
| { |
| ltc_pkha_mode_params_t params; |
| uint32_t clearMask; |
| status_t status; |
| |
| ltc_pkha_default_parms(¶ms); |
| params.func = kLTC_PKHA_ArithEccDouble; |
| params.arithType = arithType; |
| |
| clearMask = kLTC_ClearMode; |
| |
| /* Clear internal register states. */ |
| clearMask |= kLTC_ClearPkhaSizeA; |
| clearMask |= kLTC_ClearPkhaSizeB; |
| clearMask |= kLTC_ClearPkhaSizeN; |
| clearMask |= kLTC_ClearPkhaSizeE; |
| |
| base->CW = clearMask; |
| base->STA = kLTC_StatusDoneIsr; |
| ltc_pkha_clear_regabne(base, true, true, true, false); |
| |
| /* sizeN should be less than 64 bytes. */ |
| base->PKNSZ = size; |
| ltc_pkha_write_reg(base, kLTC_PKHA_RegN, 0, N, size); |
| |
| base->PKASZ = size; |
| ltc_pkha_write_reg(base, kLTC_PKHA_RegA, 3, aCurveParam, size); |
| |
| base->PKBSZ = size; |
| ltc_pkha_write_reg(base, kLTC_PKHA_RegB, 0, bCurveParam, size); |
| ltc_pkha_write_reg(base, kLTC_PKHA_RegB, 1, B->X, size); |
| ltc_pkha_write_reg(base, kLTC_PKHA_RegB, 2, B->Y, size); |
| status = ltc_pkha_init_mode(base, ¶ms); |
| |
| if (status == kStatus_Success) |
| { |
| /* Read the data from the result register into place. */ |
| ltc_pkha_read_reg(base, kLTC_PKHA_RegB, 1, result->X, size); |
| ltc_pkha_read_reg(base, kLTC_PKHA_RegB, 2, result->Y, size); |
| } |
| |
| ltc_clear_all(base, true); |
| return status; |
| } |
| |
| status_t LTC_PKHA_ECC_PointMul(LTC_Type *base, |
| const ltc_pkha_ecc_point_t *A, |
| const uint8_t *E, |
| uint8_t sizeE, |
| const uint8_t *N, |
| const uint8_t *R2modN, |
| const uint8_t *aCurveParam, |
| const uint8_t *bCurveParam, |
| uint8_t size, |
| ltc_pkha_timing_t equalTime, |
| ltc_pkha_f2m_t arithType, |
| ltc_pkha_ecc_point_t *result, |
| bool *infinity) |
| { |
| ltc_pkha_mode_params_t params; |
| uint32_t clearMask; |
| status_t status; |
| |
| ltc_pkha_default_parms(¶ms); |
| params.func = kLTC_PKHA_ArithEccMul; |
| params.equalTime = equalTime; |
| params.arithType = arithType; |
| params.r2modn = R2modN ? kLTC_PKHA_InputR2 : kLTC_PKHA_CalcR2; |
| |
| clearMask = kLTC_ClearMode; |
| |
| /* Clear internal register states. */ |
| clearMask |= kLTC_ClearPkhaSizeA; |
| clearMask |= kLTC_ClearPkhaSizeB; |
| clearMask |= kLTC_ClearPkhaSizeN; |
| clearMask |= kLTC_ClearPkhaSizeE; |
| |
| base->CW = clearMask; |
| base->STA = kLTC_StatusDoneIsr; |
| ltc_pkha_clear_regabne(base, true, true, true, true); |
| |
| /* sizeN should be less than 64 bytes. */ |
| base->PKNSZ = size; |
| ltc_pkha_write_reg(base, kLTC_PKHA_RegN, 0, N, size); |
| |
| base->PKESZ = sizeE; |
| ltc_pkha_write_reg(base, kLTC_PKHA_RegE, 0, E, sizeE); |
| |
| base->PKASZ = size; |
| ltc_pkha_write_reg(base, kLTC_PKHA_RegA, 0, A->X, size); |
| ltc_pkha_write_reg(base, kLTC_PKHA_RegA, 1, A->Y, size); |
| ltc_pkha_write_reg(base, kLTC_PKHA_RegA, 3, aCurveParam, size); |
| |
| base->PKBSZ = size; |
| ltc_pkha_write_reg(base, kLTC_PKHA_RegB, 0, bCurveParam, size); |
| if (R2modN) |
| { |
| ltc_pkha_write_reg(base, kLTC_PKHA_RegB, 1, R2modN, size); |
| } |
| |
| status = ltc_pkha_init_mode(base, ¶ms); |
| |
| if (status == kStatus_Success) |
| { |
| /* Read the data from the result register into place. */ |
| ltc_pkha_read_reg(base, kLTC_PKHA_RegB, 1, result->X, size); |
| ltc_pkha_read_reg(base, kLTC_PKHA_RegB, 2, result->Y, size); |
| |
| if (infinity) |
| { |
| *infinity = (bool)(base->STA & kLTC_StatusPublicKeyOpZero); |
| } |
| } |
| |
| ltc_clear_all(base, true); |
| return status; |
| } |
| |
| #endif /* FSL_FEATURE_LTC_HAS_PKHA */ |