added prescaler for 16 bit pwm in LPC1347 target

Fork of mbed-dev by mbed official

Revision:
50:a417edff4437
diff -r 57ac6e3cdfd3 -r a417edff4437 targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/emlib/src/em_crypto.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/emlib/src/em_crypto.c	Fri Jan 15 07:45:16 2016 +0000
@@ -0,0 +1,1847 @@
+/***************************************************************************//**
+ * @file em_crypto.c
+ * @brief Cryptography accelerator peripheral API
+ * @version 4.2.1
+ *******************************************************************************
+ * @section License
+ * <b>(C) Copyright 2015 Silicon Labs, http://www.silabs.com</b>
+ *******************************************************************************
+ *
+ * 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"
+#include "em_bitband.h"
+
+/***************************************************************************//**
+ * @addtogroup EM_Library
+ * @{
+ ******************************************************************************/
+
+/***************************************************************************//**
+ * @addtogroup CRYPTO
+ *
+ * @brief Cryptography accelerator peripheral API
+ *
+ * @details
+ *   This API is intended for use on Silicon Labs target devices, and provides
+ *   a thin software interface for the functions of the crypto module, including
+ *   @li AES (Advanced Encryption Standard) @ref crypto_aes
+ *   @li SHA (Secure Hash Algorithm) @ref crypto_sha
+ *   @li Big Integer multiplier @ref crypto_mul
+ *   @li Functions for loading data and executing instruction sequences @ref crypto_exec
+ *
+ *   @n @section crypto_aes AES
+ *   The AES APIs include support for AES-128 and AES-256 with block cipher
+ *   modes:
+ *   @li CBC - Cipher Block Chaining mode
+ *   @li CFB - Cipher Feedback mode
+ *   @li CTR - Counter mode
+ *   @li ECB - Electronic Code Book mode
+ *   @li OFB - Output Feedback mode
+ *
+ *   For the AES APIs Input/output data (plaintext, ciphertext, key etc) are
+ *   treated as byte arrays, starting with most significant byte. Ie, 32 bytes
+ *   of plaintext (B0...B31) is located in memory in the same order, with B0 at
+ *   the lower address and B31 at the higher address.
+ *
+ *   Byte arrays must always be a multiple of AES block size, ie. a multiple
+ *   of 16. Padding, if required, is done at the end of the byte array.
+ *
+ *   Byte arrays should be word (32 bit) aligned for performance
+ *   considerations, since the array is accessed with 32 bit access type.
+ *   The core MCUs supports unaligned accesses, but with a performance penalty.
+ *
+ *   It is possible to specify the same output buffer as input buffer as long
+ *   as they point to the same address. In that case the provided input buffer
+ *   is replaced with the encrypted/decrypted output. Notice that the buffers
+ *   must be exactly overlapping. If partly overlapping, the behavior is
+ *   undefined.
+ *
+ *   It is up to the user to use a cipher mode according to its requirements
+ *   in order to not break security. Please refer to specific cipher mode
+ *   theory for details.
+ *
+ *   References:
+ *   @li Wikipedia - Cipher modes, http://en.wikipedia.org/wiki/Cipher_modes
+ *
+ *   @li Recommendation for Block Cipher Modes of Operation,
+ *      NIST Special Publication 800-38A, 2001 Edition,
+ *      http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
+ *
+ *   @li Recommendation for Block Cipher Modes of Operation,
+ *      http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
+ *
+ *   @n @section crypto_sha SHA
+ *   The SHA APIs include support for 
+ *   @li SHA-1 @ref CRYPTO_SHA_1
+ *   @li SHA-256 @ref CRYPTO_SHA_256
+ *
+ *   The SHA-1 implementation is FIPS-180-1 compliant, ref:
+ *   @li Wikipedia -  SHA-1, https://en.wikipedia.org/wiki/SHA-1
+ *   @li SHA-1 spec - http://www.itl.nist.gov/fipspubs/fip180-1.htm
+ *
+ *   The SHA-256 implementation is FIPS-180-2 compliant, ref:
+ *   @li Wikipedia -  SHA-2, https://en.wikipedia.org/wiki/SHA-2
+ *   @li SHA-2 spec - http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf
+ *
+ *   @n @section crypto_mul CRYPTO_Mul
+ *   @ref CRYPTO_Mul is a function for multiplying big integers that are
+ *   bigger than the operand size of the MUL instruction which is 128 bits.
+ *   CRYPTO_Mul multiplies all partial operands of the input operands using
+ *   MUL to form a resulting number which may be twice the size of
+ *   the operands.
+ *
+ *   CRPYTO_Mul is typically used by RSA implementations which perform a
+ *   huge amount of multiplication and square operations in order to
+ *   implement modular exponentiation.
+ *   Some RSA implementations use a number representation including arrays
+ *   of 32bit words of variable size. The user should compile with
+ *   -D USE_VARIABLE_SIZED_DATA_LOADS in order to load these numbers
+ *   directly into CRYPTO without converting the number representation.
+ *
+ *   @n @section crypto_exec Load and Execute Instruction Sequences
+ *   The functions for loading data and executing instruction sequences can
+ *   be used to implement complex algorithms like elliptic curve cryptography
+ *   (ECC)) and authenticated encryption algorithms. There are two typical
+ *   modes of operation:
+ *   @li Multi sequence operation
+ *   @li Single static instruction sequence operation
+ *
+ *   In multi sequence mode the software starts by loading input data, then
+ *   an instruction sequence, execute, and finally read the result. This
+ *   process is repeated until the full crypto operation is complete.
+ *
+ *   When using a single static instruction sequence, there is just one
+ *   instruction sequence which is loaded initially. The sequence can be setup
+ *   to run multiple times. The data can be loaded during the execution of the
+ *   sequence by using DMA, BUFC and/or programmed I/O directly from the MCU
+ *   core. For details on how to program the instruction sequences please refer
+ *   to the reference manual of the particular Silicon Labs device.
+ *
+ *   In order to load input data to the CRYPTO module use any of the following
+ *   functions:
+ *   @li @ref CRYPTO_DataWrite  - Write 128 bits to a DATA register.
+ *   @li @ref CRYPTO_DDataWrite - Write 256 bits to a DDATA register.
+ *   @li @ref CRYPTO_QDataWrite - Write 512 bits to a QDATA register.
+ *
+ *   In order to read output data from the CRYPTO module use any of the
+ *   following functions:
+ *   @li @ref CRYPTO_DataRead  - Read 128 bits from a DATA register.
+ *   @li @ref CRYPTO_DDataRead - Read 256 bits from a DDATA register.
+ *   @li @ref CRYPTO_QDataRead - Read 512 bits from a QDATA register.
+ *
+ *   In order to load an instruction sequence to the CRYPTO module use
+ *   @ref CRYPTO_InstructionSequenceLoad.
+ *
+ *   In order to execute the current instruction sequence in the CRYPTO module
+ *   use @ref CRYPTO_InstructionSequenceExecute.
+ *
+ *   In order to check whether an instruction sequence has completed
+ *   use @ref CRYPTO_InstructionSequenceDone.
+ *
+ *   In order to wait for an instruction sequence to complete
+ *   use @ref CRYPTO_InstructionSequenceWait.
+ *
+ *   In order to optimally load (with regards to speed) and execute an
+ *   instruction sequence use any of the CRYPTO_EXECUTE_X macros (where X is
+ *   in the range 1-20) defined in @ref em_crypto.h. E.g. CRYPTO_EXECUTE_19.
+ * @{
+ ******************************************************************************/
+
+/*******************************************************************************
+ *******************************   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(uint32_t len,
+                                          CRYPTO_DataReg_TypeDef inReg,
+                                          uint32_t * in,
+                                          CRYPTO_DataReg_TypeDef outReg,
+                                          uint32_t * out);
+
+static void CRYPTO_AES_CBCx(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(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(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(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(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 type used for wide arithmetic operations.
+ *
+ * @details
+ *   This function sets the modulus type to be used by the Modulus instructions
+ *   of the CRYPTO module.
+ *
+ * @param[in]  modType  Modulus type.
+ ******************************************************************************/
+void CRYPTO_ModulusSet(CRYPTO_ModulusType_TypeDef modType)
+{
+  uint32_t temp = CRYPTO->WAC & (~(_CRYPTO_WAC_MODULUS_MASK | _CRYPTO_WAC_MODOP_MASK));
+
+  switch (modType)
+  {
+    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 | modType | 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 | modType | CRYPTO_WAC_MODOP_REGULAR;
+      break;
+
+    default:
+      /* Unknown modulus type. */
+      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]  val     Value of the data to write to the KEYBUF register.
+ * @param[in]  keyWidth Key width - 128 or 256 bits
+ ******************************************************************************/
+void CRYPTO_KeyRead(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]  msg        Message to hash.
+ * @param[in]  msgLen     Length of message in bytes.
+ * @param[out] msgDigest  Message digest.
+ ******************************************************************************/
+void CRYPTO_SHA_1(const uint8_t *              msg,
+                  uint64_t                     msgLen,
+                  CRYPTO_SHA1_Digest_TypeDef   msgDigest)
+{
+  uint32_t  temp;
+  int       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(cryptoResult256Bits);
+  
+  /* Write init value to DDATA1.  */
+  CRYPTO_DDataWrite(cryptoRegDDATA1, shaBlock);
+
+  /* Copy data to DDATA0 and select DDATA0 and DDATA1 for SHA operation. */
+  CRYPTO_EXECUTE_2(CRYPTO_CMD_INSTR_DDATA1TODDATA0,
+                   CRYPTO_CMD_INSTR_SELDDATA0DDATA1);
+
+  len = msgLen;
+
+  while (len >= CRYPTO_SHA1_BLOCK_SIZE_IN_BYTES)
+  {
+    /* Write block to QDATA1.  */
+    CRYPTO_QDataWrite(cryptoRegQDATA1BIG, (uint32_t *) msg);
+
+    /* Execute SHA */
+    CRYPTO_EXECUTE_3(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(cryptoRegQDATA1BIG, shaBlock);
+
+    /* Execute SHA */
+    CRYPTO_EXECUTE_3(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(cryptoRegQDATA1BIG, shaBlock);
+
+  /* Execute SHA */
+  CRYPTO_EXECUTE_3(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]  msg        Message to hash.
+ * @param[in]  msgLen     Length of message in bytes.
+ * @param[out] msgDigest  Message digest.
+ ******************************************************************************/
+void CRYPTO_SHA_256(const uint8_t *              msg,
+                    uint64_t                     msgLen,
+                    CRYPTO_SHA256_Digest_TypeDef msgDigest)
+{
+  uint32_t  temp;
+  int       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(cryptoResult256Bits);
+
+  /* Write init value to DDATA1.  */
+  CRYPTO_DDataWrite(cryptoRegDDATA1, shaBlock);
+
+  /* Copy data ot DDATA0 and select DDATA0 and DDATA1 for SHA operation. */
+  CRYPTO_EXECUTE_2(CRYPTO_CMD_INSTR_DDATA1TODDATA0,
+                   CRYPTO_CMD_INSTR_SELDDATA0DDATA1);
+  len = msgLen;
+
+  while (len >= CRYPTO_SHA256_BLOCK_SIZE_IN_BYTES)
+  {
+    /* Write block to QDATA1BIG.  */
+    CRYPTO_QDataWrite(cryptoRegQDATA1BIG, (uint32_t *) msg);
+
+    /* Execute SHA */
+    CRYPTO_EXECUTE_3(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(cryptoRegQDATA1BIG, shaBlock);
+
+    /* Execute SHA */
+    CRYPTO_EXECUTE_3(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(cryptoRegQDATA1BIG, shaBlock);
+
+  /* Execute SHA */
+  CRYPTO_EXECUTE_3(CRYPTO_CMD_INSTR_SHA,
+                   CRYPTO_CMD_INSTR_MADD32,
+                   CRYPTO_CMD_INSTR_DDATA0TODDATA1);
+
+  /* Read resulting message digest from DDATA0BIG.  */
+  CRYPTO_DDataRead(cryptoRegDDATA0BIG, (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(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_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(
+                     /* 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(cryptoRegDATA2,
+                                   &A[i*PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS],
+                                   numWordsLastOperandA);
+    else
+      CRYPTO_DataWrite(cryptoRegDATA2, &A[i*PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS]);
+#else
+    CRYPTO_DataWrite(cryptoRegDATA2, &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(cryptoRegDATA1,
+                                   &R[i*PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS],
+                                   numWordsLastOperandR);
+    else
+      CRYPTO_DataWrite(cryptoRegDATA1, &R[i*PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS]);
+#else
+    CRYPTO_DataWrite(cryptoRegDATA1, &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();
+
+    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(cryptoRegDATA0,
+                                     &B[j*PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS],
+                                     numWordsLastOperandB);
+      else
+        CRYPTO_DataWrite(cryptoRegDATA0,
+                         &B[j*PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS]);
+#else
+      CRYPTO_DataWrite(cryptoRegDATA0,
+                       &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(cryptoRegDATA1,
+                                     &R[(i+j+1)*PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS],
+                                     numWordsLastOperandR);
+      else
+        CRYPTO_DataWrite(cryptoRegDATA1,
+                         &R[(i+j+1)*PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS]);
+#else
+      CRYPTO_DataWrite(cryptoRegDATA1,
+                       &R[(i+j+1)*PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS]);
+#endif
+      /* Store least significant partial result */
+      CRYPTO_DataRead(cryptoRegDATA0,
+                      &R[(i+j)*PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS]);
+
+    } /* for (j=0; j<numPartialOperandsB; j++) */
+
+    /* Handle carry at the end of the inner loop. */
+    if (CRYPTO_CarryIsSet())
+      cryptoBigintIncrement(&R[(i+numPartialOperandsB+1)
+                               *PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS],
+                            (numPartialOperandsA-i-1)
+                            *PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS);
+
+    CRYPTO_DataRead(cryptoRegDATA1,
+                    &R[(i+numPartialOperandsB)
+                       * PARTIAL_OPERAND_WIDTH_IN_32BIT_WORDS]);
+
+  } /* for (i=0; i<numPartialOperandsA; i++) */
+}
+
+/***************************************************************************//**
+ * @brief
+ *   AES Cipher-block chaining (CBC) cipher mode encryption/decryption, 128 bit key.
+ *
+ * @details
+ *   Encryption:
+ * @verbatim
+ *           Plaintext                  Plaintext
+ *               |                          |
+ *               V                          V
+ * InitVector ->XOR        +-------------->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[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(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(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[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(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(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[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(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(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[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(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(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[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(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(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[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(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(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[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(uint8_t * out, const uint8_t * in)
+{
+  uint32_t       * _out = (uint32_t *) out;
+  const uint32_t * _in  = (const uint32_t *) in;
+
+  /* Load key */
+  CRYPTO_BurstToCrypto(&CRYPTO->KEYBUF, &_in[0]);
+
+  /* Do dummy encryption to generate decrypt key */
+  CRYPTO->CTRL = CRYPTO_CTRL_AES_AES128;
+  CRYPTO_IntClear(CRYPTO_IF_INSTRDONE);
+  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[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(uint8_t * out, const uint8_t * in)
+{
+  uint32_t       * _out = (uint32_t *) out;
+  const uint32_t * _in  = (const uint32_t *) in;
+
+  /* Load key */
+  CRYPTO_BurstToCrypto(&CRYPTO->KEYBUF, &_in[0]);
+  CRYPTO_BurstToCrypto(&CRYPTO->KEYBUF, &_in[4]);
+
+  /* Do dummy encryption to generate decrypt key */
+  CRYPTO->CTRL = CRYPTO_CTRL_AES_AES256;
+  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[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(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(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[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(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(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[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(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(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[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(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(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[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(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((uint32_t *)key, keyWidth);
+
+  if (encrypt)
+  {
+    CRYPTO_DataWrite(cryptoRegDATA0, (uint32_t *)iv);
+
+    CRYPTO->SEQ0 =
+      CRYPTO_CMD_INSTR_DATA1TODATA0XOR << _CRYPTO_SEQ0_INSTR0_SHIFT |
+      CRYPTO_CMD_INSTR_AESENC          << _CRYPTO_SEQ0_INSTR1_SHIFT;
+        
+    CRYPTO_AES_ProcessLoop(len,
+                           cryptoRegDATA1, (uint32_t *) in,
+                           cryptoRegDATA0, (uint32_t *) out);
+  }
+  else
+  {
+    CRYPTO_DataWrite(cryptoRegDATA2, (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(len,
+                           cryptoRegDATA1, (uint32_t *) in,
+                           cryptoRegDATA0, (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[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(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((uint32_t *)key, keyWidth);
+
+  /* Load instructions to CRYPTO sequencer. */
+  if (encrypt)
+  {
+    /* Load IV */
+    CRYPTO_DataWrite(cryptoRegDATA0, (uint32_t *)iv);
+
+    CRYPTO->SEQ0 =
+      CRYPTO_CMD_INSTR_AESENC          << _CRYPTO_SEQ0_INSTR0_SHIFT |
+      CRYPTO_CMD_INSTR_DATA1TODATA0XOR << _CRYPTO_SEQ0_INSTR1_SHIFT;
+    
+    CRYPTO_AES_ProcessLoop(len,
+                           cryptoRegDATA1, (uint32_t *)in,
+                           cryptoRegDATA0, (uint32_t *)out
+                           );
+  }
+  else
+  {
+    /* Load IV */
+    CRYPTO_DataWrite(cryptoRegDATA2, (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(len,
+                           cryptoRegDATA1, (uint32_t *)in,
+                           cryptoRegDATA0, (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[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(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((uint32_t *)key, keyWidth);
+
+  CRYPTO_DataWrite(cryptoRegDATA1, (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(len,
+                         cryptoRegDATA2, (uint32_t *) in,
+                         cryptoRegDATA0, (uint32_t *) out);
+
+  CRYPTO_DataRead(cryptoRegDATA1, (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[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(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((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(len,
+                         cryptoRegDATA0, (uint32_t *) in,
+                         cryptoRegDATA1, (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[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(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((uint32_t *)key, keyWidth);
+
+  CRYPTO_DataWrite(cryptoRegDATA2, (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(len,
+                         cryptoRegDATA0, (uint32_t *) in,
+                         cryptoRegDATA1, (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] 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(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 EM_Library) */
+
+#endif /* defined(CRYPTO_COUNT) && (CRYPTO_COUNT > 0) */