imob

Dependencies:   mbedtls mbed BLE_API nRF51822 AccelSensor

crypt.h

Committer:
osilvam
Date:
2021-03-20
Revision:
1:471d502617fe
Parent:
0:5284859bb3e8

File content as of revision 1:471d502617fe:

#include "nrf_soc.h"
#include "nrf_delay.h"
#include "app_error.h"

#define ECB_KEY_LEN            (16UL)
#define COUNTER_BYTE_LEN       (4UL)
#define NONCE_RAND_BYTE_LEN    (12UL)

// The RNG wait values are typical and not guaranteed. See Product Specifications for more info.
#ifdef NRF51
#define RNG_BYTE_WAIT_US       (677UL)
#elif defined NRF52
#define RNG_BYTE_WAIT_US       (124UL)
#else
#error "Either NRF51 or NRF52 must be defined."
#endif

/**
 * @brief Uses the RNG to write a 12-byte nonce to a buffer
 * @details The 12 bytes will be written to the buffer starting at index 4 to leave
 *          space for the 4-byte counter value.
 *
 * @param[in]    p_buf    An array of length 16
 */
void nonce_generate(uint8_t * p_buf)
{
    uint8_t i         = COUNTER_BYTE_LEN;
    uint8_t remaining = NONCE_RAND_BYTE_LEN;

    // The random number pool may not contain enough bytes at the moment so
    // a busy wait may be necessary.
    while(0 != remaining)
    {
        uint32_t err_code;
        uint8_t  available = 0;

        err_code = sd_rand_application_bytes_available_get(&available);
        APP_ERROR_CHECK(err_code);

        available = ((available > remaining) ? remaining : available);
        if (0 != available)
        {
            err_code = sd_rand_application_vector_get((p_buf + i), available);
            APP_ERROR_CHECK(err_code);

            i         += available;
            remaining -= available;
        }

        if (0 != remaining)
        {
            nrf_delay_us(RNG_BYTE_WAIT_US * remaining);
        }
    }    
}

static bool m_initialized = false;

// NOTE: The ECB data must be located in RAM or a HardFault will be triggered.
static nrf_ecb_hal_data_t m_ecb_data;

/**
 * @brief Initializes the module with the given nonce and key
 * @details The nonce will be copied to an internal buffer so it does not need to
 *          be retained after the function returns. Additionally, a 32-bit counter
 *          will be initialized to zero and placed into the least-significant 4 bytes
 *          of the internal buffer. The nonce value should be generated in a
 *          reasonable manner (e.g. using this module's nonce_generate function).
 *
 * @param[in]    p_nonce    An array of length 16 containing 12 random bytes
 *                          starting at index 4
 * @param[in]    p_ecb_key  An array of length 16 containing the ECB key
 */
void ctr_init(const uint8_t * p_nonce, const uint8_t * p_ecb_key)
{
    m_initialized = true;

    // Save the key.
    memcpy(&m_ecb_data.key[0], p_ecb_key, ECB_KEY_LEN);

    // Copy the nonce.
    memcpy(&m_ecb_data.cleartext[COUNTER_BYTE_LEN],
              &p_nonce[COUNTER_BYTE_LEN],
              NONCE_RAND_BYTE_LEN);

    // Zero the counter value.
    memset(&m_ecb_data.cleartext[0], 0x00, COUNTER_BYTE_LEN);
}

static uint32_t crypt(uint8_t * buf)
{
    uint8_t  i;
    uint32_t err_code;

    if (!m_initialized)
    {
        return NRF_ERROR_INVALID_STATE;
    }

    err_code = sd_ecb_block_encrypt(&m_ecb_data);
    if (NRF_SUCCESS != err_code)
    {
        return err_code;
    }

    for (i=0; i < ECB_KEY_LEN; i++)
    {
        buf[i] ^= m_ecb_data.ciphertext[i];
    }

    // Increment the counter.
    (*((uint32_t*) m_ecb_data.cleartext))++;

    return NRF_SUCCESS;
}

/**
 * @brief Encrypts the given buffer in-situ
 * @details The encryption step is done separately (using the nonce, counter, and
 *          key) and then the result from the encryption is XOR'd with the given
 *          buffer in-situ. The counter will be incremented only if no error occurs.
 *
 * @param[in]    p_clear_text    An array of length 16 containing the clear text
 *
 * @retval    NRF_SUCCESS                         Success
 * @retval    NRF_ERROR_INVALID_STATE             Module has not been initialized
 * @retval    NRF_ERROR_SOFTDEVICE_NOT_ENABLED    SoftDevice is present, but not enabled
 */
uint32_t ctr_encrypt(uint8_t * p_clear_text)
{
    return crypt(p_clear_text);
}

/**
 * @brief Decrypts the given buffer in-situ
 * @details The encryption step is done separately (using the nonce, counter, and
 *          key) and then the result from the encryption is XOR'd with the given
 *          buffer in-situ. The counter will be incremented only if no error occurs.
 *
 * @param[in]    p_cipher_text    An array of length 16 containing the cipher text
 *
 * @retval    NRF_SUCCESS                         Succeess
 * @retval    NRF_ERROR_INVALID_STATE             Module has not been initialized
 * @retval    NRF_ERROR_SOFTDEVICE_NOT_ENABLED    SoftDevice is present, but not enabled
 */
uint32_t ctr_decrypt(uint8_t * p_cipher_text)
{
    return crypt(p_cipher_text);
}