/* * Copyright 2019 NXP * * SPDX-License-Identifier: BSD-3-Clause */ #include "fsl_cau3_ble.h" /******************************************************************************* * Definitions ******************************************************************************/ /* Component ID definition, used by tools. */ #ifndef FSL_COMPONENT_ID #define FSL_COMPONENT_ID "platform.drivers.cau3" #endif /*! Compile time sizeof() check */ #define BUILD_ASSURE(condition, msg) extern int msg[1 - 2 * (!(condition))] __attribute__((unused)) #define CAU3_SR_TKCS_INITRUN 0x00000000U #define CAU3_SR_TKCS_RUN 0x00000100U #define CAU3_SR_TKCS_DBGHALT 0x00000200U #define CAU3_SR_TKCS_STOPNOERR 0x00000900U #define CAU3_SR_TKCS_STOPERROR 0x00000A00U #define CAU3_SR_TKCS_SECV 0x00000E00U #define CAU3_SR_TKCS_EXTSECV 0x00000F00U #define CAU3_DMEM_STK_BASE 0xfff003f8U #define CAU3_DMEM_AES_RCON 0xfff00A00U #define CAU3_TASK_SECV_INIT (0x00 * 4) #define CAU3_TASK_STOPERROR (0x01 * 4) #define CAU3_TASK_STOPNOERR (0x02 * 4) #define CAU3_TASK_NULL (0x02 * 4) #define CAU3_TASK_BLKLD_DMEM (0x03 * 4) #define CAU3_TASK_LD_KEYCTX (0x04 * 4) #define CAU3_TASK_LD_SP_KEYCTX (0x05 * 4) #define CAU3_TASK_CLR_KEYCTX (0x06 * 4) #define CAU3_TASK_LD_KEY (0x07 * 4) #define CAU3_TASK_LD_IV (0x08 * 4) #define CAU3_TASK_AES_KEY_SCH (0x09 * 4) #define CAU3_TASK_AES_ENCRYPT (0x0A * 4) #define CAU3_TASK_AES_DECRYPT (0x0B * 4) #define CAU3_TASK_AES128_ENCRYPT (0x0C * 4) #define CAU3_TASK_AES128_DECRYPT (0x0D * 4) #define CAU3_TASK_AES128_CMAC (0x0E * 4) #define CAU3_TASK_SHA256_INIT_STATE (0x0F * 4) #define CAU3_TASK_SHA256_UPDATE (0x10 * 4) #define CAU3_TASK_KEY_BLOB_UNWRAP (0x11 * 4) #define CAU3_TASK_SHA1_HASH (0x12 * 4) #define CAU3_TASK_SHA1_INIT_STATE (0x13 * 4) #define CAU3_TASK_SHA512_INIT_STATE (0x14 * 4) #define CAU3_TASK_SHA512_UPDATE (0x15 * 4) #define CAU3_TASK_3DES_CHECK_PARITY (0x16 * 4) #define CAU3_TASK_3DES_ENCRYPT (0x17 * 4) #define CAU3_TASK_3DES_DECRYPT (0x18 * 4) #define CAU3_TASK_CHA_POLY_ENCRYPT (0x19 * 4) #define CAU3_TASK_CHA_POLY_DECRYPT (0x1A * 4) #define CAU3_TASK_RPA_TABLE_SIZE (0x1B * 4) #define CAU3_TASK_RPA_INSERT_KEY (0x1C * 4) #define CAU3_TASK_RPA_REMOVE_KEY (0x1D * 4) #define CAU3_TASK_RPA_TABLE_SEARCH (0x1E * 4) #define CAU3_SEMA4_LOCK 0x80000000U #define CAU3_SEMA4_RELEASE 0x00000000U #define CAU3_SMOWNR_OWNED_BY_ME 0x00000001U #define CAU3_SMOWNR_UNLOCKED 0x80000000U /*! @brief keyContext structure in the CAU3's DataMemory */ typedef struct _cau3_key_context { uint32_t keySize; /*!< key size in bytes, 0 = invalid context */ uint32_t streamSize; /*!< rfu-firmware; stream length in bytes */ uint32_t *keySched; /*!< rfu-firmware; ptr to expanded key schedule */ uint32_t zeroFill; /*!< zero (unused) to keep 0-mod-4 alignment */ uint8_t iv[16]; /*!< initialization vector */ uint8_t key[32]; /*!< key for 3des, aes[128,192,256] */ } cau3_key_context_t; typedef enum _cau3_crypt { kCAU3_Encrypt = 0, kCAU3_Decrypt = 1, } cau3_crypt_t; #define cau3_memcpy memcpy #define cau3_force_zero(ptr, len) (memset((ptr), 0, (len))) /*! Internal states of the HASH creation process */ typedef enum _cau3_hash_algo_state { kCAU3_StateHashInit = 1u, /*!< Init state. */ kCAU3_StateHashUpdate, /*!< Update state. */ } cau3_hash_algo_state_t; /*! multiple of 64-byte block represented as byte array of 32-bit words */ typedef union _cau3_hash_block { uint32_t w[CAU3_HASH_BLOCK_SIZE / 4]; /*!< array of 32-bit words */ uint8_t b[CAU3_HASH_BLOCK_SIZE]; /*!< byte array */ } cau3_hash_block_t; /*! internal cau3_hash context structure */ typedef struct _cau3_hash_ctx_internal { cau3_hash_block_t blk; /*!< memory buffer. only full blocks are written to CAU3 during hash/cmac updates */ size_t blksz; /*!< number of valid bytes in memory buffer */ cau3_hash_algo_t algo; /*!< selected algorithm from the set of supported algorithms */ cau3_hash_algo_state_t state; /*!< finite machine state of the hash software process */ size_t fullMessageSize; /*!< track message size during CAU3_HASH_Update(). The value is used for padding. */ uint32_t runningHash[8]; } cau3_hash_ctx_internal_t; /*!< SHA-1/SHA-2 digest length in bytes */ enum _cau3_hash_digest_len { kCAU3_OutLenSha1 = 20u, kCAU3_OutLenSha256 = 32u, }; /*! 64-byte block represented as byte array of 16 32-bit words */ typedef union _cau3_sha_block { uint32_t w[64 / 4]; /*!< array of 32-bit words */ uint8_t b[64]; /*!< byte array */ } cau3_sha_block_t; /*! Full word representing the actual bit values for the CAU3 1.0 mode register. */ typedef uint32_t cau3_mode_t; #define CAU3_MDPK_ALG_PKHA (0x80U) /*!< Bit field value for CAU3_MDPK_ALG: PKHA */ #define CAU3_MD_ALG_SHIFT 16 typedef enum _cau3_algorithm { kCAU3_AlgorithmPKHA = CAU3_MDPK_ALG_PKHA << CAU3_MD_ALG_SHIFT, } cau3_algorithm_t; /*! @brief CAU3 status flags */ enum _cau3_status_flag { kCAU3_StatusPkhaBusy = 1U << CAU3_STA_PB_SHIFT, kCAU3_StatusDoneIsr = 1U << CAU3_STA_DI_SHIFT, kCAU3_StatusErrorIsr = 1U << CAU3_STA_EI_SHIFT, kCAU3_StatusPublicKeyPrime = 1U << CAU3_STA_PKP_SHIFT, kCAU3_StatusPublicKeyOpOne = 1U << CAU3_STA_PKO_SHIFT, kCAU3_StatusPublicKeyOpZero = 1U << CAU3_STA_PKZ_SHIFT, kCAU3_StatusAll = 0 | kCAU3_StatusDoneIsr | kCAU3_StatusErrorIsr | kCAU3_StatusPkhaBusy | kCAU3_StatusPublicKeyPrime | kCAU3_StatusPublicKeyOpOne | kCAU3_StatusPublicKeyOpZero }; /*! @brief CAU3 clear register */ typedef enum _cau3_clear_written { kCAU3_ClearMode = 1U << 0, kCAU3_ClearDataSize = 1U << 2, kCAU3_ClearPkhaSizeA = 1U << 12, kCAU3_ClearPkhaSizeB = 1U << 13, kCAU3_ClearPkhaSizeN = 1U << 14, kCAU3_ClearPkhaSizeE = 1U << 15, kCAU3_ClearAllSize = (int)kCAU3_ClearPkhaSizeA | kCAU3_ClearPkhaSizeB | kCAU3_ClearPkhaSizeN | kCAU3_ClearPkhaSizeE, kCAU3_ClearAll = (int)(kCAU3_ClearMode | kCAU3_ClearDataSize | kCAU3_ClearAllSize | 0) } cau3_clear_written_t; /*! @brief PKHA functions - arithmetic, copy/clear memory. */ typedef enum _cau3_pkha_func_t { kCAU3_PKHA_ClearMem = 1U, kCAU3_PKHA_ArithModAdd = 2U, /*!< (A + B) mod N */ kCAU3_PKHA_ArithModSub1 = 3U, /*!< (A - B) mod N */ kCAU3_PKHA_ArithModSub2 = 4U, /*!< (B - A) mod N */ kCAU3_PKHA_ArithModMul = 5U, /*!< (A x B) mod N */ kCAU3_PKHA_ArithModExp = 6U, /*!< (A^E) mod N */ kCAU3_PKHA_ArithModRed = 7U, /*!< (A) mod N */ kCAU3_PKHA_ArithModInv = 8U, /*!< (A^-1) mod N */ kCAU3_PKHA_ArithEccAdd = 9U, /*!< (P1 + P2) */ kCAU3_PKHA_ArithEccDouble = 10U, /*!< (P2 + P2) */ kCAU3_PKHA_ArithEccMul = 11U, /*!< (E x P(A0,A1) */ kCAU3_PKHA_ArithModR2 = 12U, /*!< (R^2 mod N) */ kCAU3_PKHA_ArithModRR = 13U, /*!< (RERP mod N) */ kCAU3_PKHA_ArithGcd = 14U, /*!< GCD (A, N) */ kCAU3_PKHA_ArithPrimalityTest = 15U, /*!< Miller-Rabin */ kCAU3_PKHA_CopyMemSizeN = 16U, kCAU3_PKHA_CopyMemSizeSrc = 17U, kCAU3_PKHA_ArithModSqrt = 0x17U, /*!< (B0 x B0) mod N = A mod N */ kCAU3_PKHA_ArithEcmMul = 0x4B, /*!< (E x P[A0]) */ kCAU3_PKHA_ArithEctAdd = 0x89, /*!< (P[A0,A1] + P[B1,B2]) */ kCAU3_PKHA_ArithEctMul = 0x8B, /*!< (E x P[A0,A1]) */ } cau3_pkha_func_t; /*! @brief Register areas for PKHA clear memory operations. */ typedef enum _cau3_pkha_reg_area { kCAU3_PKHA_RegA = 8U, kCAU3_PKHA_RegB = 4U, kCAU3_PKHA_RegE = 2U, kCAU3_PKHA_RegN = 1U, kCAU3_PKHA_RegAll = kCAU3_PKHA_RegA | kCAU3_PKHA_RegB | kCAU3_PKHA_RegE | kCAU3_PKHA_RegN, } cau3_pkha_reg_area_t; /*! @brief Quadrant areas for 2048-bit registers for PKHA copy memory * operations. */ typedef enum _cau3_pkha_quad_area_t { kCAU3_PKHA_Quad0 = 0U, kCAU3_PKHA_Quad1 = 1U, kCAU3_PKHA_Quad2 = 2U, kCAU3_PKHA_Quad3 = 3U, } cau3_pkha_quad_area_t; /*! @brief User-supplied (R^2 mod N) input or CAU3 should calculate. */ typedef enum _cau3_pkha_r2_t { kCAU3_PKHA_CalcR2 = 0U, /*!< Calculate (R^2 mod N) */ kCAU3_PKHA_InputR2 = 1U /*!< (R^2 mod N) supplied as input */ } cau3_pkha_r2_t; /*! @brief CAU3 PKHA parameters */ typedef struct _cau3_pkha_mode_params_t { cau3_pkha_func_t func; cau3_pkha_f2m_t arithType; cau3_pkha_montgomery_form_t montFormIn; cau3_pkha_montgomery_form_t montFormOut; cau3_pkha_reg_area_t srcReg; cau3_pkha_quad_area_t srcQuad; cau3_pkha_reg_area_t dstReg; cau3_pkha_quad_area_t dstQuad; cau3_pkha_timing_t equalTime; cau3_pkha_r2_t r2modn; } cau3_pkha_mode_params_t; /******************************************************************************* * Variables ******************************************************************************/ /******************************************************************************* * CAU3 Read-Only Data Constants and CryptoCore Code Image ******************************************************************************/ /* in the cau3's private, local data memory, there is a section for read-only */ /* constants associated with AES, SHA-1, SHA-256, SHA-384 and SHA-512. */ /* the memory organization and layout of this section is defined as: */ /* */ /* description size dmem_base description */ /* cau_dmem_aes_rcon 48 FFF00800 RO aes constants 10 x 32b */ /* cau_dmem_sha1_k 16 FFF00830 RO sha1 initial "k" 4 x 32b */ /* cau_dmem_sha1_init_h 32 FFF00840 RO sha1 initial state 5 x 32b */ /* cau_dmem_sha224_init_h 32 FFF00860 RO sha224 initial state 8 x 32b */ /* cau_dmem_sha256_init_h 32 FFF00880 RO sha256 initial state 8 x 32b */ /* cau_dmem_sha256_k 256 FFF008A0 RO sha256 initial "k" 64 x 32b */ /* cau_dmem_sha384_init_h 64 FFF009A0 RO sha384 initial state 16 x 32b */ /* cau_dmem_sha512_init_h 64 FFF009E0 RO sha512 initial state 16 x 32b */ /* cau_dmem_sha512_k 640 FFF00A20 RO sha512 initial "k" 160 x 32b */ /* */ /* data size allocation are rounded up to be modulo 16 bytes as required. */ /* */ static const uint32_t s_cau3ReadOnlyConstants[] __attribute__((aligned(16))) = { /* AES RCON[] */ 0x01000000U, 0x02000000U, 0x04000000U, 0x08000000U, 0x10000000U, 0x20000000U, 0x40000000U, 0x80000000U, 0x1b000000U, 0x36000000U, 0x00000000U, 0x00000000U, /* zero fill for 0-mod-16 alignment */ /* SHA1_K[] */ 0x5a827999U, 0x6ed9eba1U, 0x8f1bbcdcU, 0xca62c1d6U, /* SHA1_INIT_H[] */ 0x67452301U, 0xefcdab89U, 0x98badcfeU, 0x10325476U, 0xc3d2e1f0U, 0x00000000U, 0x00000000U, 0x00000000U, /* zero fill for 0-mod-16 alignemnt */ /* SHA224_INIT_H[] */ 0xc1059ed8U, 0x367cd507U, 0x3070dd17U, 0xf70e5939U, 0xffc00b31U, 0x68581511U, 0x64f98fa7U, 0xbefa4fa4U, /* SHA256_INIT_H[] */ /* As described in FIPS PUB 180-4 "Secure Hash Standard", the initial hash value */ /* for SHA-256 is obtained by taking the first thirty-two bits of the fractional */ /* parts of the square roots of the first eight prime numbers. */ 0x6a09e667U, 0xbb67ae85U, 0x3c6ef372U, 0xa54ff53aU, 0x510e527fU, 0x9b05688cU, 0x1f83d9abU, 0x5be0cd19U, /* SHA256_K[], also used as SHA224_K[] */ /* As described in FIPS PUB 180-4 "Secure Hash Standard", SHA-224 & SHA-256 use */ /* the same sequence of sixty-four constant 32-bit words (K[]), where the words */ /* represent the first thirty-two bits of the fractional parts of the cube roots */ /* of the first sixty-four prime numbers. */ 0x428a2f98U, 0x71374491U, 0xb5c0fbcfU, 0xe9b5dba5U, 0x3956c25bU, 0x59f111f1U, 0x923f82a4U, 0xab1c5ed5U, 0xd807aa98U, 0x12835b01U, 0x243185beU, 0x550c7dc3U, 0x72be5d74U, 0x80deb1feU, 0x9bdc06a7U, 0xc19bf174U, 0xe49b69c1U, 0xefbe4786U, 0x0fc19dc6U, 0x240ca1ccU, 0x2de92c6fU, 0x4a7484aaU, 0x5cb0a9dcU, 0x76f988daU, 0x983e5152U, 0xa831c66dU, 0xb00327c8U, 0xbf597fc7U, 0xc6e00bf3U, 0xd5a79147U, 0x06ca6351U, 0x14292967U, 0x27b70a85U, 0x2e1b2138U, 0x4d2c6dfcU, 0x53380d13U, 0x650a7354U, 0x766a0abbU, 0x81c2c92eU, 0x92722c85U, 0xa2bfe8a1U, 0xa81a664bU, 0xc24b8b70U, 0xc76c51a3U, 0xd192e819U, 0xd6990624U, 0xf40e3585U, 0x106aa070U, 0x19a4c116U, 0x1e376c08U, 0x2748774cU, 0x34b0bcb5U, 0x391c0cb3U, 0x4ed8aa4aU, 0x5b9cca4fU, 0x682e6ff3U, 0x748f82eeU, 0x78a5636fU, 0x84c87814U, 0x8cc70208U, 0x90befffaU, 0xa4506cebU, 0xbef9a3f7U, 0xc67178f2U, /* SHA384_INIT_H[] */ /* 8 x 64-bit words in little-endian format */ 0xc1059ed8U, 0xcbbb9d5dU, 0x367cd507U, 0x629a292aU, 0x3070dd17U, 0x9159015aU, 0xf70e5939U, 0x152fecd8U, 0xffc00b31U, 0x67332667U, 0x68581511U, 0x8eb44a87U, 0x64f98fa7U, 0xdb0c2e0dU, 0xbefa4fa4U, 0x47b5481dU, /* SHA512_INIT_H[] */ /* 8 x 64-bit words in little-endian format */ 0xf3bcc908U, 0x6a09e667U, 0x84caa73bU, 0xbb67ae85U, 0xfe94f82bU, 0x3c6ef372U, 0x5f1d36f1U, 0xa54ff53aU, 0xade682d1U, 0x510e527fU, 0x2b3e6c1fU, 0x9b05688cU, 0xfb41bd6bU, 0x1f83d9abU, 0x137e2179U, 0x5be0cd19U, /* SHA512_K[] */ /* 80 x 64-bit words in little-endian format */ 0xd728ae22U, 0x428a2f98U, 0x23ef65cdU, 0x71374491U, 0xec4d3b2fU, 0xb5c0fbcfU, 0x8189dbbcU, 0xe9b5dba5U, 0xf348b538U, 0x3956c25bU, 0xb605d019U, 0x59f111f1U, 0xaf194f9bU, 0x923f82a4U, 0xda6d8118U, 0xab1c5ed5U, 0xa3030242U, 0xd807aa98U, 0x45706fbeU, 0x12835b01U, 0x4ee4b28cU, 0x243185beU, 0xd5ffb4e2U, 0x550c7dc3U, 0xf27b896fU, 0x72be5d74U, 0x3b1696b1U, 0x80deb1feU, 0x25c71235U, 0x9bdc06a7U, 0xcf692694U, 0xc19bf174U, 0x9ef14ad2U, 0xe49b69c1U, 0x384f25e3U, 0xefbe4786U, 0x8b8cd5b5U, 0x0fc19dc6U, 0x77ac9c65U, 0x240ca1ccU, 0x592b0275U, 0x2de92c6fU, 0x6ea6e483U, 0x4a7484aaU, 0xbd41fbd4U, 0x5cb0a9dcU, 0x831153b5U, 0x76f988daU, 0xee66dfabU, 0x983e5152U, 0x2db43210U, 0xa831c66dU, 0x98fb213fU, 0xb00327c8U, 0xbeef0ee4U, 0xbf597fc7U, 0x3da88fc2U, 0xc6e00bf3U, 0x930aa725U, 0xd5a79147U, 0xe003826fU, 0x06ca6351U, 0x0a0e6e70U, 0x14292967U, 0x46d22ffcU, 0x27b70a85U, 0x5c26c926U, 0x2e1b2138U, 0x5ac42aedU, 0x4d2c6dfcU, 0x9d95b3dfU, 0x53380d13U, 0x8baf63deU, 0x650a7354U, 0x3c77b2a8U, 0x766a0abbU, 0x47edaee6U, 0x81c2c92eU, 0x1482353bU, 0x92722c85U, 0x4cf10364U, 0xa2bfe8a1U, 0xbc423001U, 0xa81a664bU, 0xd0f89791U, 0xc24b8b70U, 0x0654be30U, 0xc76c51a3U, 0xd6ef5218U, 0xd192e819U, 0x5565a910U, 0xd6990624U, 0x5771202aU, 0xf40e3585U, 0x32bbd1b8U, 0x106aa070U, 0xb8d2d0c8U, 0x19a4c116U, 0x5141ab53U, 0x1e376c08U, 0xdf8eeb99U, 0x2748774cU, 0xe19b48a8U, 0x34b0bcb5U, 0xc5c95a63U, 0x391c0cb3U, 0xe3418acbU, 0x4ed8aa4aU, 0x7763e373U, 0x5b9cca4fU, 0xd6b2b8a3U, 0x682e6ff3U, 0x5defb2fcU, 0x748f82eeU, 0x43172f60U, 0x78a5636fU, 0xa1f0ab72U, 0x84c87814U, 0x1a6439ecU, 0x8cc70208U, 0x23631e28U, 0x90befffaU, 0xde82bde9U, 0xa4506cebU, 0xb2c67915U, 0xbef9a3f7U, 0xe372532bU, 0xc67178f2U, 0xea26619cU, 0xca273eceU, 0x21c0c207U, 0xd186b8c7U, 0xcde0eb1eU, 0xeada7dd6U, 0xee6ed178U, 0xf57d4f7fU, 0x72176fbaU, 0x06f067aaU, 0xa2c898a6U, 0x0a637dc5U, 0xbef90daeU, 0x113f9804U, 0x131c471bU, 0x1b710b35U, 0x23047d84U, 0x28db77f5U, 0x40c72493U, 0x32caab7bU, 0x15c9bebcU, 0x3c9ebe0aU, 0x9c100d4cU, 0x431d67c4U, 0xcb3e42b6U, 0x4cc5d4beU, 0xfc657e2aU, 0x597f299cU, 0x3ad6faecU, 0x5fcb6fabU, 0x4a475817U, 0x6c44198cU, /* CHACHA_K[] */ 0x61707865U, 0x3320646eU, 0x79622d32U, 0x6b206574U}; static const uint32_t s_cau3ReadOnlyConstantsBytes = sizeof(s_cau3ReadOnlyConstants); static const uint32_t s_cau3ImemImage[] __attribute__((aligned(16))) = { 0x60C00000U, 0x54000040U, 0x54000020U, 0x608003E0U, 0x60800540U, 0x60800B80U, 0x608012C0U, 0x60801540U, 0x608018A0U, 0x60801BC0U, 0x608049E0U, 0x60806540U, 0x60808100U, 0x54000040U, 0x54000040U, 0x60809180U, 0x608093E0U, 0x60801DA0U, 0x54000040U, 0x54000040U, 0x54000040U, 0x54000040U, 0x54000040U, 0x54000040U, 0x54000040U, 0x54000040U, 0x54000040U, 0x6080C640U, 0x6080C7A0U, 0x6080CAC0U, 0x6080CDE0U, 0xC8FFE3DEU, 0x08CC1234U, 0x8C001200U, 0x8C001201U, 0x8C001202U, 0x8C001203U, 0xCE002240U, 0xCE002242U, 0x60000434U, 0x840003DEU, 0x54000020U, 0xC8FFE3DEU, 0x5C001FE0U, 0x08800E31U, 0x0CC81A31U, 0x2000A012U, 0x101FFE12U, 0x00404652U, 0x8C004200U, 0x9C001204U, 0x9C001205U, 0x9C001206U, 0x9C001207U, 0xCE002240U, 0xCE002242U, 0xCE002244U, 0xCE002246U, 0x9C001200U, 0x9C001201U, 0x9C001202U, 0x9C001203U, 0x9C001204U, 0x9C001205U, 0x9C001206U, 0x9C001207U, 0xCE002240U, 0xCE002242U, 0xCE002244U, 0xCE002246U, 0x08510252U, 0x84000240U, 0x0880E000U, 0x3C000400U, 0x67800980U, 0x20000400U, 0xC4000240U, 0x3C000100U, 0x08408254U, 0x00800012U, 0x08CC1A31U, 0x67800B20U, 0x3C000300U, 0x66800AE0U, 0x63800AC0U, 0x08501A52U, 0x08501A52U, 0x08501A52U, 0x70002D5FU, 0x5C1FFFE0U, 0x5801FFE0U, 0x54000020U, 0xC8FFE3DEU, 0x5C001FE0U, 0x08800E31U, 0x0CC81A31U, 0x2000A012U, 0x101FFE12U, 0x00404652U, 0x00804200U, 0xCE002240U, 0xCE002242U, 0x20D4D4C4U, 0x1014D4C4U, 0x20D4D4C5U, 0x1014D4C5U, 0xCE002244U, 0xCE002246U, 0x24000100U, 0x24000121U, 0x24000142U, 0x24000163U, 0x24000184U, 0x240001A5U, 0x240001C6U, 0x240001E7U, 0x00040000U, 0x00040021U, 0x00040042U, 0x00040063U, 0x00040084U, 0x000400A5U, 0x000400C6U, 0x000400E7U, 0xCE002240U, 0xCE002242U, 0xCE002244U, 0xCE002246U, 0x08510252U, 0x84000240U, 0x0880E000U, 0x3C000400U, 0x678010C0U, 0x20000400U, 0xC4000240U, 0x3C000100U, 0x08408254U, 0x00800012U, 0x08CC1A31U, 0x67801260U, 0x3C000300U, 0x66801220U, 0x63801200U, 0x08501A52U, 0x08501A52U, 0x08501A52U, 0x70002D5FU, 0x5C1FFFE0U, 0x5801FFE0U, 0x54000020U, 0x08800E31U, 0x08C81A31U, 0x2000A012U, 0x101FFE12U, 0x00404652U, 0x5C1FFFE0U, 0xCE002240U, 0xCE002242U, 0xCE002244U, 0xCE002246U, 0xCE002240U, 0xCE002242U, 0xCE002244U, 0xCE002246U, 0x5C1FFFE0U, 0x5801FFE0U, 0x04807FFFU, 0x63801520U, 0x7080001FU, 0x54000020U, 0x0CCC7E48U, 0x638015C0U, 0x088C7E52U, 0x28000032U, 0x08800E52U, 0x08C81A52U, 0x2000A013U, 0x101FFE13U, 0x00404A73U, 0xC4000271U, 0x28000413U, 0x0C800E21U, 0x08CC0A31U, 0x63801720U, 0x28000031U, 0x3C000008U, 0x638017E0U, 0x8C001201U, 0xCC001261U, 0x60001771U, 0x60801840U, 0x8C001201U, 0xDC001261U, 0x600017F1U, 0x5C1FFFE0U, 0x581FFFE0U, 0x54000020U, 0x0CCC7E28U, 0x63801920U, 0x088C7E31U, 0x28000031U, 0x08800E31U, 0x08C81A31U, 0x2000A212U, 0x101FFE12U, 0x00404652U, 0x8C001204U, 0x8C001205U, 0x8C001206U, 0x8C001207U, 0x3C000008U, 0x63801AE0U, 0xCE002244U, 0xCE002246U, 0x60801B60U, 0xDC001244U, 0xDC001245U, 0xDC001246U, 0xDC001247U, 0x5C1FFFE0U, 0x5801FFE0U, 0x54000020U, 0xC8FFE3DEU, 0x08800E31U, 0x08C81A20U, 0x2000A014U, 0x101FFE14U, 0x00400294U, 0x84000292U, 0x3C000312U, 0x66801D40U, 0x63801D20U, 0x08501A52U, 0x08501A52U, 0x08501A52U, 0x28000414U, 0x60802D40U, 0x0C8013C6U, 0x63801E40U, 0xC8FEB3DEU, 0xC40013DFU, 0x60801E80U, 0xC8FEC3DEU, 0xC40013DFU, 0x00804A55U, 0x00804636U, 0x00804E77U, 0x084006F4U, 0x3C000094U, 0x63001F60U, 0x20000034U, 0x3C000055U, 0x63802080U, 0x3C000095U, 0x63802080U, 0x3C000115U, 0x63802080U, 0x3C000095U, 0x67002780U, 0x60802700U, 0x08800EC6U, 0x08C818C6U, 0x2000A00CU, 0x101FFE0CU, 0x0040198CU, 0x8C004198U, 0x08800E31U, 0x08C82226U, 0x2000C011U, 0x101FFE11U, 0x00401A31U, 0x3C000318U, 0x66802280U, 0x638026C0U, 0x200001D2U, 0x608022A0U, 0x20000152U, 0x2001E313U, 0x101FFE13U, 0x9C001200U, 0x9C001201U, 0x20000106U, 0x004078C6U, 0x008056AAU, 0x9C00120EU, 0x9C00120FU, 0xCE0020CEU, 0x6000238AU, 0x200000C9U, 0x008056AAU, 0x08500527U, 0x01001EA7U, 0x004028E6U, 0x008C1821U, 0x08C80D48U, 0x800023C2U, 0x08401108U, 0x800023C3U, 0x70006F3FU, 0x08501108U, 0xC00023C2U, 0x08401108U, 0xC00023C3U, 0x6000248AU, 0x60002429U, 0x8600018EU, 0x008C01CBU, 0x008C05E6U, 0x0488196BU, 0x63802860U, 0x3C000115U, 0x63802780U, 0x00805EF1U, 0x700012DFU, 0x581FFFE0U, 0x54000040U, 0x00805EF1U, 0x0080529DU, 0x700012DFU, 0x008077B1U, 0x700012DFU, 0x581FFFE0U, 0x54000040U, 0x00805EE7U, 0x08800EF7U, 0x08C81AE6U, 0x2000A017U, 0x101FFE17U, 0x00401AF7U, 0x3C000055U, 0x638029E0U, 0x3C000095U, 0x638029E0U, 0x20000407U, 0x60802A00U, 0x08C80EA7U, 0xCC0082E7U, 0x20000106U, 0x004078C6U, 0x008056AAU, 0x3C000115U, 0x63802B40U, 0x8E0020C0U, 0xCE0022E0U, 0x60002ACAU, 0x60802D20U, 0x0850114AU, 0x8E0020C0U, 0xCE0022E0U, 0x60002B6AU, 0x08800E94U, 0x08C81A87U, 0x2000A014U, 0x101FFE14U, 0x00401E94U, 0x2000008AU, 0x20000407U, 0xCC008287U, 0x8E0020C0U, 0xCE002280U, 0x60002CCAU, 0x54000020U, 0x08C82236U, 0x2000C011U, 0x101FFE11U, 0x00405A31U, 0x86000280U, 0x86002282U, 0x20014015U, 0x101FFE15U, 0x00800004U, 0x00800425U, 0x00800846U, 0x00800C67U, 0xCE002220U, 0xCE002222U, 0x3C000192U, 0x66803D60U, 0x63803D40U, 0x86004284U, 0x86006286U, 0xCE002224U, 0xCE002226U, 0x08D020E8U, 0x01800108U, 0xAC0012A8U, 0x008C2000U, 0x008C0021U, 0x008C0442U, 0x008C0863U, 0xCE002220U, 0xCE002222U, 0x01800068U, 0x008C2084U, 0x008C10A5U, 0x008C14C6U, 0x008C18E7U, 0xCE002224U, 0xCE002226U, 0x08D020E8U, 0x01800108U, 0xAC0012A8U, 0x008C2000U, 0x008C0021U, 0x008C0442U, 0x008C0863U, 0xCE002220U, 0xCE002222U, 0x01800068U, 0x008C2084U, 0x008C10A5U, 0x008C14C6U, 0x008C18E7U, 0xCE002224U, 0xCE002226U, 0x08D020E8U, 0x01800108U, 0xAC0012A8U, 0x008C2000U, 0x008C0021U, 0x008C0442U, 0x008C0863U, 0xCE002220U, 0xCE002222U, 0x01800068U, 0x008C2084U, 0x008C10A5U, 0x008C14C6U, 0x008C18E7U, 0xCE002224U, 0xCE002226U, 0x08D020E8U, 0x01800108U, 0xAC0012A8U, 0x008C2000U, 0x008C0021U, 0x008C0442U, 0x008C0863U, 0xCE002220U, 0xCE002222U, 0x01800068U, 0x008C2084U, 0x008C10A5U, 0x008C14C6U, 0x008C18E7U, 0xCE002224U, 0xCE002226U, 0x08D020E8U, 0x01800108U, 0xAC0012A8U, 0x008C2000U, 0x008C0021U, 0x008C0442U, 0x008C0863U, 0xCE002220U, 0xCE002222U, 0x01800068U, 0x008C2084U, 0x008C10A5U, 0x008C14C6U, 0x008C18E7U, 0xCE002224U, 0xCE002226U, 0x08D020E8U, 0x01800108U, 0xAC0012A8U, 0x008C2000U, 0x008C0021U, 0x008C0442U, 0x008C0863U, 0xCE002220U, 0xCE002222U, 0x01800068U, 0x008C2084U, 0x008C10A5U, 0x008C14C6U, 0x008C18E7U, 0xCE002224U, 0xCE002226U, 0x08D020E8U, 0x01800108U, 0xAC0012A8U, 0x008C2000U, 0x008C0021U, 0x008C0442U, 0x008C0863U, 0xCE002220U, 0xCE002222U, 0x29FFE211U, 0x608048C0U, 0x54000040U, 0x08D02067U, 0x018000E7U, 0xAC0012A7U, 0x008C1C00U, 0x008C0021U, 0x008C0442U, 0x008C0863U, 0xCE002220U, 0xCE002222U, 0x08D02067U, 0x018000E7U, 0xAC0012A7U, 0x008C1C00U, 0x008C0021U, 0x008C0442U, 0x008C0863U, 0xCE002220U, 0xCE002222U, 0x08D02067U, 0x018000E7U, 0xAC0012A7U, 0x008C1C00U, 0x008C0021U, 0x008C0442U, 0x008C0863U, 0xCE002220U, 0xCE002222U, 0x08D02067U, 0x018000E7U, 0xAC0012A7U, 0x008C1C00U, 0x008C0021U, 0x008C0442U, 0x008C0863U, 0xCE002220U, 0xCE002222U, 0x08D02067U, 0x018000E7U, 0xAC0012A7U, 0x008C1C00U, 0x008C0021U, 0x008C0442U, 0x008C0863U, 0xCE002220U, 0xCE002222U, 0x08D02067U, 0x018000E7U, 0xAC0012A7U, 0x008C1C00U, 0x008C0021U, 0x008C0442U, 0x008C0863U, 0xCE002220U, 0xCE002222U, 0x08D02067U, 0x018000E7U, 0xAC0012A7U, 0x008C1C00U, 0x008C0021U, 0x008C0442U, 0x008C0863U, 0xCE002220U, 0xCE002222U, 0x08D02067U, 0x018000E7U, 0xAC0012A7U, 0x008C1C00U, 0x008C0021U, 0x008C0442U, 0x008C0863U, 0xCE002220U, 0xCE002222U, 0x08D02067U, 0x018000E7U, 0xAC0012A7U, 0x008C1C00U, 0x008C0021U, 0x008C0442U, 0x008C0863U, 0xCE002220U, 0xCE002222U, 0x08D02067U, 0x018000E7U, 0xAC0012A7U, 0x008C1C00U, 0x008C0021U, 0x008C0442U, 0x008C0863U, 0xCE002220U, 0xCE002222U, 0x29FFEA11U, 0x04805294U, 0x63804920U, 0xC4FFA291U, 0x04807FFFU, 0x63804980U, 0x7080001FU, 0x5C1FFFE0U, 0x581FFFE0U, 0x54000020U, 0x08800E31U, 0x08C81A20U, 0x2000A012U, 0x101FFE12U, 0x80000252U, 0x3C000312U, 0x66804B20U, 0x63804B00U, 0x08501A52U, 0x08501A52U, 0x08501A52U, 0x08C82236U, 0x2000C011U, 0x101FFE11U, 0x00405A31U, 0x0C800E04U, 0x63805340U, 0x3C000024U, 0x63805100U, 0x3C000044U, 0x63804EC0U, 0x94FFF605U, 0x08C860A0U, 0x94000605U, 0x08CC20A6U, 0x00881800U, 0x08C860A1U, 0x94001605U, 0x08CC20A6U, 0x00881821U, 0x08C860A2U, 0x94002605U, 0x08CC20A6U, 0x00881842U, 0x08C860A3U, 0x94003605U, 0x08CC20A6U, 0x00881863U, 0x608053C0U, 0x94FFFA05U, 0x08C840A0U, 0x94000A05U, 0x08CC40A6U, 0x00881800U, 0x08C840A1U, 0x94001A05U, 0x08CC40A6U, 0x00881821U, 0x08C840A2U, 0x94002A05U, 0x08CC40A6U, 0x00881842U, 0x08C840A3U, 0x94003A05U, 0x08CC40A6U, 0x00881863U, 0x608053C0U, 0x94FFFE05U, 0x08C820A0U, 0x94000E05U, 0x08CC60A6U, 0x00881800U, 0x08C820A1U, 0x94001E05U, 0x08CC60A6U, 0x00881821U, 0x08C820A2U, 0x94002E05U, 0x08CC60A6U, 0x00881842U, 0x08C820A3U, 0x94003E05U, 0x08CC60A6U, 0x00881863U, 0x608053C0U, 0x94000200U, 0x94001201U, 0x94002202U, 0x94003203U, 0xAC001220U, 0xAC001221U, 0xAC001222U, 0xAC001223U, 0x08500A48U, 0x08CC0508U, 0x01800000U, 0x01800021U, 0x01800042U, 0x01800063U, 0x01900000U, 0x8E002224U, 0x8E002226U, 0x01881000U, 0x01881421U, 0x01881842U, 0x01881C63U, 0x01800000U, 0x01800021U, 0x01800042U, 0x01800063U, 0x01900000U, 0x8E002224U, 0x8E002226U, 0x01881000U, 0x01881421U, 0x01881842U, 0x01881C63U, 0x60005488U, 0x01800000U, 0x01800021U, 0x01800042U, 0x01800063U, 0x01900000U, 0x8E002224U, 0x8E002226U, 0x01881000U, 0x01881421U, 0x01881842U, 0x01881C63U, 0x01800000U, 0x01800021U, 0x01800042U, 0x01800063U, 0x01900000U, 0xAC001220U, 0xAC001221U, 0xAC001222U, 0xAC001223U, 0x0C800E64U, 0x63806400U, 0x3C000024U, 0x638060E0U, 0x3C000044U, 0x63805DC0U, 0x94FFF664U, 0x08CC2084U, 0x08C82084U, 0x08CC6005U, 0x008810A5U, 0xD4FFF665U, 0x08C82005U, 0x08CC6024U, 0x008810A5U, 0xD4000665U, 0x08C82025U, 0x08CC6044U, 0x008810A5U, 0xD4001665U, 0x08C82045U, 0x08CC6064U, 0x008810A5U, 0xD4002665U, 0x94003664U, 0x08C86084U, 0x08CC6084U, 0x08C82065U, 0x008810A5U, 0xD4003665U, 0x60806480U, 0x94FFFA64U, 0x08CC4084U, 0x08C84084U, 0x08CC4005U, 0x008810A5U, 0xD4FFFA65U, 0x08C84005U, 0x08CC4024U, 0x008810A5U, 0xD4000A65U, 0x08C84025U, 0x08CC4044U, 0x008810A5U, 0xD4001A65U, 0x08C84045U, 0x08CC4064U, 0x008810A5U, 0xD4002A65U, 0x94003A64U, 0x08C84084U, 0x08CC4084U, 0x08C84065U, 0x008810A5U, 0xD4003A65U, 0x60806480U, 0x94FFFE64U, 0x08CC6084U, 0x08C86084U, 0x08CC2005U, 0x008810A5U, 0xD4FFFE65U, 0x08C86005U, 0x08CC2024U, 0x008810A5U, 0xD4000E65U, 0x08C86025U, 0x08CC2044U, 0x008810A5U, 0xD4001E65U, 0x08C86045U, 0x08CC2064U, 0x008810A5U, 0xD4002E65U, 0x94003E64U, 0x08C82084U, 0x08CC2084U, 0x08C86065U, 0x008810A5U, 0xD4003E65U, 0x60806480U, 0xD4000260U, 0xD4001261U, 0xD4002262U, 0xD4003263U, 0x04807FFFU, 0x638064E0U, 0x7080001FU, 0x5C1FFFE0U, 0x581FFFE0U, 0x54000020U, 0x08800E31U, 0x08C81A20U, 0x2000A012U, 0x101FFE12U, 0x80000252U, 0x3C000312U, 0x66806680U, 0x63806660U, 0x08501A52U, 0x08501A52U, 0x08501A52U, 0x08C82236U, 0x2000C011U, 0x101FFE11U, 0x00405A31U, 0x0C800E04U, 0x63806EA0U, 0x3C000024U, 0x63806C60U, 0x3C000044U, 0x63806A20U, 0x94FFF605U, 0x08C860A0U, 0x94000605U, 0x08CC20A6U, 0x00881800U, 0x08C860A1U, 0x94001605U, 0x08CC20A6U, 0x00881821U, 0x08C860A2U, 0x94002605U, 0x08CC20A6U, 0x00881842U, 0x08C860A3U, 0x94003605U, 0x08CC20A6U, 0x00881863U, 0x60806F20U, 0x94FFFA05U, 0x08C840A0U, 0x94000A05U, 0x08CC40A6U, 0x00881800U, 0x08C840A1U, 0x94001A05U, 0x08CC40A6U, 0x00881821U, 0x08C840A2U, 0x94002A05U, 0x08CC40A6U, 0x00881842U, 0x08C840A3U, 0x94003A05U, 0x08CC40A6U, 0x00881863U, 0x60806F20U, 0x94FFFE05U, 0x08C820A0U, 0x94000E05U, 0x08CC60A6U, 0x00881800U, 0x08C820A1U, 0x94001E05U, 0x08CC60A6U, 0x00881821U, 0x08C820A2U, 0x94002E05U, 0x08CC60A6U, 0x00881842U, 0x08C820A3U, 0x94003E05U, 0x08CC60A6U, 0x00881863U, 0x60806F20U, 0x94000200U, 0x94001201U, 0x94002202U, 0x94003203U, 0x08C81259U, 0x00406631U, 0xA8003223U, 0xA8FFF222U, 0xA8FFF221U, 0xA8FFF220U, 0x08500A59U, 0x08CC0739U, 0x01940000U, 0x01840063U, 0x01840042U, 0x01840021U, 0x01840000U, 0x8AFFE23CU, 0x8AFFE23AU, 0x018C7463U, 0x018C7042U, 0x018C6C21U, 0x018C6800U, 0x01940000U, 0x01840063U, 0x01840042U, 0x01840021U, 0x01840000U, 0x8AFFE23CU, 0x8AFFE23AU, 0x018C7463U, 0x018C7042U, 0x018C6C21U, 0x018C6800U, 0x60007039U, 0x01940000U, 0x01840063U, 0x01840042U, 0x01840021U, 0x01840000U, 0x8AFFE23CU, 0x8AFFE23AU, 0x018C7463U, 0x018C7042U, 0x018C6C21U, 0x018C6800U, 0x01940000U, 0x01840063U, 0x01840042U, 0x01840021U, 0x01840000U, 0xA8FFF223U, 0xA8FFF222U, 0xA8FFF221U, 0xA8FFF220U, 0x0C800E79U, 0x63807FA0U, 0x3C000039U, 0x63807C80U, 0x3C000059U, 0x63807960U, 0x94FFF664U, 0x08CC2084U, 0x08C82084U, 0x08CC6005U, 0x008810A5U, 0xD4FFF665U, 0x08C82005U, 0x08CC6024U, 0x008810A5U, 0xD4000665U, 0x08C82025U, 0x08CC6044U, 0x008810A5U, 0xD4001665U, 0x08C82045U, 0x08CC6064U, 0x008810A5U, 0xD4002665U, 0x94003664U, 0x08C86084U, 0x08CC6084U, 0x08C82065U, 0x008810A5U, 0xD4003665U, 0x60808020U, 0x94FFFA64U, 0x08CC4084U, 0x08C84084U, 0x08CC4005U, 0x008810A5U, 0xD4FFFA65U, 0x08C84005U, 0x08CC4024U, 0x008810A5U, 0xD4000A65U, 0x08C84025U, 0x08CC4044U, 0x008810A5U, 0xD4001A65U, 0x08C84045U, 0x08CC4064U, 0x008810A5U, 0xD4002A65U, 0x94003A64U, 0x08C84084U, 0x08CC4084U, 0x08C84065U, 0x008810A5U, 0xD4003A65U, 0x60808020U, 0x94FFFE64U, 0x08CC6084U, 0x08C86084U, 0x08CC2005U, 0x008810A5U, 0xD4FFFE65U, 0x08C86005U, 0x08CC2024U, 0x008810A5U, 0xD4000E65U, 0x08C86025U, 0x08CC2044U, 0x008810A5U, 0xD4001E65U, 0x08C86045U, 0x08CC2064U, 0x008810A5U, 0xD4002E65U, 0x94003E64U, 0x08C82084U, 0x08CC2084U, 0x08C86065U, 0x008810A5U, 0xD4003E65U, 0x60808020U, 0xD4003263U, 0xD4002262U, 0xD4001261U, 0xD4000260U, 0x04807FFFU, 0x63808080U, 0x7080001FU, 0x5C1FFFE0U, 0x581FFFE0U, 0x54000020U, 0x7080001FU, 0x08800E31U, 0x08C82236U, 0x2000C011U, 0x101FFE11U, 0x00405A31U, 0x94000200U, 0x94001201U, 0x94002202U, 0x94003203U, 0xAC001220U, 0xAC001221U, 0xAC001222U, 0xAC001223U, 0x01800000U, 0x01800021U, 0x01800042U, 0x01800063U, 0x01900000U, 0x8E002224U, 0x8E002226U, 0x01881000U, 0x01881421U, 0x01881842U, 0x01881C63U, 0x01800000U, 0x01800021U, 0x01800042U, 0x01800063U, 0x01900000U, 0x8E002224U, 0x8E002226U, 0x01881000U, 0x01881421U, 0x01881842U, 0x01881C63U, 0x01800000U, 0x01800021U, 0x01800042U, 0x01800063U, 0x01900000U, 0x8E002224U, 0x8E002226U, 0x01881000U, 0x01881421U, 0x01881842U, 0x01881C63U, 0x01800000U, 0x01800021U, 0x01800042U, 0x01800063U, 0x01900000U, 0x8E002224U, 0x8E002226U, 0x01881000U, 0x01881421U, 0x01881842U, 0x01881C63U, 0x01800000U, 0x01800021U, 0x01800042U, 0x01800063U, 0x01900000U, 0x8E002224U, 0x8E002226U, 0x01881000U, 0x01881421U, 0x01881842U, 0x01881C63U, 0x01800000U, 0x01800021U, 0x01800042U, 0x01800063U, 0x01900000U, 0x8E002224U, 0x8E002226U, 0x01881000U, 0x01881421U, 0x01881842U, 0x01881C63U, 0x01800000U, 0x01800021U, 0x01800042U, 0x01800063U, 0x01900000U, 0x8E002224U, 0x8E002226U, 0x01881000U, 0x01881421U, 0x01881842U, 0x01881C63U, 0x01800000U, 0x01800021U, 0x01800042U, 0x01800063U, 0x01900000U, 0x8E002224U, 0x8E002226U, 0x01881000U, 0x01881421U, 0x01881842U, 0x01881C63U, 0x01800000U, 0x01800021U, 0x01800042U, 0x01800063U, 0x01900000U, 0x8E002224U, 0x8E002226U, 0x01881000U, 0x01881421U, 0x01881842U, 0x01881C63U, 0x01800000U, 0x01800021U, 0x01800042U, 0x01800063U, 0x01900000U, 0xAC001220U, 0xAC001221U, 0xAC001222U, 0xAC001223U, 0xD4000260U, 0xD4001261U, 0xD4002262U, 0xD4003263U, 0x04807FFFU, 0x29FFEA11U, 0x63809120U, 0x7080001FU, 0x5C1FFFE0U, 0x581FFFE0U, 0x54000020U, 0x20015000U, 0x101FFE00U, 0x84000001U, 0x84001002U, 0x84002003U, 0x84003004U, 0x84004005U, 0x84005006U, 0x84006007U, 0x84007008U, 0xD40003A1U, 0xD40013A2U, 0xD40023A3U, 0xD40033A4U, 0xD40043A5U, 0xD40053A6U, 0xD40063A7U, 0xD40073A8U, 0x54000020U, 0xC8FF93DEU, 0xC40013DFU, 0x940003A1U, 0x940013A2U, 0x940023A3U, 0x940033A4U, 0x940043A5U, 0x940053A6U, 0x940063A7U, 0x940073A8U, 0xC40043DBU, 0x0C800F7AU, 0x63809660U, 0x00506B7BU, 0x2800009BU, 0x08C80F5AU, 0xC40053DAU, 0x088C7F5AU, 0x2800003AU, 0xC40063DAU, 0x2001541AU, 0x101FFE1AU, 0xC40033DDU, 0xC40023DCU, 0x840043DFU, 0x0C800FFFU, 0x6380AF80U, 0x94FFF37FU, 0x840053DCU, 0x00C873E9U, 0x9C00137FU, 0x840063DCU, 0x00CC73FDU, 0x00887529U, 0x8C001340U, 0x01E80100U, 0x01E41520U, 0x00400084U, 0x01EC0020U, 0x41FFFEFFU, 0x840053DCU, 0x00C873E9U, 0x9C00137FU, 0x840063DCU, 0x00CC73FDU, 0x00887529U, 0x8C001340U, 0x01E80100U, 0x01E41520U, 0x00400084U, 0x01EC0020U, 0x41FFFEFFU, 0x840053DCU, 0x00C873E9U, 0x9C00137FU, 0x840063DCU, 0x00CC73FDU, 0x00887529U, 0x8C001340U, 0x01E80100U, 0x01E41520U, 0x00400084U, 0x01EC0020U, 0x41FFFEFFU, 0x840053DCU, 0x00C873E9U, 0x9C00137FU, 0x840063DCU, 0x00CC73FDU, 0x00887529U, 0x8C001340U, 0x01E80100U, 0x01E41520U, 0x00400084U, 0x01EC0020U, 0x41FFFEFFU, 0x840053DCU, 0x00C873E9U, 0x9C00137FU, 0x840063DCU, 0x00CC73FDU, 0x00887529U, 0x8C001340U, 0x01E80100U, 0x01E41520U, 0x00400084U, 0x01EC0020U, 0x41FFFEFFU, 0x840053DCU, 0x00C873E9U, 0x9C00137FU, 0x840063DCU, 0x00CC73FDU, 0x00887529U, 0x8C001340U, 0x01E80100U, 0x01E41520U, 0x00400084U, 0x01EC0020U, 0x41FFFEFFU, 0x840053DCU, 0x00C873E9U, 0x9C00137FU, 0x840063DCU, 0x00CC73FDU, 0x00887529U, 0x8C001340U, 0x01E80100U, 0x01E41520U, 0x00400084U, 0x01EC0020U, 0x41FFFEFFU, 0x840053DCU, 0x00C873E9U, 0x9C00137FU, 0x840063DCU, 0x00CC73FDU, 0x00887529U, 0x8C001340U, 0x01E80100U, 0x01E41520U, 0x00400084U, 0x01EC0020U, 0x41FFFEFFU, 0x840053DCU, 0x00C873E9U, 0x9C00137FU, 0x840063DCU, 0x00CC73FDU, 0x00887529U, 0x8C001340U, 0x01E80100U, 0x01E41520U, 0x00400084U, 0x01EC0020U, 0x41FFFEFFU, 0x840053DCU, 0x00C873E9U, 0x9C00137FU, 0x840063DCU, 0x00CC73FDU, 0x00887529U, 0x8C001340U, 0x01E80100U, 0x01E41520U, 0x00400084U, 0x01EC0020U, 0x41FFFEFFU, 0x840053DCU, 0x00C873E9U, 0x9C00137FU, 0x840063DCU, 0x00CC73FDU, 0x00887529U, 0x8C001340U, 0x01E80100U, 0x01E41520U, 0x00400084U, 0x01EC0020U, 0x41FFFEFFU, 0x840053DCU, 0x00C873E9U, 0x9C00137FU, 0x840063DCU, 0x00CC73FDU, 0x00887529U, 0x8C001340U, 0x01E80100U, 0x01E41520U, 0x00400084U, 0x01EC0020U, 0x41FFFEFFU, 0x840053DCU, 0x00C873E9U, 0x9C00137FU, 0x840063DCU, 0x00CC73FDU, 0x00887529U, 0x8C001340U, 0x01E80100U, 0x01E41520U, 0x00400084U, 0x01EC0020U, 0x41FFFEFFU, 0x840053DCU, 0x00C873E9U, 0x9C00137FU, 0x840063DCU, 0x00CC73FDU, 0x00887529U, 0x8C001340U, 0x01E80100U, 0x01E41520U, 0x00400084U, 0x01EC0020U, 0x41FFFEFFU, 0x840053DCU, 0x00C873E9U, 0x9C00137FU, 0x840063DCU, 0x00CC73FDU, 0x00887529U, 0x8C001340U, 0x01E80100U, 0x01E41520U, 0x00400084U, 0x01EC0020U, 0x41FFFEFFU, 0x840053DCU, 0x00C873E9U, 0x9C00137FU, 0x840063DCU, 0x00CC73FDU, 0x00887529U, 0x8C001340U, 0x01E80100U, 0x01E41520U, 0x00400084U, 0x01EC0020U, 0x41FFFEFFU, 0x6080BD80U, 0x9C001369U, 0x8C001340U, 0x01E80100U, 0x01E41520U, 0x00400084U, 0x01EC0020U, 0x41FFFEFFU, 0x9C001369U, 0x8C001340U, 0x01E80100U, 0x01E41520U, 0x00400084U, 0x01EC0020U, 0x41FFFEFFU, 0x9C001369U, 0x8C001340U, 0x01E80100U, 0x01E41520U, 0x00400084U, 0x01EC0020U, 0x41FFFEFFU, 0x9C001369U, 0x8C001340U, 0x01E80100U, 0x01E41520U, 0x00400084U, 0x01EC0020U, 0x41FFFEFFU, 0x9C001369U, 0x8C001340U, 0x01E80100U, 0x01E41520U, 0x00400084U, 0x01EC0020U, 0x41FFFEFFU, 0x9C001369U, 0x8C001340U, 0x01E80100U, 0x01E41520U, 0x00400084U, 0x01EC0020U, 0x41FFFEFFU, 0x9C001369U, 0x8C001340U, 0x01E80100U, 0x01E41520U, 0x00400084U, 0x01EC0020U, 0x41FFFEFFU, 0x9C001369U, 0x8C001340U, 0x01E80100U, 0x01E41520U, 0x00400084U, 0x01EC0020U, 0x41FFFEFFU, 0x9C001369U, 0x8C001340U, 0x01E80100U, 0x01E41520U, 0x00400084U, 0x01EC0020U, 0x41FFFEFFU, 0x9C001369U, 0x8C001340U, 0x01E80100U, 0x01E41520U, 0x00400084U, 0x01EC0020U, 0x41FFFEFFU, 0x9C001369U, 0x8C001340U, 0x01E80100U, 0x01E41520U, 0x00400084U, 0x01EC0020U, 0x41FFFEFFU, 0x9C001369U, 0x8C001340U, 0x01E80100U, 0x01E41520U, 0x00400084U, 0x01EC0020U, 0x41FFFEFFU, 0x9C001369U, 0x8C001340U, 0x01E80100U, 0x01E41520U, 0x00400084U, 0x01EC0020U, 0x41FFFEFFU, 0x9C001369U, 0x8C001340U, 0x01E80100U, 0x01E41520U, 0x00400084U, 0x01EC0020U, 0x41FFFEFFU, 0x9C001369U, 0x8C001340U, 0x01E80100U, 0x01E41520U, 0x00400084U, 0x01EC0020U, 0x41FFFEFFU, 0x9C001369U, 0x8C001340U, 0x01E80100U, 0x01E41520U, 0x00400084U, 0x01EC0020U, 0x41FFFEFFU, 0x2000019FU, 0x00406609U, 0x01E06169U, 0x8C001340U, 0x01E80120U, 0x01E41500U, 0x00400084U, 0x01EC0020U, 0x41FFFEFFU, 0x00406609U, 0x01E06169U, 0x8C001340U, 0x01E80120U, 0x01E41500U, 0x00400084U, 0x01EC0020U, 0x41FFFEFFU, 0x00406609U, 0x01E06169U, 0x8C001340U, 0x01E80120U, 0x01E41500U, 0x00400084U, 0x01EC0020U, 0x41FFFEFFU, 0x00406609U, 0x01E06169U, 0x8C001340U, 0x01E80120U, 0x01E41500U, 0x00400084U, 0x01EC0020U, 0x41FFFEFFU, 0x6000BDBFU, 0x840033DDU, 0x940003A0U, 0x00400021U, 0x940013A0U, 0x00400042U, 0x940023A0U, 0x00400063U, 0x940033A0U, 0x00400084U, 0x940043A0U, 0x004000A5U, 0x940053A0U, 0x004000C6U, 0x940063A0U, 0x004000E7U, 0x940073A0U, 0x00400108U, 0xD40003A1U, 0xD40013A2U, 0xD40023A3U, 0xD40033A4U, 0xD40043A5U, 0xD40053A6U, 0xD40063A7U, 0xD40073A8U, 0x29FFE01AU, 0x840023DCU, 0x600096BCU, 0x840013DFU, 0x840003DEU, 0x04807FFFU, 0x6380C5E0U, 0x7080001FU, 0x581FFFE0U, 0x5C1FFFE0U, 0x54000020U, 0x04804210U, 0x6300C700U, 0x2001D611U, 0x101FFE11U, 0x84000231U, 0x54000020U, 0x20000011U, 0x2001D610U, 0x101FFE10U, 0xC4000211U, 0x54000020U, 0x2001D608U, 0x101FFE08U, 0x84000108U, 0x3C000108U, 0x6680C860U, 0x54000040U, 0x2000160AU, 0x0100290AU, 0x2001DB11U, 0x101FFE11U, 0x00402A31U, 0x28000028U, 0x2001D60AU, 0x101FFE0AU, 0xC4000148U, 0x84003200U, 0x84002201U, 0x84001202U, 0x84000203U, 0x20000152U, 0x20000014U, 0x70002E1FU, 0x5C1FFFE0U, 0x581FFFE0U, 0x54000020U, 0x2001D60AU, 0x101FFE0AU, 0x84000148U, 0x04584100U, 0x6700CB80U, 0x54000040U, 0x08500508U, 0xC4000148U, 0x04584100U, 0x6380CDC0U, 0x2000160CU, 0x0100310AU, 0x2001DB09U, 0x101FFE09U, 0x0080252DU, 0x00402929U, 0x0100320AU, 0x004029ADU, 0x200002CCU, 0x8E00212AU, 0xCE0021AAU, 0x6000CD2CU, 0x5C1FFFE0U, 0x581FFFE0U, 0x54000020U, 0x2001D70BU, 0x101FFE0BU, 0x2000000AU, 0xD400016AU, 0xD400116AU, 0xD400216AU, 0xD4003170U, 0x2001DB09U, 0x101FFE09U, 0x00802D70U, 0x2001D913U, 0x101FFE13U, 0x2001D608U, 0x101FFE08U, 0x84000108U, 0x2000000CU, 0x085053DEU, 0xC40003C8U, 0xC40033D1U, 0xC40043DFU, 0x04582180U, 0x20001FF2U, 0x6600D2E0U, 0xC40023CCU, 0xC40013C9U, 0x00802531U, 0x700081BFU, 0x9400326DU, 0x08C821ADU, 0x08CC21ADU, 0x840033CEU, 0x840023CCU, 0x045839A0U, 0x6380D2C0U, 0x2800002CU, 0x840013C9U, 0x28001609U, 0x840003C8U, 0x6080D060U, 0x00803192U, 0x840043DFU, 0x2800029EU, 0x04807FFFU, 0x6380D380U, 0x7080001FU, 0x5C1FFFE0U, 0x581FFF60U, 0x54000020U, 0x00000000}; static const uint32_t s_cau3ImemBytes = sizeof(s_cau3ImemImage); /******************************************************************************* * Prototypes ******************************************************************************/ static status_t cau3_initialize_inst_memory(CAU3_Type *base, const uint32_t *cau3ImemImage, size_t cau3ImemBytes); static status_t cau3_initialize_data_memory(CAU3_Type *base, cau3_task_done_t taskDone); static status_t cau3_initialize_read_only_data_memory(CAU3_Type *base, const uint32_t *cau3ReadOnlyConstants, size_t cau3ReadOnlyConstantsBytes, cau3_task_done_t taskDone); static status_t cau3_load_key_context(CAU3_Type *base, cau3_key_context_t *cauKeyContext, cau3_key_slot_t keySlot, cau3_task_done_t taskDone); static status_t cau3_load_key( CAU3_Type *base, const uint8_t *key, size_t keySize, uint32_t keySlot, cau3_task_done_t taskDone); static status_t cau3_pkha_clear_regabne(CAU3_Type *base, bool A, bool B, bool N, bool E); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) static status_t cau3_lock_semaphore(CAU3_Type *base); static void cau3_release_semaphore(CAU3_Type *base); #endif /******************************************************************************* * Code ******************************************************************************/ static status_t cau3_process_task_completion(CAU3_Type *base, cau3_task_done_t taskDone) { status_t taskCompletionStatus; taskCompletionStatus = kStatus_Fail; /* assume an error completion status */ switch (((uint32_t)taskDone >> 16U) & 7U) { uint32_t tkcs; case 0: /* poll the cau3 status register */ tkcs = base->SR & CAU3_SR_TKCS_MASK; while (tkcs == CAU3_SR_TKCS_RUN) { tkcs = base->SR & CAU3_SR_TKCS_MASK; }; /* check the task completion status*/ if (tkcs == CAU3_SR_TKCS_STOPNOERR) { taskCompletionStatus = kStatus_Success; /* signal error-free completion status */ } break; case 2: /* task completion signaled by event_done */ do { __WFE(); /* cpu is waiting for cau3 event_done */ tkcs = base->SR & CAU3_SR_TKCS_MASK; } while (tkcs == CAU3_SR_TKCS_RUN); /* check the task completion status */ if (tkcs == CAU3_SR_TKCS_STOPNOERR) { taskCompletionStatus = kStatus_Success; /* signal error-free completion status */ } break; case 1: /* task completion signaled by irq */ /* TEMP FIX - for boot ROM with IRQ task completion, simply return */ case 4: /* task completion signaled by dma_req */ /* processing here is complete */ taskCompletionStatus = kStatus_Success; /* signal error-free completion status */ break; default: /* undefined taskDone specifier defaults to kStatus_Fail */ break; } /* end - switch (taskDone & 7U) */ return (taskCompletionStatus); } /*! * @brief Initialize the CAU3's Instruction Memory * * Initializes the CAU3, including configuring it to enable the execution of * crypto tasks, loading the CryptoCore's firmware image into the CAU3's * instruction memory, and then performing a simple read-verify of its contents. * NOTE: All the operations for this function are executed on the host processor. * * cau3_initialize_inst_memory * @param cau3ImemImage - binary firmware image for CryptoCore * @param cau3ImemBytes - size of the firmware image in bytes * * @retval status from the readVerify check: CAU_[OK (=0), ERROR (!0)] * if an error is signaled, the retval is 0xbad10000UU + i, where i is * the first miscompare word index location */ static status_t cau3_initialize_inst_memory(CAU3_Type *base, const uint32_t *cau3ImemImage, size_t cau3ImemBytes) { uint32_t i; /* enable the cau3 */ base->CR = 0U; /* poll if/while the cau3 is running initialization */ while ((base->SR & CAU3_SR_TKCS_MASK) == CAU3_SR_TKCS_INITRUN) { }; /* check for error-free stop state */ if ((base->SR & CAU3_SR_TKCS_MASK) != CAU3_SR_TKCS_STOPNOERR) { return (0xbad00000U + (base->SR & CAU3_SR_TKCS_MASK)); /* exit with error */ } base->SR = CAU3_SR_TCIRQ_MASK; /* clear the TCIRQ interrupt flag */ /* write the code hex image into the cau3's imem * initialize the memory cmd and address registers */ base->DBGMCMD = 0xac000000U; /* wt=1, ia=1, imem=0 */ base->DBGMADR = 0U; /* imem starting address */ for (i = 0; i < cau3ImemBytes / 4; i++) { base->DBGMDR = cau3ImemImage[i]; /* indirect write into cau3Imem */ } /* read-verify the cau3 imem code image * initialize the memory cmd and address registers */ base->DBGMCMD = 0x8c000000U; /* wt=0, ia=1, imem=0 */ base->DBGMADR = 0U; /* imem starting address */ for (i = 0; i < cau3ImemBytes / 4; i++) { if (base->DBGMDR != cau3ImemImage[i]) /* indirect read from cau3Imem */ { return (0xbad10000U + i); /* exit on miscompare */ } } /* this function does *not* disable reads/writes of the cau3 local memories * but, this operation is needed to "secure" (i.e., make private) the cau3 * local memories */ return 0U; } /*! * @brief Initializes the CAU3's entire private Data Memory * * Initialize the CAU3's data memory, and then perform a read-verify versus a * precalculated "pseudo-hash" value. * * cau3_initialize_data_memory * @param taskDone indicates completion signal: CAU_[POLL, IRQ, EVENT, DMAREQ] * * @retval status from the readVerify check: CAU_[OK, ERROR] */ static status_t cau3_initialize_data_memory(CAU3_Type *base, cau3_task_done_t taskDone) { status_t completionStatus; /* execute the cau3 "security violation + data initialization" task */ base->CC_R30 = CAU3_DMEM_STK_BASE; /* initialize stack pointer (sp) */ base->CC_R31 = 0U; /* set LR = 0 to signal a host task */ base->CC_PC = CAU3_TASK_SECV_INIT; /* call cau_secv_init() */ base->CC_CMD = taskDone; /* trigger cau3 execution */ /* process the cau3 task completion signal specified by taskDone */ completionStatus = cau3_process_task_completion(base, taskDone); return (completionStatus); } /*! * @brief Copies read-only constants from sysMemory to CAU3's DataMemory * * Initialize the read-only constants in the CAU3's data memory. This includes * the AES constants (RCON) and most of the constants used in the hash functions. * The constants associated with SHA-512 are NOT included and must be loaded * separately. * * cau3_initialize_read_only_data_memory * @param cauReadOnlyConstants - sysMemory table of constants needed by CAU3 * @param cauReadOnlyConstantsSize - size of read-only constants in bytes * @param taskDone indicates completion signal: CAU_[POLL, IRQ, EVENT, DMAREQ] * * @retval status check from task completion: CAU_[OK, ERROR] */ static status_t cau3_initialize_read_only_data_memory(CAU3_Type *base, const uint32_t *cau3ReadOnlyConstants, size_t cau3ReadOnlyConstantsBytes, cau3_task_done_t taskDone) { status_t completionStatus; /* execute the cau3 "initialize dmem read-only constants" task */ base->CC_R[16] = (uint32_t)s_cau3ReadOnlyConstants; /* pReadOnlyConstants */ base->CC_R[17] = s_cau3ReadOnlyConstantsBytes; /* byte count (0-mod-16) */ base->CC_R[18] = CAU3_DMEM_AES_RCON; /* pDMEM_AES_RCON constants base */ base->CC_R30 = CAU3_DMEM_STK_BASE; /* initialize stack pointer (sp) */ base->CC_R31 = 0U; /* set LR = 0 to signal a host task */ base->CC_PC = CAU3_TASK_BLKLD_DMEM; /* call cau_block_load_dmem task */ base->CC_CMD = taskDone; /* trigger cau3 execution */ /* process the cau3 task completion signal specified by taskDone */ completionStatus = cau3_process_task_completion(base, taskDone); return (completionStatus); } status_t CAU3_MakeMemsPrivate(CAU3_Type *base, cau3_task_done_t taskDone) { #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) uint32_t completionStatus; completionStatus = cau3_lock_semaphore(base); if (kStatus_Success != completionStatus) { cau3_release_semaphore(base); return completionStatus; } #endif /* FSL_CAU3_USE_HW_SEMA */ /* making the xMEMs private involves setting DBGCSR[DDBGMC] = 1 */ base->DBGCSR = CAU3_DBGCSR_DDBGMC_MASK; /* set DBGCSR[DDBGMC] */ #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return kStatus_Success; } /*! * @brief Execute a CAU3 null task to "establish ownership" by host processor * * Execute a null task to claim ownership of the CAU3 by the host processor. * This is required for correct IRQ, EVT and DMA_REQ signaling by subsequent * PKHA operations. The CryptoCore task executes one instruction - a "stop". * * cau3_execute_null_task * @param taskDone indicates completion signal: CAU_[POLL, IRQ, EVENT, DMAREQ] * * @retval status check from task completion: CAU_[OK, ERROR] */ static status_t cau3_execute_null_task(CAU3_Type *base, cau3_task_done_t taskDone) { status_t completionStatus; /* execute the cau3 null task */ base->CC_R30 = CAU3_DMEM_STK_BASE; /* initialize stack pointer (sp) */ base->CC_R31 = 0; /* set LR = 0 to signal a host task */ base->CC_PC = CAU3_TASK_NULL; /* call cau_null() */ base->CC_CMD = taskDone; /* trigger cau3 execution */ /* process the cau3 task completion signal specified by taskDone */ completionStatus = cau3_process_task_completion(base, taskDone); return (completionStatus); } /*! * @brief Load a key into a key context * * Loads up to 32-byte key into the specified key slot. * There is support for a maximum of 4 key slots. * This does not do AES key expansion (as in cau3_load_key_context() case) so we use this one for loading TDES keys. * * @param key is the key pointer, ALIGNED ON A 0-MOD-4 ADDRESS * @param keySize is the size in bytes of the key * @param keySlot is the destination key context * @param taskDone indicates completion signal: CAU_[POLL, IRQ, EVENT, DMAREQ] * * @retval status check from task completion: CAU_[OK, ERROR] */ static status_t cau3_load_key( CAU3_Type *base, const uint8_t *key, size_t keySize, uint32_t keySlot, cau3_task_done_t taskDone) { status_t completionStatus; #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) completionStatus = cau3_lock_semaphore(base); if (kStatus_Success != completionStatus) { cau3_release_semaphore(base); return completionStatus; } #endif /* execute the cau3 "load initialization vector into key context" task */ base->CC_R[16] = (uintptr_t)key; /* pKey */ base->CC_R[17] = keySize; /* IV size */ base->CC_R[18] = keySlot; /* keySlot */ base->CC_R30 = CAU3_DMEM_STK_BASE; /* initialize stack pointer (sp) */ base->CC_R31 = 0U; /* set LR = 0 to signal a host task */ base->CC_PC = CAU3_TASK_LD_KEY; /* call cau_load_key() */ base->CC_CMD = taskDone; /* trigger cau3 execution */ /* process the cau3 task completion signal specified by taskDone */ completionStatus = cau3_process_task_completion(base, taskDone); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return (completionStatus); } status_t CAU3_AES_Encrypt(CAU3_Type *base, cau3_handle_t *handle, const uint8_t plaintext[16], uint8_t ciphertext[16]) { status_t completionStatus; cau3_task_done_t taskDone; taskDone = handle->taskDone; #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) completionStatus = cau3_lock_semaphore(base); if (kStatus_Success != completionStatus) { cau3_release_semaphore(base); return completionStatus; } #endif /* execute the cau3 "aes_encrypt_ecb" task */ base->CC_R[16] = (uint32_t)plaintext; /* pPlainText */ base->CC_R[17] = handle->keySlot; /* keySlot */ base->CC_R[19] = (uint32_t)ciphertext; /* pCipherText */ base->CC_R30 = CAU3_DMEM_STK_BASE; /* initialize stack pointer (sp) */ base->CC_R31 = 0U; /* set LR = 0 to signal a host task */ base->CC_PC = CAU3_TASK_AES_ENCRYPT; /* call cau_aes_encrypt() */ base->CC_CMD = taskDone; /* trigger cau3 execution */ /* process the cau3 task completion signal specified by taskDone */ completionStatus = cau3_process_task_completion(base, taskDone); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return (completionStatus); } status_t CAU3_AES_Decrypt(CAU3_Type *base, cau3_handle_t *handle, const uint8_t ciphertext[16], uint8_t plaintext[16]) { status_t completionStatus; cau3_task_done_t taskDone; taskDone = handle->taskDone; #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) completionStatus = cau3_lock_semaphore(base); if (kStatus_Success != completionStatus) { cau3_release_semaphore(base); return completionStatus; } #endif /* execute the cau3 "aes_decrypt_ecb" task */ base->CC_R[16] = (uint32_t)ciphertext; /* pCipherText */ base->CC_R[17] = handle->keySlot; /* keySlot */ base->CC_R[19] = (uint32_t)plaintext; /* pPlainText */ base->CC_R30 = CAU3_DMEM_STK_BASE; /* initialize stack pointer (sp) */ base->CC_R31 = 0U; /* set LR = 0 to signal a host task */ base->CC_PC = CAU3_TASK_AES_DECRYPT; /* call cau_aes_decrypt() */ base->CC_CMD = taskDone; /* trigger cau3 execution */ /* process the cau3 task completion signal specified by taskDone */ completionStatus = cau3_process_task_completion(base, taskDone); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return (completionStatus); } static void cau3_xor_buf(uint8_t *buf, const uint8_t *mask, uint32_t count) { uint32_t i; for (i = 0; i < count; i++) *(buf + i) ^= (uint8_t)*(mask + i); } static void cau3_aes_ctr_inc(uint8_t *B, uint32_t lenSz) { uint32_t i; uint8_t *ptr; for (i = 0; i < lenSz; i++) { ptr = B + CAU3_AES_BLOCK_SIZE - 1 - i; *ptr += (uint8_t) 1; if ((uint8_t) *ptr != 0) return; } } /* CAU3_Type *base, cau3_handle_t *handle, const uint8_t plaintext[16], uint8_t ciphertext[16] */ static status_t cau3_aes_ecb_encrypt(CAU3_Type *base, cau3_key_slot_t keySlot, const uint8_t *inBlock, uint8_t *outBlock) { status_t completionStatus; cau3_handle_t handle; handle.keySlot = keySlot; handle.taskDone = kCAU3_TaskDonePoll; completionStatus = CAU3_AES_Encrypt(base, &handle, inBlock, outBlock); if (completionStatus != kStatus_Success) cau3_force_zero(outBlock, CAU3_AES_BLOCK_SIZE); return completionStatus; } static status_t cau3_aes_ccm_auth(CAU3_Type *base, cau3_key_slot_t keySlot, const uint8_t *data, uint32_t len, uint8_t *x) { uint32_t last = len % CAU3_AES_BLOCK_SIZE, i; status_t completionStatus = kStatus_Success; for (i = 0; i < len / CAU3_AES_BLOCK_SIZE; i++) { /* X_i+1 = E(K, X_i XOR B_i) */ cau3_xor_buf(x, data, CAU3_AES_BLOCK_SIZE); data += CAU3_AES_BLOCK_SIZE; completionStatus = cau3_aes_ecb_encrypt(base, keySlot, x, x); if (completionStatus != kStatus_Success) return (completionStatus); } if (last) { /* XOR zero-padded last block */ for (i = 0; i < last; i++) x[i] ^= (uint8_t) *data++; completionStatus = cau3_aes_ecb_encrypt(base, keySlot, x, x); if (completionStatus != kStatus_Success) return (completionStatus); } return (completionStatus); } static status_t cau3_aes_ccm_auth_start(CAU3_Type *base, cau3_key_slot_t keySlot, uint32_t authTagSz, uint32_t L, const uint8_t *nonce, const uint8_t *authIn, uint32_t authInSz, uint32_t inSz, uint8_t *x) { uint32_t wordSz = (uint32_t)sizeof(uint32_t); status_t completionStatus = kStatus_Success; uint32_t authLenSz, remainder, i; uint8_t b[CAU3_AES_BLOCK_SIZE]; uint8_t *bPtr = (uint8_t *)&b[0]; uint8_t mask = 0xFF; /* Authentication */ /* B_0: Flags | Nonce N | l(m) */ b[0] = authInSz ? 0x40 : 0 /* Adata */; b[0] |= (((authTagSz - 2) / 2) /* M' */<< 3); b[0] |= (L - 1) /* L' */; cau3_memcpy(&b[1], nonce, 15 - L); for (i = 0; i < L; i++) { if (mask && i >= wordSz) mask = 0x00; b[CAU3_AES_BLOCK_SIZE - 1 - i] = (uint8_t)((inSz >> ((8 * i) & mask)) & mask); } /* X_1 = E(K, B_0) */ completionStatus = cau3_aes_ecb_encrypt(base, keySlot, bPtr, x); if (completionStatus != kStatus_Success) return (completionStatus); if (!authInSz) return 0; /* encode the length in */ if (authInSz <= 0xFEFF) { authLenSz = 2; x[0] ^= (uint8_t) ((authInSz & 0xFF00) >> 8); x[1] ^= (uint8_t) (authInSz & 0x00FF); } else if (authInSz <= 0xFFFFFFFF) { authLenSz = 6; x[0] ^= (uint8_t) 0xFF; x[1] ^= (uint8_t) 0xFE; x[2] ^= (uint8_t) ((authInSz & 0xFF000000) >> 24); x[3] ^= (uint8_t) ((authInSz & 0x00FF0000) >> 16); x[4] ^= (uint8_t) ((authInSz & 0x0000FF00) >> 8); x[5] ^= (uint8_t) (authInSz & 0x000000FF); } /* Note, the protocol handles auth data up to 2^64, but we are * using 32-bit sizes right now, so the bigger data isn't handled * else if (inSz <= 0xFFFFFFFFFFFFFFFF) {} */ else return (completionStatus); /* start fill out the rest of the first block */ remainder = CAU3_AES_BLOCK_SIZE - authLenSz; if (authInSz >= remainder) { /* plenty of bulk data to fill the remainder of this block */ cau3_xor_buf(x + authLenSz, authIn, remainder); authInSz -= remainder; authIn += remainder; } else { /* not enough bulk data, copy what is available, and pad zero */ cau3_xor_buf(x + authLenSz, authIn, authInSz); authInSz = 0; } completionStatus = cau3_aes_ecb_encrypt(base, keySlot, x, x); if (completionStatus != kStatus_Success) return (completionStatus); if (authInSz > 0) { completionStatus = cau3_aes_ccm_auth(base, keySlot, authIn, authInSz, x); if (completionStatus != kStatus_Success) return (completionStatus); } return (completionStatus); } static status_t cau3_aes_ccm_encr(CAU3_Type *base, cau3_key_slot_t keySlot, uint32_t L, const uint8_t *in, uint32_t inSz, uint8_t *out, uint8_t * a) { uint32_t last = inSz % CAU3_AES_BLOCK_SIZE, i; status_t completionStatus = kStatus_Success; for (i = 0; i < L; i++) a[CAU3_AES_BLOCK_SIZE - 1 - i] = (uint8_t)0; /* crypt = msg XOR (S_1 | S_2 | ... | S_n) */ for (i = 1; i <= (inSz / CAU3_AES_BLOCK_SIZE); i++) { cau3_aes_ctr_inc(a, L); /* S_i = E(K, A_i) */ completionStatus = cau3_aes_ecb_encrypt(base, keySlot, a, out); if (completionStatus != kStatus_Success) return (completionStatus); cau3_xor_buf(out, in,CAU3_AES_BLOCK_SIZE); out += CAU3_AES_BLOCK_SIZE; in += CAU3_AES_BLOCK_SIZE; } if (last) { cau3_aes_ctr_inc(a, L); completionStatus = cau3_aes_ecb_encrypt(base, keySlot, a, out); if (completionStatus != kStatus_Success) return (completionStatus); /* XOR zero-padded last block */ for (i = 0; i < last; i++) *out++ ^= (uint8_t) *in++; } return (completionStatus); } static void cau3_aes_ccm_encr_start(uint32_t L, const uint8_t *nonce, uint8_t *a) { /* A_i = Flags | Nonce N | Counter i */ a[0] = L - 1; /* Flags = L' */ cau3_memcpy(&a[1], nonce, 15 - L); } static status_t cau3_aes_ccm_encr_auth(CAU3_Type *base, cau3_key_slot_t keySlot, uint32_t L, uint32_t authTagSz, uint8_t *x, uint8_t *a, uint8_t *authTag) { uint32_t i; uint8_t tmp[CAU3_AES_BLOCK_SIZE]; /* U = T XOR S_0; S_0 = E(K, A_0) */ for (i = 0; i < L; i++) a[CAU3_AES_BLOCK_SIZE - 1 - i] = (uint8_t) 0; if (cau3_aes_ecb_encrypt(base, keySlot, a, &tmp[0])) { cau3_force_zero(&tmp[0], CAU3_AES_BLOCK_SIZE); return kStatus_Fail; } for (i = 0; i < authTagSz; i++) authTag[i] = (uint8_t) x[i] ^ (uint8_t) tmp[i]; return kStatus_Success; } static status_t cau3_aes_ccm_decr_auth(CAU3_Type *base, cau3_key_slot_t keySlot, uint32_t L, uint32_t authTagSz, uint8_t *a, const uint8_t *authTag, uint8_t *t) { uint32_t i; uint8_t tmp[CAU3_AES_BLOCK_SIZE]; /* U = T XOR S_0; S_0 = E(K, A_0) */ for (i = 0; i < L; i++) a[CAU3_AES_BLOCK_SIZE - 1 - i] = (uint8_t) 0; if (cau3_aes_ecb_encrypt(base, keySlot, a, &tmp[0])) { cau3_force_zero(&tmp[0], CAU3_AES_BLOCK_SIZE); return kStatus_Fail; } for (i = 0; i < authTagSz; i++) t[i] = (uint8_t) authTag[i] ^ (uint8_t) tmp[i]; return kStatus_Success; } static inline void cau3_aes_ccm_clear_mem(uint8_t *A, uint8_t *B, uint32_t len) { cau3_force_zero(A, len); cau3_force_zero(B, len); } static status_t cau3_aes_ccm_encrypt(CAU3_Type *base, cau3_key_slot_t keySlot, const uint8_t *in, uint32_t inSz, uint8_t *out, const uint8_t *nonce, uint32_t nonceSz, const uint8_t *authIn, uint32_t authInSz, uint8_t *authTag, uint32_t authTagSz) { const uint32_t L = CAU3_AES_BLOCK_SIZE - 1 - nonceSz; uint8_t x[CAU3_AES_BLOCK_SIZE]; uint8_t *xPtr = (uint8_t*) &x[0]; uint8_t a[CAU3_AES_BLOCK_SIZE]; uint8_t *aPtr = (uint8_t*) &a[0]; status_t completionStatus; /* sanity check on arguments */ if (nonceSz < 7 || nonceSz > 13 || authTagSz < 4 || authTagSz > 16) return kStatus_InvalidArgument; completionStatus = cau3_aes_ccm_auth_start(base, keySlot, authTagSz, L, nonce, authIn, authInSz, inSz, xPtr); if (completionStatus != kStatus_Success) { cau3_aes_ccm_clear_mem(xPtr, aPtr, CAU3_AES_BLOCK_SIZE); return (completionStatus); } completionStatus = cau3_aes_ccm_auth(base, keySlot, in, inSz, xPtr); if (completionStatus != kStatus_Success) { cau3_aes_ccm_clear_mem(xPtr, aPtr, CAU3_AES_BLOCK_SIZE); return (completionStatus); } /* Encryption */ cau3_aes_ccm_encr_start(L, nonce, aPtr); completionStatus = cau3_aes_ccm_encr(base, keySlot, L, in, inSz, out, aPtr); if (completionStatus != kStatus_Success) { cau3_aes_ccm_clear_mem(xPtr, aPtr, CAU3_AES_BLOCK_SIZE); return (completionStatus); } completionStatus = cau3_aes_ccm_encr_auth(base, keySlot, L, authTagSz, xPtr, aPtr, authTag); if (completionStatus != kStatus_Success) { cau3_aes_ccm_clear_mem(xPtr, aPtr, CAU3_AES_BLOCK_SIZE); return (completionStatus); } cau3_aes_ccm_clear_mem(xPtr, aPtr, CAU3_AES_BLOCK_SIZE); return (completionStatus); } static int cau3_aes_ccm_decrypt(CAU3_Type *base, cau3_key_slot_t keySlot, uint8_t *out, const uint8_t *in, uint32_t inSz, const uint8_t *nonce, uint32_t nonceSz, const uint8_t *authTag, uint32_t authTagSz, uint8_t *authPassed, const uint8_t *authIn, uint32_t authInSz) { const uint32_t L = CAU3_AES_BLOCK_SIZE - 1 - nonceSz; uint8_t x[CAU3_AES_BLOCK_SIZE]; uint8_t *xPtr = (uint8_t*) &x[0]; uint8_t a[CAU3_AES_BLOCK_SIZE]; uint8_t *aPtr = (uint8_t*) &a[0]; uint8_t t[CAU3_AES_BLOCK_SIZE]; uint8_t *tPtr = (uint8_t*) &t[0]; status_t completionStatus; /* sanity check on arguments */ if (nonceSz < 7 || nonceSz > 13 || authTagSz < 4 || authTagSz > 16) return kStatus_InvalidArgument; /* Decryption */ cau3_aes_ccm_encr_start(L, nonce, aPtr); completionStatus = cau3_aes_ccm_decr_auth(base, keySlot, L, authTagSz, aPtr, authTag, tPtr); if (completionStatus != kStatus_Success) { cau3_aes_ccm_clear_mem(xPtr, aPtr, CAU3_AES_BLOCK_SIZE); cau3_force_zero(tPtr, CAU3_AES_BLOCK_SIZE); return (completionStatus); } /* plaintext = msg XOR (S_1 | S_2 | ... | S_n) */ completionStatus = cau3_aes_ccm_encr(base, keySlot, L, in, inSz, out, aPtr); if (completionStatus != kStatus_Success) { cau3_aes_ccm_clear_mem(xPtr, aPtr, CAU3_AES_BLOCK_SIZE); cau3_force_zero(tPtr, CAU3_AES_BLOCK_SIZE); return (completionStatus); } completionStatus = cau3_aes_ccm_auth_start(base, keySlot, authTagSz, L, nonce, authIn, authInSz, inSz, xPtr); if (completionStatus != kStatus_Success) { cau3_aes_ccm_clear_mem(xPtr, aPtr, CAU3_AES_BLOCK_SIZE); cau3_force_zero(tPtr, CAU3_AES_BLOCK_SIZE); return (completionStatus); } completionStatus = cau3_aes_ccm_auth(base, keySlot, out, inSz, xPtr); if (completionStatus != kStatus_Success) { cau3_aes_ccm_clear_mem(xPtr, aPtr, CAU3_AES_BLOCK_SIZE); cau3_force_zero(tPtr, CAU3_AES_BLOCK_SIZE); return (completionStatus); } if (memcmp(xPtr, tPtr, authTagSz) != 0) { // If the authTag check fails, don't keep the decrypted data. memset(out, 0, inSz); *authPassed = 0; return (completionStatus); } else { *authPassed = 1; } cau3_aes_ccm_clear_mem(xPtr, aPtr, CAU3_AES_BLOCK_SIZE); cau3_force_zero(tPtr, CAU3_AES_BLOCK_SIZE); return (completionStatus); } status_t CAU3_AES_CCM_EncryptTag(CAU3_Type *base, cau3_handle_t *handle, const uint8_t *plainText, size_t plainTextSize, uint8_t *cipherText, const uint8_t *nonce, size_t nonceSize, const uint8_t *aad, size_t aadSize, uint8_t *authTag, size_t authTagSize) { status_t completionStatus; completionStatus = cau3_aes_ccm_encrypt(base, handle->keySlot, plainText, plainTextSize, cipherText, nonce, nonceSize, aad, aadSize, authTag, authTagSize); if (completionStatus != kStatus_Success) CAU3_ForceError(base, handle->taskDone); else completionStatus = cau3_execute_null_task(base, handle->taskDone); return (completionStatus); } uint32_t CAU3_AES_CCM_DecryptTag(CAU3_Type *base, cau3_handle_t *handle, const uint8_t *cipherText, uint8_t *plainText, size_t plainTextSize, const uint8_t *nonce, size_t nonceSize, const uint8_t *aad, size_t aadSize, const uint8_t *authTag, size_t authTagSize) { status_t completionStatus; uint8_t authPassed = 0; completionStatus = cau3_aes_ccm_decrypt(base, handle->keySlot, plainText, cipherText, plainTextSize, nonce, nonceSize, authTag, authTagSize, &authPassed, aad, aadSize); if (completionStatus != kStatus_Success) CAU3_ForceError(base, handle->taskDone); else completionStatus = cau3_execute_null_task(base, handle->taskDone); handle->micPassed = authPassed; return (completionStatus); } void CAU3_Init(CAU3_Type *base) { #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) /* ungate clock */ CLOCK_EnableClock(kCLOCK_Cau3); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) CLOCK_EnableClock(FSL_CAU3_SEMA42_CLOCK_NAME); #endif /* FSL_CAU3_USE_HW_SEMA */ #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ base->CR = CAU3_CR_RSTSM4(1); base->CR = CAU3_CR_RSTSM4(2); cau3_initialize_inst_memory(base, s_cau3ImemImage, s_cau3ImemBytes); cau3_initialize_data_memory(base, kCAU3_TaskDonePoll); cau3_initialize_read_only_data_memory(base, s_cau3ReadOnlyConstants, s_cau3ReadOnlyConstantsBytes, kCAU3_TaskDonePoll); cau3_pkha_clear_regabne(base, true, true, true, true); } #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) static status_t cau3_lock_semaphore(CAU3_Type *base) { uint32_t processorNumber = 0; /* cm4 will be 1, cm0+ will be 2 */ /* For next SoC, the processor number shall be defined in the SoC header file */ #if __CORTEX_M == 0U processorNumber++; #endif processorNumber++; while (processorNumber != SEMA42_GATEn(FSL_CAU3_SEMA42_BASE, 1)) { /* Wait for unlocked status. */ while (SEMA42_GATEn(FSL_CAU3_SEMA42_BASE, FSL_CAU3_SEMA42_GATE)) { } /* Lock the gate. */ SEMA42_GATEn(FSL_CAU3_SEMA42_BASE, FSL_CAU3_SEMA42_GATE) = processorNumber; } return cau3_execute_null_task(base, kCAU3_TaskDonePoll); } #endif /* FSL_CAU3_USE_HW_SEMA */ #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) static void cau3_release_semaphore(CAU3_Type *base) { /* unlock the semaphore */ SEMA42_GATEn(FSL_CAU3_SEMA42_BASE, FSL_CAU3_SEMA42_GATE) = 0; } #endif /* FSL_CAU3_USE_HW_SEMA */ /*! * @brief Load a 64-byte "key context" into the CAU3's private data memory * * Load the key context into the private DMEM. This includes size and config * information, a 16-byte initialization vector and a key of size [8,16,24,32] * bytes (for DES or AES-[128,192,256]). There is support for 4 "key slots" with * slot 0 typically used for the system key encryption key (KEK). * * See the GENERAL COMMENTS for more information on the keyContext structure. * * NOTE: This function also performs an AES key expansion if a keySize > 8 * is specified. * * cau3_load_key_context * @param cauKeyContext is pointer to key structure in sysMemory * @param keySlot is the destination key slot number [0-3] * @param taskDone indicates completion signal: CAU_[POLL, IRQ, EVENT, DMAREQ] * * @return status check from task completion: CAU_[OK, ERROR] */ static status_t cau3_load_key_context(CAU3_Type *base, cau3_key_context_t *cauKeyContext, cau3_key_slot_t keySlot, cau3_task_done_t taskDone) { status_t completionStatus; #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) completionStatus = cau3_lock_semaphore(base); if (kStatus_Success != completionStatus) { cau3_release_semaphore(base); return completionStatus; } #endif /* execute the cau3 "load key context" task */ base->CC_R[16] = (uint32_t)cauKeyContext; /* pKeyContext */ base->CC_R[17] = keySlot; /* keySlot */ base->CC_R30 = CAU3_DMEM_STK_BASE; /* initialize stack pointer (sp) */ base->CC_R31 = 0U; /* set LR = 0 to signal a host task */ base->CC_PC = CAU3_TASK_LD_KEYCTX; /* call cau_load_key_context() */ base->CC_CMD = taskDone; /* trigger cau3 execution */ /* process the cau3 task completion signal specified by taskDone */ completionStatus = cau3_process_task_completion(base, taskDone); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return (completionStatus); } status_t CAU3_ForceError(CAU3_Type *base, cau3_task_done_t taskDone) { status_t completionStatus; #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) completionStatus = cau3_lock_semaphore(base); if (kStatus_Success != completionStatus) { cau3_release_semaphore(base); return completionStatus; } #endif /* execute the cau3 null task */ base->CC_R30 = CAU3_DMEM_STK_BASE; /* initialize stack pointer (sp) */ base->CC_R31 = 0; /* set LR = 0 to signal a host task */ base->CC_PC = CAU3_TASK_STOPERROR; base->CC_CMD = taskDone; /* trigger cau3 execution */ /* process the cau3 task completion signal specified by taskDone */ completionStatus = cau3_process_task_completion(base, taskDone); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return (completionStatus); } status_t CAU3_LoadSpecialKeyContext(CAU3_Type *base, size_t keySize, cau3_key_slot_t keySlot, cau3_task_done_t taskDone) { status_t completionStatus; #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) completionStatus = cau3_lock_semaphore(base); if (kStatus_Success != completionStatus) { cau3_release_semaphore(base); return completionStatus; } #endif /* execute the cau3 "load special key context" task */ base->CC_R[16] = keySize; /* keySize [8,16,24,32] */ base->CC_R[17] = keySlot; /* keySlot */ base->CC_R30 = CAU3_DMEM_STK_BASE; /* initialize stack pointer (sp) */ base->CC_R31 = 0U; /* set LR = 0 to signal a host task */ base->CC_PC = CAU3_TASK_LD_SP_KEYCTX; /* call cau_load_special_key_context() */ base->CC_CMD = taskDone; /* trigger cau3 execution */ /* process the cau3 task completion signal specified by taskDone */ completionStatus = cau3_process_task_completion(base, taskDone); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return (completionStatus); } status_t CAU3_ClearKeyContext(CAU3_Type *base, cau3_key_slot_t keySlot, cau3_task_done_t taskDone) { uint32_t completionStatus; #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) completionStatus = cau3_lock_semaphore(base); if (kStatus_Success != completionStatus) { cau3_release_semaphore(base); return completionStatus; } #endif /* execute the cau3 "clear key context" task */ base->CC_R[17] = keySlot; /* keySlot */ base->CC_R30 = CAU3_DMEM_STK_BASE; /* initialize stack pointer (sp) */ base->CC_R31 = 0U; /* set LR = 0 to signal a host task */ base->CC_PC = CAU3_TASK_CLR_KEYCTX; /* call cau_clear_key_context() */ base->CC_CMD = taskDone; /* trigger cau3 execution */ /* process the cau3 task completion signal specified by taskDone */ completionStatus = cau3_process_task_completion(base, taskDone); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return (completionStatus); } status_t CAU3_LoadKeyInitVector(CAU3_Type *base, const uint8_t *iv, cau3_key_slot_t keySlot, cau3_task_done_t taskDone) { status_t completionStatus; #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) completionStatus = cau3_lock_semaphore(base); if (kStatus_Success != completionStatus) { cau3_release_semaphore(base); return completionStatus; } #endif /* execute the cau3 "load initialization vector into key context" task */ base->CC_R[16] = (uintptr_t)iv; /* pIv */ base->CC_R[17] = keySlot; /* keySlot */ base->CC_R30 = CAU3_DMEM_STK_BASE; /* initialize stack pointer (sp) */ base->CC_R31 = 0U; /* set LR = 0 to signal a host task */ base->CC_PC = CAU3_TASK_LD_IV; /* call cau_load_iv() */ base->CC_CMD = taskDone; /* trigger cau3 execution */ /* process the cau3 task completion signal specified by taskDone */ completionStatus = cau3_process_task_completion(base, taskDone); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return (completionStatus); } status_t CAU3_AES_KeyExpansion(CAU3_Type *base, cau3_key_slot_t keySlot, cau3_task_done_t taskDone) { status_t completionStatus; #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) completionStatus = cau3_lock_semaphore(base); if (kStatus_Success != completionStatus) { cau3_release_semaphore(base); return completionStatus; } #endif /* execute the cau3 "aes_key_expansion" task */ base->CC_R[17] = keySlot; /* keySlot */ base->CC_R30 = CAU3_DMEM_STK_BASE; /* initialize stack pointer (sp) */ base->CC_R31 = 0U; /* set LR = 0 to signal a host task */ base->CC_PC = CAU3_TASK_AES_KEY_SCH; /* call cau_aes_key_sched() */ base->CC_CMD = taskDone; /* trigger cau3 execution */ /* process the cau3 task completion signal specified by taskDone */ completionStatus = cau3_process_task_completion(base, taskDone); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return (completionStatus); } status_t CAU3_AES_SetKey(CAU3_Type *base, cau3_handle_t *handle, const uint8_t *key, size_t keySize) { cau3_key_context_t cau3KeyCtx = {0}; /* only work with aligned key[] */ if (0x3U & (uintptr_t)key) { return kStatus_InvalidArgument; } /* keySize must be 16 or 32. initial CAU3 firmware doesn't support 24 bytes. */ if ((keySize != 16U) && (keySize != 32U)) { return kStatus_InvalidArgument; } cau3KeyCtx.keySize = keySize; /* move the key by 32-bit words */ int i = 0; while (keySize) { keySize -= sizeof(uint32_t); ((uint32_t *)((uintptr_t)cau3KeyCtx.key))[i] = ((uint32_t *)(uintptr_t)key)[i]; i++; } return cau3_load_key_context(base, &cau3KeyCtx, handle->keySlot, handle->taskDone); } status_t CAU3_AES_Cmac(CAU3_Type *base, cau3_handle_t *handle, const uint8_t *message, size_t size, uint8_t *mac) { status_t completionStatus; /* mac must be 0-mod-4 aligned */ if (0x3U & (uintptr_t)mac) { return kStatus_InvalidArgument; } #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) completionStatus = cau3_lock_semaphore(base); if (kStatus_Success != completionStatus) { cau3_release_semaphore(base); return completionStatus; } #endif /* execute the cau3 "aes_cmac" task */ base->CC_R[16] = (uintptr_t)message; /* pMessage */ base->CC_R[17] = handle->keySlot; /* keySlot */ base->CC_R[18] = size; /* messageSize */ base->CC_R[19] = (uintptr_t)mac; /* pMac */ base->CC_R30 = CAU3_DMEM_STK_BASE; /* initialize stack pointer (sp) */ base->CC_R31 = 0U; /* set LR = 0 to signal a host task */ base->CC_PC = CAU3_TASK_AES128_CMAC; /* call cau_aes128_cmac() */ base->CC_CMD = handle->taskDone; /* trigger cau3 execution */ /* process the cau3 task completion signal specified by taskDone */ completionStatus = cau3_process_task_completion(base, handle->taskDone); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return (completionStatus); } /*! * @brief Check validity of algoritm. * * This function checks the validity of input argument. * * @param algo Tested algorithm value. * @return kStatus_Success if valid, kStatus_InvalidArgument otherwise. */ static status_t cau3_hash_check_input_alg(cau3_hash_algo_t algo) { if ((algo != kCAU3_Sha256) && (algo != kCAU3_Sha1)) { return kStatus_InvalidArgument; } return kStatus_Success; } /*! * @brief Check validity of input arguments. * * This function checks the validity of input arguments. * * @param base CAU3 peripheral base address. * @param ctx Memory buffer given by user application where the CAU3_HASH_Init/CAU3_HASH_Update/CAU3_HASH_Finish store * context. * @param algo Tested algorithm value. * @return kStatus_Success if valid, kStatus_InvalidArgument otherwise. */ static status_t cau3_hash_check_input_args(CAU3_Type *base, cau3_hash_ctx_t *ctx, cau3_hash_algo_t algo) { /* Check validity of input algorithm */ if (kStatus_Success != cau3_hash_check_input_alg(algo)) { return kStatus_InvalidArgument; } if ((NULL == ctx) || (NULL == base)) { return kStatus_InvalidArgument; } return kStatus_Success; } /*! * @brief Check validity of internal software context. * * This function checks if the internal context structure looks correct. * * @param ctxInternal Internal context. * @param message Input message address. * @return kStatus_Success if valid, kStatus_InvalidArgument otherwise. */ static status_t cau3_hash_check_context(cau3_hash_ctx_internal_t *ctxInternal, const uint8_t *message) { if ((NULL == message) || (NULL == ctxInternal) || (kStatus_Success != cau3_hash_check_input_alg(ctxInternal->algo))) { return kStatus_InvalidArgument; } return kStatus_Success; } /*! * @brief Initialize message digest output state for SHA-1 hash * * Initializes the message digest output state for a SHA-1 hash. * * @param sha1State is message digest output in sysMemory in BE format * @param taskDone indicates completion signal: CAU_[POLL, IRQ, EVENT, DMAREQ] * * @retval status check from task completion: CAU_[OK, ERROR] */ static status_t CAU3_Sha1InitializeOutput(CAU3_Type *base, uint32_t *sha1State, cau3_task_done_t taskDone) { status_t completionStatus; #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) completionStatus = cau3_lock_semaphore(base); if (kStatus_Success != completionStatus) { cau3_release_semaphore(base); return completionStatus; } #endif /* execute the cau3 "sha1_init_output" task */ base->CC_R[29] = (uintptr_t)sha1State; /* pSha1State */ base->CC_R30 = CAU3_DMEM_STK_BASE; /* initialize stack pointer (sp) */ base->CC_R31 = 0U; /* set LR = 0 to signal a host task */ base->CC_PC = CAU3_TASK_SHA1_INIT_STATE; /* call cau_sha1_init_state() */ base->CC_CMD = taskDone; /* trigger cau3 execution */ /* process the cau3 task completion signal specified by taskDone */ completionStatus = cau3_process_task_completion(base, taskDone); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return (completionStatus); } /*! * @brief Perform a SHA-1 hash function over a message of "n" 64-byte blocks * * Perform a SHA-1 hash function over a message of "n" 64-byte data blocks, * returning an 8-word message digest (aka "state"). The input message must * be padded appropriately as defined by the SHA-1 algorithm. * * @param message is the uint8_t input message, any alignment * @param numberOfBlocks is the message length as multiple of 64-byte blocks * @param sha1State is uint32_t message digest output (state) in BE format * @param taskDone indicates completion signal: CAU_[POLL, IRQ, EVENT, DMAREQ] * * @retval status check from task completion: CAU_[OK, ERROR] */ static status_t CAU3_Sha1Update( CAU3_Type *base, const uint8_t *message, uint32_t numberOfBlocks, uint32_t *sha1State, cau3_task_done_t taskDone) { status_t completionStatus; #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) completionStatus = cau3_lock_semaphore(base); if (kStatus_Success != completionStatus) { cau3_release_semaphore(base); return completionStatus; } #endif /* execute the cau3 "sha1_update" task */ base->CC_R[27] = (uintptr_t)message; /* pMessage */ base->CC_R[28] = numberOfBlocks; /* n blocks */ base->CC_R[29] = (uintptr_t)sha1State; /* output */ base->CC_R30 = CAU3_DMEM_STK_BASE; /* initialize stack pointer (sp) */ base->CC_R31 = 0U; /* set LR = 0 to signal a host task */ base->CC_PC = CAU3_TASK_SHA1_HASH; /* call cau_sha1_hash_n() */ base->CC_CMD = taskDone; /* trigger cau3 execution */ /* process the cau3 task completion signal specified by taskDone */ completionStatus = cau3_process_task_completion(base, taskDone); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return (completionStatus); } /*! * @brief Initialize message digest output state for SHA-256 hash * * Initializes the message digest output state for a SHA-256 hash. * * CAU3_Sha256InitializeOutput * @param sha256State is message digest output in sysMemory in BE format * @param taskDone indicates completion signal: CAU_[POLL, IRQ, EVENT, DMAREQ] * * @retval status check from task completion: CAU_[OK, ERROR] */ status_t CAU3_Sha256InitializeOutput(CAU3_Type *base, uint32_t *sha256State, cau3_task_done_t taskDone) { status_t completionStatus; #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) completionStatus = cau3_lock_semaphore(base); if (kStatus_Success != completionStatus) { cau3_release_semaphore(base); return completionStatus; } #endif /* execute the cau3 "sha256_init_output" task */ base->CC_R[29] = (uint32_t)sha256State; /* pSha256State */ base->CC_R30 = CAU3_DMEM_STK_BASE; /* initialize stack pointer (sp) */ base->CC_R31 = 0U; /* set LR = 0 to signal a host task */ base->CC_PC = CAU3_TASK_SHA256_INIT_STATE; /* call cau_sha256_init_state() */ base->CC_CMD = taskDone; /* trigger cau3 execution */ /* process the cau3 task completion signal specified by taskDone */ completionStatus = cau3_process_task_completion(base, taskDone); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return (completionStatus); } /*! * @brief Perform a SHA-256 hash function over a message of "n" 64-byte blocks * * Perform a SHA-256 hash function over a message of "n" 64-byte data blocks, * returning an 8-word message digest (aka "state"). The input message must * be padded appropriately as defined by the SHA-256 algorithm. * * CAU_Sha256Update * @param message is the uint8_t input message, LE, ANY ALIGNMENT * @param numberOfBlocks is the message length as multiple of 64-byte blocks * @param sha256State is uint32_t message digest output (state) in BE format * @param taskDone indicates completion signal: CAU_[POLL, IRQ, EVENT, DMAREQ] * * @retval status check from task completion: CAU_[OK, ERROR] */ status_t CAU3_Sha256Update( CAU3_Type *base, const uint8_t *message, uint32_t numberOfBlocks, uint32_t *sha256State, cau3_task_done_t taskDone) { status_t completionStatus; #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) completionStatus = cau3_lock_semaphore(base); if (kStatus_Success != completionStatus) { cau3_release_semaphore(base); return completionStatus; } #endif /* execute the cau3 "sha256_update" task */ base->CC_R[27] = (uint32_t)message; /* pMessage */ base->CC_R[28] = numberOfBlocks; /* = (64*numberOfBlocks) bytes */ base->CC_R[29] = (uint32_t)sha256State; /* pSha256State */ base->CC_R30 = CAU3_DMEM_STK_BASE; /* initialize stack pointer (sp) */ base->CC_R31 = 0U; /* set LR = 0 to signal a host task */ base->CC_PC = CAU3_TASK_SHA256_UPDATE; /* call cau_sha256_update() */ base->CC_CMD = taskDone; /* trigger cau3 execution */ /* process the cau3 task completion signal specified by taskDone */ completionStatus = cau3_process_task_completion(base, taskDone); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return (completionStatus); } /*! * @brief Initialize the SHA engine for new hash. * * This function sets NEW and MODE fields in SHA Control register to start new hash. * * @param base SHA peripheral base address. * @param ctxInternal Internal context. */ static status_t cau3_hash_engine_init(CAU3_Type *base, cau3_hash_ctx_internal_t *ctxInternal) { status_t status; status = kStatus_InvalidArgument; if (kCAU3_Sha256 == ctxInternal->algo) { status = CAU3_Sha256InitializeOutput(base, ctxInternal->runningHash, kCAU3_TaskDonePoll); } if (kCAU3_Sha1 == ctxInternal->algo) { status = CAU3_Sha1InitializeOutput(base, ctxInternal->runningHash, kCAU3_TaskDonePoll); } return status; } /*! * @brief Adds message to current hash. * * This function merges the message to fill the internal buffer, empties the internal buffer if * it becomes full, then process all remaining message data. * * * @param base CAU3 peripheral base address. * @param ctxInternal Internal context. * @param message Input message. * @param messageSize Size of input message in bytes. * @return kStatus_Success. */ static status_t cau3_hash_process_message_data(CAU3_Type *base, cau3_hash_ctx_internal_t *ctxInternal, const uint8_t *message, size_t messageSize) { status_t status; status_t (*funcUpdate)(CAU3_Type * cau3base, const uint8_t *msg, uint32_t numberOfBlocks, uint32_t *shaState, cau3_task_done_t taskDone); /* first fill the internal buffer to full block */ size_t toCopy = CAU3_HASH_BLOCK_SIZE - ctxInternal->blksz; cau3_memcpy(&ctxInternal->blk.b[ctxInternal->blksz], message, toCopy); message += toCopy; messageSize -= toCopy; status = kStatus_InvalidArgument; funcUpdate = NULL; switch (ctxInternal->algo) { case kCAU3_Sha256: funcUpdate = CAU3_Sha256Update; break; case kCAU3_Sha1: funcUpdate = CAU3_Sha1Update; break; default: break; } if (NULL != funcUpdate) { /* process full internal block */ status = funcUpdate(base, &ctxInternal->blk.b[0], CAU3_HASH_BLOCK_SIZE / 64u, ctxInternal->runningHash, kCAU3_TaskDonePoll); if (kStatus_Success != status) { return status; } /* process all full blocks in message[] */ while (messageSize >= CAU3_HASH_BLOCK_SIZE) { status = funcUpdate(base, message, CAU3_HASH_BLOCK_SIZE / 64u, ctxInternal->runningHash, kCAU3_TaskDonePoll); if (kStatus_Success != status) { return status; } message += CAU3_HASH_BLOCK_SIZE; messageSize -= CAU3_HASH_BLOCK_SIZE; } /* copy last incomplete message bytes into internal block */ cau3_memcpy(&ctxInternal->blk.b[0], message, messageSize); ctxInternal->blksz = messageSize; } return status; } /*! * @brief Finalize the running hash to make digest. * * This function empties the internal buffer, adds padding bits, and generates final digest. * * @param base SHA peripheral base address. * @param ctxInternal Internal context. * @return kStatus_Success. */ static status_t cau3_hash_finalize(CAU3_Type *base, cau3_hash_ctx_internal_t *ctxInternal) { cau3_sha_block_t lastBlock; status_t status; status_t (*funcUpdate)(CAU3_Type * cau3base, const uint8_t *msg, uint32_t numberOfBlocks, uint32_t *shaState, cau3_task_done_t taskDone); status = kStatus_InvalidArgument; funcUpdate = NULL; switch (ctxInternal->algo) { case kCAU3_Sha256: funcUpdate = CAU3_Sha256Update; break; case kCAU3_Sha1: funcUpdate = CAU3_Sha1Update; break; default: break; } if (NULL == funcUpdate) { return kStatus_InvalidArgument; } memset(&lastBlock, 0, sizeof(cau3_sha_block_t)); status = kStatus_Success; while (ctxInternal->blksz >= 64u) { status = funcUpdate(base, &ctxInternal->blk.b[0], 1, ctxInternal->runningHash, kCAU3_TaskDonePoll); if (kStatus_Success != status) { return status; } ctxInternal->blksz -= 64u; cau3_memcpy(&ctxInternal->blk.b[0], &ctxInternal->blk.b[64], ctxInternal->blksz); } /* this is last call, so need to flush buffered message bytes along with padding */ if (ctxInternal->blksz <= 55u) { /* last data is 440 bits or less. */ cau3_memcpy(&lastBlock.b[0], &ctxInternal->blk.b[0], ctxInternal->blksz); lastBlock.b[ctxInternal->blksz] = (uint8_t)0x80U; lastBlock.w[15] = __REV(8u * ctxInternal->fullMessageSize); status = funcUpdate(base, &lastBlock.b[0], 1, ctxInternal->runningHash, kCAU3_TaskDonePoll); if (kStatus_Success != status) { return status; } } else { if (ctxInternal->blksz < 64u) { ctxInternal->blk.b[ctxInternal->blksz] = (uint8_t)0x80U; for (uint32_t i = ctxInternal->blksz + 1u; i < 64u; i++) { ctxInternal->blk.b[i] = 0; } } else { lastBlock.b[0] = (uint8_t)0x80U; } status = funcUpdate(base, &ctxInternal->blk.b[0], 1, ctxInternal->runningHash, kCAU3_TaskDonePoll); if (kStatus_Success != status) { return status; } lastBlock.w[15] = __REV(8u * ctxInternal->fullMessageSize); status = funcUpdate(base, &lastBlock.b[0], 1, ctxInternal->runningHash, kCAU3_TaskDonePoll); if (kStatus_Success != status) { return status; } } return status; } status_t CAU3_HASH_Init(CAU3_Type *base, cau3_hash_ctx_t *ctx, cau3_hash_algo_t algo) { status_t status; cau3_hash_ctx_internal_t *ctxInternal; /* compile time check for the correct structure size */ BUILD_ASSURE(sizeof(cau3_hash_ctx_t) >= sizeof(cau3_hash_ctx_internal_t), cau3_hash_ctx_t_size); uint32_t i; status = cau3_hash_check_input_args(base, ctx, algo); if (status != kStatus_Success) { return status; } /* set algorithm in context struct for later use */ ctxInternal = (cau3_hash_ctx_internal_t *)ctx; ctxInternal->algo = algo; ctxInternal->blksz = 0u; for (i = 0; i < sizeof(ctxInternal->blk.w) / sizeof(ctxInternal->blk.w[0]); i++) { ctxInternal->blk.w[0] = 0u; } ctxInternal->state = kCAU3_StateHashInit; ctxInternal->fullMessageSize = 0; return status; } status_t CAU3_HASH_Update(CAU3_Type *base, cau3_hash_ctx_t *ctx, const uint8_t *input, size_t inputSize) { bool isUpdateState; status_t status; cau3_hash_ctx_internal_t *ctxInternal; size_t blockSize; if (inputSize == 0) { return kStatus_Success; } ctxInternal = (cau3_hash_ctx_internal_t *)ctx; status = cau3_hash_check_context(ctxInternal, input); if (kStatus_Success != status) { return status; } ctxInternal->fullMessageSize += inputSize; blockSize = CAU3_HASH_BLOCK_SIZE; /* if we are still less than CAU3_HASH_BLOCK_SIZE bytes, keep only in context */ if ((ctxInternal->blksz + inputSize) <= blockSize) { cau3_memcpy((&ctxInternal->blk.b[0]) + ctxInternal->blksz, input, inputSize); ctxInternal->blksz += inputSize; return status; } else { isUpdateState = ctxInternal->state == kCAU3_StateHashUpdate; if (!isUpdateState) { /* start NEW hash */ status = cau3_hash_engine_init(base, ctxInternal); if (status != kStatus_Success) { return status; } ctxInternal->state = kCAU3_StateHashUpdate; } } /* process input data */ status = cau3_hash_process_message_data(base, ctxInternal, input, inputSize); return status; } status_t CAU3_HASH_Finish(CAU3_Type *base, cau3_hash_ctx_t *ctx, uint8_t *output, size_t *outputSize) { size_t algOutSize = 0; status_t status; cau3_hash_ctx_internal_t *ctxInternal; ctxInternal = (cau3_hash_ctx_internal_t *)ctx; status = cau3_hash_check_context(ctxInternal, output); if (kStatus_Success != status) { return status; } if (ctxInternal->state == kCAU3_StateHashInit) { status = cau3_hash_engine_init(base, ctxInternal); if (status != kStatus_Success) { return status; } } size_t outSize = 0u; /* compute algorithm output length */ switch (ctxInternal->algo) { case kCAU3_Sha256: outSize = kCAU3_OutLenSha256; break; case kCAU3_Sha1: outSize = kCAU3_OutLenSha1; break; default: break; } algOutSize = outSize; /* flush message last incomplete block, if there is any, and add padding bits */ status = cau3_hash_finalize(base, ctxInternal); if (outputSize) { if (algOutSize < *outputSize) { *outputSize = algOutSize; } else { algOutSize = *outputSize; } } cau3_memcpy(&output[0], ctxInternal->runningHash, algOutSize); memset(ctx, 0, sizeof(cau3_hash_ctx_t)); return status; } status_t CAU3_HASH( CAU3_Type *base, cau3_hash_algo_t algo, const uint8_t *input, size_t inputSize, uint8_t *output, size_t *outputSize) { cau3_hash_ctx_t hashCtx; status_t status; status = CAU3_HASH_Init(base, &hashCtx, algo); if (status != kStatus_Success) { return status; } status = CAU3_HASH_Update(base, &hashCtx, input, inputSize); if (status != kStatus_Success) { return status; } status = CAU3_HASH_Finish(base, &hashCtx, output, outputSize); return status; } /*! @brief CAU3 driver wait mechanism. */ status_t cau3_wait(CAU3_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 & kCAU3_StatusErrorIsr; done = temp32 & kCAU3_StatusDoneIsr; } if (error) { base->COM = CAU3_COM_ALL_MASK; /* Reset all engine to clear the error flag */ status = kStatus_Fail; } else /* 'done' */ { status = kStatus_Success; base->CW = kCAU3_ClearDataSize; /* Clear 'done' interrupt status. This also clears the mode register. */ base->STA = kCAU3_StatusDoneIsr; } return status; } /*! * @brief Clears the CAU3 module. * This function can be used to clear all sensitive data from theCAU3 module, such as private keys. It is called * internally by the CAU3 driver in case of an error or operation complete. * @param base CAU3 peripheral base address * @param pkha Include CAU3 PKHA register clear. If there is no PKHA, the argument is ignored. */ void cau3_clear_all(CAU3_Type *base, bool addPKHA) { base->CW = (uint32_t)kCAU3_ClearAll; if (addPKHA) { cau3_pkha_clear_regabne(base, true, true, true, true); } } /*! * @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 cau3_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 Compiler 5 uses LDM instruction here (LDM r4!, {r0}) * which is wrong, because srcAddr might be unaligned. * LDM on unaligned address causes hard-fault. so use memcpy() */ uint32_t ret; memcpy(&ret, srcAddr, sizeof(uint32_t)); return ret; #else return *((const uint32_t *)srcAddr); #endif } /******************************************************************************* * PKHA Code static ******************************************************************************/ static status_t cau3_pkha_clear_regabne(CAU3_Type *base, bool A, bool B, bool N, bool E) { cau3_mode_t mode; /* Set the PKHA algorithm and the appropriate function. */ mode = (uint32_t)kCAU3_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 cau3_wait(base); } static void cau3_pkha_default_parms(cau3_pkha_mode_params_t *params) { params->func = (cau3_pkha_func_t)0; params->arithType = kCAU3_PKHA_IntegerArith; params->montFormIn = kCAU3_PKHA_NormalValue; params->montFormOut = kCAU3_PKHA_NormalValue; params->srcReg = kCAU3_PKHA_RegAll; params->srcQuad = kCAU3_PKHA_Quad0; params->dstReg = kCAU3_PKHA_RegAll; params->dstQuad = kCAU3_PKHA_Quad0; params->equalTime = kCAU3_PKHA_NoTimingEqualized; params->r2modn = kCAU3_PKHA_CalcR2; } static void cau3_pkha_write_word(CAU3_Type *base, cau3_pkha_reg_area_t reg, uint8_t index, uint32_t data) { __IO uint32_t *pka = base->PKA0; __IO uint32_t *pkb = base->PKB0; __IO uint32_t *pkn = base->PKN0; switch (reg) { case kCAU3_PKHA_RegA: pka[index] = data; break; case kCAU3_PKHA_RegB: pkb[index] = data; break; case kCAU3_PKHA_RegN: pkn[index] = data; break; case kCAU3_PKHA_RegE: base->PKE[index] = data; break; default: break; } } static uint32_t cau3_pkha_read_word(CAU3_Type *base, cau3_pkha_reg_area_t reg, uint8_t index) { uint32_t retval; __IO uint32_t *pka = base->PKA0; __IO uint32_t *pkb = base->PKB0; __IO uint32_t *pkn = base->PKN0; switch (reg) { case kCAU3_PKHA_RegA: retval = pka[index]; break; case kCAU3_PKHA_RegB: retval = pkb[index]; break; case kCAU3_PKHA_RegN: retval = pkn[index]; break; default: retval = 0; break; } return retval; } static status_t cau3_pkha_write_reg( CAU3_Type *base, cau3_pkha_reg_area_t reg, uint8_t quad, const uint8_t *data, size_t dataSize) { /* Select the word-based start index for each quadrant of 128 bytes. */ uint8_t startIndex = (quad * 32u); uint32_t outWord; while (dataSize > 0) { if (dataSize >= sizeof(uint32_t)) { cau3_pkha_write_word(base, reg, startIndex++, cau3_get_word_from_unaligned(data)); dataSize -= sizeof(uint32_t); data += sizeof(uint32_t); } else /* (dataSize > 0) && (dataSize < 4) */ { outWord = 0; cau3_memcpy(&outWord, data, dataSize); cau3_pkha_write_word(base, reg, startIndex, outWord); dataSize = 0; } } return kStatus_Success; } static void cau3_pkha_read_reg(CAU3_Type *base, cau3_pkha_reg_area_t reg, uint8_t quad, uint8_t *data, size_t dataSize) { /* Select the word-based start index for each quadrant of 128 bytes. */ uint8_t startIndex = (quad * 32u); size_t calcSize; uint32_t word; while (dataSize > 0) { word = cau3_pkha_read_word(base, reg, startIndex++); calcSize = (dataSize >= sizeof(uint32_t)) ? sizeof(uint32_t) : dataSize; cau3_memcpy(data, &word, calcSize); data += calcSize; dataSize -= calcSize; } } static void cau3_pkha_init_data(CAU3_Type *base, const uint8_t *A, size_t sizeA, const uint8_t *B, size_t sizeB, const uint8_t *N, size_t sizeN, const uint8_t *E, size_t sizeE) { uint32_t clearMask = kCAU3_ClearMode; /* clear Mode Register */ /* Clear internal register states. */ if (sizeA) { clearMask |= kCAU3_ClearPkhaSizeA; } if (sizeB) { clearMask |= kCAU3_ClearPkhaSizeB; } if (sizeN) { clearMask |= kCAU3_ClearPkhaSizeN; } if (sizeE) { clearMask |= kCAU3_ClearPkhaSizeE; } base->CW = clearMask; base->STA = kCAU3_StatusDoneIsr; cau3_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) { cau3_pkha_write_reg(base, kCAU3_PKHA_RegN, 0, N, sizeN); } } if (sizeA) { base->PKASZ = sizeA; if (A) { cau3_pkha_write_reg(base, kCAU3_PKHA_RegA, 0, A, sizeA); } } if (sizeB) { base->PKBSZ = sizeB; if (B) { cau3_pkha_write_reg(base, kCAU3_PKHA_RegB, 0, B, sizeB); } } if (sizeE) { base->PKESZ = sizeE; if (E) { cau3_pkha_write_reg(base, kCAU3_PKHA_RegE, 0, E, sizeE); } } } static void cau3_pkha_mode_set_src_reg_copy(cau3_mode_t *outMode, cau3_pkha_reg_area_t reg) { int i = 0; do { reg = (cau3_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 cau3_pkha_mode_set_dst_reg_copy(cau3_mode_t *outMode, cau3_pkha_reg_area_t reg) { int i = 0; do { reg = (cau3_pkha_reg_area_t)(((uint32_t)reg) >> 1u); i++; } while (reg); i = 4 - i; *outMode |= ((uint32_t)i << 10u); } static void cau3_pkha_mode_set_src_seg_copy(cau3_mode_t *outMode, const cau3_pkha_quad_area_t quad) { *outMode |= ((uint32_t)quad << 8u); } static void cau3_pkha_mode_set_dst_seg_copy(cau3_mode_t *outMode, const cau3_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 CAU3 peripheral base address * @param params Configuration structure containing all settings required for PKHA operation. */ static status_t cau3_pkha_init_mode(CAU3_Type *base, const cau3_pkha_mode_params_t *params) { cau3_mode_t modeReg; status_t retval; /* Set the PKHA algorithm and the appropriate function. */ modeReg = kCAU3_AlgorithmPKHA; modeReg |= (uint32_t)params->func; if ((params->func == kCAU3_PKHA_CopyMemSizeN) || (params->func == kCAU3_PKHA_CopyMemSizeSrc)) { /* Set source and destination registers and quads. */ cau3_pkha_mode_set_src_reg_copy(&modeReg, params->srcReg); cau3_pkha_mode_set_dst_reg_copy(&modeReg, params->dstReg); cau3_pkha_mode_set_src_seg_copy(&modeReg, params->srcQuad); cau3_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 = cau3_wait(base); return (retval); } static status_t cau3_pkha_modR2( CAU3_Type *base, const uint8_t *N, size_t sizeN, uint8_t *result, size_t *resultSize, cau3_pkha_f2m_t arithType) { status_t status; cau3_pkha_mode_params_t params; cau3_pkha_default_parms(¶ms); params.func = kCAU3_PKHA_ArithModR2; params.arithType = arithType; cau3_pkha_init_data(base, NULL, 0, NULL, 0, N, sizeN, NULL, 0); status = cau3_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. */ cau3_pkha_read_reg(base, kCAU3_PKHA_RegB, 0, result, *resultSize); } } return status; } static status_t cau3_pkha_modmul(CAU3_Type *base, const uint8_t *A, size_t sizeA, const uint8_t *B, size_t sizeB, const uint8_t *N, size_t sizeN, uint8_t *result, size_t *resultSize, cau3_pkha_f2m_t arithType, cau3_pkha_montgomery_form_t montIn, cau3_pkha_montgomery_form_t montOut, cau3_pkha_timing_t equalTime) { cau3_pkha_mode_params_t params; status_t status; if (arithType == kCAU3_PKHA_IntegerArith) { if (CAU3_PKHA_CompareBigNum(A, sizeA, N, sizeN) >= 0) { return (kStatus_InvalidArgument); } if (CAU3_PKHA_CompareBigNum(B, sizeB, N, sizeN) >= 0) { return (kStatus_InvalidArgument); } } cau3_pkha_default_parms(¶ms); params.func = kCAU3_PKHA_ArithModMul; params.arithType = arithType; params.montFormIn = montIn; params.montFormOut = montOut; params.equalTime = equalTime; cau3_pkha_init_data(base, A, sizeA, B, sizeB, N, sizeN, NULL, 0); status = cau3_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. */ cau3_pkha_read_reg(base, kCAU3_PKHA_RegB, 0, result, *resultSize); } } return status; } /******************************************************************************* * PKHA Code public ******************************************************************************/ int CAU3_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 CAU3_PKHA_NormalToMontgomery(CAU3_Type *base, const uint8_t *N, size_t sizeN, uint8_t *A, size_t *sizeA, uint8_t *B, size_t *sizeB, uint8_t *R2, size_t *sizeR2, cau3_pkha_timing_t equalTime, cau3_pkha_f2m_t arithType) { status_t status; #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) status = cau3_lock_semaphore(base); if (kStatus_Success != status) { cau3_release_semaphore(base); return status; } #endif /* need to convert our Integer inputs into Montgomery format */ if (N && sizeN && R2 && sizeR2) { /* 1. R2 = MOD_R2(N) */ status = cau3_pkha_modR2(base, N, sizeN, R2, sizeR2, arithType); if (status != kStatus_Success) { #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return status; } /* 2. A(Montgomery) = MOD_MUL_IM_OM(A, R2, N) */ if (A && sizeA) { status = cau3_pkha_modmul(base, A, *sizeA, R2, *sizeR2, N, sizeN, A, sizeA, arithType, kCAU3_PKHA_MontgomeryFormat, kCAU3_PKHA_MontgomeryFormat, equalTime); if (status != kStatus_Success) { #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return status; } } /* 2. B(Montgomery) = MOD_MUL_IM_OM(B, R2, N) */ if (B && sizeB) { status = cau3_pkha_modmul(base, B, *sizeB, R2, *sizeR2, N, sizeN, B, sizeB, arithType, kCAU3_PKHA_MontgomeryFormat, kCAU3_PKHA_MontgomeryFormat, equalTime); if (status != kStatus_Success) { #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return status; } } cau3_clear_all(base, true); } else { status = kStatus_InvalidArgument; } #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return status; } status_t CAU3_PKHA_MontgomeryToNormal(CAU3_Type *base, const uint8_t *N, size_t sizeN, uint8_t *A, size_t *sizeA, uint8_t *B, size_t *sizeB, cau3_pkha_timing_t equalTime, cau3_pkha_f2m_t arithType) { uint8_t one = 1; status_t status = kStatus_InvalidArgument; #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) status = cau3_lock_semaphore(base); if (kStatus_Success != status) { cau3_release_semaphore(base); return status; } #endif /* A = MOD_MUL_IM_OM(A(Montgomery), 1, N) */ if (A && sizeA) { status = cau3_pkha_modmul(base, A, *sizeA, &one, sizeof(one), N, sizeN, A, sizeA, arithType, kCAU3_PKHA_MontgomeryFormat, kCAU3_PKHA_MontgomeryFormat, equalTime); if (kStatus_Success != status) { #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return status; } } /* B = MOD_MUL_IM_OM(B(Montgomery), 1, N) */ if (B && sizeB) { status = cau3_pkha_modmul(base, B, *sizeB, &one, sizeof(one), N, sizeN, B, sizeB, arithType, kCAU3_PKHA_MontgomeryFormat, kCAU3_PKHA_MontgomeryFormat, equalTime); if (kStatus_Success != status) { #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return status; } } cau3_clear_all(base, true); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return status; } status_t CAU3_PKHA_ModAdd(CAU3_Type *base, const uint8_t *A, size_t sizeA, const uint8_t *B, size_t sizeB, const uint8_t *N, size_t sizeN, uint8_t *result, size_t *resultSize, cau3_pkha_f2m_t arithType) { cau3_pkha_mode_params_t params; status_t status; if (arithType == kCAU3_PKHA_IntegerArith) { if (CAU3_PKHA_CompareBigNum(A, sizeA, N, sizeN) >= 0) { return (kStatus_InvalidArgument); } if (CAU3_PKHA_CompareBigNum(B, sizeB, N, sizeN) >= 0) { return (kStatus_InvalidArgument); } } #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) status = cau3_lock_semaphore(base); if (kStatus_Success != status) { cau3_release_semaphore(base); return status; } #endif cau3_pkha_default_parms(¶ms); params.func = kCAU3_PKHA_ArithModAdd; params.arithType = arithType; cau3_pkha_init_data(base, A, sizeA, B, sizeB, N, sizeN, NULL, 0); status = cau3_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. */ cau3_pkha_read_reg(base, kCAU3_PKHA_RegB, 0, result, *resultSize); } } cau3_clear_all(base, true); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return status; } status_t CAU3_PKHA_ModSub1(CAU3_Type *base, const uint8_t *A, size_t sizeA, const uint8_t *B, size_t sizeB, const uint8_t *N, size_t sizeN, uint8_t *result, size_t *resultSize) { cau3_pkha_mode_params_t params; status_t status; if (CAU3_PKHA_CompareBigNum(A, sizeA, N, sizeN) >= 0) { return (kStatus_InvalidArgument); } if (CAU3_PKHA_CompareBigNum(B, sizeB, N, sizeN) >= 0) { return (kStatus_InvalidArgument); } #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) status = cau3_lock_semaphore(base); if (kStatus_Success != status) { cau3_release_semaphore(base); return status; } #endif cau3_pkha_default_parms(¶ms); params.func = kCAU3_PKHA_ArithModSub1; cau3_pkha_init_data(base, A, sizeA, B, sizeB, N, sizeN, NULL, 0); status = cau3_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. */ cau3_pkha_read_reg(base, kCAU3_PKHA_RegB, 0, result, *resultSize); } } cau3_clear_all(base, true); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return status; } status_t CAU3_PKHA_ModSub2(CAU3_Type *base, const uint8_t *A, size_t sizeA, const uint8_t *B, size_t sizeB, const uint8_t *N, size_t sizeN, uint8_t *result, size_t *resultSize) { cau3_pkha_mode_params_t params; status_t status; #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) status = cau3_lock_semaphore(base); if (kStatus_Success != status) { cau3_release_semaphore(base); return status; } #endif cau3_pkha_default_parms(¶ms); params.func = kCAU3_PKHA_ArithModSub2; cau3_pkha_init_data(base, A, sizeA, B, sizeB, N, sizeN, NULL, 0); status = cau3_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. */ cau3_pkha_read_reg(base, kCAU3_PKHA_RegB, 0, result, *resultSize); } } cau3_clear_all(base, true); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return status; } status_t CAU3_PKHA_ModMul(CAU3_Type *base, const uint8_t *A, size_t sizeA, const uint8_t *B, size_t sizeB, const uint8_t *N, size_t sizeN, uint8_t *result, size_t *resultSize, cau3_pkha_f2m_t arithType, cau3_pkha_montgomery_form_t montIn, cau3_pkha_montgomery_form_t montOut, cau3_pkha_timing_t equalTime) { status_t status; #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) status = cau3_lock_semaphore(base); if (kStatus_Success != status) { cau3_release_semaphore(base); return status; } #endif status = cau3_pkha_modmul(base, A, sizeA, B, sizeB, N, sizeN, result, resultSize, arithType, montIn, montOut, equalTime); cau3_clear_all(base, true); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return status; } status_t CAU3_PKHA_ModExp(CAU3_Type *base, const uint8_t *A, size_t sizeA, const uint8_t *N, size_t sizeN, const uint8_t *E, size_t sizeE, uint8_t *result, size_t *resultSize, cau3_pkha_f2m_t arithType, cau3_pkha_montgomery_form_t montIn, cau3_pkha_timing_t equalTime) { cau3_pkha_mode_params_t params; status_t status; if (arithType == kCAU3_PKHA_IntegerArith) { if (CAU3_PKHA_CompareBigNum(A, sizeA, N, sizeN) >= 0) { return (kStatus_InvalidArgument); } } #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) status = cau3_lock_semaphore(base); if (kStatus_Success != status) { cau3_release_semaphore(base); return status; } #endif cau3_pkha_default_parms(¶ms); params.func = kCAU3_PKHA_ArithModExp; params.arithType = arithType; params.montFormIn = montIn; params.equalTime = equalTime; cau3_pkha_init_data(base, A, sizeA, NULL, 0, N, sizeN, E, sizeE); status = cau3_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. */ cau3_pkha_read_reg(base, kCAU3_PKHA_RegB, 0, result, *resultSize); } } cau3_clear_all(base, true); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return status; } status_t CAU3_PKHA_ModSqrt(CAU3_Type *base, const uint8_t *A, size_t sizeA, const uint8_t *N, size_t sizeN, uint8_t *result, size_t *resultSize) { cau3_pkha_mode_params_t params; status_t status; /* A < N */ if (CAU3_PKHA_CompareBigNum(A, sizeA, N, sizeN) >= 0) { return (kStatus_InvalidArgument); } #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) status = cau3_lock_semaphore(base); if (kStatus_Success != status) { cau3_release_semaphore(base); return status; } #endif cau3_pkha_default_parms(¶ms); params.func = kCAU3_PKHA_ArithModSqrt; cau3_pkha_init_data(base, A, sizeA, NULL, 0, N, sizeN, NULL, 0); status = cau3_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. */ cau3_pkha_read_reg(base, kCAU3_PKHA_RegB, 0, result, *resultSize); } } cau3_clear_all(base, true); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return status; } status_t CAU3_PKHA_ModRed(CAU3_Type *base, const uint8_t *A, size_t sizeA, const uint8_t *N, size_t sizeN, uint8_t *result, size_t *resultSize, cau3_pkha_f2m_t arithType) { cau3_pkha_mode_params_t params; status_t status; #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) status = cau3_lock_semaphore(base); if (kStatus_Success != status) { cau3_release_semaphore(base); return status; } #endif cau3_pkha_default_parms(¶ms); params.func = kCAU3_PKHA_ArithModRed; params.arithType = arithType; cau3_pkha_init_data(base, A, sizeA, NULL, 0, N, sizeN, NULL, 0); status = cau3_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. */ cau3_pkha_read_reg(base, kCAU3_PKHA_RegB, 0, result, *resultSize); } } cau3_clear_all(base, true); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return status; } status_t CAU3_PKHA_ModInv(CAU3_Type *base, const uint8_t *A, size_t sizeA, const uint8_t *N, size_t sizeN, uint8_t *result, size_t *resultSize, cau3_pkha_f2m_t arithType) { cau3_pkha_mode_params_t params; status_t status; /* A must be less than N -> CAU3_PKHA_CompareBigNum() must return -1 */ if (arithType == kCAU3_PKHA_IntegerArith) { if (CAU3_PKHA_CompareBigNum(A, sizeA, N, sizeN) >= 0) { return (kStatus_InvalidArgument); } } #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) status = cau3_lock_semaphore(base); if (kStatus_Success != status) { cau3_release_semaphore(base); return status; } #endif cau3_pkha_default_parms(¶ms); params.func = kCAU3_PKHA_ArithModInv; params.arithType = arithType; cau3_pkha_init_data(base, A, sizeA, NULL, 0, N, sizeN, NULL, 0); status = cau3_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. */ cau3_pkha_read_reg(base, kCAU3_PKHA_RegB, 0, result, *resultSize); } } cau3_clear_all(base, true); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return status; } status_t CAU3_PKHA_ModR2( CAU3_Type *base, const uint8_t *N, size_t sizeN, uint8_t *result, size_t *resultSize, cau3_pkha_f2m_t arithType) { status_t status; #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) status = cau3_lock_semaphore(base); if (kStatus_Success != status) { cau3_release_semaphore(base); return status; } #endif status = cau3_pkha_modR2(base, N, sizeN, result, resultSize, arithType); cau3_clear_all(base, true); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return status; } status_t CAU3_PKHA_ModRR( CAU3_Type *base, const uint8_t *P, size_t sizeP, size_t sizeE, uint8_t *result, size_t *resultSize) { status_t status; cau3_pkha_mode_params_t params; #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) status = cau3_lock_semaphore(base); if (kStatus_Success != status) { cau3_release_semaphore(base); return status; } #endif cau3_pkha_default_parms(¶ms); params.func = kCAU3_PKHA_ArithModRR; cau3_pkha_init_data(base, NULL, 0, NULL, 0, P, sizeP, NULL, sizeE); status = cau3_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. */ cau3_pkha_read_reg(base, kCAU3_PKHA_RegB, 0, result, *resultSize); } } #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return status; } status_t CAU3_PKHA_ModGcd(CAU3_Type *base, const uint8_t *A, size_t sizeA, const uint8_t *N, size_t sizeN, uint8_t *result, size_t *resultSize, cau3_pkha_f2m_t arithType) { cau3_pkha_mode_params_t params; status_t status; #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) status = cau3_lock_semaphore(base); if (kStatus_Success != status) { cau3_release_semaphore(base); return status; } #endif cau3_pkha_default_parms(¶ms); params.func = kCAU3_PKHA_ArithGcd; params.arithType = arithType; cau3_pkha_init_data(base, A, sizeA, NULL, 0, N, sizeN, NULL, 0); status = cau3_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. */ cau3_pkha_read_reg(base, kCAU3_PKHA_RegB, 0, result, *resultSize); } } cau3_clear_all(base, true); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return status; } status_t CAU3_PKHA_PrimalityTest(CAU3_Type *base, const uint8_t *A, size_t sizeA, const uint8_t *B, size_t sizeB, const uint8_t *N, size_t sizeN, bool *res) { uint8_t result; cau3_pkha_mode_params_t params; status_t status; #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) status = cau3_lock_semaphore(base); if (kStatus_Success != status) { cau3_release_semaphore(base); return status; } #endif cau3_pkha_default_parms(¶ms); params.func = kCAU3_PKHA_ArithPrimalityTest; cau3_pkha_init_data(base, A, sizeA, B, sizeB, N, sizeN, NULL, 0); status = cau3_pkha_init_mode(base, ¶ms); if (status == kStatus_Success) { /* Read the data from the result register into place. */ cau3_pkha_read_reg(base, kCAU3_PKHA_RegB, 0, &result, 1); *res = (bool)result; } cau3_clear_all(base, true); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return status; } status_t CAU3_PKHA_ECC_PointAdd(CAU3_Type *base, const cau3_pkha_ecc_point_t *A, const cau3_pkha_ecc_point_t *B, const uint8_t *N, const uint8_t *R2modN, const uint8_t *aCurveParam, const uint8_t *bCurveParam, size_t size, cau3_pkha_f2m_t arithType, cau3_pkha_ecc_point_t *result) { cau3_pkha_mode_params_t params; uint32_t clearMask; status_t status; #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) status = cau3_lock_semaphore(base); if (kStatus_Success != status) { cau3_release_semaphore(base); return status; } #endif cau3_pkha_default_parms(¶ms); params.func = kCAU3_PKHA_ArithEccAdd; params.arithType = arithType; params.r2modn = R2modN ? kCAU3_PKHA_InputR2 : kCAU3_PKHA_CalcR2; clearMask = kCAU3_ClearMode; /* Clear internal register states. */ clearMask |= kCAU3_ClearPkhaSizeA; clearMask |= kCAU3_ClearPkhaSizeB; clearMask |= kCAU3_ClearPkhaSizeN; clearMask |= kCAU3_ClearPkhaSizeE; base->CW = clearMask; base->STA = kCAU3_StatusDoneIsr; cau3_pkha_clear_regabne(base, true, true, true, false); /* sizeN should be less than 64 bytes. */ base->PKNSZ = size; cau3_pkha_write_reg(base, kCAU3_PKHA_RegN, 0, N, size); base->PKASZ = size; cau3_pkha_write_reg(base, kCAU3_PKHA_RegA, 0, A->X, size); cau3_pkha_write_reg(base, kCAU3_PKHA_RegA, 1, A->Y, size); cau3_pkha_write_reg(base, kCAU3_PKHA_RegA, 3, aCurveParam, size); base->PKBSZ = size; cau3_pkha_write_reg(base, kCAU3_PKHA_RegB, 0, bCurveParam, size); cau3_pkha_write_reg(base, kCAU3_PKHA_RegB, 1, B->X, size); cau3_pkha_write_reg(base, kCAU3_PKHA_RegB, 2, B->Y, size); if (R2modN) { cau3_pkha_write_reg(base, kCAU3_PKHA_RegB, 3, R2modN, size); } status = cau3_pkha_init_mode(base, ¶ms); if (status == kStatus_Success) { /* Read the data from the result register into place. */ cau3_pkha_read_reg(base, kCAU3_PKHA_RegB, 1, result->X, size); cau3_pkha_read_reg(base, kCAU3_PKHA_RegB, 2, result->Y, size); } cau3_clear_all(base, true); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return status; } status_t CAU3_PKHA_ECC_PointDouble(CAU3_Type *base, const cau3_pkha_ecc_point_t *B, const uint8_t *N, const uint8_t *aCurveParam, const uint8_t *bCurveParam, size_t size, cau3_pkha_f2m_t arithType, cau3_pkha_ecc_point_t *result) { cau3_pkha_mode_params_t params; uint32_t clearMask; status_t status; #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) status = cau3_lock_semaphore(base); if (kStatus_Success != status) { cau3_release_semaphore(base); return status; } #endif cau3_pkha_default_parms(¶ms); params.func = kCAU3_PKHA_ArithEccDouble; params.arithType = arithType; clearMask = kCAU3_ClearMode; /* Clear internal register states. */ clearMask |= kCAU3_ClearPkhaSizeA; clearMask |= kCAU3_ClearPkhaSizeB; clearMask |= kCAU3_ClearPkhaSizeN; clearMask |= kCAU3_ClearPkhaSizeE; base->CW = clearMask; base->STA = kCAU3_StatusDoneIsr; cau3_pkha_clear_regabne(base, true, true, true, false); /* sizeN should be less than 64 bytes. */ base->PKNSZ = size; cau3_pkha_write_reg(base, kCAU3_PKHA_RegN, 0, N, size); base->PKASZ = size; cau3_pkha_write_reg(base, kCAU3_PKHA_RegA, 3, aCurveParam, size); base->PKBSZ = size; cau3_pkha_write_reg(base, kCAU3_PKHA_RegB, 0, bCurveParam, size); cau3_pkha_write_reg(base, kCAU3_PKHA_RegB, 1, B->X, size); cau3_pkha_write_reg(base, kCAU3_PKHA_RegB, 2, B->Y, size); status = cau3_pkha_init_mode(base, ¶ms); if (status == kStatus_Success) { /* Read the data from the result register into place. */ cau3_pkha_read_reg(base, kCAU3_PKHA_RegB, 1, result->X, size); cau3_pkha_read_reg(base, kCAU3_PKHA_RegB, 2, result->Y, size); } cau3_clear_all(base, true); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return status; } status_t CAU3_PKHA_ECC_PointMul(CAU3_Type *base, const cau3_pkha_ecc_point_t *A, const uint8_t *E, size_t sizeE, const uint8_t *N, const uint8_t *R2modN, const uint8_t *aCurveParam, const uint8_t *bCurveParam, size_t size, cau3_pkha_timing_t equalTime, cau3_pkha_f2m_t arithType, cau3_pkha_ecc_point_t *result) { cau3_pkha_mode_params_t params; uint32_t clearMask; status_t status; #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) status = cau3_lock_semaphore(base); if (kStatus_Success != status) { cau3_release_semaphore(base); return status; } #endif cau3_pkha_default_parms(¶ms); params.func = kCAU3_PKHA_ArithEccMul; params.equalTime = equalTime; params.arithType = arithType; params.r2modn = R2modN ? kCAU3_PKHA_InputR2 : kCAU3_PKHA_CalcR2; clearMask = kCAU3_ClearMode; /* Clear internal register states. */ clearMask |= kCAU3_ClearPkhaSizeA; clearMask |= kCAU3_ClearPkhaSizeB; clearMask |= kCAU3_ClearPkhaSizeN; clearMask |= kCAU3_ClearPkhaSizeE; base->CW = clearMask; base->STA = kCAU3_StatusDoneIsr; cau3_pkha_clear_regabne(base, true, true, true, true); /* sizeN should be less than 64 bytes. */ base->PKNSZ = size; cau3_pkha_write_reg(base, kCAU3_PKHA_RegN, 0, N, size); base->PKESZ = sizeE; cau3_pkha_write_reg(base, kCAU3_PKHA_RegE, 0, E, sizeE); base->PKASZ = size; cau3_pkha_write_reg(base, kCAU3_PKHA_RegA, 0, A->X, size); cau3_pkha_write_reg(base, kCAU3_PKHA_RegA, 1, A->Y, size); cau3_pkha_write_reg(base, kCAU3_PKHA_RegA, 3, aCurveParam, size); base->PKBSZ = size; cau3_pkha_write_reg(base, kCAU3_PKHA_RegB, 0, bCurveParam, size); if (R2modN) { cau3_pkha_write_reg(base, kCAU3_PKHA_RegB, 1, R2modN, size); } status = cau3_pkha_init_mode(base, ¶ms); if (status == kStatus_Success) { /* Read the data from the result register into place. */ cau3_pkha_read_reg(base, kCAU3_PKHA_RegB, 1, result->X, size); cau3_pkha_read_reg(base, kCAU3_PKHA_RegB, 2, result->Y, size); } cau3_clear_all(base, true); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return status; } status_t CAU3_PKHA_ECM_PointMul(CAU3_Type *base, const uint8_t *E, size_t sizeE, const uint8_t *inputCoordinate, const uint8_t *A24, const uint8_t *N, const uint8_t *R2modN, size_t size, cau3_pkha_timing_t equalTime, uint8_t *outputCoordinate) { cau3_pkha_mode_params_t params; uint32_t clearMask; status_t status; #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) status = cau3_lock_semaphore(base); if (kStatus_Success != status) { cau3_release_semaphore(base); return status; } #endif cau3_pkha_default_parms(¶ms); params.func = kCAU3_PKHA_ArithEcmMul; params.equalTime = equalTime; params.r2modn = R2modN ? kCAU3_PKHA_InputR2 : kCAU3_PKHA_CalcR2; clearMask = kCAU3_ClearMode; /* Clear internal register states. */ clearMask |= kCAU3_ClearPkhaSizeA; clearMask |= kCAU3_ClearPkhaSizeB; clearMask |= kCAU3_ClearPkhaSizeN; clearMask |= kCAU3_ClearPkhaSizeE; base->CW = clearMask; base->STA = kCAU3_StatusDoneIsr; cau3_pkha_clear_regabne(base, true, true, true, true); base->PKNSZ = size; cau3_pkha_write_reg(base, kCAU3_PKHA_RegN, 0, N, size); base->PKESZ = sizeE; cau3_pkha_write_reg(base, kCAU3_PKHA_RegE, 0, E, sizeE); base->PKASZ = size; cau3_pkha_write_reg(base, kCAU3_PKHA_RegA, 0, inputCoordinate, size); cau3_pkha_write_reg(base, kCAU3_PKHA_RegA, 3, A24, size); if (R2modN) { base->PKBSZ = size; cau3_pkha_write_reg(base, kCAU3_PKHA_RegB, 1, R2modN, size); } status = cau3_pkha_init_mode(base, ¶ms); if (status == kStatus_Success) { /* Read the data from the result register into place. */ cau3_pkha_read_reg(base, kCAU3_PKHA_RegB, 1, outputCoordinate, size); } cau3_clear_all(base, true); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return status; } status_t CAU3_PKHA_ECT_PointMul(CAU3_Type *base, const cau3_pkha_ecc_point_t *A, const uint8_t *E, size_t sizeE, const uint8_t *N, const uint8_t *R2modN, const uint8_t *aCurveParam, const uint8_t *dCurveParam, size_t size, cau3_pkha_timing_t equalTime, cau3_pkha_ecc_point_t *result) { cau3_pkha_mode_params_t params; uint32_t clearMask; status_t status; #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) status = cau3_lock_semaphore(base); if (kStatus_Success != status) { cau3_release_semaphore(base); return status; } #endif cau3_pkha_default_parms(¶ms); params.func = kCAU3_PKHA_ArithEctMul; params.equalTime = equalTime; params.r2modn = R2modN ? kCAU3_PKHA_InputR2 : kCAU3_PKHA_CalcR2; clearMask = kCAU3_ClearMode; /* Clear internal register states. */ clearMask |= kCAU3_ClearPkhaSizeA; clearMask |= kCAU3_ClearPkhaSizeB; clearMask |= kCAU3_ClearPkhaSizeN; clearMask |= kCAU3_ClearPkhaSizeE; base->CW = clearMask; base->STA = kCAU3_StatusDoneIsr; cau3_pkha_clear_regabne(base, true, true, true, true); base->PKNSZ = size; cau3_pkha_write_reg(base, kCAU3_PKHA_RegN, 0, N, size); base->PKESZ = sizeE; cau3_pkha_write_reg(base, kCAU3_PKHA_RegE, 0, E, sizeE); base->PKASZ = size; cau3_pkha_write_reg(base, kCAU3_PKHA_RegA, 0, A->X, size); cau3_pkha_write_reg(base, kCAU3_PKHA_RegA, 1, A->Y, size); cau3_pkha_write_reg(base, kCAU3_PKHA_RegA, 3, aCurveParam, size); base->PKBSZ = size; cau3_pkha_write_reg(base, kCAU3_PKHA_RegB, 0, dCurveParam, size); if (R2modN) { cau3_pkha_write_reg(base, kCAU3_PKHA_RegB, 1, R2modN, size); } status = cau3_pkha_init_mode(base, ¶ms); if (status == kStatus_Success) { /* Read the data from the result register into place. */ cau3_pkha_read_reg(base, kCAU3_PKHA_RegB, 1, result->X, size); cau3_pkha_read_reg(base, kCAU3_PKHA_RegB, 2, result->Y, size); } cau3_clear_all(base, true); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return status; } status_t CAU3_PKHA_ECT_PointAdd(CAU3_Type *base, const cau3_pkha_ecc_point_t *A, const cau3_pkha_ecc_point_t *B, const uint8_t *N, const uint8_t *R2modN, const uint8_t *aCurveParam, const uint8_t *dCurveParam, size_t size, cau3_pkha_ecc_point_t *result) { cau3_pkha_mode_params_t params; uint32_t clearMask; status_t status; #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) status = cau3_lock_semaphore(base); if (kStatus_Success != status) { cau3_release_semaphore(base); return status; } #endif cau3_pkha_default_parms(¶ms); params.func = kCAU3_PKHA_ArithEctAdd; params.r2modn = R2modN ? kCAU3_PKHA_InputR2 : kCAU3_PKHA_CalcR2; clearMask = kCAU3_ClearMode; /* Clear internal register states. */ clearMask |= kCAU3_ClearPkhaSizeA; clearMask |= kCAU3_ClearPkhaSizeB; clearMask |= kCAU3_ClearPkhaSizeN; clearMask |= kCAU3_ClearPkhaSizeE; base->CW = clearMask; base->STA = kCAU3_StatusDoneIsr; cau3_pkha_clear_regabne(base, true, true, true, false); /* sizeN should be less than 64 bytes. */ base->PKNSZ = size; cau3_pkha_write_reg(base, kCAU3_PKHA_RegN, 0, N, size); base->PKASZ = size; cau3_pkha_write_reg(base, kCAU3_PKHA_RegA, 0, A->X, size); cau3_pkha_write_reg(base, kCAU3_PKHA_RegA, 1, A->Y, size); cau3_pkha_write_reg(base, kCAU3_PKHA_RegA, 3, aCurveParam, size); base->PKBSZ = size; cau3_pkha_write_reg(base, kCAU3_PKHA_RegB, 0, dCurveParam, size); cau3_pkha_write_reg(base, kCAU3_PKHA_RegB, 1, B->X, size); cau3_pkha_write_reg(base, kCAU3_PKHA_RegB, 2, B->Y, size); if (R2modN) { cau3_pkha_write_reg(base, kCAU3_PKHA_RegB, 3, R2modN, size); } status = cau3_pkha_init_mode(base, ¶ms); if (status == kStatus_Success) { /* Read the data from the result register into place. */ cau3_pkha_read_reg(base, kCAU3_PKHA_RegB, 1, result->X, size); cau3_pkha_read_reg(base, kCAU3_PKHA_RegB, 2, result->Y, size); } cau3_clear_all(base, true); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return status; } status_t CAU3_TDES_CheckParity(CAU3_Type *base, cau3_key_slot_t keySlot) { status_t completionStatus; cau3_task_done_t taskDone; #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) completionStatus = cau3_lock_semaphore(base); if (kStatus_Success != completionStatus) { cau3_release_semaphore(base); return completionStatus; } #endif taskDone = kCAU3_TaskDonePoll; /* execute the cau3 "3des_check_parity" task */ base->CC_R[17] = keySlot; /* keySlot */ base->CC_R30 = CAU3_DMEM_STK_BASE; /* initialize stack pointer (sp) */ base->CC_R31 = 0U; /* set LR = 0 to signal a host task */ base->CC_PC = CAU3_TASK_3DES_CHECK_PARITY; /* call cau_3des_chk_parity() */ base->CC_CMD = taskDone; /* trigger cau3 execution */ /* process the cau3 task completion signal specified by taskDone */ completionStatus = cau3_process_task_completion(base, taskDone); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return (completionStatus); } status_t CAU3_TDES_SetKey(CAU3_Type *base, cau3_handle_t *handle, const uint8_t *key, size_t keySize) { /* only work with aligned key[] */ if (0x3U & (uintptr_t)key) { return kStatus_InvalidArgument; } /* keySize must be 24. */ if (keySize != 24U) { return kStatus_InvalidArgument; } return cau3_load_key(base, key, keySize, handle->keySlot, handle->taskDone); } status_t CAU3_TDES_Encrypt(CAU3_Type *base, cau3_handle_t *handle, const uint8_t *plaintext, uint8_t *ciphertext) { status_t completionStatus; #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) completionStatus = cau3_lock_semaphore(base); if (kStatus_Success != completionStatus) { cau3_release_semaphore(base); return completionStatus; } #endif /* execute the cau3 "3des_encrypt_ecb" task */ base->CC_R[16] = (uintptr_t)plaintext; /* pPlainText */ base->CC_R[17] = handle->keySlot; /* keySlot */ base->CC_R[19] = (uintptr_t)ciphertext; /* pCipherText */ base->CC_R30 = CAU3_DMEM_STK_BASE; /* initialize stack pointer (sp) */ base->CC_R31 = 0U; /* set LR = 0 to signal a host task */ base->CC_PC = CAU3_TASK_3DES_ENCRYPT; /* call cau_3des_encrypt() */ base->CC_CMD = handle->taskDone; /* trigger cau3 execution */ /* process the cau3 task completion signal specified by taskDone */ completionStatus = cau3_process_task_completion(base, handle->taskDone); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return (completionStatus); } status_t CAU3_TDES_Decrypt(CAU3_Type *base, cau3_handle_t *handle, const uint8_t *ciphertext, uint8_t *plaintext) { status_t completionStatus; #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) completionStatus = cau3_lock_semaphore(base); if (kStatus_Success != completionStatus) { cau3_release_semaphore(base); return completionStatus; } #endif /* execute the cau3 "3des_decrypt_ecb" task */ base->CC_R[16] = (uintptr_t)ciphertext; /* pCipherText */ base->CC_R[17] = handle->keySlot; /* keySlot */ base->CC_R[19] = (uintptr_t)plaintext; /* pPlainText */ base->CC_R30 = CAU3_DMEM_STK_BASE; /* initialize stack pointer (sp) */ base->CC_R31 = 0U; /* set LR = 0 to signal a host task */ base->CC_PC = CAU3_TASK_3DES_DECRYPT; /* call cau_3des_decrypt() */ base->CC_CMD = handle->taskDone; /* trigger cau3 execution */ /* process the cau3 task completion signal specified by taskDone */ completionStatus = cau3_process_task_completion(base, handle->taskDone); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return (completionStatus); } status_t CAU3_CHACHA20_POLY1305_SetKey(CAU3_Type *base, cau3_handle_t *handle, const uint8_t *key, size_t keySize) { /* only work with aligned key[] */ if (0x3U & (uintptr_t)key) { return kStatus_InvalidArgument; } /* keySize must be 32. */ if (keySize != 32U) { return kStatus_InvalidArgument; } union { uint8_t b[32]; uint32_t w[8]; } tempKey; for (int i = 0; i < ARRAY_SIZE(tempKey.w); i++) { tempKey.w[i] = __REV(((const uint32_t *)(uintptr_t)key)[i]); } return cau3_load_key(base, tempKey.b, keySize, handle->keySlot, handle->taskDone); } static status_t cau3_load_nonce(CAU3_Type *base, const uint8_t *nonce, cau3_key_slot_t keySlot) { #if defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #endif union { uint8_t b[16]; uint32_t w[4]; } tempIv; memset(&tempIv, 0, sizeof(tempIv)); /* set nonce to keySlot */ cau3_memcpy(tempIv.b, nonce, 12); /* swap bytes */ tempIv.w[0] = __REV(tempIv.w[0]); tempIv.w[1] = __REV(tempIv.w[1]); tempIv.w[2] = __REV(tempIv.w[2]); return CAU3_LoadKeyInitVector(base, tempIv.b, keySlot, kCAU3_TaskDonePoll); #if defined(__GNUC__) #pragma GCC diagnostic pop #endif } status_t CAU3_CHACHA20_POLY1305_Encrypt(CAU3_Type *base, cau3_handle_t *handle, const uint8_t *plaintext, uint8_t *ciphertext, size_t size, const uint8_t *aad, size_t aadLen, const uint8_t *nonce, uint8_t *tag) { status_t completionStatus; completionStatus = cau3_load_nonce(base, nonce, handle->keySlot); if (kStatus_Success != completionStatus) { return completionStatus; } #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) completionStatus = cau3_lock_semaphore(base); if (kStatus_Success != completionStatus) { cau3_release_semaphore(base); return completionStatus; } #endif base->CC_R[17] = handle->keySlot; /* key/iv slot */ base->CC_R[18] = (uintptr_t)aad; /* AAD pointer */ base->CC_R[19] = aadLen; /* AAD length (bytes) */ base->CC_R[20] = (uintptr_t)plaintext; /* Plaintext pointer */ base->CC_R[21] = size; /* Plaintext length */ base->CC_R[22] = (uintptr_t)ciphertext; /* Ciphertext pointer */ base->CC_R[23] = (uintptr_t)tag; /* Tag pointer */ base->CC_R30 = CAU3_DMEM_STK_BASE; /* initialize stack pointer (sp) */ base->CC_R31 = 0U; /* set LR = 0 to signal a host task */ base->CC_PC = CAU3_TASK_CHA_POLY_ENCRYPT; /* ChaChaPoly encrypt vector */ base->CC_CMD = handle->taskDone; /* trigger cau3 execution */ /* process the cau3 task completion signal specified by taskDone */ completionStatus = cau3_process_task_completion(base, handle->taskDone); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return (completionStatus); } status_t CAU3_CHACHA20_POLY1305_Decrypt(CAU3_Type *base, cau3_handle_t *handle, const uint8_t *ciphertext, uint8_t *plaintext, size_t size, const uint8_t *aad, size_t aadLen, const uint8_t *nonce, const uint8_t *tag) { status_t completionStatus; completionStatus = cau3_load_nonce(base, nonce, handle->keySlot); if (kStatus_Success != completionStatus) { return completionStatus; } #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) completionStatus = cau3_lock_semaphore(base); if (kStatus_Success != completionStatus) { cau3_release_semaphore(base); return completionStatus; } #endif base->CC_R[17] = handle->keySlot; /* key/iv slot */ base->CC_R[18] = (uintptr_t)aad; /* AAD pointer */ base->CC_R[19] = aadLen; /* AAD length (bytes) */ base->CC_R[20] = (uintptr_t)ciphertext; /* Ciphertext pointer */ base->CC_R[21] = size; /* Cyphertext length */ base->CC_R[22] = (uintptr_t)plaintext; /* Plaintext pointer */ base->CC_R[23] = (uintptr_t)tag; /* Tag pointer */ base->CC_R30 = CAU3_DMEM_STK_BASE; /* initialize stack pointer (sp) */ base->CC_R31 = 0U; /* set LR = 0 to signal a host task */ base->CC_PC = CAU3_TASK_CHA_POLY_DECRYPT; /* ChaChaPoly decrypt vector */ base->CC_CMD = handle->taskDone; /* trigger cau3 execution */ /* process the cau3 task completion signal specified by taskDone */ completionStatus = cau3_process_task_completion(base, handle->taskDone); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return (completionStatus); } status_t CAU3_KeyBlobUnwrap(CAU3_Type *base, cau3_key_slot_t keySlot, const uint8_t *keyBlob, uint32_t numberOfBlocks, cau3_key_slot_t dstContext) { status_t completionStatus; cau3_task_done_t taskDone; if (0x3U & (uintptr_t)keyBlob) { return kStatus_InvalidArgument; } #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) completionStatus = cau3_lock_semaphore(base); if (kStatus_Success != completionStatus) { cau3_release_semaphore(base); return completionStatus; } #endif taskDone = kCAU3_TaskDonePoll; /* execute the cau3 "key blob unwrap" task */ base->CC_R[16] = (uintptr_t)keyBlob; /* pKeyBlob */ base->CC_R[17] = keySlot; /* keySlot */ base->CC_R[18] = numberOfBlocks; /* numberOfBlocks */ base->CC_R[19] = dstContext; /* destination key context */ base->CC_R30 = CAU3_DMEM_STK_BASE; /* initialize stack pointer (sp) */ base->CC_R31 = 0U; /* set LR = 0 to signal a host task */ base->CC_PC = CAU3_TASK_KEY_BLOB_UNWRAP; /* call cau_key_blob_unwrap() */ base->CC_CMD = taskDone; /* trigger cau3 execution */ /* process the cau3 task completion signal specified by taskDone */ completionStatus = cau3_process_task_completion(base, taskDone); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return (completionStatus); } status_t CAU3_RPAtableInit(CAU3_Type *base, cau3_task_done_t taskDone) { status_t completionStatus; base->CC_R[16] = 1U; /* initialize the RPA table */ base->CC_R30 = CAU3_DMEM_STK_BASE; /* initialize stack pointer (sp) */ base->CC_R31 = 0U; /* set LR = 0 to signal a host task */ base->CC_PC = CAU3_TASK_RPA_TABLE_SIZE; /* call cau_rpa_insert_key() */ base->CC_CMD = taskDone; /* trigger cau3 execution */ /* process the cau3 task completion signal specified by taskDone */ completionStatus = cau3_process_task_completion(base, taskDone); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return (completionStatus); } status_t CAU3_RPAtableSize(CAU3_Type *base, uint32_t *result) { status_t completionStatus; /* execute the cau3 "rpa table size" task */ base->CC_R[16] = 0U; /* do not initialize the RPA table */ base->CC_R30 = CAU3_DMEM_STK_BASE; /* initialize stack pointer (sp) */ base->CC_PC = CAU3_TASK_RPA_TABLE_SIZE; /* call cau_rpa_table_size */ /* this is a simple/fast task, hence the task completion signal can be polled */ base->CC_CMD = kCAU3_TaskDonePoll; completionStatus = cau3_process_task_completion(base, kCAU3_TaskDonePoll); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif *result = ((completionStatus == kStatus_Success) ? (uint32_t)base->CC_R[17] : 0); return (completionStatus); } status_t CAU3_RPAtableInsertKey(CAU3_Type *base, const uint32_t *cauKey, cau3_task_done_t taskDone) { status_t completionStatus; base->CC_R[16] = (uintptr_t)cauKey; /* pointer to the key */ base->CC_R30 = CAU3_DMEM_STK_BASE; /* initialize stack pointer (sp) */ base->CC_R31 = 0U; /* set LR = 0 to signal a host task */ base->CC_PC = CAU3_TASK_RPA_INSERT_KEY; /* call cau_rpa_insert_key() */ base->CC_CMD = taskDone; /* trigger cau3 execution */ /* process the cau3 task completion signal specified by taskDone */ completionStatus = cau3_process_task_completion(base, taskDone); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return (completionStatus); } status_t CAU3_RPAtableRemoveKey(CAU3_Type *base, uint32_t irkIx, cau3_task_done_t taskDone) { status_t completionStatus; base->CC_R[16] = irkIx; /* IRK index */ base->CC_R30 = CAU3_DMEM_STK_BASE; /* initialize stack pointer (sp) */ base->CC_R31 = 0U; /* set LR = 0 to signal a host task */ base->CC_PC = CAU3_TASK_RPA_REMOVE_KEY; /* call cau_rpa_remove_key() */ base->CC_CMD = taskDone; /* trigger cau3 execution */ /* process the cau3 task completion signal specified by taskDone */ completionStatus = cau3_process_task_completion(base, taskDone); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif return (completionStatus); } status_t CAU3_RPAtableSearch(CAU3_Type *base, const uint32_t prand, const uint32_t hash, uint32_t *result, cau3_task_done_t taskDone) { status_t completionStatus; base->CC_R[16] = prand; /* PRAND value */ base->CC_R[17] = hash; /* hash value */ base->CC_R30 = CAU3_DMEM_STK_BASE; /* initialize stack pointer (sp) */ base->CC_R31 = 0U; /* set LR = 0 to signal a host task */ base->CC_PC = CAU3_TASK_RPA_TABLE_SEARCH; /* call cau_rpa_search() */ base->CC_CMD = taskDone; /* trigger cau3 execution */ /* process the cau3 task completion signal specified by taskDone */ completionStatus = cau3_process_task_completion(base, taskDone); #if defined(FSL_CAU3_USE_HW_SEMA) && (FSL_CAU3_USE_HW_SEMA > 0) cau3_release_semaphore(base); #endif *result = ((completionStatus == kStatus_Success) ? (uint32_t)base->CC_R[18] : 0xFF); return (completionStatus); }