/* Copyright (c) 2010 - 2017, Nordic Semiconductor ASA
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form, except as embedded into a Nordic
 *    Semiconductor ASA integrated circuit in a product or a software update for
 *    such product, must reproduce the above copyright notice, this list of
 *    conditions and the following disclaimer in the documentation and/or other
 *    materials provided with the distribution.
 *
 * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
 *    contributors may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * 4. This software, with or without modification, must only be used with a
 *    Nordic Semiconductor ASA integrated circuit.
 *
 * 5. Any software provided in binary form under this license must not be reverse
 *    engineered, decompiled, modified and/or disassembled.
 *
 * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "enc.h"

#include <stddef.h>
#include <string.h>
#include <nrf_error.h>

#include "rand.h"
#include "aes.h"
#include "aes_cmac.h"
#include "ccm_soft.h"
#include "log.h"
#include "packet_mesh.h"

#define ENC_K2_SALT_INPUT { 's', 'm', 'k', '2' }
#define ENC_K2_NID_MASK   PACKET_MESH_NID_MASK

#define ENC_K3_SALT_INPUT { 's', 'm', 'k', '3' }
#define ENC_K3_KEY_DATA   { 'i', 'd', '6', '4', 0x01 }

#define ENC_K4_SALT_INPUT  { 's', 'm', 'k', '4' }
#define ENC_K4_KEY_DATA    { 'i', 'd', '5', 0x01 }
#define ENC_K4_OUTPUT_MASK 0x1f

/********************/
/* Public functions */
/********************/

void enc_key_generate(uint8_t * p_key)
{
    rand_hw_rng_get(p_key, 16);
}

void enc_aes_encrypt(const uint8_t * p_key, const uint8_t * p_plaintext, uint8_t * p_result)
{
    aes_encrypt(p_key, p_plaintext, p_result);
}

void enc_aes_cmac(const uint8_t * p_key, const uint8_t * p_data, uint16_t data_len, uint8_t * p_result)
{
    aes_cmac(p_key, p_data, data_len, p_result);
}

void enc_aes_ccm_encrypt(ccm_soft_data_t * const p_ccm_data)
{
    ccm_soft_encrypt(p_ccm_data);
}

void enc_aes_ccm_decrypt(ccm_soft_data_t * const p_ccm_data, bool * const p_mic_passed)
{
    ccm_soft_decrypt(p_ccm_data, p_mic_passed);
}


/*********************/
/* Utility functions */
/*********************/

void enc_nonce_generate(packet_net_hdr_t const * const p_net_pkt_hdr,
                        uint32_t iv_index,
                        enc_nonce_t type,
                        uint8_t * const p_nonce)
{
    switch (type)
    {
        case ENC_NONCE_NET:
        {
            enc_nonce_net_t * p_net_nonce = (enc_nonce_net_t *) p_nonce;
            p_net_nonce->type     = ENC_NONCE_NET;
            p_net_nonce->ttl      = p_net_pkt_hdr->ttl;
            p_net_nonce->ctl      = p_net_pkt_hdr->ctl;
            p_net_nonce->seq      = p_net_pkt_hdr->seq;
            p_net_nonce->src      = p_net_pkt_hdr->src;
            p_net_nonce->padding  = 0;
            p_net_nonce->iv_index = iv_index;
            __LOG_XB(LOG_SRC_NETWORK, LOG_LEVEL_INFO, "Nonce NET: ", p_nonce, 13);
            break;
        }
        case ENC_NONCE_APP:
        {
            enc_nonce_app_t * p_app_nonce = (enc_nonce_app_t *) p_nonce;
            p_app_nonce->type     = ENC_NONCE_APP;
            p_app_nonce->zero1    = 0;
            p_app_nonce->seq      = p_net_pkt_hdr->seq;
            p_app_nonce->src      = p_net_pkt_hdr->src;
            p_app_nonce->dst      = p_net_pkt_hdr->dst;
            p_app_nonce->iv_index = iv_index;
            __LOG_XB(LOG_SRC_TRANSPORT, LOG_LEVEL_INFO, "Nonce APP: ", p_nonce, 13);
            break;
        }
        case ENC_NONCE_DEV:
        {
            enc_nonce_dev_t * p_dev_nonce = (enc_nonce_dev_t *) p_nonce;
            p_dev_nonce->type     = ENC_NONCE_DEV;
            p_dev_nonce->zero1    = 0;
            p_dev_nonce->seq      = p_net_pkt_hdr->seq;
            p_dev_nonce->src      = p_net_pkt_hdr->src;
            p_dev_nonce->dst      = p_net_pkt_hdr->dst;
            p_dev_nonce->iv_index = iv_index;
            __LOG_XB(LOG_SRC_TRANSPORT, LOG_LEVEL_INFO, "Nonce DEV: ", p_nonce, 13);
            break;
        }
        default:
            break;
    }
}

void enc_s1(const uint8_t * p_in, uint16_t in_length, uint8_t * p_out)
{
    NRF_MESH_ASSERT(p_in != NULL && p_out != NULL);

    uint8_t key[16] = {0};
    enc_aes_cmac(key, p_in, in_length, p_out);
}

void enc_k1(const uint8_t * p_ikm, const uint8_t ikm_length, const uint8_t * p_salt,
            const uint8_t * p_info, const uint8_t info_length, uint8_t * const p_out)
{
    uint8_t tmp[NRF_MESH_KEY_SIZE];

    NRF_MESH_ASSERT(p_ikm != NULL && p_salt != NULL && p_info != NULL && p_out != NULL);

    enc_aes_cmac(p_salt, p_ikm, ikm_length, tmp);
    enc_aes_cmac(tmp, p_info, info_length, p_out);
}

void enc_k2(const uint8_t * p_netkey, const uint8_t * p_p, uint16_t length_p,
            nrf_mesh_network_secmat_t * p_output)
{
    NRF_MESH_ASSERT(p_netkey != NULL && p_p != NULL && p_output != NULL);

    uint8_t tmp[NRF_MESH_KEY_SIZE + length_p + 1];
    const uint8_t salt_input[] = ENC_K2_SALT_INPUT;
    enc_s1(salt_input, sizeof(salt_input), tmp);

    uint8_t key[NRF_MESH_KEY_SIZE];
    enc_aes_cmac(tmp, p_netkey, NRF_MESH_KEY_SIZE, key);

    /* T0 = zero length input */
    /* T1 = AES-CMAC(key, T0 || P || 0x01) */
    memcpy(tmp, p_p, length_p);
    tmp[length_p] = 0x01;
    enc_aes_cmac(key, tmp, length_p + 1, tmp);
    p_output->nid = tmp[NRF_MESH_KEY_SIZE - 1] & ENC_K2_NID_MASK;

    /* T2 = AES-CMAC(key, T1 || P || 0x02) */
    memcpy(tmp + NRF_MESH_KEY_SIZE, p_p, length_p);
    tmp[NRF_MESH_KEY_SIZE + length_p] = 0x02;
    enc_aes_cmac(key, tmp, NRF_MESH_KEY_SIZE + length_p + 1, p_output->encryption_key);

    /* T3 = AES-CMAC(key, T2 || P || 0x03) */
    memcpy(tmp, p_output->encryption_key, NRF_MESH_KEY_SIZE);
    tmp[NRF_MESH_KEY_SIZE + length_p] = 0x03;
    enc_aes_cmac(key, tmp, NRF_MESH_KEY_SIZE + length_p + 1, p_output->privacy_key);
}

void enc_k3(const uint8_t * p_in, uint8_t * p_out)
{
    NRF_MESH_ASSERT(p_in != NULL && p_out != NULL);

    uint8_t tmp[NRF_MESH_KEY_SIZE];
    const uint8_t salt_input[] = ENC_K3_SALT_INPUT;
    enc_s1(salt_input, sizeof(salt_input), tmp);

    enc_aes_cmac(tmp, p_in, NRF_MESH_KEY_SIZE, tmp);

    const uint8_t data_array[] = ENC_K3_KEY_DATA;
    enc_aes_cmac(tmp, data_array, sizeof(data_array), tmp);

    /* Only the 8 least significant bytes are returned (mod 2^64): */
    memcpy(p_out, tmp + 8, 8);
}

void enc_k4(const uint8_t * p_in, uint8_t * p_out)
{
    NRF_MESH_ASSERT(p_in != NULL && p_out != NULL);

    uint8_t tmp[NRF_MESH_KEY_SIZE];

    const uint8_t salt_input[] = ENC_K4_SALT_INPUT;
    enc_s1(salt_input, sizeof(salt_input), tmp);

    enc_aes_cmac(tmp, p_in, NRF_MESH_KEY_SIZE, tmp);

    const uint8_t data_array[] = ENC_K4_KEY_DATA;
    enc_aes_cmac(tmp, data_array, sizeof(data_array), tmp);

    *p_out = tmp[NRF_MESH_KEY_SIZE - 1] & ENC_K4_OUTPUT_MASK;
}

