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