/* packet-rf4ce-secur.h
 * Security related functions and objects for RF4CE dissector
 * Copyright (C) Atmosic 2023
 *
 * Wireshark - Network traffic analyzer
 * By Gerald Combs <gerald@wireshark.org>
 * Copyright 1998 Gerald Combs
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 */

#ifndef PACKET_RF4CE_SECUR_H
#define PACKET_RF4CE_SECUR_H

#include <stdbool.h>
#include "config.h"
#include <epan/packet.h>
#include <epan/expert.h>
#include <epan/uat.h>
#include <epan/value_string.h>

#define RF4CE_IEEE_ADDR_LEN                 8
#define RF4CE_SHORT_ADDR_LEN                2

#define RF4CE_MIN_NWK_LENGTH                5
#define RF4CE_MAX_NWK_LENGTH                148

#define RF4CE_VENDOR_SECRET_STORAGE_SIZE    64
#define RF4CE_NWK_KEY_STORAGE_SIZE          64
#define RF4CE_ADDR_TABLE_SIZE               (RF4CE_NWK_KEY_STORAGE_SIZE * 2)

#define RF4CE_NWK_KEY_SEED_DATA_LENGTH      80

#define RF4CE_CCM_M                         4
#define RF4CE_CCM_L                         2
#define RF4CE_CCM_NONCE_LEN                 (15 - RF4CE_CCM_L)
#define RF4CE_SECUR_CONTROL                 5
#define SEC_STR_LEN                         16
#define KEY_LEN                             SEC_STR_LEN

typedef struct keypair_context_s {
    uint8_t nwk_key_seed_latest[RF4CE_NWK_KEY_SEED_DATA_LENGTH];
    uint8_t nwk_key_seed_prev[RF4CE_NWK_KEY_SEED_DATA_LENGTH];
    uint8_t nwk_key_seed[RF4CE_NWK_KEY_SEED_DATA_LENGTH];
    uint8_t controller_addr[RF4CE_IEEE_ADDR_LEN];
    uint8_t target_addr[RF4CE_IEEE_ADDR_LEN];
    uint8_t nwk_key_exchange_transfer_expected;
    uint8_t nwk_key_exchange_transfer_received;
} keypair_context_t;

#define RF4CE_PROFILE_CMD_KEY_EXCHANGE_RAND_A_LENGTH    8
#define RF4CE_PROFILE_CMD_KEY_EXCHANGE_RAND_B_LENGTH    8

#define RF4CE_PROFILE_CMD_KEY_EXCHANGE_RAND_AB_LENGTH   \
    (RF4CE_PROFILE_CMD_KEY_EXCHANGE_RAND_A_LENGTH       \
     + RF4CE_PROFILE_CMD_KEY_EXCHANGE_RAND_B_LENGTH)

#define RF4CE_PROFILE_CMD_KEY_EXCHANGE_TAG_A_LENGTH     4
#define RF4CE_PROFILE_CMD_KEY_EXCHANGE_TAG_B_LENGTH     4

#define RF4CE_KEY_EXCHANGE_CONTEXT_LENGTH               9
#define RF4CE_KEY_EXCHANGE_LABEL_LENGTH                 (2 * (RF4CE_IEEE_ADDR_LEN))

#define RF4CE_CMAC_ARG_2_LENGTH         \
    (RF4CE_KEY_EXCHANGE_CONTEXT_LENGTH  \
     + RF4CE_KEY_EXCHANGE_LABEL_LENGTH  \
     + KEY_LEN)

/* RF4CE GDP 2.0 spec, part 7.4.2 Key generation
 * Context shall be set to the ASCII representation of the nine character string (including a space
 * after "RF4CE" but without quotes and without null termination) "RF4CE GDP".
 */
#define CONTEXT_STR         "RF4CE GDP"
#define CONTEXT_STR_LEN     9

extern uint8_t DEFAULT_SECRET[SEC_STR_LEN];

typedef struct key_exchange_context_s {
    uint8_t rand_a[RF4CE_PROFILE_CMD_KEY_EXCHANGE_RAND_A_LENGTH];
    uint8_t rand_b[RF4CE_PROFILE_CMD_KEY_EXCHANGE_RAND_B_LENGTH];
    uint8_t mac_a[RF4CE_IEEE_ADDR_LEN]; /* target address     */
    uint8_t mac_b[RF4CE_IEEE_ADDR_LEN]; /* controller address */
    bool is_proc_started;
} key_exchange_context_t;

typedef struct
#if defined(_MSC_VER)
# pragma pack(push, 1)
#else
__attribute__((__packed__))
#endif
rf4ce_key_dk_tag_s
{
    uint8_t a[RF4CE_PROFILE_CMD_KEY_EXCHANGE_RAND_A_LENGTH];
    uint8_t b[RF4CE_PROFILE_CMD_KEY_EXCHANGE_RAND_B_LENGTH];
} rf4ce_key_dk_tag_t;
#ifdef _MSC_VER
# pragma pack(pop)
#endif

typedef struct
#if defined(_MSC_VER)
# pragma pack(push, 1)
#else
__attribute__((__packed__))
#endif
rf4ce_key_context_s
{
    uint8_t context[CONTEXT_STR_LEN];
    uint8_t mac_a[RF4CE_IEEE_ADDR_LEN];
    uint8_t mac_b[RF4CE_IEEE_ADDR_LEN];
    uint8_t pairing_key[KEY_LEN];
}
rf4ce_key_context_t;
#ifdef _MSC_VER
# pragma pack(pop)
#endif

void rf4ce_aes_cmac(unsigned char *input, unsigned long length, unsigned char *key, unsigned char *mac_value);

typedef struct addr_entry_s {
    uint8_t ieee_addr[RF4CE_IEEE_ADDR_LEN];
    uint16_t short_addr;
    bool is_used;
} addr_entry_t;

typedef struct nwk_key_entry_s {
    uint8_t nwk_key[KEY_LEN];
    addr_entry_t *controller_addr_ent;
    addr_entry_t *target_addr_ent;
    bool key_from_gui;
    bool is_used;
    bool is_pairing_key;
} nwk_key_entry_t;

typedef struct vendor_secret_entry_s {
    uint8_t secret[SEC_STR_LEN];
    bool is_used;
} vendor_secret_entry_t;

typedef struct uat_security_record_s {
    char *sec_str;
    uint8_t type;
    char *label;
} uat_security_record_t;

void keypair_context_init(const uint8_t *controller_ieee, const uint8_t *target_ieee, uint8_t expected_transfer_count);
void keypair_context_update_seed(uint8_t *seed, uint8_t seed_seqn);

void nwk_key_storage_add_entry(uint8_t *nwk_key, addr_entry_t *controller_addr_ent, addr_entry_t *target_addr_ent, bool key_from_gui, bool is_pairing_key);
void nwk_key_storage_release_entry(uint8_t *nwk_key, bool key_from_gui);

void rf4ce_addr_table_add_addrs(const void *ieee_addr, uint16_t short_addr);
bool rf4ce_addr_table_get_ieee_addr(uint8_t *ieee_addr, packet_info *pinfo, bool is_src);
addr_entry_t *rf4ce_addr_table_get_addr_entry_by_ieee(uint8_t *ieee_addr);

void key_exchange_context_init(void);

void key_exchange_context_start_procedure(void);
void key_exchange_context_stop_procedure(void);
bool key_exchange_context_is_procedure_started(void);

void key_exchange_context_set_rand_a(uint8_t *rand_a);
void key_exchange_context_set_rand_b(uint8_t *rand_b);

void key_exchange_context_set_mac_a(uint8_t *mac_a);
void key_exchange_context_set_mac_b(uint8_t *mac_b);

void key_exchange_calc_key(uint32_t tag_b_pack);

void vendor_secret_storage_add_entry(uint8_t *secret);
void vendor_secret_storage_release_entry(uint8_t *secret);

void rf4ce_secur_cleanup(void);

typedef struct
#if defined(_MSC_VER)
# pragma pack(push, 1)
#else
__attribute__((__packed__))
#endif
rf4ce_secur_ccm_nonce_s
{
    uint8_t source_address[RF4CE_IEEE_ADDR_LEN];     /*!< Extended Source */
    uint32_t frame_counter;                          /*!< Frame Counter */
    uint8_t secur_control;                           /*!< Security Control Field */
} rf4ce_secur_ccm_nonce_t;
#ifdef _MSC_VER
# pragma pack(pop)
#endif

typedef struct
#if defined(_MSC_VER)
# pragma pack(push, 1)
#else
__attribute__((__packed__))
#endif
rf4ce_secur_ccm_auth_s
{
    uint8_t frame_control;                           /*!< Security Control Field */
    uint32_t frame_counter;                          /*!< Frame Counter */
    uint8_t dest_address[RF4CE_IEEE_ADDR_LEN];       /*!< Extended Source */
} rf4ce_secur_ccm_auth_t;
#ifdef _MSC_VER
# pragma pack(pop)
#endif

bool decrypt_data(
    const uint8_t *in,
    uint8_t *out,
    uint16_t payload_offset,
    uint16_t *len,
    uint8_t src_ieee[RF4CE_IEEE_ADDR_LEN],
    uint8_t dst_ieee[RF4CE_IEEE_ADDR_LEN]);

#endif /* PACKET_RF4CE_SECUR_H */
