#ifndef DK_CRYPTO_H
#define DK_CRYPTO_H

#include "dk_common.h"
#include "dk_log.h"
#include "dk_scp_common.h"
#include "dk_constants.h"

/**
 * Calculates the SHA-256 hash for a given input.
 * 
 * @param in The data to be hashed
 * @param in_len The data buffer size
 * @param out The output buffer contaning the hash of the input. This buffer will always be 32 bytes (256 bits) long
 * @return The error code for the operation
 */
DK_Result sha256(byte* in, size_t in_len, byte* out);

/**
 * Calculates C-MAC according using the session key passed in @s_key.
 *
 * @param s_key The key to be used for C-MAC calculation
 * @param s_key_len The length of the key buffer in bytes
 * @param out The C-MAC digest
 * @param n The number of byte arrays to follow
 * @param ... n byte arrays followed by it's length
 * @return The error code for the operation
 */
DK_Result calculate_cmac(
    byte* s_key, 
    size_t s_key_len, 
    byte* out, 
    size_t out_len,
    size_t n, ...);

/**
 * KDF in counter mode according to NIST 800-108 following sequence defined in
 * Section 4.1.5.
 * Please note the standard lists L as an input value.
 * @param ki Key derivation key
 * @param label Binary string identifying the purpose for the derived keying material
 * @param context Binary string containing information related to the derived keying material
 * @param L Bit-length of keying material output (output key)
 * @param out Derived key from ki
 * @return The error code for the operation
 */
DK_Result kdf_counter (
    byte *ki, 
    size_t ki_len, 
    byte *label, 
    size_t label_len, 
    byte *context, size_t 
    context_len, 
    uint32_t L,
    byte **out);

/**
 * Encrypts plaintext with the given key using AES in CBC mode with no 
 * padding. Expects data size to be a multiple of AES_BLOCK_SIZE, iv size
 * to be AES_BLOCK_SIZE and key size to be one of 128/192/256 bits. Output
 * buffer must be at least plaintext_len + AES_BLOCK_SIZE bytes long.
 * 
 * @param plaintext The data to be encrypted.
 * @param plaintext_len The size of the data buffer.
 * @param key The encryption key.
 * @param key_len The length of the encryption key in bytes. Must be one of 16/24/32 bytes.
 * @param iv Buffer containing the initialization vector for AES-CBC
 * @param iv_len Length of the IV. Must be AES_BLOCK_SIZE.
 * @param cyphertext The buffer that will store the encrypted data.
 * @param cyphertext_len Pointer to the length of the encrypted data.
 * @result The error code for the operation.
 */
DK_Result aes_encrypt(
    byte* plaintext, 
    size_t plaintext_len, 
    byte* key, 
    size_t key_len, 
    byte* iv, 
    size_t iv_len,
    byte* cyphertext, 
    size_t* cyphertext_len);

/**
 * Decrypts cyphertext with the given key using AES in CBC mode with no 
 * padding. Expects data size to be a multiple of AES_BLOCK_SIZE, iv size
 * to be AES_BLOCK_SIZE and key size to be one of 128/192/256 bits. Output
 * buffer must be at least cyphertext_len + AES_BLOCK_SIZE bytes long.
 * 
 * @param cyphertext The data to be decrypted.
 * @param cyphertext_len The size of the input buffer.
 * @param key The decryption key.
 * @param key_len The length of the decryption key in bytes. Must be one of 16/24/32 bytes.
 * @param iv Buffer containing the initialization vector for AES-CBC
 * @param iv_len Length of the IV. Must be AES_BLOCK_SIZE.
 * @param plaintext The buffer that will store the decrypted data.
 * @param plaintext_len Pointer to the length of the decrypted data.
 * @result The error code for the operation.
 */
DK_Result aes_decrypt(
    byte* cyphertext, 
    size_t cyphertext_len, 
    byte* key, 
    size_t key_len, 
    byte* iv, 
    size_t iv_len,
    byte* plaintext, 
    size_t* plaintext_len);


#endif