diff --git a/efm32/.cproject b/efm32/.cproject index 02bf5c0..62ccd51 100644 --- a/efm32/.cproject +++ b/efm32/.cproject @@ -23,7 +23,7 @@ - + @@ -37,28 +37,37 @@ - + @@ -74,13 +83,15 @@ - - - - - + + + + + + + - + - + @@ -138,7 +149,7 @@ - + @@ -157,12 +168,12 @@ @@ -174,12 +185,12 @@ - + - + diff --git a/efm32/EFM32.hwconf b/efm32/EFM32.hwconf index 4915d0a..a1d92ca 100644 --- a/efm32/EFM32.hwconf +++ b/efm32/EFM32.hwconf @@ -7,9 +7,11 @@ + + diff --git a/efm32/emlib/em_crypto.c b/efm32/emlib/em_crypto.c new file mode 100644 index 0000000..61f5bc9 --- /dev/null +++ b/efm32/emlib/em_crypto.c @@ -0,0 +1,1822 @@ +/***************************************************************************//** + * @file em_crypto.c + * @brief Cryptography accelerator peripheral API + * @version 5.2.2 + ******************************************************************************* + * # License + * Copyright 2016 Silicon Laboratories, Inc. http://www.silabs.com + ******************************************************************************* + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software.@n + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software.@n + * 3. This notice may not be removed or altered from any source distribution. + * + * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Labs has no + * obligation to support this Software. Silicon Labs is providing the + * Software "AS IS", with no express or implied warranties of any kind, + * including, but not limited to, any implied warranties of merchantability + * or fitness for any particular purpose or warranties against infringement + * of any proprietary rights of a third party. + * + * Silicon Labs will not be liable for any consequential, incidental, or + * special damages, or any other relief, or for any claim by any third party, + * arising from your use of this Software. + * + ******************************************************************************/ +#include "em_device.h" + +#if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) + +#include "em_crypto.h" +#include "em_assert.h" + +/***************************************************************************//** + * @addtogroup emlib + * @{ + ******************************************************************************/ + +/***************************************************************************//** + * @addtogroup CRYPTO + * @{ + ******************************************************************************/ + +/******************************************************************************* + ******************************* DEFINES *********************************** + ******************************************************************************/ + +/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */ + +#define CRYPTO_INSTRUCTIONS_PER_REG (4) +#define CRYPTO_INSTRUCTIONS_MAX (12) +#define CRYPTO_INSTRUCTION_REGS (CRYPTO_INSTRUCTIONS_MAX / CRYPTO_INSTRUCTIONS_PER_REG) + +#define CRYPTO_SHA1_BLOCK_SIZE_IN_BITS (512) +#define CRYPTO_SHA1_BLOCK_SIZE_IN_BYTES (CRYPTO_SHA1_BLOCK_SIZE_IN_BITS / 8) +#define CRYPTO_SHA1_BLOCK_SIZE_IN_32BIT_WORDS (CRYPTO_SHA1_BLOCK_SIZE_IN_BYTES / sizeof(uint32_t)) +#define CRYPTO_SHA1_DIGEST_SIZE_IN_32BIT_WORDS (CRYPTO_SHA1_DIGEST_SIZE_IN_BYTES / sizeof(uint32_t)) + +#define CRYPTO_SHA256_BLOCK_SIZE_IN_BITS (512) +#define CRYPTO_SHA256_BLOCK_SIZE_IN_BYTES (CRYPTO_SHA256_BLOCK_SIZE_IN_BITS / 8) +#define CRYPTO_SHA256_BLOCK_SIZE_IN_32BIT_WORDS (CRYPTO_SHA256_BLOCK_SIZE_IN_BYTES / sizeof(uint32_t)) + +#define CRYPTO_SHA256_DIGEST_SIZE_IN_32BIT_WORDS (CRYPTO_SHA256_DIGEST_SIZE_IN_BYTES / sizeof(uint32_t)) + +#define PARTIAL_OPERAND_WIDTH_LOG2 (7) /* 2^7 = 128 */ +#define PARTIAL_OPERAND_WIDTH (1 << PARTIAL_OPERAND_WIDTH_LOG2) +#define PARTIAL_OPERAND_WIDTH_MASK (PARTIAL_OPERAND_WIDTH - 1) +#define PARTIAL_OPERAND_WIDTH_IN_BYTES (PARTIAL_OPERAND_WIDTH / 8) +#define PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS (PARTIAL_OPERAND_WIDTH_IN_BYTES / sizeof(uint32_t)) + +#define SWAP32(x) (__REV(x)) + +#define CRYPTO_AES_BLOCKSIZE (16) + +/******************************************************************************* + *********************** STATIC FUNCTIONS ********************************** + ******************************************************************************/ + +static inline void CRYPTO_AES_ProcessLoop(CRYPTO_TypeDef *crypto, + uint32_t len, + CRYPTO_DataReg_TypeDef inReg, + uint32_t * in, + CRYPTO_DataReg_TypeDef outReg, + uint32_t * out); + +static void CRYPTO_AES_CBCx(CRYPTO_TypeDef *crypto, + uint8_t * out, + const uint8_t * in, + unsigned int len, + const uint8_t * key, + const uint8_t * iv, + bool encrypt, + CRYPTO_KeyWidth_TypeDef keyWidth); + +static void CRYPTO_AES_CFBx(CRYPTO_TypeDef *crypto, + uint8_t * out, + const uint8_t * in, + unsigned int len, + const uint8_t * key, + const uint8_t * iv, + bool encrypt, + CRYPTO_KeyWidth_TypeDef keyWidth); + +static void CRYPTO_AES_CTRx(CRYPTO_TypeDef *crypto, + uint8_t * out, + const uint8_t * in, + unsigned int len, + const uint8_t * key, + uint8_t * ctr, + CRYPTO_AES_CtrFuncPtr_TypeDef ctrFunc, + CRYPTO_KeyWidth_TypeDef keyWidth); + +static void CRYPTO_AES_ECBx(CRYPTO_TypeDef *crypto, + uint8_t * out, + const uint8_t * in, + unsigned int len, + const uint8_t * key, + bool encrypt, + CRYPTO_KeyWidth_TypeDef keyWidth); + +static void CRYPTO_AES_OFBx(CRYPTO_TypeDef *crypto, + uint8_t * out, + const uint8_t * in, + unsigned int len, + const uint8_t * key, + const uint8_t * iv, + CRYPTO_KeyWidth_TypeDef keyWidth); + +#ifdef USE_VARIABLE_SIZED_DATA_LOADS +/***************************************************************************//** + * @brief + * Write variable sized 32 bit data array (max 128 bits) to a DATAX register + * + * @details + * Write variable sized 32 bit array (max 128 bits / 4 words) to a DATAX + * register in the CRYPTO module. + * + * @param[in] dataReg The 128 bits DATA register. + * @param[in] val Value of the data to write to the DATA register. + * @param[in] valSize Size of @ref val in number of 32bit words. + ******************************************************************************/ +__STATIC_INLINE +void CRYPTO_DataWriteVariableSize(CRYPTO_DataReg_TypeDef dataReg, + const CRYPTO_Data_TypeDef val, + int valSize) +{ + int i; + volatile uint32_t * reg = (volatile uint32_t *) dataReg; + + if (valSize < 4) { + /* Non optimal write of data. */ + for (i = 0; i < valSize; i++) { + *reg = *val++; + } + for (; i < 4; i++) { + *reg = 0; + } + } else { + CRYPTO_BurstToCrypto(reg, &val[0]); + } +} +#endif + +/** @endcond */ + +/******************************************************************************* + ************************** GLOBAL FUNCTIONS ******************************* + ******************************************************************************/ + +/***************************************************************************//** + * @brief + * Set the modulus used for wide modular operations. + * + * @details + * This function sets the modulus to be used by the modular instructions + * of the CRYPTO module. + * + * @param[in] crypto + * Pointer to CRYPTO peripheral register block. + * + * @param[in] modulusId + * Modulus identifier. + ******************************************************************************/ +void CRYPTO_ModulusSet(CRYPTO_TypeDef * crypto, + CRYPTO_ModulusId_TypeDef modulusId) +{ + uint32_t temp = crypto->WAC & (~(_CRYPTO_WAC_MODULUS_MASK | _CRYPTO_WAC_MODOP_MASK)); + + switch (modulusId) { + case cryptoModulusBin256: + case cryptoModulusBin128: + case cryptoModulusGcmBin128: + case cryptoModulusEccB233: + case cryptoModulusEccB163: +#ifdef _CRYPTO_WAC_MODULUS_ECCBIN233N + case cryptoModulusEccB233Order: + case cryptoModulusEccB233KOrder: + case cryptoModulusEccB163Order: + case cryptoModulusEccB163KOrder: +#endif + crypto->WAC = temp | modulusId | CRYPTO_WAC_MODOP_BINARY; + break; + + case cryptoModulusEccP256: + case cryptoModulusEccP224: + case cryptoModulusEccP192: +#ifdef _CRYPTO_WAC_MODULUS_ECCPRIME256P + case cryptoModulusEccP256Order: + case cryptoModulusEccP224Order: + case cryptoModulusEccP192Order: +#endif + crypto->WAC = temp | modulusId | CRYPTO_WAC_MODOP_REGULAR; + break; + + default: + /* Unknown modulus identifier. */ + EFM_ASSERT(0); + } +} + +/***************************************************************************//** + * @brief + * Read the key value currently used by the CRYPTO module. + * + * @details + * Read 128 bits or 256 bits from KEY register in the CRYPTO module. + * + * @param[in] crypto + * Pointer to CRYPTO peripheral register block. + * + * @param[in] val + * Value of the data to write to the KEYBUF register. + * + * @param[in] keyWidth + * Key width - 128 or 256 bits + ******************************************************************************/ +void CRYPTO_KeyRead(CRYPTO_TypeDef * crypto, + CRYPTO_KeyBuf_TypeDef val, + CRYPTO_KeyWidth_TypeDef keyWidth) +{ + EFM_ASSERT(val); + + CRYPTO_BurstFromCrypto(&crypto->KEY, &val[0]); + if (keyWidth == cryptoKey256Bits) { + CRYPTO_BurstFromCrypto(&crypto->KEY, &val[4]); + } +} + +/***************************************************************************//** + * @brief + * Perform a SHA-1 hash operation on a message. + * + * @details + * This function performs a SHA-1 hash operation on the message specified by + * msg with length msgLen, and returns the message digest in msgDigest. + * + * @param[in] crypto + * Pointer to CRYPTO peripheral register block. + * + * @param[in] msg + * Message to hash. + * + * @param[in] msgLen + * Length of message in bytes. + * + * @param[out] msgDigest + * Message digest. + ******************************************************************************/ +void CRYPTO_SHA_1(CRYPTO_TypeDef * crypto, + const uint8_t * msg, + uint64_t msgLen, + CRYPTO_SHA1_Digest_TypeDef msgDigest) +{ + uint32_t temp; + uint32_t len; + int blockLen; + uint32_t shaBlock[CRYPTO_SHA1_BLOCK_SIZE_IN_32BIT_WORDS] = + { + /* Initial value */ + 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 + }; + uint8_t * p8ShaBlock = (uint8_t *) shaBlock; + + /* Initialize crypto module to do SHA-1. */ + crypto->CTRL = CRYPTO_CTRL_SHA_SHA1; + crypto->SEQCTRL = 0; + crypto->SEQCTRLB = 0; + + /* Set result width of MADD32 operation. */ + CRYPTO_ResultWidthSet(crypto, cryptoResult256Bits); + + /* Write init value to DDATA1. */ + CRYPTO_DDataWrite(&crypto->DDATA1, shaBlock); + + /* Copy data to DDATA0 and select DDATA0 and DDATA1 for SHA operation. */ + CRYPTO_EXECUTE_2(crypto, + CRYPTO_CMD_INSTR_DDATA1TODDATA0, + CRYPTO_CMD_INSTR_SELDDATA0DDATA1); + + len = msgLen; + + while (len >= CRYPTO_SHA1_BLOCK_SIZE_IN_BYTES) { + /* Write block to QDATA1. */ + CRYPTO_QDataWrite(&crypto->QDATA1BIG, (uint32_t *) msg); + + /* Execute SHA */ + CRYPTO_EXECUTE_3(crypto, + CRYPTO_CMD_INSTR_SHA, + CRYPTO_CMD_INSTR_MADD32, + CRYPTO_CMD_INSTR_DDATA0TODDATA1); + + len -= CRYPTO_SHA1_BLOCK_SIZE_IN_BYTES; + msg += CRYPTO_SHA1_BLOCK_SIZE_IN_BYTES; + } + + blockLen = 0; + + /* Build the last (or second to last) block */ + for (; len; len--) { + p8ShaBlock[blockLen++] = *msg++; + } + + /* append the '1' bit */ + p8ShaBlock[blockLen++] = 0x80; + + /* if the length is currently above 56 bytes we append zeros + * then compress. Then we can fall back to padding zeros and length + * encoding like normal. + */ + if (blockLen > 56) { + while (blockLen < 64) + p8ShaBlock[blockLen++] = 0; + + /* Write block to QDATA1BIG. */ + CRYPTO_QDataWrite(&crypto->QDATA1BIG, shaBlock); + + /* Execute SHA */ + CRYPTO_EXECUTE_3(crypto, + CRYPTO_CMD_INSTR_SHA, + CRYPTO_CMD_INSTR_MADD32, + CRYPTO_CMD_INSTR_DDATA0TODDATA1); + blockLen = 0; + } + + /* pad upto 56 bytes of zeroes */ + while (blockLen < 56) + p8ShaBlock[blockLen++] = 0; + + /* And finally, encode the message length. */ + { + uint64_t msgLenInBits = msgLen << 3; + temp = msgLenInBits >> 32; + *(uint32_t*)&p8ShaBlock[56] = SWAP32(temp); + temp = msgLenInBits & 0xFFFFFFFF; + *(uint32_t*)&p8ShaBlock[60] = SWAP32(temp); + } + + /* Write block to QDATA1BIG. */ + CRYPTO_QDataWrite(&crypto->QDATA1BIG, shaBlock); + + /* Execute SHA */ + CRYPTO_EXECUTE_3(crypto, + CRYPTO_CMD_INSTR_SHA, + CRYPTO_CMD_INSTR_MADD32, + CRYPTO_CMD_INSTR_DDATA0TODDATA1); + + /* Read resulting message digest from DDATA0BIG. */ + ((uint32_t*)msgDigest)[0] = crypto->DDATA0BIG; + ((uint32_t*)msgDigest)[1] = crypto->DDATA0BIG; + ((uint32_t*)msgDigest)[2] = crypto->DDATA0BIG; + ((uint32_t*)msgDigest)[3] = crypto->DDATA0BIG; + ((uint32_t*)msgDigest)[4] = crypto->DDATA0BIG; + temp = crypto->DDATA0BIG; + temp = crypto->DDATA0BIG; + temp = crypto->DDATA0BIG; +} + +/***************************************************************************//** + * @brief + * Perform a SHA-256 hash operation on a message. + * + * @details + * This function performs a SHA-256 hash operation on the message specified + * by msg with length msgLen, and returns the message digest in msgDigest. + * + * @param[in] crypto + * Pointer to CRYPTO peripheral register block. + * + * @param[in] msg + * Message to hash. + * + * @param[in] msgLen + * Length of message in bytes. + * + * @param[out] msgDigest + * Message digest. + ******************************************************************************/ +void CRYPTO_SHA_256(CRYPTO_TypeDef * crypto, + const uint8_t * msg, + uint64_t msgLen, + CRYPTO_SHA256_Digest_TypeDef msgDigest) +{ + uint32_t temp; + uint32_t len; + int blockLen; + uint32_t shaBlock[CRYPTO_SHA256_BLOCK_SIZE_IN_32BIT_WORDS] = + { + /* Initial value */ + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 + }; + uint8_t * p8ShaBlock = (uint8_t *) shaBlock; + + /* Initialize crypyo module to do SHA-256 (SHA-2). */ + crypto->CTRL = CRYPTO_CTRL_SHA_SHA2; + crypto->SEQCTRL = 0; + crypto->SEQCTRLB = 0; + + /* Set result width of MADD32 operation. */ + CRYPTO_ResultWidthSet(crypto, cryptoResult256Bits); + + /* Write init value to DDATA1. */ + CRYPTO_DDataWrite(&crypto->DDATA1, shaBlock); + + /* Copy data ot DDATA0 and select DDATA0 and DDATA1 for SHA operation. */ + CRYPTO_EXECUTE_2(crypto, + CRYPTO_CMD_INSTR_DDATA1TODDATA0, + CRYPTO_CMD_INSTR_SELDDATA0DDATA1); + len = msgLen; + + while (len >= CRYPTO_SHA256_BLOCK_SIZE_IN_BYTES) { + /* Write block to QDATA1BIG. */ + CRYPTO_QDataWrite(&crypto->QDATA1BIG, (uint32_t *) msg); + + /* Execute SHA */ + CRYPTO_EXECUTE_3(crypto, + CRYPTO_CMD_INSTR_SHA, + CRYPTO_CMD_INSTR_MADD32, + CRYPTO_CMD_INSTR_DDATA0TODDATA1); + + len -= CRYPTO_SHA256_BLOCK_SIZE_IN_BYTES; + msg += CRYPTO_SHA256_BLOCK_SIZE_IN_BYTES; + } + + blockLen = 0; + + /* Build the last (or second to last) block */ + for (; len; len--) { + p8ShaBlock[blockLen++] = *msg++; + } + + /* append the '1' bit */ + p8ShaBlock[blockLen++] = 0x80; + + /* if the length is currently above 56 bytes we append zeros + * then compress. Then we can fall back to padding zeros and length + * encoding like normal. + */ + if (blockLen > 56) { + while (blockLen < 64) + p8ShaBlock[blockLen++] = 0; + + /* Write block to QDATA1BIG. */ + CRYPTO_QDataWrite(&crypto->QDATA1BIG, shaBlock); + + /* Execute SHA */ + CRYPTO_EXECUTE_3(crypto, + CRYPTO_CMD_INSTR_SHA, + CRYPTO_CMD_INSTR_MADD32, + CRYPTO_CMD_INSTR_DDATA0TODDATA1); + blockLen = 0; + } + + /* Pad upto 56 bytes of zeroes */ + while (blockLen < 56) + p8ShaBlock[blockLen++] = 0; + + /* And finally, encode the message length. */ + { + uint64_t msgLenInBits = msgLen << 3; + temp = msgLenInBits >> 32; + *(uint32_t *)&p8ShaBlock[56] = SWAP32(temp); + temp = msgLenInBits & 0xFFFFFFFF; + *(uint32_t *)&p8ShaBlock[60] = SWAP32(temp); + } + + /* Write the final block to QDATA1BIG. */ + CRYPTO_QDataWrite(&crypto->QDATA1BIG, shaBlock); + + /* Execute SHA */ + CRYPTO_EXECUTE_3(crypto, + CRYPTO_CMD_INSTR_SHA, + CRYPTO_CMD_INSTR_MADD32, + CRYPTO_CMD_INSTR_DDATA0TODDATA1); + + /* Read resulting message digest from DDATA0BIG. */ + CRYPTO_DDataRead(&crypto->DDATA0BIG, (uint32_t *)msgDigest); +} + +/***************************************************************************//** + * @brief + * Set 32bit word array to zero. + * + * @param[in] words32bits Pointer to 32bit word array + * @param[in] num32bitWords Number of 32bit words in array + ******************************************************************************/ +__STATIC_INLINE void cryptoBigintZeroize(uint32_t * words32bits, + int num32bitWords) +{ + while (num32bitWords--) + *words32bits++ = 0; +} + +/***************************************************************************//** + * @brief + * Increment value of 32bit word array by one. + * + * @param[in] words32bits Pointer to 32bit word array + * @param[in] num32bitWords Number of 32bit words in array + ******************************************************************************/ +__STATIC_INLINE void cryptoBigintIncrement(uint32_t * words32bits, + int num32bitWords) +{ + int i; + for (i = 0; i < num32bitWords; i++) { + if (++words32bits[i] != 0) { + break; + } + } + return; +} + +/***************************************************************************//** + * @brief + * Multiply two big integers. + * + * @details + * This function uses the CRYPTO unit to multiply two big integer operands. + * If USE_VARIABLE_SIZED_DATA_LOADS is defined, the sizes of the operands + * may be any multiple of 32 bits. If USE_VARIABLE_SIZED_DATA_LOADS is _not_ + * defined, the sizes of the operands must be a multiple of 128 bits. + * + * @param[in] A operand A + * @param[in] aSize size of operand A in bits + * @param[in] B operand B + * @param[in] bSize size of operand B in bits + * @param[out] R result of multiplication + * @param[in] rSize size of result buffer R in bits + ******************************************************************************/ +void CRYPTO_Mul(CRYPTO_TypeDef * crypto, + uint32_t * A, int aSize, + uint32_t * B, int bSize, + uint32_t * R, int rSize) +{ + int i, j; + + /**************** Initializations ******************/ + +#ifdef USE_VARIABLE_SIZED_DATA_LOADS + int numWordsLastOperandA = (aSize & PARTIAL_OPERAND_WIDTH_MASK) >> 5; + int numPartialOperandsA = numWordsLastOperandA + ? (aSize >> PARTIAL_OPERAND_WIDTH_LOG2) + 1 + : aSize >> PARTIAL_OPERAND_WIDTH_LOG2; + int numWordsLastOperandB = (bSize & PARTIAL_OPERAND_WIDTH_MASK) >> 5; + int numPartialOperandsB = numWordsLastOperandB + ? (bSize >> PARTIAL_OPERAND_WIDTH_LOG2) + 1 + : bSize >> PARTIAL_OPERAND_WIDTH_LOG2; + int numWordsLastOperandR = (rSize & PARTIAL_OPERAND_WIDTH_MASK) >> 5; + int numPartialOperandsR = numWordsLastOperandR + ? (rSize >> PARTIAL_OPERAND_WIDTH_LOG2) + 1 + : rSize >> PARTIAL_OPERAND_WIDTH_LOG2; + EFM_ASSERT(numPartialOperandsA + numPartialOperandsB <= numPartialOperandsR); +#else + int numPartialOperandsA = aSize >> PARTIAL_OPERAND_WIDTH_LOG2; + int numPartialOperandsB = bSize >> PARTIAL_OPERAND_WIDTH_LOG2; + EFM_ASSERT((aSize & PARTIAL_OPERAND_WIDTH_MASK) == 0); + EFM_ASSERT((bSize & PARTIAL_OPERAND_WIDTH_MASK) == 0); +#endif + EFM_ASSERT(aSize + bSize <= rSize); + + /* Set R to zero. */ + cryptoBigintZeroize(R, rSize >> 5); + + /* Set multiplication width. */ + crypto->WAC = CRYPTO_WAC_MULWIDTH_MUL128 | CRYPTO_WAC_RESULTWIDTH_256BIT; + + /* Setup DMA request signalling in order for MCU to run in parallel with + CRYPTO instruction sequence execution, and prepare data loading which + can take place immediately when CRYPTO is ready inside the instruction + sequence. */ + crypto->CTRL = + CRYPTO_CTRL_DMA0RSEL_DATA0 | CRYPTO_CTRL_DMA0MODE_FULL + | CRYPTO_CTRL_DMA1RSEL_DATA1 | CRYPTO_CTRL_DMA1MODE_FULL; + + CRYPTO_EXECUTE_4(crypto, + CRYPTO_CMD_INSTR_CCLR, /* Carry = 0 */ + CRYPTO_CMD_INSTR_CLR, /* DDATA0 = 0 */ + /* clear result accumulation register */ + CRYPTO_CMD_INSTR_DDATA0TODDATA2, + CRYPTO_CMD_INSTR_SELDDATA1DDATA3); + /* + register map: + DDATA0: working register + DDATA1: B(j) + DDATA2: R(i+j+1) and R(i+j), combined with DMA entry for B(j) + DDATA3: A(i) + */ + + CRYPTO_SEQ_LOAD_10(crypto, + /* Temporarily load partial operand B(j) to DATA0. */ + /* R(i+j+1) is still in DATA1 */ + CRYPTO_CMD_INSTR_DMA0TODATA, + /* Move B(j) to DDATA1 */ + CRYPTO_CMD_INSTR_DDATA2TODDATA1, + + /* Restore previous partial result (now R(i+j)) */ + CRYPTO_CMD_INSTR_DATA1TODATA0, + + /* Load next partial result R(i+j+1) */ + CRYPTO_CMD_INSTR_DMA1TODATA, + + /* Execute partial multiplication A(i)inDDATA1 * B(j)inDDATA3*/ + CRYPTO_CMD_INSTR_MULO, + + /* Add the result to the previous partial result */ + /* AND take the previous carry value into account */ + /* at the right place (bit 128, ADDIC instruction */ + CRYPTO_CMD_INSTR_SELDDATA0DDATA2, + CRYPTO_CMD_INSTR_ADDIC, + + /* Save the new partial result (lower half) */ + CRYPTO_CMD_INSTR_DDATA0TODDATA2, + CRYPTO_CMD_INSTR_DATATODMA0, + /* Reset the operand selector for next*/ + CRYPTO_CMD_INSTR_SELDDATA2DDATA3 + ); + + /**************** End Initializations ******************/ + + for (i = 0; i < numPartialOperandsA; i++) { + /* Load partial operand #1 A>>(i*PARTIAL_OPERAND_WIDTH) to DDATA1. */ +#ifdef USE_VARIABLE_SIZED_DATA_LOADS + if ( (numWordsLastOperandA != 0) && (i == numPartialOperandsA - 1) ) { + CRYPTO_DataWriteVariableSize(&crypto->DATA2, + &A[i * PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS], + numWordsLastOperandA); + } else { + CRYPTO_DataWrite(&crypto->DATA2, &A[i * PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS]); + } +#else + CRYPTO_DataWrite(&crypto->DATA2, &A[i * PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS]); +#endif + + /* Load partial result in R>>(i*PARTIAL_OPERAND_WIDTH) to DATA1. */ +#ifdef USE_VARIABLE_SIZED_DATA_LOADS + if ( (numWordsLastOperandR != 0) && (i == numPartialOperandsR - 1) ) { + CRYPTO_DataWriteVariableSize(&crypto->DATA1, + &R[i * PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS], + numWordsLastOperandR); + } else { + CRYPTO_DataWrite(&crypto->DATA1, &R[i * PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS]); + } +#else + CRYPTO_DataWrite(&crypto->DATA1, &R[i * PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS]); +#endif + + /* Clear carry */ + crypto->CMD = CRYPTO_CMD_INSTR_CCLR; + + /* Setup number of sequence iterations and block size. */ + crypto->SEQCTRL = CRYPTO_SEQCTRL_BLOCKSIZE_16BYTES + | (PARTIAL_OPERAND_WIDTH_IN_BYTES * numPartialOperandsB); + + /* Execute the MULtiply instruction sequence. */ + CRYPTO_InstructionSequenceExecute(crypto); + + for (j = 0; j < numPartialOperandsB; j++) { + /* Load partial operand 2 B>>(j*`PARTIAL_OPERAND_WIDTH) to DDATA2 + (via DATA0). */ +#ifdef USE_VARIABLE_SIZED_DATA_LOADS + if ( (numWordsLastOperandB != 0) && (j == numPartialOperandsB - 1) ) { + CRYPTO_DataWriteVariableSize(&crypto->DATA0, + &B[j * PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS], + numWordsLastOperandB); + } else { + CRYPTO_DataWrite(&crypto->DATA0, + &B[j * PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS]); + } +#else + CRYPTO_DataWrite(&crypto->DATA0, + &B[j * PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS]); +#endif + + /* Load most significant partial result + R>>((i+j+1)*`PARTIAL_OPERAND_WIDTH) into DATA1. */ +#ifdef USE_VARIABLE_SIZED_DATA_LOADS + if ( (numWordsLastOperandR != 0) && ( (i + j + 1) == numPartialOperandsR - 1) ) { + CRYPTO_DataWriteVariableSize(&crypto->DATA1, + &R[(i + j + 1) * PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS], + numWordsLastOperandR); + } else { + CRYPTO_DataWrite(&crypto->DATA1, + &R[(i + j + 1) * PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS]); + } +#else + CRYPTO_DataWrite(&crypto->DATA1, + &R[(i + j + 1) * PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS]); +#endif + /* Store least significant partial result */ + CRYPTO_DataRead(&crypto->DATA0, + &R[(i + j) * PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS]); + } /* for (j=0; jDATA1, + &R[(i + numPartialOperandsB) + * PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS]); + } /* for (i=0; iXOR +-------------->XOR + * | | | + * V | V + * +--------------+ | +--------------+ + * Key ->| Block cipher | | Key ->| Block cipher | + * | encryption | | | encryption | + * +--------------+ | +--------------+ + * |---------+ | + * V V + * Ciphertext Ciphertext + * @endverbatim + * Decryption: + * @verbatim + * Ciphertext Ciphertext + * |----------+ | + * V | V + * +--------------+ | +--------------+ + * Key ->| Block cipher | | Key ->| Block cipher | + * | decryption | | | decryption | + * +--------------+ | +--------------+ + * | | | + * V | V + * InitVector ->XOR +-------------->XOR + * | | + * V V + * Plaintext Plaintext + * @endverbatim + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[in] crypto + * Pointer to CRYPTO peripheral register block. + * + * @param[out] out + * Buffer to place encrypted/decrypted data. Must be at least @p len long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + * + * @param[in] in + * Buffer holding data to encrypt/decrypt. Must be at least @p len long. + * + * @param[in] len + * Number of bytes to encrypt/decrypt. Must be a multiple of 16. + * + * @param[in] key + * When doing encryption, this is the 128 bit encryption key. When doing + * decryption, this is the 128 bit decryption key. The decryption key may + * be generated from the encryption key with CRYPTO_AES_DecryptKey128(). + * If this argument is null, the key will not be loaded, as it is assumed + * the key has been loaded into KEYHA previously. + * + * @param[in] iv + * 128 bit initialization vector to use. + * + * @param[in] encrypt + * Set to true to encrypt, false to decrypt. + ******************************************************************************/ +void CRYPTO_AES_CBC128(CRYPTO_TypeDef * crypto, + uint8_t * out, + const uint8_t * in, + unsigned int len, + const uint8_t * key, + const uint8_t * iv, + bool encrypt) +{ + crypto->CTRL = CRYPTO_CTRL_AES_AES128; + CRYPTO_AES_CBCx(crypto, out, in, len, key, iv, encrypt, cryptoKey128Bits); +} + +/***************************************************************************//** + * @brief + * AES Cipher-block chaining (CBC) cipher mode encryption/decryption, 256 bit + * key. + * + * @details + * Please see CRYPTO_AES_CBC128() for CBC figure. + * + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[in] crypto + * Pointer to CRYPTO peripheral register block. + * + * @param[out] out + * Buffer to place encrypted/decrypted data. Must be at least @p len long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + * + * @param[in] in + * Buffer holding data to encrypt/decrypt. Must be at least @p len long. + * + * @param[in] len + * Number of bytes to encrypt/decrypt. Must be a multiple of 16. + * + * @param[in] key + * When doing encryption, this is the 256 bit encryption key. When doing + * decryption, this is the 256 bit decryption key. The decryption key may + * be generated from the encryption key with CRYPTO_AES_DecryptKey256(). + * + * @param[in] iv + * 128 bit initialization vector to use. + * + * @param[in] encrypt + * Set to true to encrypt, false to decrypt. + ******************************************************************************/ +void CRYPTO_AES_CBC256(CRYPTO_TypeDef * crypto, + uint8_t * out, + const uint8_t * in, + unsigned int len, + const uint8_t * key, + const uint8_t * iv, + bool encrypt) +{ + crypto->CTRL = CRYPTO_CTRL_AES_AES256; + CRYPTO_AES_CBCx(crypto, out, in, len, key, iv, encrypt, cryptoKey256Bits); +} + +/***************************************************************************//** + * @brief + * AES Cipher feedback (CFB) cipher mode encryption/decryption, 128 bit key. + * + * @details + * Encryption: + * @verbatim + * InitVector +----------------+ + * | | | + * V | V + * +--------------+ | +--------------+ + * Key ->| Block cipher | | Key ->| Block cipher | + * | encryption | | | encryption | + * +--------------+ | +--------------+ + * | | | + * V | V + * Plaintext ->XOR | Plaintext ->XOR + * |---------+ | + * V V + * Ciphertext Ciphertext + * @endverbatim + * Decryption: + * @verbatim + * InitVector +----------------+ + * | | | + * V | V + * +--------------+ | +--------------+ + * Key ->| Block cipher | | Key ->| Block cipher | + * | encryption | | | encryption | + * +--------------+ | +--------------+ + * | | | + * V | V + * XOR<- Ciphertext XOR<- Ciphertext + * | | + * V V + * Plaintext Plaintext + * @endverbatim + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[in] crypto + * Pointer to CRYPTO peripheral register block. + * + * @param[out] out + * Buffer to place encrypted/decrypted data. Must be at least @p len long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + * + * @param[in] in + * Buffer holding data to encrypt/decrypt. Must be at least @p len long. + * + * @param[in] len + * Number of bytes to encrypt/decrypt. Must be a multiple of 16. + * + * @param[in] key + * 128 bit encryption key is used for both encryption and decryption modes. + * + * @param[in] iv + * 128 bit initialization vector to use. + * + * @param[in] encrypt + * Set to true to encrypt, false to decrypt. + ******************************************************************************/ +void CRYPTO_AES_CFB128(CRYPTO_TypeDef * crypto, + uint8_t * out, + const uint8_t * in, + unsigned int len, + const uint8_t * key, + const uint8_t * iv, + bool encrypt) +{ + crypto->CTRL = CRYPTO_CTRL_AES_AES128; + CRYPTO_AES_CFBx(crypto, out, in, len, key, iv, encrypt, cryptoKey128Bits); +} + +/***************************************************************************//** + * @brief + * AES Cipher feedback (CFB) cipher mode encryption/decryption, 256 bit key. + * + * @details + * Please see CRYPTO_AES_CFB128() for CFB figure. + * + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[in] crypto + * Pointer to CRYPTO peripheral register block. + * + * @param[out] out + * Buffer to place encrypted/decrypted data. Must be at least @p len long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + * + * @param[in] in + * Buffer holding data to encrypt/decrypt. Must be at least @p len long. + * + * @param[in] len + * Number of bytes to encrypt/decrypt. Must be a multiple of 16. + * + * @param[in] key + * 256 bit encryption key is used for both encryption and decryption modes. + * + * @param[in] iv + * 128 bit initialization vector to use. + * + * @param[in] encrypt + * Set to true to encrypt, false to decrypt. + ******************************************************************************/ +void CRYPTO_AES_CFB256(CRYPTO_TypeDef * crypto, + uint8_t * out, + const uint8_t * in, + unsigned int len, + const uint8_t * key, + const uint8_t * iv, + bool encrypt) +{ + crypto->CTRL = CRYPTO_CTRL_AES_AES256; + CRYPTO_AES_CFBx(crypto, out, in, len, key, iv, encrypt, cryptoKey256Bits); +} + +/***************************************************************************//** + * @brief + * AES Counter (CTR) cipher mode encryption/decryption, 128 bit key. + * + * @details + * Encryption: + * @verbatim + * Counter Counter + * | | + * V V + * +--------------+ +--------------+ + * Key ->| Block cipher | Key ->| Block cipher | + * | encryption | | encryption | + * +--------------+ +--------------+ + * | | + * Plaintext ->XOR Plaintext ->XOR + * | | + * V V + * Ciphertext Ciphertext + * @endverbatim + * Decryption: + * @verbatim + * Counter Counter + * | | + * V V + * +--------------+ +--------------+ + * Key ->| Block cipher | Key ->| Block cipher | + * | encryption | | encryption | + * +--------------+ +--------------+ + * | | + * Ciphertext ->XOR Ciphertext ->XOR + * | | + * V V + * Plaintext Plaintext + * @endverbatim + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[in] crypto + * Pointer to CRYPTO peripheral register block. + * + * @param[out] out + * Buffer to place encrypted/decrypted data. Must be at least @p len long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + * + * @param[in] in + * Buffer holding data to encrypt/decrypt. Must be at least @p len long. + * + * @param[in] len + * Number of bytes to encrypt/decrypt. Must be a multiple of 16. + * + * @param[in] key + * 128 bit encryption key. + * If this argument is null, the key will not be loaded, as it is assumed + * the key has been loaded into KEYHA previously. + * + * @param[in,out] ctr + * 128 bit initial counter value. The counter is updated after each AES + * block encoding through use of @p ctrFunc. + * + * @param[in] ctrFunc + * Function used to update counter value. Not supported by CRYPTO. + * This parameter is included in order for backwards compatibility with + * the EFM32 em_aes.h API. + ******************************************************************************/ +void CRYPTO_AES_CTR128(CRYPTO_TypeDef * crypto, + uint8_t * out, + const uint8_t * in, + unsigned int len, + const uint8_t * key, + uint8_t * ctr, + CRYPTO_AES_CtrFuncPtr_TypeDef ctrFunc) +{ + crypto->CTRL = CRYPTO_CTRL_AES_AES128; + CRYPTO_AES_CTRx(crypto, out, in, len, key, ctr, ctrFunc, cryptoKey128Bits); +} + +/***************************************************************************//** + * @brief + * AES Counter (CTR) cipher mode encryption/decryption, 256 bit key. + * + * @details + * Please see CRYPTO_AES_CTR128() for CTR figure. + * + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[in] crypto + * Pointer to CRYPTO peripheral register block. + * + * @param[out] out + * Buffer to place encrypted/decrypted data. Must be at least @p len long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + * + * @param[in] in + * Buffer holding data to encrypt/decrypt. Must be at least @p len long. + * + * @param[in] len + * Number of bytes to encrypt/decrypt. Must be a multiple of 16. + * + * @param[in] key + * 256 bit encryption key. + * + * @param[in,out] ctr + * 128 bit initial counter value. The counter is updated after each AES + * block encoding through use of @p ctrFunc. + * + * @param[in] ctrFunc + * Function used to update counter value. Not supported by CRYPTO. + * This parameter is included in order for backwards compatibility with + * the EFM32 em_aes.h API. + ******************************************************************************/ +void CRYPTO_AES_CTR256(CRYPTO_TypeDef * crypto, + uint8_t * out, + const uint8_t * in, + unsigned int len, + const uint8_t * key, + uint8_t * ctr, + CRYPTO_AES_CtrFuncPtr_TypeDef ctrFunc) +{ + crypto->CTRL = CRYPTO_CTRL_AES_AES256; + CRYPTO_AES_CTRx(crypto, out, in, len, key, ctr, ctrFunc, cryptoKey256Bits); +} + +/***************************************************************************//** + * @brief + * Update last 32 bits of 128 bit counter, by incrementing with 1. + * + * @details + * Notice that no special consideration is given to possible wrap around. If + * 32 least significant bits are 0xFFFFFFFF, they will be updated to 0x00000000, + * ignoring overflow. + * + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[in,out] ctr + * Buffer holding 128 bit counter to be updated. + ******************************************************************************/ +void CRYPTO_AES_CTRUpdate32Bit(uint8_t * ctr) +{ + uint32_t * _ctr = (uint32_t *) ctr; + + _ctr[3] = __REV(__REV(_ctr[3]) + 1); +} + +/***************************************************************************//** + * @brief + * Generate 128 bit AES decryption key from 128 bit encryption key. The + * decryption key is used for some cipher modes when decrypting. + * + * @details + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[in] crypto + * Pointer to CRYPTO peripheral register block. + * + * @param[out] out + * Buffer to place 128 bit decryption key. Must be at least 16 bytes long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + * + * @param[in] in + * Buffer holding 128 bit encryption key. Must be at least 16 bytes long. + ******************************************************************************/ +void CRYPTO_AES_DecryptKey128(CRYPTO_TypeDef * crypto, + uint8_t * out, + const uint8_t * in) +{ + uint32_t * _out = (uint32_t *) out; + const uint32_t * _in = (const uint32_t *) in; + + /* Setup CRYPTO in AES-128 mode. */ + crypto->CTRL = CRYPTO_CTRL_AES_AES128; + + /* Load key */ + CRYPTO_BurstToCrypto(&crypto->KEYBUF, &_in[0]); + + /* Do dummy encryption to generate decrypt key */ + crypto->CMD = CRYPTO_CMD_INSTR_AESENC; + + /* Save decryption key */ + CRYPTO_BurstFromCrypto(&crypto->KEY, &_out[0]); +} + +/***************************************************************************//** + * @brief + * Generate 256 bit AES decryption key from 256 bit encryption key. The + * decryption key is used for some cipher modes when decrypting. + * + * @details + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[in] crypto + * Pointer to CRYPTO peripheral register block. + * + * @param[out] out + * Buffer to place 256 bit decryption key. Must be at least 32 bytes long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + * + * @param[in] in + * Buffer holding 256 bit encryption key. Must be at least 32 bytes long. + ******************************************************************************/ +void CRYPTO_AES_DecryptKey256(CRYPTO_TypeDef * crypto, + uint8_t * out, + const uint8_t * in) +{ + uint32_t * _out = (uint32_t *) out; + const uint32_t * _in = (const uint32_t *) in; + + /* Setup CRYPTO in AES-256 mode. */ + crypto->CTRL = CRYPTO_CTRL_AES_AES256; + + /* Load key */ + CRYPTO_BurstToCrypto(&crypto->KEYBUF, &_in[0]); + CRYPTO_BurstToCrypto(&crypto->KEYBUF, &_in[4]); + + /* Do dummy encryption to generate decrypt key */ + crypto->CMD = CRYPTO_CMD_INSTR_AESENC; + + /* Save decryption key */ + CRYPTO_BurstFromCrypto(&crypto->KEY, &_out[0]); + CRYPTO_BurstFromCrypto(&crypto->KEY, &_out[4]); +} + +/***************************************************************************//** + * @brief + * AES Electronic Codebook (ECB) cipher mode encryption/decryption, + * 128 bit key. + * + * @details + * Encryption: + * @verbatim + * Plaintext Plaintext + * | | + * V V + * +--------------+ +--------------+ + * Key ->| Block cipher | Key ->| Block cipher | + * | encryption | | encryption | + * +--------------+ +--------------+ + * | | + * V V + * Ciphertext Ciphertext + * @endverbatim + * Decryption: + * @verbatim + * Ciphertext Ciphertext + * | | + * V V + * +--------------+ +--------------+ + * Key ->| Block cipher | Key ->| Block cipher | + * | decryption | | decryption | + * +--------------+ +--------------+ + * | | + * V V + * Plaintext Plaintext + * @endverbatim + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[in] crypto + * Pointer to CRYPTO peripheral register block. + * + * @param[out] out + * Buffer to place encrypted/decrypted data. Must be at least @p len long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + * + * @param[in] in + * Buffer holding data to encrypt/decrypt. Must be at least @p len long. + * + * @param[in] len + * Number of bytes to encrypt/decrypt. Must be a multiple of 16. + * + * @param[in] key + * When doing encryption, this is the 128 bit encryption key. When doing + * decryption, this is the 128 bit decryption key. The decryption key may + * be generated from the encryption key with CRYPTO_AES_DecryptKey128(). + * + * @param[in] encrypt + * Set to true to encrypt, false to decrypt. + ******************************************************************************/ +void CRYPTO_AES_ECB128(CRYPTO_TypeDef * crypto, + uint8_t * out, + const uint8_t * in, + unsigned int len, + const uint8_t * key, + bool encrypt) +{ + crypto->CTRL = CRYPTO_CTRL_AES_AES128; + CRYPTO_AES_ECBx(crypto, out, in, len, key, encrypt, cryptoKey128Bits); +} + +/***************************************************************************//** + * @brief + * AES Electronic Codebook (ECB) cipher mode encryption/decryption, + * 256 bit key. + * + * @details + * Please see CRYPTO_AES_ECB128() for ECB figure. + * + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[in] crypto + * Pointer to CRYPTO peripheral register block. + * + * @param[out] out + * Buffer to place encrypted/decrypted data. Must be at least @p len long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + * + * @param[in] in + * Buffer holding data to encrypt/decrypt. Must be at least @p len long. + * + * @param[in] len + * Number of bytes to encrypt/decrypt. Must be a multiple of 16. + * + * @param[in] key + * When doing encryption, this is the 256 bit encryption key. When doing + * decryption, this is the 256 bit decryption key. The decryption key may + * be generated from the encryption key with CRYPTO_AES_DecryptKey256(). + * + * @param[in] encrypt + * Set to true to encrypt, false to decrypt. + ******************************************************************************/ +void CRYPTO_AES_ECB256(CRYPTO_TypeDef * crypto, + uint8_t * out, + const uint8_t * in, + unsigned int len, + const uint8_t * key, + bool encrypt) +{ + crypto->CTRL = CRYPTO_CTRL_AES_AES256; + CRYPTO_AES_ECBx(crypto, out, in, len, key, encrypt, cryptoKey256Bits); +} + +/***************************************************************************//** + * @brief + * AES Output feedback (OFB) cipher mode encryption/decryption, 128 bit key. + * + * @details + * Encryption: + * @verbatim + * InitVector +----------------+ + * | | | + * V | V + * +--------------+ | +--------------+ + * Key ->| Block cipher | | Key ->| Block cipher | + * | encryption | | | encryption | + * +--------------+ | +--------------+ + * | | | + * |---------+ | + * V V + * Plaintext ->XOR Plaintext ->XOR + * | | + * V V + * Ciphertext Ciphertext + * @endverbatim + * Decryption: + * @verbatim + * InitVector +----------------+ + * | | | + * V | V + * +--------------+ | +--------------+ + * Key ->| Block cipher | | Key ->| Block cipher | + * | encryption | | | encryption | + * +--------------+ | +--------------+ + * | | | + * |---------+ | + * V V + * Ciphertext ->XOR Ciphertext ->XOR + * | | + * V V + * Plaintext Plaintext + * @endverbatim + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[in] crypto + * Pointer to CRYPTO peripheral register block. + * + * @param[out] out + * Buffer to place encrypted/decrypted data. Must be at least @p len long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + * + * @param[in] in + * Buffer holding data to encrypt/decrypt. Must be at least @p len long. + * + * @param[in] len + * Number of bytes to encrypt/decrypt. Must be a multiple of 16. + * + * @param[in] key + * 128 bit encryption key. + * + * @param[in] iv + * 128 bit initialization vector to use. + ******************************************************************************/ +void CRYPTO_AES_OFB128(CRYPTO_TypeDef * crypto, + uint8_t * out, + const uint8_t * in, + unsigned int len, + const uint8_t * key, + const uint8_t * iv) +{ + crypto->CTRL = CRYPTO_CTRL_AES_AES128; + CRYPTO_AES_OFBx(crypto, out, in, len, key, iv, cryptoKey128Bits); +} + +/***************************************************************************//** + * @brief + * AES Output feedback (OFB) cipher mode encryption/decryption, 256 bit key. + * + * @details + * Please see CRYPTO_AES_OFB128() for OFB figure. + * + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[in] crypto + * Pointer to CRYPTO peripheral register block. + * + * @param[out] out + * Buffer to place encrypted/decrypted data. Must be at least @p len long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + * + * @param[in] in + * Buffer holding data to encrypt/decrypt. Must be at least @p len long. + * + * @param[in] len + * Number of bytes to encrypt/decrypt. Must be a multiple of 16. + * + * @param[in] key + * 256 bit encryption key. + * + * @param[in] iv + * 128 bit initialization vector to use. + ******************************************************************************/ +void CRYPTO_AES_OFB256(CRYPTO_TypeDef * crypto, + uint8_t * out, + const uint8_t * in, + unsigned int len, + const uint8_t * key, + const uint8_t * iv) +{ + crypto->CTRL = CRYPTO_CTRL_AES_AES256; + CRYPTO_AES_OFBx(crypto, out, in, len, key, iv, cryptoKey256Bits); +} + +/******************************************************************************* + ************************** LOCAL FUNCTIONS ******************************* + ******************************************************************************/ + +/***************************************************************************//** + * @brief + * Cipher-block chaining (CBC) cipher mode encryption/decryption, 128/256 bit key. + * + * @details + * Please see CRYPTO_AES_CBC128() for CBC figure. + * + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[in] crypto + * Pointer to CRYPTO peripheral register block. + * + * @param[out] out + * Buffer to place encrypted/decrypted data. Must be at least @p len long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + * + * @param[in] in + * Buffer holding data to encrypt/decrypt. Must be at least @p len long. + * + * @param[in] len + * Number of bytes to encrypt/decrypt. Must be a multiple of 16. + * + * @param[in] key + * When doing encryption, this is the 256 bit encryption key. When doing + * decryption, this is the 256 bit decryption key. The decryption key may + * be generated from the encryption key with CRYPTO_AES_DecryptKey256(). + * + * @param[in] iv + * 128 bit initialization vector to use. + * + * @param[in] encrypt + * Set to true to encrypt, false to decrypt. + * + * @param[in] keyWidth + * Set to cryptoKey128Bits or cryptoKey256Bits. + ******************************************************************************/ +static void CRYPTO_AES_CBCx(CRYPTO_TypeDef * crypto, + uint8_t * out, + const uint8_t * in, + unsigned int len, + const uint8_t * key, + const uint8_t * iv, + bool encrypt, + CRYPTO_KeyWidth_TypeDef keyWidth) +{ + EFM_ASSERT(!(len % CRYPTO_AES_BLOCKSIZE)); + + /* Initialize control registers. */ + crypto->WAC = 0; + + CRYPTO_KeyBufWrite(crypto, (uint32_t *)key, keyWidth); + + if (encrypt) { + CRYPTO_DataWrite(&crypto->DATA0, (uint32_t *)iv); + + crypto->SEQ0 = CRYPTO_CMD_INSTR_DATA1TODATA0XOR << _CRYPTO_SEQ0_INSTR0_SHIFT + | CRYPTO_CMD_INSTR_AESENC << _CRYPTO_SEQ0_INSTR1_SHIFT; + + CRYPTO_AES_ProcessLoop(crypto, len, + &crypto->DATA1, (uint32_t *) in, + &crypto->DATA0, (uint32_t *) out); + } else { + CRYPTO_DataWrite(&crypto->DATA2, (uint32_t *) iv); + + crypto->SEQ0 = CRYPTO_CMD_INSTR_DATA1TODATA0 << _CRYPTO_SEQ0_INSTR0_SHIFT + | CRYPTO_CMD_INSTR_AESDEC << _CRYPTO_SEQ0_INSTR1_SHIFT + | CRYPTO_CMD_INSTR_DATA2TODATA0XOR << _CRYPTO_SEQ0_INSTR2_SHIFT + | CRYPTO_CMD_INSTR_DATA1TODATA2 << _CRYPTO_SEQ0_INSTR3_SHIFT; + + crypto->SEQ1 = 0; + + /* The following call is equivalent to the last call in the + 'if( encrypt )' branch. However moving this + call outside the conditional scope results in slightly poorer + performance for some compiler optimizations. */ + CRYPTO_AES_ProcessLoop(crypto, len, + &crypto->DATA1, (uint32_t *) in, + &crypto->DATA0, (uint32_t *) out); + } +} + +/***************************************************************************//** + * @brief + * Cipher feedback (CFB) cipher mode encryption/decryption, 128/256 bit key. + * + * @details + * Please see CRYPTO_AES_CFB128() for CFB figure. + * + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[in] crypto + * Pointer to CRYPTO peripheral register block. + * + * @param[out] out + * Buffer to place encrypted/decrypted data. Must be at least @p len long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + * + * @param[in] in + * Buffer holding data to encrypt/decrypt. Must be at least @p len long. + * + * @param[in] len + * Number of bytes to encrypt/decrypt. Must be a multiple of 16. + * + * @param[in] key + * 256 bit encryption key is used for both encryption and decryption modes. + * + * @param[in] iv + * 128 bit initialization vector to use. + * + * @param[in] encrypt + * Set to true to encrypt, false to decrypt. + * + * @param[in] keyWidth + * Set to cryptoKey128Bits or cryptoKey256Bits. + ******************************************************************************/ +static void CRYPTO_AES_CFBx(CRYPTO_TypeDef * crypto, + uint8_t * out, + const uint8_t * in, + unsigned int len, + const uint8_t * key, + const uint8_t * iv, + bool encrypt, + CRYPTO_KeyWidth_TypeDef keyWidth) +{ + EFM_ASSERT(!(len % CRYPTO_AES_BLOCKSIZE)); + + /* Initialize control registers. */ + crypto->WAC = 0; + + /* Load Key */ + CRYPTO_KeyBufWrite(crypto, (uint32_t *)key, keyWidth); + + /* Load instructions to CRYPTO sequencer. */ + if (encrypt) { + /* Load IV */ + CRYPTO_DataWrite(&crypto->DATA0, (uint32_t *)iv); + + crypto->SEQ0 = CRYPTO_CMD_INSTR_AESENC << _CRYPTO_SEQ0_INSTR0_SHIFT + | CRYPTO_CMD_INSTR_DATA1TODATA0XOR << _CRYPTO_SEQ0_INSTR1_SHIFT; + + CRYPTO_AES_ProcessLoop(crypto, len, + &crypto->DATA1, (uint32_t *)in, + &crypto->DATA0, (uint32_t *)out + ); + } else { + /* Load IV */ + CRYPTO_DataWrite(&crypto->DATA2, (uint32_t *)iv); + + crypto->SEQ0 = CRYPTO_CMD_INSTR_DATA2TODATA0 << _CRYPTO_SEQ0_INSTR0_SHIFT + | CRYPTO_CMD_INSTR_AESENC << _CRYPTO_SEQ0_INSTR1_SHIFT + | CRYPTO_CMD_INSTR_DATA1TODATA0XOR << _CRYPTO_SEQ0_INSTR2_SHIFT + | CRYPTO_CMD_INSTR_DATA1TODATA2 << _CRYPTO_SEQ0_INSTR3_SHIFT; + crypto->SEQ1 = 0; + + CRYPTO_AES_ProcessLoop(crypto, len, + &crypto->DATA1, (uint32_t *)in, + &crypto->DATA0, (uint32_t *)out + ); + } +} + +/***************************************************************************//** + * @brief + * Counter (CTR) cipher mode encryption/decryption, 128/256 bit key. + * + * @details + * Please see CRYPTO_AES_CTR128() for CTR figure. + * + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[in] crypto + * Pointer to CRYPTO peripheral register block. + * + * @param[out] out + * Buffer to place encrypted/decrypted data. Must be at least @p len long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + * + * @param[in] in + * Buffer holding data to encrypt/decrypt. Must be at least @p len long. + * + * @param[in] len + * Number of bytes to encrypt/decrypt. Must be a multiple of 16. + * + * @param[in] key + * 256 bit encryption key. + * + * @param[in,out] ctr + * 128 bit initial counter value. The counter is updated after each AES + * block encoding through use of @p ctrFunc. + * + * @param[in] ctrFunc + * Function used to update counter value. Not supported by CRYPTO. + * This parameter is included in order for backwards compatibility with + * the EFM32 em_aes.h API. + * + * @param[in] keyWidth + * Set to cryptoKey128Bits or cryptoKey256Bits. + ******************************************************************************/ +static void CRYPTO_AES_CTRx(CRYPTO_TypeDef * crypto, + uint8_t * out, + const uint8_t * in, + unsigned int len, + const uint8_t * key, + uint8_t * ctr, + CRYPTO_AES_CtrFuncPtr_TypeDef ctrFunc, + CRYPTO_KeyWidth_TypeDef keyWidth) +{ + (void) ctrFunc; + + EFM_ASSERT(!(len % CRYPTO_AES_BLOCKSIZE)); + + /* Initialize control registers. */ + crypto->CTRL |= CRYPTO_CTRL_INCWIDTH_INCWIDTH4; + crypto->WAC = 0; + + CRYPTO_KeyBufWrite(crypto, (uint32_t *)key, keyWidth); + + CRYPTO_DataWrite(&crypto->DATA1, (uint32_t *) ctr); + + crypto->SEQ0 = CRYPTO_CMD_INSTR_DATA1TODATA0 << _CRYPTO_SEQ0_INSTR0_SHIFT + | CRYPTO_CMD_INSTR_AESENC << _CRYPTO_SEQ0_INSTR1_SHIFT + | CRYPTO_CMD_INSTR_DATA0TODATA3 << _CRYPTO_SEQ0_INSTR2_SHIFT + | CRYPTO_CMD_INSTR_DATA1INC << _CRYPTO_SEQ0_INSTR3_SHIFT; + + crypto->SEQ1 = CRYPTO_CMD_INSTR_DATA2TODATA0XOR << _CRYPTO_SEQ1_INSTR4_SHIFT; + + CRYPTO_AES_ProcessLoop(crypto, len, + &crypto->DATA2, (uint32_t *) in, + &crypto->DATA0, (uint32_t *) out); + + CRYPTO_DataRead(&crypto->DATA1, (uint32_t *) ctr); +} + +/***************************************************************************//** + * @brief + * Electronic Codebook (ECB) cipher mode encryption/decryption, 128/256 bit key. + * + * @details + * Please see CRYPTO_AES_ECB128() for ECB figure. + * + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[in] crypto + * Pointer to CRYPTO peripheral register block. + * + * @param[out] out + * Buffer to place encrypted/decrypted data. Must be at least @p len long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + * + * @param[in] in + * Buffer holding data to encrypt/decrypt. Must be at least @p len long. + * + * @param[in] len + * Number of bytes to encrypt/decrypt. Must be a multiple of 16. + * + * @param[in] key + * When doing encryption, this is the 256 bit encryption key. When doing + * decryption, this is the 256 bit decryption key. The decryption key may + * be generated from the encryption key with CRYPTO_AES_DecryptKey256(). + * + * @param[in] encrypt + * Set to true to encrypt, false to decrypt. + * + * @param[in] keyWidth + * Set to cryptoKey128Bits or cryptoKey256Bits. + ******************************************************************************/ +static void CRYPTO_AES_ECBx(CRYPTO_TypeDef * crypto, + uint8_t * out, + const uint8_t * in, + unsigned int len, + const uint8_t * key, + bool encrypt, + CRYPTO_KeyWidth_TypeDef keyWidth) +{ + EFM_ASSERT(!(len % CRYPTO_AES_BLOCKSIZE)); + + crypto->WAC = 0; + + CRYPTO_KeyBufWrite(crypto, (uint32_t *)key, keyWidth); + + if (encrypt) { + crypto->SEQ0 = CRYPTO_CMD_INSTR_AESENC << _CRYPTO_SEQ0_INSTR0_SHIFT + | CRYPTO_CMD_INSTR_DATA0TODATA1 << _CRYPTO_SEQ0_INSTR1_SHIFT; + } else { + crypto->SEQ0 = CRYPTO_CMD_INSTR_AESDEC << _CRYPTO_SEQ0_INSTR0_SHIFT + | CRYPTO_CMD_INSTR_DATA0TODATA1 << _CRYPTO_SEQ0_INSTR1_SHIFT; + } + + CRYPTO_AES_ProcessLoop(crypto, len, + &crypto->DATA0, (uint32_t *) in, + &crypto->DATA1, (uint32_t *) out); +} + +/***************************************************************************//** + * @brief + * Output feedback (OFB) cipher mode encryption/decryption, 128/256 bit key. + * + * @details + * Please see CRYPTO_AES_OFB128() for OFB figure. + * + * Please refer to general comments on layout and byte ordering of parameters. + * + * @param[in] crypto + * Pointer to CRYPTO peripheral register block. + * + * @param[out] out + * Buffer to place encrypted/decrypted data. Must be at least @p len long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + * + * @param[in] in + * Buffer holding data to encrypt/decrypt. Must be at least @p len long. + * + * @param[in] len + * Number of bytes to encrypt/decrypt. Must be a multiple of 16. + * + * @param[in] key + * 256 bit encryption key. + * + * @param[in] iv + * 128 bit initialization vector to use. + * + * @param[in] keyWidth + * Set to cryptoKey128Bits or cryptoKey256Bits. + ******************************************************************************/ +static void CRYPTO_AES_OFBx(CRYPTO_TypeDef * crypto, + uint8_t * out, + const uint8_t * in, + unsigned int len, + const uint8_t * key, + const uint8_t * iv, + CRYPTO_KeyWidth_TypeDef keyWidth) +{ + EFM_ASSERT(!(len % CRYPTO_AES_BLOCKSIZE)); + + crypto->WAC = 0; + + CRYPTO_KeyBufWrite(crypto, (uint32_t *)key, keyWidth); + + CRYPTO_DataWrite(&crypto->DATA2, (uint32_t *)iv); + + crypto->SEQ0 = CRYPTO_CMD_INSTR_DATA0TODATA1 << _CRYPTO_SEQ0_INSTR0_SHIFT + | CRYPTO_CMD_INSTR_DATA2TODATA0 << _CRYPTO_SEQ0_INSTR1_SHIFT + | CRYPTO_CMD_INSTR_AESENC << _CRYPTO_SEQ0_INSTR2_SHIFT + | CRYPTO_CMD_INSTR_DATA0TODATA2 << _CRYPTO_SEQ0_INSTR3_SHIFT; + crypto->SEQ1 = CRYPTO_CMD_INSTR_DATA1TODATA0XOR << _CRYPTO_SEQ1_INSTR4_SHIFT + | CRYPTO_CMD_INSTR_DATA0TODATA1 << _CRYPTO_SEQ1_INSTR5_SHIFT; + + CRYPTO_AES_ProcessLoop(crypto, len, + &crypto->DATA0, (uint32_t *) in, + &crypto->DATA1, (uint32_t *) out); +} + +/***************************************************************************//** + * @brief + * Function performs generic AES loop. + * + * @details + * Function loads given register with provided input data. Triggers CRYPTO to + * perform sequence of instructions and read specified output register to + * output buffer. + * + * @param[in] crypto + * Pointer to CRYPTO peripheral register block. + * + * @param[in] len + * Number of bytes to encrypt/decrypt. Must be a multiple of 16. + * + * @param[in] inReg + * Input register - one of DATA0,DATA1,DATA2,DATA3 + * + * @param[in] in + * Buffer holding data to encrypt/decrypt. Must be at least @p len long. + * + * @param[in] outReg + * Output register - one of DATA0,DATA1,DATA2,DATA3 + * + * @param[out] out + * Buffer to place encrypted/decrypted data. Must be at least @p len long. It + * may be set equal to @p in, in which case the input buffer is overwritten. + ******************************************************************************/ +static inline void CRYPTO_AES_ProcessLoop(CRYPTO_TypeDef * crypto, + uint32_t len, + CRYPTO_DataReg_TypeDef inReg, + uint32_t * in, + CRYPTO_DataReg_TypeDef outReg, + uint32_t * out) +{ + len /= CRYPTO_AES_BLOCKSIZE; + crypto->SEQCTRL = 16 << _CRYPTO_SEQCTRL_LENGTHA_SHIFT; + + while (len--) { + /* Load data and trigger encryption */ + CRYPTO_DataWrite(inReg, (uint32_t *)in); + + crypto->CMD = CRYPTO_CMD_SEQSTART; + + /* Save encrypted/decrypted data */ + CRYPTO_DataRead(outReg, (uint32_t *)out); + + out += 4; + in += 4; + } +} + +/** @} (end addtogroup CRYPTO) */ +/** @} (end addtogroup emlib) */ + +#endif /* defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) */ diff --git a/efm32/inc/crypto-config.h b/efm32/inc/crypto-config.h new file mode 100644 index 0000000..d5bf24a --- /dev/null +++ b/efm32/inc/crypto-config.h @@ -0,0 +1,278 @@ +/* + * Configuration for enabling CRYPTO hardware acceleration in all mbedtls + * modules when running on SiliconLabs devices. + * + * Copyright (C) 2016, Silicon Labs, http://www.silabs.com + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @defgroup sl_crypto_config Silicon Labs CRYPTO Hardware Acceleration Configuration + * @addtogroup sl_crypto_config + * + * @brief + * mbed TLS configuration for Silicon Labs CRYPTO hardware acceleration + * + * @details + * mbed TLS configuration is composed of settings in this Silicon Labs specific CRYPTO hardware acceleration file located in mbedtls/configs and the mbed TLS configuration file in mbedtls/include/mbedtls/config.h. + * This configuration can be used as a starting point to evaluate hardware acceleration available on Silicon Labs devices. + * + * @{ + */ + +#ifndef MBEDTLS_CONFIG_SL_CRYPTO_ALL_ACCELERATION_H +#define MBEDTLS_CONFIG_SL_CRYPTO_ALL_ACCELERATION_H + +#include "em_device.h" + +#if !defined(NO_CRYPTO_ACCELERATION) +/** + * @name SECTION: Silicon Labs Acceleration settings + * + * This section sets Silicon Labs Acceleration settings. + * @{ + + */ + +/** + * \def MBEDTLS_AES_ALT + * + * Enable hardware acceleration for the AES block cipher + * + * Module: sl_crypto/src/crypto_aes.c for devices with CRYPTO + * sl_crypto/src/aes_aes.c for devices with AES + * + * See MBEDTLS_AES_C for more information. + */ +#define MBEDTLS_AES_ALT +#define MBEDTLS_ECP_ALT +/** + * \def MBEDTLS_ECP_INTERNAL_ALT + * \def ECP_SHORTWEIERSTRASS + * \def MBEDTLS_ECP_ADD_MIXED_ALT + * \def MBEDTLS_ECP_DOUBLE_JAC_ALT + * \def MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT + * \def MBEDTLS_ECP_NORMALIZE_JAC_ALT + * + * Enable hardware acceleration for the elliptic curve over GF(p) library. + * + * Module: sl_crypto/src/crypto_ecp.c + * Caller: library/ecp.c + * + * Requires: MBEDTLS_BIGNUM_C, MBEDTLS_ECP_C and at least one + * MBEDTLS_ECP_DP_XXX_ENABLED and (CRYPTO_COUNT > 0) + */ +#if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) +#define MBEDTLS_ECP_INTERNAL_ALT +#define ECP_SHORTWEIERSTRASS +#define MBEDTLS_ECP_ADD_MIXED_ALT +#define MBEDTLS_ECP_DOUBLE_JAC_ALT +#define MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT +#define MBEDTLS_ECP_NORMALIZE_JAC_ALT +#define MBEDTLS_ECP_RANDOMIZE_JAC_ALT +#endif + +/** + * \def MBEDTLS_SHA1_ALT + * + * Enable hardware acceleration for the SHA1 cryptographic hash algorithm. + * + * Module: sl_crypto/src/crypto_sha.c + * Caller: library/mbedtls_md.c + * library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * library/x509write_crt.c + * + * Requires: MBEDTLS_SHA1_C and (CRYPTO_COUNT > 0) + * See MBEDTLS_SHA1_C for more information. + */ +#if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) +#define MBEDTLS_SHA1_ALT +#endif + +/** + * \def MBEDTLS_SHA256_ALT + * + * Enable hardware acceleration for the SHA-224 and SHA-256 cryptographic + * hash algorithms. + * + * Module: sl_crypto/src/crypto_sha.c + * Caller: library/entropy.c + * library/mbedtls_md.c + * library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * Requires: MBEDTLS_SHA256_C and (CRYPTO_COUNT > 0) + * See MBEDTLS_SHA256_C for more information. + */ +#if defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) +#define MBEDTLS_SHA256_ALT +#endif + +#endif /* #if !defined(NO_CRYPTO_ACCELERATION) */ + +/** + * \def MBEDTLS_TRNG_C + * + * Enable software support for the True Random Number Generator (TRNG) + * incorporated from Series 1 Configuration 2 devices (EFR32MG12, etc.) + * from Silicon Labs. + * + * TRNG is not supported by software for EFR32XG13 (SDID_89) and + * EFR32XG14 (SDID_95). + * + * Requires TRNG_PRESENT && + * !(_SILICON_LABS_GECKO_INTERNAL_SDID_89 || + * _SILICON_LABS_GECKO_INTERNAL_SDID_95) + */ +#if defined(TRNG_PRESENT) && \ + !(defined(_SILICON_LABS_GECKO_INTERNAL_SDID_89) || \ + defined(_SILICON_LABS_GECKO_INTERNAL_SDID_95)) +#define MBEDTLS_TRNG_C +#endif + +/** + * \def MBEDTLS_ENTROPY_ADC_C + * + * Enable software support for the retrieving entropy data from the ADC + * incorporated on devices from Silicon Labs. + * + * Requires ADC_PRESENT && _ADC_SINGLECTRLX_VREFSEL_VENTROPY + */ +#if defined(ADC_PRESENT) && defined(_ADC_SINGLECTRLX_VREFSEL_VENTROPY) +#define MBEDTLS_ENTROPY_ADC_C +#endif + +/** + * \def MBEDTLS_ENTROPY_ADC_INSTANCE + * + * Specify which ADC instance shall be used as entropy source. + * + * Requires MBEDTLS_ENTROPY_ADC_C + */ +#if defined(MBEDTLS_ENTROPY_ADC_C) +#define MBEDTLS_ENTROPY_ADC_INSTANCE (0) +#endif + +/** + * \def MBEDTLS_ENTROPY_RAIL_C + * + * Enable software support for the retrieving entropy data from the RAIL + * incorporated on devices from Silicon Labs. + * + * Requires _EFR_DEVICE + */ +#if defined(_EFR_DEVICE) +#define MBEDTLS_ENTROPY_RAIL_C +#endif + +/** + * \def MBEDTLS_ENTROPY_HARDWARE_ALT_RAIL + * + * Use the radio (RAIL) as default hardware entropy source. + * + * Requires MBEDTLS_ENTROPY_RAIL_C && _EFR_DEVICE && !MBEDTLS_TRNG_C + */ +#if defined(MBEDTLS_ENTROPY_RAIL_C) && \ + defined(_EFR_DEVICE) && !defined(MBEDTLS_TRNG_C) +#define MBEDTLS_ENTROPY_HARDWARE_ALT_RAIL +#endif + +/** + * \def MBEDTLS_ENTROPY_HARDWARE_ALT + * + * Integrate the provided default entropy source into the mbed + * TLS entropy infrastructure. + * + * Requires MBEDTLS_TRNG_C || MBEDTLS_ENTROPY_HARDWARE_ALT_RAIL + */ +#if defined(MBEDTLS_TRNG_C) || defined(MBEDTLS_ENTROPY_HARDWARE_ALT_RAIL) +#define MBEDTLS_ENTROPY_HARDWARE_ALT +#endif + +/* Default ECC configuration for Silicon Labs devices: */ + +/* ECC curves supported by CRYPTO hardware module: */ +#define MBEDTLS_ECP_DP_SECP192R1_ENABLED +#define MBEDTLS_ECP_DP_SECP224R1_ENABLED +#define MBEDTLS_ECP_DP_SECP256R1_ENABLED + +/* Save RAM by adjusting to our exact needs */ +#define MBEDTLS_ECP_MAX_BITS 256 +#ifndef MBEDTLS_MPI_MAX_SIZE +#define MBEDTLS_MPI_MAX_SIZE 32 // 384 bits is 48 bytes +#endif + +/* + Set MBEDTLS_ECP_WINDOW_SIZE to configure + ECC point multiplication window size, see ecp.h: + 2 = Save RAM at the expense of speed + 3 = Improve speed at the expense of RAM + 4 = Optimize speed at the expense of RAM +*/ +#define MBEDTLS_ECP_WINDOW_SIZE 3 +#define MBEDTLS_ECP_FIXED_POINT_OPTIM 0 + +/* Significant speed benefit at the expense of some ROM */ +#define MBEDTLS_ECP_NIST_OPTIM + +/* Include the default mbed TLS config file */ +#include "mbedtls/config.h" + +#undef MBEDTLS_TIMING_C +#undef MBEDTLS_FS_IO +#undef MBEDTLS_SHA512_C +#undef MBEDTLS_ENTROPY_SHA512_ACCUMULATOR + +#undef MBEDTLS_NET_C + +#define MBEDTLS_ECP_NORMALIZE_JAC_ALT +#define MBEDTLS_ECP_DEVICE_ALT +#define MBEDTLS_MPI_MODULAR_DIVISION_ALT + +#define MBEDTLS_ECP_INTERNAL_ALT +#define ECP_SHORTWEIERSTRASS +#define MBEDTLS_ECP_ADD_MIXED_ALT +#define MBEDTLS_ECP_DOUBLE_JAC_ALT +#define MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT +#define MBEDTLS_ECP_NORMALIZE_JAC_ALT +#define MBEDTLS_ECP_RANDOMIZE_JAC_ALT +#define MBEDTLS_ECP_DEVICE_ADD_MIXED_ALT + + + +//#define MBEDTLS_MPI_MUL_MPI_ALT // doesnt seem to be implemented +//#define MBEDTLS_MPI_MUL_INT_ALT // makes no difference or slightly slower + +#define MBEDTLS_NO_PLATFORM_ENTROPY +/* Hardware entropy source is not yet supported. Uncomment this macro to + provide your own implementation of an entropy collector. */ +//#define MBEDTLS_ENTROPY_HARDWARE_ALT + +/* Exclude and/or change default config here. E.g.: */ +//#undef MBEDTLS_ECP_DP_SECP384R1_ENABLED +//#undef MBEDTLS_ECP_DP_SECP521R1_ENABLED +//#undef MBEDTLS_ECP_DP_BP384R1_ENABLED +//#undef MBEDTLS_ECP_DP_BP512R1_ENABLED +//#undef MBEDTLS_SHA512_C + +#include "mbedtls/check_config.h" + +/** @} (end section sl_crypto_config) */ +/** @} (end addtogroup sl_crypto_config) */ + +#endif /* MBEDTLS_CONFIG_SL_CRYPTO_ALL_ACCELERATION_H */ diff --git a/efm32/src/InitDevice.c b/efm32/src/InitDevice.c index f8204b0..031d162 100644 --- a/efm32/src/InitDevice.c +++ b/efm32/src/InitDevice.c @@ -20,7 +20,9 @@ #include "em_chip.h" #include "em_assert.h" #include "em_cryotimer.h" +#include "em_crypto.h" #include "em_gpio.h" +#include "em_ldma.h" #include "em_usart.h" // [Library includes]$ @@ -35,6 +37,7 @@ extern void enter_DefaultMode_from_RESET(void) { CMU_enter_DefaultMode_from_RESET(); USART0_enter_DefaultMode_from_RESET(); USART1_enter_DefaultMode_from_RESET(); + LDMA_enter_DefaultMode_from_RESET(); CRYOTIMER_enter_DefaultMode_from_RESET(); PORTIO_enter_DefaultMode_from_RESET(); // [Config Calls]$ @@ -127,6 +130,9 @@ extern void CMU_enter_DefaultMode_from_RESET(void) { /* Enable clock for CRYOTIMER */ CMU_ClockEnable(cmuClock_CRYOTIMER, true); + /* Enable clock for LDMA */ + CMU_ClockEnable(cmuClock_LDMA, true); + /* Enable clock for USART0 */ CMU_ClockEnable(cmuClock_USART0, true); diff --git a/efm32/src/crypto.c b/efm32/src/crypto.c new file mode 100644 index 0000000..5f9cfa8 --- /dev/null +++ b/efm32/src/crypto.c @@ -0,0 +1,547 @@ +/* + * Wrapper for crypto implementation on device + * + * */ +#include +#include +#include + +#include "util.h" +#include "crypto.h" + + +#include "sha256.h" +#include "uECC.h" +#include "aes.h" +#include "ctap.h" + +#include MBEDTLS_CONFIG_FILE +#include "sha256_alt.h" +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/ecdsa.h" + +const uint8_t attestation_cert_der[]; +const uint16_t attestation_cert_der_size; +const uint8_t attestation_key[]; +const uint16_t attestation_key_size; + + + +static SHA256_CTX sha256_ctx; +mbedtls_sha256_context embed_sha256_ctx; + +static const struct uECC_Curve_t * _es256_curve = NULL; +static const uint8_t * _signing_key = NULL; + +// Secrets for testing only +static uint8_t master_secret[32] = "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff" + "\xff\xee\xdd\xcc\xbb\xaa\x99\x88\x77\x66\x55\x44\x33\x22\x11\x00"; + +static uint8_t transport_secret[32] = "\x10\x01\x22\x33\x44\x55\x66\x77\x87\x90\x0a\xbb\x3c\xd8\xee\xff" + "\xff\xee\x8d\x1c\x3b\xfa\x99\x88\x77\x86\x55\x44\xd3\xff\x33\x00"; + + + +void crypto_sha256_init() +{ + mbedtls_sha256_init( &embed_sha256_ctx ); + mbedtls_sha256_starts(&embed_sha256_ctx,0); +// sha256_init(&sha256_ctx); +} + +void crypto_reset_master_secret() +{ + ctap_generate_rng(master_secret, 32); +} + + +void crypto_sha256_update(uint8_t * data, size_t len) +{ + mbedtls_sha256_update(&embed_sha256_ctx,data,len); +// sha256_update(&sha256_ctx, data, len); +} + +void crypto_sha256_update_secret() +{ + mbedtls_sha256_update(&embed_sha256_ctx,master_secret,32); +// sha256_update(&sha256_ctx, master_secret, 32); +} + +void crypto_sha256_final(uint8_t * hash) +{ + mbedtls_sha256_finish( &embed_sha256_ctx, hash ); +// sha256_final(&sha256_ctx, hash); +} + +void crypto_sha256_hmac_init(uint8_t * key, uint32_t klen, uint8_t * hmac) +{ + uint8_t buf[64]; + int i; + memset(buf, 0, sizeof(buf)); + + if (key == CRYPTO_MASTER_KEY) + { + key = master_secret; + klen = sizeof(master_secret); + } + + if(klen > 64) + { + printf("Error, key size must be <= 64\n"); + exit(1); + } + + memmove(buf, key, klen); + + for (i = 0; i < sizeof(buf); i++) + { + buf[i] = buf[i] ^ 0x36; + } + + crypto_sha256_init(); + crypto_sha256_update(buf, 64); +} + +void crypto_sha256_hmac_final(uint8_t * key, uint32_t klen, uint8_t * hmac) +{ + uint8_t buf[64]; + int i; + crypto_sha256_final(hmac); + memset(buf, 0, sizeof(buf)); + if (key == CRYPTO_MASTER_KEY) + { + key = master_secret; + klen = sizeof(master_secret); + } + + + if(klen > 64) + { + printf("Error, key size must be <= 64\n"); + exit(1); + } + memmove(buf, key, klen); + + for (i = 0; i < sizeof(buf); i++) + { + buf[i] = buf[i] ^ 0x5c; + } + + crypto_sha256_init(); + crypto_sha256_update(buf, 64); + crypto_sha256_update(hmac, 32); + crypto_sha256_final(hmac); +} + +mbedtls_ctr_drbg_context ctr_drbg; + +void crypto_ecc256_init() +{ + uECC_set_rng((uECC_RNG_Function)ctap_generate_rng); + _es256_curve = uECC_secp256r1(); + mbedtls_ctr_drbg_init(&ctr_drbg); +} + + +void crypto_ecc256_load_attestation_key() +{ + _signing_key = attestation_key; +} + +/** + * \brief Import a point from unsigned binary data + * + * \param grp Group to which the point should belong + * \param P Point to import + * \param buf Input buffer + * \param ilen Actual length of input + * + * \return 0 if successful, + * MBEDTLS_ERR_ECP_BAD_INPUT_DATA if input is invalid, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if the point format + * is not implemented. + * + * \note This function does NOT check that the point actually + * belongs to the given group, see mbedtls_ecp_check_pubkey() for + * that. + */ +//int mbedtls_ecp_point_read_binary( const mbedtls_ecp_group *grp, mbedtls_ecp_point *P, +// const unsigned char *buf, size_t ilen ); + +/** + * \brief Import X from unsigned binary data, big endian + * + * \param X Destination MPI + * \param buf Input buffer + * \param buflen Input buffer size + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +//int mbedtls_mpi_read_binary( mbedtls_mpi *X, const unsigned char *buf, size_t buflen ); + +/* + * Set context from an mbedtls_ecp_keypair + */ +//int mbedtls_ecdsa_from_keypair( mbedtls_ecdsa_context *ctx, const mbedtls_ecp_keypair *key ); + + + +void crypto_ecc256_sign(uint8_t * data, int len, uint8_t * sig) +{ + mbedtls_ecp_group grp; /*!< Elliptic curve and base point */ + mbedtls_mpi d; /*!< our secret value */ +//#define CRYPTO_ENABLE CMU->HFBUSCLKEN0 |= CMU_HFBUSCLKEN0_CRYPTO; \ +// CRYPTO->IFC = _CRYPTO_IFC_MASK; \ +// CRYPTO->CMD = CRYPTO_CMD_SEQSTOP; \ +// CRYPTO->CTRL = CRYPTO_CTRL_DMA0RSEL_DDATA0; \ +// CRYPTO->SEQCTRL = 0; \ +// CRYPTO->SEQCTRLB = 0 +// +//#define CRYPTO_DISABLE \ +// CRYPTO->IEN = 0; \ +// CMU->HFBUSCLKEN0 &= ~CMU_HFBUSCLKEN0_CRYPTO; +// CRYPTO_DISABLE; +// CRYPTO_ENABLE; + mbedtls_ecp_group_init( &grp ); + mbedtls_mpi_init( &d ); + mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1); + mbedtls_mpi_read_binary(&d, _signing_key, 32); + + mbedtls_mpi r,s; + mbedtls_mpi_init(&r); + mbedtls_mpi_init(&s); + + printf("signing..\n"); + dump_hex(data,len); + mbedtls_ecdsa_sign_det( &grp, &r, &s, &d, + data, 32, MBEDTLS_MD_SHA256 );// Issue: this will freeze on 13th iteration.. + printf("signed\n"); + + mbedtls_mpi_write_binary(&r,sig,32); + mbedtls_mpi_write_binary(&s,sig+32,32); + +// if ( uECC_sign(_signing_key, data, len, sig, _es256_curve) == 0) +// { +// printf("error, uECC failed\n"); +// exit(1); +// } + +} + +/* + * Generate a keypair with configurable base point + */ +// mbedtls_ecp_gen_keypair( &ctx->grp, &ctx->d, &ctx->Q, f_rng, p_rng ) +// mbedtls_ecp_gen_keypair_base( grp, &grp->G, d, Q, f_rng, p_rng ) +/* + * Curve types: internal for now, might be exposed later + */ +typedef enum +{ + ECP_TYPE_NONE = 0, + ECP_TYPE_SHORT_WEIERSTRASS, /* y^2 = x^3 + a x + b */ + ECP_TYPE_MONTGOMERY, /* y^2 = x^3 + a x^2 + x */ +} ecp_curve_type; +/* + * Get the type of a curve + */ +static inline ecp_curve_type ecp_get_type( const mbedtls_ecp_group *grp ) +{ + if( grp->G.X.p == NULL ) + return( ECP_TYPE_NONE ); + + if( grp->G.Y.p == NULL ) + return( ECP_TYPE_MONTGOMERY ); + else + return( ECP_TYPE_SHORT_WEIERSTRASS ); +} +static int mbedtls_ecp_gen_privkey( mbedtls_ecp_group *grp, + const mbedtls_ecp_point *G, + mbedtls_mpi *d, mbedtls_ecp_point *Q, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + size_t n_size = ( grp->nbits + 7 ) / 8; + +#if defined(ECP_MONTGOMERY) + if( ecp_get_type( grp ) == ECP_TYPE_MONTGOMERY ) + { + /* [M225] page 5 */ + size_t b; + + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( d, n_size, f_rng, p_rng ) ); + + /* Make sure the most significant bit is nbits */ + b = mbedtls_mpi_bitlen( d ) - 1; /* mbedtls_mpi_bitlen is one-based */ + if( b > grp->nbits ) + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( d, b - grp->nbits ) ); + else + MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( d, grp->nbits, 1 ) ); + + /* Make sure the last three bits are unset */ + MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( d, 0, 0 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( d, 1, 0 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( d, 2, 0 ) ); + } + else +#endif /* ECP_MONTGOMERY */ +#if defined(ECP_SHORTWEIERSTRASS) + if( ecp_get_type( grp ) == ECP_TYPE_SHORT_WEIERSTRASS ) + { + /* SEC1 3.2.1: Generate d such that 1 <= n < N */ + int count = 0; + unsigned char rnd[MBEDTLS_ECP_MAX_BYTES]; + + /* + * Match the procedure given in RFC 6979 (deterministic ECDSA): + * - use the same byte ordering; + * - keep the leftmost nbits bits of the generated octet string; + * - try until result is in the desired range. + * This also avoids any biais, which is especially important for ECDSA. + */ + do + { + MBEDTLS_MPI_CHK( f_rng( p_rng, rnd, n_size ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( d, rnd, n_size ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( d, 8 * n_size - grp->nbits ) ); + + /* + * Each try has at worst a probability 1/2 of failing (the msb has + * a probability 1/2 of being 0, and then the result will be < N), + * so after 30 tries failure probability is a most 2**(-30). + * + * For most curves, 1 try is enough with overwhelming probability, + * since N starts with a lot of 1s in binary, but some curves + * such as secp224k1 are actually very close to the worst case. + */ + if( ++count > 30 ) + return( MBEDTLS_ERR_ECP_RANDOM_FAILED ); + } + while( mbedtls_mpi_cmp_int( d, 1 ) < 0 || + mbedtls_mpi_cmp_mpi( d, &grp->N ) >= 0 ); + } + else +#endif /* ECP_SHORTWEIERSTRASS */ + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + +cleanup: + if( ret != 0 ) + return( ret ); + + return 0; +} + +static int mbedtls_ecp_derive_pubkey( mbedtls_ecp_group *grp, + const mbedtls_ecp_point *G, + mbedtls_mpi *d, mbedtls_ecp_point *Q, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + return( mbedtls_ecp_mul( grp, Q, d, G, f_rng, p_rng ) ); +} + + +static int hmac_vector_func(uint8_t * hmac, uint8_t * dst, int len) +{ + static int hmac_ptr = 0; + if (hmac==NULL) + { + hmac_ptr = 0; + return 0; + } + int i; + while(len--) + { + *dst++ = hmac[hmac_ptr++ % 32]; + } + return 0; +} + +void generate_private_key(uint8_t * data, int len, uint8_t * data2, int len2, uint8_t * privkey) +{ + crypto_sha256_hmac_init(CRYPTO_MASTER_KEY, 0, privkey); + crypto_sha256_update(data, len); + crypto_sha256_update(data2, len2); + crypto_sha256_update(master_secret, 32); + crypto_sha256_hmac_final(CRYPTO_MASTER_KEY, 0, privkey); + + mbedtls_ecp_group grp; /*!< Elliptic curve and base point */ + mbedtls_mpi d; /*!< our secret value */ + mbedtls_ecp_point Q; + + mbedtls_ecp_group_init( &grp ); + mbedtls_mpi_init( &d ); + mbedtls_ecp_point_init(&Q); + + mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1); + +// mbedtls_mpi_read_binary(&d, _signing_key, 32); + hmac_vector_func(NULL, NULL, 0); + mbedtls_ecp_gen_privkey(&grp, &grp.G, &d, &Q, hmac_vector_func, privkey); + mbedtls_mpi_write_binary(&d,privkey,32); +} + + +/*int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key, uECC_Curve curve);*/ +void crypto_ecc256_derive_public_key(uint8_t * data, int len, uint8_t * x, uint8_t * y) +{ + int ret; + uint8_t privkey[32]; + uint8_t pubkey[64]; + +// generate_private_key(data,len,NULL,0,privkey); + + crypto_sha256_hmac_init(CRYPTO_MASTER_KEY, 0, privkey); + crypto_sha256_update(data, len); + crypto_sha256_update(NULL, 0); + crypto_sha256_update(master_secret, 32); + crypto_sha256_hmac_final(CRYPTO_MASTER_KEY, 0, privkey); + + mbedtls_ecp_group grp; /*!< Elliptic curve and base point */ + mbedtls_mpi d; /*!< our secret value */ + mbedtls_ecp_point Q; + + mbedtls_ecp_group_init( &grp ); + mbedtls_mpi_init( &d ); + mbedtls_ecp_point_init(&Q); + + mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1); + +// mbedtls_mpi_read_binary(&d, _signing_key, 32); + hmac_vector_func(NULL, NULL, 0); + ret= mbedtls_ecp_gen_privkey(&grp, &grp.G, &d, &Q, hmac_vector_func, privkey); + if (ret != 0) + { + printf("error with priv key -0x04%x\n", -ret); + } +// mbedtls_mpi_write_binary(&d,privkey,32); + + memset(pubkey,0,sizeof(pubkey)); + + ret = mbedtls_ecp_derive_pubkey( &grp, &grp.G, + &d, &Q, hmac_vector_func, privkey); + + if (ret != 0) + { + printf("error with public key\n"); + } + + mbedtls_mpi_write_binary(&Q.X,x,32); + mbedtls_mpi_write_binary(&Q.Y,y,32); + +// uECC_compute_public_key(privkey, pubkey, _es256_curve); +// memmove(x,pubkey,32); +// memmove(y,pubkey+32,32); +} + +void crypto_ecc256_load_key(uint8_t * data, int len, uint8_t * data2, int len2) +{ + static uint8_t privkey[32]; + generate_private_key(data,len,data2,len2,privkey); + _signing_key = privkey; +} + +void crypto_ecc256_make_key_pair(uint8_t * pubkey, uint8_t * privkey) +{ + if (uECC_make_key(pubkey, privkey, _es256_curve) != 1) + { + printf("Error, uECC_make_key failed\n"); + exit(1); + } +} + +void crypto_ecc256_shared_secret(const uint8_t * pubkey, const uint8_t * privkey, uint8_t * shared_secret) +{ + if (uECC_shared_secret(pubkey, privkey, shared_secret, _es256_curve) != 1) + { + printf("Error, uECC_shared_secret failed\n"); + exit(1); + } + +} + +struct AES_ctx aes_ctx; +void crypto_aes256_init(uint8_t * key, uint8_t * nonce) +{ + if (key == CRYPTO_TRANSPORT_KEY) + { + AES_init_ctx(&aes_ctx, transport_secret); + } + else + { + AES_init_ctx(&aes_ctx, key); + } + if (nonce == NULL) + { + memset(aes_ctx.Iv, 0, 16); + } + else + { + memmove(aes_ctx.Iv, nonce, 16); + } +} + +// prevent round key recomputation +void crypto_aes256_reset_iv(uint8_t * nonce) +{ + if (nonce == NULL) + { + memset(aes_ctx.Iv, 0, 16); + } + else + { + memmove(aes_ctx.Iv, nonce, 16); + } +} + +void crypto_aes256_decrypt(uint8_t * buf, int length) +{ + AES_CBC_decrypt_buffer(&aes_ctx, buf, length); +} + +void crypto_aes256_encrypt(uint8_t * buf, int length) +{ + AES_CBC_encrypt_buffer(&aes_ctx, buf, length); +} + + +const uint8_t attestation_cert_der[] = +"\x30\x82\x01\xfb\x30\x82\x01\xa1\xa0\x03\x02\x01\x02\x02\x01\x00\x30\x0a\x06\x08" +"\x2a\x86\x48\xce\x3d\x04\x03\x02\x30\x2c\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13" +"\x02\x55\x53\x31\x0b\x30\x09\x06\x03\x55\x04\x08\x0c\x02\x4d\x44\x31\x10\x30\x0e" +"\x06\x03\x55\x04\x0a\x0c\x07\x54\x45\x53\x54\x20\x43\x41\x30\x20\x17\x0d\x31\x38" +"\x30\x35\x31\x30\x30\x33\x30\x36\x32\x30\x5a\x18\x0f\x32\x30\x36\x38\x30\x34\x32" +"\x37\x30\x33\x30\x36\x32\x30\x5a\x30\x7c\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13" +"\x02\x55\x53\x31\x0b\x30\x09\x06\x03\x55\x04\x08\x0c\x02\x4d\x44\x31\x0f\x30\x0d" +"\x06\x03\x55\x04\x07\x0c\x06\x4c\x61\x75\x72\x65\x6c\x31\x15\x30\x13\x06\x03\x55" +"\x04\x0a\x0c\x0c\x54\x45\x53\x54\x20\x43\x4f\x4d\x50\x41\x4e\x59\x31\x22\x30\x20" +"\x06\x03\x55\x04\x0b\x0c\x19\x41\x75\x74\x68\x65\x6e\x74\x69\x63\x61\x74\x6f\x72" +"\x20\x41\x74\x74\x65\x73\x74\x61\x74\x69\x6f\x6e\x31\x14\x30\x12\x06\x03\x55\x04" +"\x03\x0c\x0b\x63\x6f\x6e\x6f\x72\x70\x70\x2e\x63\x6f\x6d\x30\x59\x30\x13\x06\x07" +"\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00" +"\x04\x45\xa9\x02\xc1\x2e\x9c\x0a\x33\xfa\x3e\x84\x50\x4a\xb8\x02\xdc\x4d\xb9\xaf" +"\x15\xb1\xb6\x3a\xea\x8d\x3f\x03\x03\x55\x65\x7d\x70\x3f\xb4\x02\xa4\x97\xf4\x83" +"\xb8\xa6\xf9\x3c\xd0\x18\xad\x92\x0c\xb7\x8a\x5a\x3e\x14\x48\x92\xef\x08\xf8\xca" +"\xea\xfb\x32\xab\x20\xa3\x62\x30\x60\x30\x46\x06\x03\x55\x1d\x23\x04\x3f\x30\x3d" +"\xa1\x30\xa4\x2e\x30\x2c\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31" +"\x0b\x30\x09\x06\x03\x55\x04\x08\x0c\x02\x4d\x44\x31\x10\x30\x0e\x06\x03\x55\x04" +"\x0a\x0c\x07\x54\x45\x53\x54\x20\x43\x41\x82\x09\x00\xf7\xc9\xec\x89\xf2\x63\x94" +"\xd9\x30\x09\x06\x03\x55\x1d\x13\x04\x02\x30\x00\x30\x0b\x06\x03\x55\x1d\x0f\x04" +"\x04\x03\x02\x04\xf0\x30\x0a\x06\x08\x2a\x86\x48\xce\x3d\x04\x03\x02\x03\x48\x00" +"\x30\x45\x02\x20\x18\x38\xb0\x45\x03\x69\xaa\xa7\xb7\x38\x62\x01\xaf\x24\x97\x5e" +"\x7e\x74\x64\x1b\xa3\x7b\xf7\xe6\xd3\xaf\x79\x28\xdb\xdc\xa5\x88\x02\x21\x00\xcd" +"\x06\xf1\xe3\xab\x16\x21\x8e\xd8\xc0\x14\xaf\x09\x4f\x5b\x73\xef\x5e\x9e\x4b\xe7" +"\x35\xeb\xdd\x9b\x6d\x8f\x7d\xf3\xc4\x3a\xd7"; + + +const uint16_t attestation_cert_der_size = sizeof(attestation_cert_der)-1; + + +const uint8_t attestation_key[] = "\xcd\x67\xaa\x31\x0d\x09\x1e\xd1\x6e\x7e\x98\x92\xaa\x07\x0e\x19\x94\xfc\xd7\x14\xae\x7c\x40\x8f\xb9\x46\xb7\x2e\x5f\xe7\x5d\x30"; +const uint16_t attestation_key_size = sizeof(attestation_key)-1; + + + diff --git a/efm32/src/device.c b/efm32/src/device.c index 993dbfa..de0093b 100644 --- a/efm32/src/device.c +++ b/efm32/src/device.c @@ -71,10 +71,11 @@ void heartbeat() static int beat = 0; GPIO_PinOutToggle(gpioPortF,4); GPIO_PinOutToggle(gpioPortF,5); -// printf("heartbeat %d\r\n", CRYOTIMER->CNT); + +// printf("heartbeat %d %d\r\n", beat++,CRYOTIMER->CNT); } -uint64_t millis() +uint32_t millis() { return CRYOTIMER->CNT; } @@ -96,11 +97,11 @@ int usbhid_recv(uint8_t * msg) for (i = 0; i < 64; i++) { msg[i] = USART_SpiTransfer(USART1, 0); - delay(1); +// delay(1); } msgs_to_recv--; -// printf(">> "); -// dump_hex(msg,64); + printf(">> "); + dump_hex(msg,64); return 64; } @@ -110,12 +111,25 @@ int usbhid_recv(uint8_t * msg) void usbhid_send(uint8_t * msg) { int i; + uint64_t t1 = millis(); + + GPIO_PinModeSet(gpioPortC, 10, gpioModeInput, 0); + + // Wait for efm8 to be ready + while (GPIO_PinInGet(gpioPortC, 10) == 0) + ; + + GPIO_PinModeSet(gpioPortC, 10, gpioModePushPull, 0); + uint64_t t2 = millis(); +// printf("wait time: %ul\n", (uint32_t)(t2-t1)); GPIO_PinOutSet(gpioPortC,10); for (i = 0; i < HID_MESSAGE_SIZE; i++) { USART_SpiTransfer(USART1, *msg++); } GPIO_PinOutClear(gpioPortC,10); + + } void usbhid_close() @@ -168,10 +182,7 @@ void device_init(void) 1); // SPI R/W indicator - GPIO_PinModeSet(gpioPortC, - 10, - gpioModePushPull, - 0); + GPIO_PinModeSet(gpioPortC, 10, gpioModePushPull, 0); // USB message rdy ext int GPIO_ExtIntConfig(gpioPortC, 9, 9, 1, 0,1); diff --git a/efm8/.cproject b/efm8/.cproject index 6a0550a..3666f4f 100644 --- a/efm8/.cproject +++ b/efm8/.cproject @@ -170,7 +170,7 @@ - + diff --git a/efm8/efm8.hwconf b/efm8/efm8.hwconf index 7189f40..58c2f01 100644 --- a/efm8/efm8.hwconf +++ b/efm8/efm8.hwconf @@ -25,6 +25,7 @@ + @@ -77,16 +78,27 @@ - + - - + + + + + + + + + + + + + diff --git a/efm8/inc/app.h b/efm8/inc/app.h index 26363a3..357b804 100644 --- a/efm8/inc/app.h +++ b/efm8/inc/app.h @@ -8,7 +8,7 @@ #ifndef INC_APP_H_ #define INC_APP_H_ -//#define USE_PRINTING +#define USE_PRINTING void usb_transfer_complete(); void spi_transfer_complete(); diff --git a/efm8/inc/config/usbconfig.h b/efm8/inc/config/usbconfig.h index 3a82317..148a510 100644 --- a/efm8/inc/config/usbconfig.h +++ b/efm8/inc/config/usbconfig.h @@ -53,11 +53,11 @@ // Enable or disable each endpoint // ----------------------------------------------------------------------------- // $[Endpoints Used] -#define SLAB_USB_EP1IN_USED 1 -#define SLAB_USB_EP1OUT_USED 1 +#define SLAB_USB_EP1IN_USED 0 +#define SLAB_USB_EP1OUT_USED 0 #define SLAB_USB_EP2IN_USED 0 -#define SLAB_USB_EP2OUT_USED 0 -#define SLAB_USB_EP3IN_USED 0 +#define SLAB_USB_EP2OUT_USED 1 +#define SLAB_USB_EP3IN_USED 1 #define SLAB_USB_EP3OUT_USED 0 // [Endpoints Used]$ @@ -67,9 +67,9 @@ // $[Endpoint Max Packet Size] #define SLAB_USB_EP1IN_MAX_PACKET_SIZE 64 #define SLAB_USB_EP1OUT_MAX_PACKET_SIZE 64 -#define SLAB_USB_EP2IN_MAX_PACKET_SIZE 1 -#define SLAB_USB_EP2OUT_MAX_PACKET_SIZE 1 -#define SLAB_USB_EP3IN_MAX_PACKET_SIZE 1 +#define SLAB_USB_EP2IN_MAX_PACKET_SIZE 64 +#define SLAB_USB_EP2OUT_MAX_PACKET_SIZE 64 +#define SLAB_USB_EP3IN_MAX_PACKET_SIZE 64 #define SLAB_USB_EP3OUT_MAX_PACKET_SIZE 1 // [Endpoint Max Packet Size]$ @@ -79,9 +79,9 @@ // $[Endpoint Transfer Type] #define SLAB_USB_EP1IN_TRANSFER_TYPE USB_EPTYPE_INTR #define SLAB_USB_EP1OUT_TRANSFER_TYPE USB_EPTYPE_INTR -#define SLAB_USB_EP2IN_TRANSFER_TYPE USB_EPTYPE_BULK -#define SLAB_USB_EP2OUT_TRANSFER_TYPE USB_EPTYPE_BULK -#define SLAB_USB_EP3IN_TRANSFER_TYPE USB_EPTYPE_ISOC +#define SLAB_USB_EP2IN_TRANSFER_TYPE USB_EPTYPE_INTR +#define SLAB_USB_EP2OUT_TRANSFER_TYPE USB_EPTYPE_INTR +#define SLAB_USB_EP3IN_TRANSFER_TYPE USB_EPTYPE_INTR #define SLAB_USB_EP3OUT_TRANSFER_TYPE USB_EPTYPE_ISOC // [Endpoint Transfer Type]$ diff --git a/efm8/src/InitDevice.c b/efm8/src/InitDevice.c index 2f86874..fcec7fb 100644 --- a/efm8/src/InitDevice.c +++ b/efm8/src/InitDevice.c @@ -407,6 +407,18 @@ extern void PORTS_0_enter_DefaultMode_from_RESET(void) { extern void PORTS_1_enter_DefaultMode_from_RESET(void) { // $[P1 - Port 1 Pin Latch] + /*********************************************************************** + - P1.0 is high. Set P1.0 to drive or float high + - P1.1 is high. Set P1.1 to drive or float high + - P1.2 is low. Set P1.2 to drive low + - P1.3 is high. Set P1.3 to drive or float high + - P1.4 is high. Set P1.4 to drive or float high + - P1.5 is high. Set P1.5 to drive or float high + - P1.6 is high. Set P1.6 to drive or float high + - P1.7 is high. Set P1.7 to drive or float high + ***********************************************************************/ + P1 = P1_B0__HIGH | P1_B1__HIGH | P1_B2__LOW | P1_B3__HIGH | P1_B4__HIGH + | P1_B5__HIGH | P1_B6__HIGH | P1_B7__HIGH; // [P1 - Port 1 Pin Latch]$ // $[P1MDOUT - Port 1 Output Mode] diff --git a/efm8/src/callback.c b/efm8/src/callback.c index 968e4b2..c8e443e 100644 --- a/efm8/src/callback.c +++ b/efm8/src/callback.c @@ -147,10 +147,14 @@ uint16_t USBD_XferCompleteCb(uint8_t epAddr, USB_Status_TypeDef status, UNUSED(xferred); UNUSED(remaining); - if (epAddr == EP1OUT) + if (epAddr == EP2OUT) { usb_transfer_complete(); } + else if (epAddr == EP3IN) + { + usb_writeback_complete(); + } return 0; } diff --git a/efm8/src/descriptors.c b/efm8/src/descriptors.c index ee84d4e..fb6a6c2 100644 --- a/efm8/src/descriptors.c +++ b/efm8/src/descriptors.c @@ -104,19 +104,19 @@ SI_SEGMENT_VARIABLE(configDesc[], sizeof( ReportDescriptor0 ),// wDescriptorLength(LSB) sizeof( ReportDescriptor0 )>>8,// wDescriptorLength(MSB) - //Endpoint 1 IN Descriptor + //Endpoint 2 IN Descriptor USB_ENDPOINT_DESCSIZE,// bLength USB_ENDPOINT_DESCRIPTOR,// bDescriptorType - 0x81,// bEndpointAddress + 0x83,// bEndpointAddress USB_EPTYPE_INTR,// bAttrib HID_PACKET_SIZE,// wMaxPacketSize (LSB) 0x00,// wMaxPacketSize (MSB) 5,// bInterval - //Endpoint 1 OUT Descriptor + //Endpoint 3 OUT Descriptor USB_ENDPOINT_DESCSIZE,// bLength USB_ENDPOINT_DESCRIPTOR,// bDescriptorType - 0x01,// bEndpointAddress + 0x02,// bEndpointAddress USB_EPTYPE_INTR,// bAttrib HID_PACKET_SIZE,// wMaxPacketSize (LSB) 0x00,// wMaxPacketSize (MSB) diff --git a/efm8/src/main.c b/efm8/src/main.c index 575e0b3..bf2b5ad 100644 --- a/efm8/src/main.c +++ b/efm8/src/main.c @@ -4,7 +4,10 @@ #include "uart_1.h" #include "printing.h" -#define BUFFER_SIZE 13 +#define BUFFER_SIZE 12 + +#define SIGNAL_WRITE_BSY() P1 = P1 & (~(1<<2)) // Set P1 low +#define SIGNAL_WRITE_RDY() P1 = P1 | (1<<2) // Set P1 high data uint8_t write_ptr = 0; data uint8_t read_ptr = 0; @@ -12,20 +15,28 @@ data uint8_t i_ptr = 0; data uint8_t count = 0; data uint8_t writebackbuf_count = 0; -uint8_t hidmsgbuf[64][BUFFER_SIZE]; +uint8_t hidmsgbuf[64*BUFFER_SIZE]; +//uint8_t debugR[64]; +//uint8_t debugRi; +//uint8_t debugW[64]; +//uint8_t debugW2[64]; +//uint8_t debugWi; data uint8_t writebackbuf[64]; void usb_transfer_complete() { count++; +// memmove(debugR, hidmsgbuf + write_ptr*64, 64); +// debugRi = write_ptr; write_ptr++; + if (write_ptr == BUFFER_SIZE) { write_ptr = 0; } if (count == 1 && i_ptr == 0) { - SPI0DAT = hidmsgbuf[read_ptr][i_ptr++]; + SPI0DAT = (hidmsgbuf+read_ptr*64)[i_ptr++]; } @@ -34,27 +45,48 @@ void usb_transfer_complete() } +uint16_t USB_TX_COUNT = 0; + +void usb_writeback_complete() +{ + if (USB_TX_COUNT >= 511/2) + { + USB_TX_COUNT -= 64; + if (USB_TX_COUNT < 511) + { + SIGNAL_WRITE_RDY(); + } + } + else + { + USB_TX_COUNT -= 64; + } +} + void spi_transfer_complete() { count--; i_ptr = 0; SPI0FCN0 |= (1<<2); // Flush rx fifo buffer - if (count) - { - SPI0DAT = hidmsgbuf[read_ptr][i_ptr++]; - } + +// debugWi = read_ptr; + read_ptr++; if (read_ptr == BUFFER_SIZE) { read_ptr = 0; } - + if (count) + { + SPI0DAT = (hidmsgbuf+read_ptr*64)[i_ptr++]; + } // cprints("sent hid msg\r\n"); } - +data int overrun = 0; SI_INTERRUPT (SPI0_ISR, SPI0_IRQn) { + data uint8_t byt; if (SPI0CN0_WCOL == 1) { // Write collision occurred @@ -65,14 +97,22 @@ SI_INTERRUPT (SPI0_ISR, SPI0_IRQn) { // Receive overrun occurred SPI0CN0_RXOVRN = 0; + overrun = 1; // cprints("SPI0CN0_RXOVRN\r\n"); } else { if (EFM32_RW_PIN) { - if (writebackbuf_count < 64) writebackbuf[writebackbuf_count++] = SPI0DAT; - else cprints("overflow\r\n"); + if (writebackbuf_count < 64) + { + writebackbuf[writebackbuf_count++] = SPI0DAT; + SIGNAL_WRITE_BSY(); + } + else + { + cprints("overflow\r\n"); + } } else { @@ -80,8 +120,12 @@ SI_INTERRUPT (SPI0_ISR, SPI0_IRQn) { if (i_ptr < 64) { - SPI0DAT = hidmsgbuf[read_ptr][i_ptr++]; - +// debugW[i_ptr] = (hidmsgbuf+read_ptr*64)[i_ptr]; +// debugW2[i_ptr] = read_ptr; +// if (i_ptr == 63) +// debugW2[i_ptr] = 0xaa; + SPI0DAT = (hidmsgbuf+read_ptr*64)[i_ptr++]; + byt = SPI0DAT; } else { @@ -97,7 +141,8 @@ SI_INTERRUPT (SPI0_ISR, SPI0_IRQn) void usb_write() { data uint8_t errors = 0; - while (USB_STATUS_OK != (USBD_Write(EP1IN, writebackbuf, 64, false))) + USB_TX_COUNT += 64; + while (USB_STATUS_OK != (USBD_Write(EP3IN, writebackbuf, 64, true))) { delay(2); if (errors++ > 30) @@ -131,6 +176,8 @@ int main(void) { IE_EA = 1; IE_ESPI0 = 1; + SIGNAL_WRITE_RDY(); + cprints("hello,world\r\n"); reset = RSTSRC; @@ -138,21 +185,30 @@ int main(void) { while (1) { // delay(1500); + if (overrun) + { + cprints("O\r\n"); + overrun = 0; + } if (millis() - t1 > 1500) { P1_B5 = k++&1; +// if (k&1) +// SIGNAL_WRITE_RDY(); +// else +// SIGNAL_WRITE_BSY(); t1 = millis(); } - if (!USBD_EpIsBusy(EP1OUT) && !USBD_EpIsBusy(EP1IN)) + if (!USBD_EpIsBusy(EP2OUT) && !USBD_EpIsBusy(EP3IN) && lastcount==count) { -// cprintd("sched read to ",1,reset); +// cprintd("sched read to ",1,(int)(hidmsgbuf + write_ptr*64)); if (count == BUFFER_SIZE) { - cprints("Warning, USB buffer full\r\n"); +// cprints("Warning, USB buffer full\r\n"); } else { - USBD_Read(EP1OUT, hidmsgbuf[write_ptr], 64, true); + USBD_Read(EP2OUT, hidmsgbuf + write_ptr*64, 64, true); } } @@ -160,26 +216,31 @@ int main(void) { { // cprints("<< "); // dump_hex(writebackbuf,64); - writebackbuf_count = 0; // while (USBD_EpIsBusy(EP1IN)) // ; usb_write(); + writebackbuf_count = 0; + if (USB_TX_COUNT < 511/2) + { + SIGNAL_WRITE_RDY(); + } } if (lastcount != count) { if (count > lastcount) { -// cprints(">> "); -// dump_hex(writebackbuf,64); +// cputd(debugRi); cprints(">> "); +// dump_hex(debugR,64); MSG_RDY_INT_PIN = 0; MSG_RDY_INT_PIN = 1; } else { -// cprints("efm32 read hid msg\r\n>> "); -// dump_hex(debug,64); +// cputd(debugWi); cprints(">>>> "); +// dump_hex(debugW,64); +// dump_hex(debugW2,64); } lastcount = count; } diff --git a/efm8/src/printing.c b/efm8/src/printing.c index d5edd85..fc866ea 100644 --- a/efm8/src/printing.c +++ b/efm8/src/printing.c @@ -42,6 +42,7 @@ void dump_hex(uint8_t* hex, uint8_t len) putf(lut[b]); b = ((*hex) & 0x0f); putf(lut[b]); + putf(' '); hex++; } cprints("\r\n"); diff --git a/fido2/ctaphid.c b/fido2/ctaphid.c index 7f67997..78068db 100644 --- a/fido2/ctaphid.c +++ b/fido2/ctaphid.c @@ -361,6 +361,7 @@ void ctaphid_handle_packet(uint8_t * pkt_raw) uint32_t newcid; static CTAPHID_WRITE_BUFFER wb; uint32_t active_cid; + uint32_t t1,t2; CTAP_RESPONSE ctap_resp; @@ -542,9 +543,13 @@ void ctaphid_handle_packet(uint8_t * pkt_raw) wb.cmd = CTAPHID_CBOR; wb.bcnt = (ctap_resp.length+1); + + t1 = millis(); ctaphid_write(&wb, &status, 1); ctaphid_write(&wb, ctap_resp.data, ctap_resp.length); ctaphid_write(&wb, NULL, 0); + t2 = millis(); + printf1(TAG_TIME,"CBOR writeback: %d ms\n",(uint32_t)(t2-t1)); break; case CTAPHID_MSG: diff --git a/fido2/device.h b/fido2/device.h index 425f2ef..861f62f 100644 --- a/fido2/device.h +++ b/fido2/device.h @@ -3,7 +3,7 @@ void device_init(); -uint64_t millis(); +uint32_t millis(); // HID message size in bytes #define HID_MESSAGE_SIZE 64 diff --git a/fido2/main.c b/fido2/main.c index 074388f..374c914 100644 --- a/fido2/main.c +++ b/fido2/main.c @@ -5,7 +5,7 @@ #include "cbor.h" #include "device.h" #include "ctaphid.h" -#include "bsp.h" +//#include "bsp.h" #include "util.h" #include "log.h" #include "ctap.h" @@ -16,23 +16,24 @@ int main(int argc, char * argv[]) { int count = 0; - uint64_t t1 = 0; - uint64_t t2 = 0; - uint64_t accum = 0; + uint32_t t1 = 0; + uint32_t t2 = 0; + uint32_t accum = 0; + uint32_t dt = 0; uint8_t hidmsg[64]; set_logging_mask( /*0*/ - TAG_GEN| +// TAG_GEN| /*TAG_MC |*/ /*TAG_GA |*/ /*TAG_CP |*/ - TAG_CTAP| - TAG_HID| +// TAG_CTAP| +// TAG_HID| /*TAG_U2F|*/ /*TAG_PARSE |*/ - /*TAG_TIME|*/ - TAG_DUMP| + TAG_TIME| +// TAG_DUMP| /*TAG_GREEN|*/ /*TAG_RED|*/ TAG_ERR @@ -67,7 +68,9 @@ int main(int argc, char * argv[]) t2 = millis(); ctaphid_handle_packet(hidmsg); accum += millis() - t2; - printf1(TAG_TIME,"accum: %lu\n", (uint32_t)accum); + printf1(TAG_TIME,"accum: %d\n", (uint32_t)accum); + printf1(TAG_TIME,"dt: %d\n", t2 - dt); + dt = t2; memset(hidmsg, 0, sizeof(hidmsg)); } else