#ifndef DK_CONSTANTS_H
#define DK_CONSTANTS_H

#define TAG_LENGTH_MAX 3
#define KEY_IDENTIFIER_TLV_LENGTH 22

#define PADDING_DELIMITER (byte)0x80U

#define KDF_COUNTER_h 128U
#define KDF_COUNTER_r_8 8U
#define KDF_COUNTER_L_64 64U
#define KDF_COUNTER_L_128 128U
#define KDF_COUNTER_L_192 192U
#define KDF_COUNTER_L_256 256U

#define SHA256_HASH_BITS 256U

#define KDF_LABEL_SIZE 12U

#ifdef AES_BLOCK_SIZE
#undef AES_BLOCK_SIZE
#define AES_BLOCK_SIZE 16U
#endif

#define C_MAC_SIZE 8U
#define R_MAC_SIZE 8U
#define CHALLENGE_SIZE 8U
#define CRYPTOGRAM_SIZE 8U
#define MAC_CHAINING_SIZE 16U

#define APDU_OFFSET_CLA   0
#define APDU_OFFSET_INS   1
#define APDU_OFFSET_P1    2
#define APDU_OFFSET_P2    3
#define APDU_OFFSET_LC    4
#define APDU_OFFSET_CDATA 5 // could be 7 if data length is > 255, but due
                            // to how SCP works, it will never be this long (?)

#define APDU_OFFSET_SW1 0
#define APDU_OFFSET_SW2 1
#define APDU_SW_SIZE 2
#define SIZE_TLV_SIZE 3
#define SIZE_TLV_TAG 128 // 0x80

#define CPDU_MAX_SIZE (261) // 6 field bytes + 255 bytes of possible data
#define CPDU_MAX_DATA_SIZE (255U)

#define RPDU_MAX_SIZE (258U) // 256 bytes of data + 2 bytes of status word
#define RPDU_MIN_SIZE (2U)

#define MAX_FULL_RESPONSE_SIZE (3074U) // 3072 data bytes + 2 status word bytes

#define RPDU_STATUS_SUCCESS (0x9000U)

/**********************************************************************/
/* SCP Contants */

#define KEY_INFO_OFFSET_KEY_VERSION 0U
#define KEY_INFO_OFFSET_SCP_VERSION 1U
#define KEY_INFO_OFFSET_i_PARAMETER 2U
#define KEY_INFO_SIZE 3U

#define SCP03_SEC_NO_SECURITY_LEVEL 0x00
#define SCP03_SEC_C_MAC 0x01
#define SCP03_SEC_R_MAC 0x10
#define SCP03_SEC_C_DECRYPTION 0x02
#define SCP03_SEC_R_ENCRYPTION 0x20
#define SCP03_SEC_C_MAC_R_RMAC ((SCP03_SEC_C_MAC) | (SCP03_SEC_R_MAC))
#define SCP03_SEC_C_DECRYPTION_C_MAC ((SCP03_SEC_C_MAC) | (SCP03_SEC_C_DECRYPTION))
#define SCP03_SEC_C_DECRYPTION_C_MAC_R_MAC ((SCP03_SEC_C_DECRYPTION_C_MAC) | (SCP03_SEC_R_MAC))
#define SCP03_SEC_C_DECRYPTION_R_ENCRYPTION_C_MAC_R_MAC ((SCP03_SEC_C_DECRYPTION_C_MAC_R_MAC) | (SCP03_SEC_R_ENCRYPTION))
#define SCP03_SEC_AUTHENTICATED (byte) 0x80

#define SCP_PARAM_i_INDEX                       2U
#define SCP_PARAM_i_RANDOM_CARD_CHALLENGE       (0b00000000U)
#define SCP_PARAM_i_PSEUDORANDOM_CARD_CHALLENGE (0b00010000U)
#define SCP_PARAM_i_NO_SECURITY                 (0b00000000U)
#define SCP_PARAM_i_RMAC_NO_RENCRYPTION         (0b00100000U)
#define SCP_PARAM_i_RMAC_RENCRYPTION            (0b01100000U)

#define SCP_EXTERNAL_AUTH_CMAC_CDECRYPT_RMAC_RENCRYPT (0b00110011U)
#define SCP_EXTERNAL_AUTH_CMAC_CDECRYPT_RMAC          (0b00010011U)
#define SCP_EXTERNAL_AUTH_CMAC_RMAC                   (0b00010001U)
#define SCP_EXTERNAL_AUTH_CMAC_CDECRYPT               (0b00000011U)
#define SCP_EXTERNAL_AUTH_CMAC                        (0b00000001U)
#define SCP_EXTERNAL_AUTH_NO_SECURITY                 (0b00000000U)

#define LOGICAL_CHANNEL_ZERO_MASK   (byte)0b11111100
#define BIT3_MASK                   (byte)0b00000100
#define BIT4_ZERO_MASK              (byte)0b11110111
#define LAST_BYTE_MASK             0x000000FFU

#define byteI_RANDOM_CARD_CHALLENGE         0x00
#define byteI_PSEUDO_RANDOM_CARD_CHALLENGE  0x10
#define byteI_NO_R_MAC_R_ENCRYPTION         0x00
#define byteI_R_MAC_NO_R_ENCRYPTION         0x20
#define byteI_R_MAC_R_ENCRYPTION            0x60

/**********************************************************************/

/**********************************************************************/
/* SCP Commands Constants */

// =================================
// CLS Bitmasks (GPCS 11.1.4.1)
// =================================
#define CLS_ISO7816_COMMAND                (0b00000000U)
#define CLS_GP_COMMAND                     (0b10000000U)
#define CLS_NO_SECURE_MESSAGE              (0b00000000U)
#define CLS_GP_SECURE_MESSAGE              (0b00000100U)
#define CLS_ISO7816_SECURE_MESSAGE_NO_CMAC (0b00001000U)
#define CLS_ISO7816_SECURE_MESSAGE_CMAC    (0b00001100U)
#define CLS_BASE_CHANNEL                   (0b00000001U)
#define CLS_LOGICAL_CHANNEL_0              (0b00000000U)
#define CLS_LOGICAL_CHANNEL_1              (0b00000001U)
#define CLS_LOGICAL_CHANNEL_2              (0b00000010U)
#define CLS_LOGICAL_CHANNEL_3              (0b00000011U)

// =================================
// Commands
// =================================

#define SCP03_INIT_UPDATE_CLA_CHANNEL_0 (CLS_GP_COMMAND | CLS_LOGICAL_CHANNEL_0)
#define SCP03_INIT_UPDATE_CLA_CHANNEL_1 (CLS_GP_COMMAND | CLS_LOGICAL_CHANNEL_1)
#define SCP03_INIT_UPDATE_CLA_CHANNEL_2 (CLS_GP_COMMAND | CLS_LOGICAL_CHANNEL_2)
#define SCP03_INIT_UPDATE_CLA_CHANNEL_3 (CLS_GP_COMMAND | CLS_LOGICAL_CHANNEL_3)
#define SCP03_INIT_UPDATE_INS           (0x50U)
#define SCP03_INIT_UPDATE_LC            (0x08U)
#define SCP03_INIT_UPDATE_LE            (0x00U)

#define SCP03_INIT_UPDATE_KEY_DIV_DATA_LEN          (10U)
#define SCP03_INIT_UPDATE_KEY_INFO_LEN              (3U)
#define SCP03_INIT_UPDATE_SEQUENCE_COUNTER_LEN      (3U)
#define SCP03_INIT_UPDATE_RESPONSE_MANDATORY_LEN    (SCP03_INIT_UPDATE_KEY_DIV_DATA_LEN + \
                                                    SCP03_INIT_UPDATE_KEY_INFO_LEN + \
                                                    CHALLENGE_SIZE + \
                                                    CRYPTOGRAM_SIZE)

#define SCP03_EXT_AUTHENTICATE_CLA_CHANNEL_0    (CLS_GP_COMMAND | CLS_GP_SECURE_MESSAGE | CLS_LOGICAL_CHANNEL_0)
#define SCP03_EXT_AUTHENTICATE_CLA_CHANNEL_1    (CLS_GP_COMMAND | CLS_GP_SECURE_MESSAGE | CLS_LOGICAL_CHANNEL_1)
#define SCP03_EXT_AUTHENTICATE_CLA_CHANNEL_2    (CLS_GP_COMMAND | CLS_GP_SECURE_MESSAGE | CLS_LOGICAL_CHANNEL_2)
#define SCP03_EXT_AUTHENTICATE_CLA_CHANNEL_3    (CLS_GP_COMMAND | CLS_GP_SECURE_MESSAGE | CLS_LOGICAL_CHANNEL_3)
#define SCP03_EXT_AUTHENTICATE_INS              (0x82U)
#define SCP03_EXT_AUTHENTICATE_P2               (0x00U)
#define SCP03_EXT_AUTHENTICATE_LC               (0x08U) // initial length is 8, 0x10 is with CMAC added
#define SCP03_EXT_AUTHENTICATE_LEN              (0x0DU) // CLA, INS, P1, P2, LC + cryptogram

#define SCP03_GET_DATA_CLA          (0x80U)
#define SCP03_GET_DATA_INS          (0xCAU)
#define SCP03_GET_DATA_P1           (0xBFU)
#define SCP03_GET_DATA_P2           (0x21U)
#define SCP03_GET_DATA_LC           (0x06U)
#define SCP03_GET_DATA_LE           (0x00U)
#define SCP03_GET_DATA_KEY_INFO_LEN (0x06U)

#define SCP03_GET_RESPONSE_CLA  (0x84U)
#define SCP03_GET_RESPONSE_INS  (0xC0U)
#define SCP03_GET_RESPONSE_P1   (0x00U)
#define SCP03_GET_RESPONSE_P2   (0x00U)
#define SCP03_GET_RESPONSE_LC   (0x00U)
#define SCP03_GET_RESPONSE_LE   (0x00U)

#define KEY_INFO_DATA	        (0xE0)

/**********************************************************************/

/**********************************************************************/
/* ISO7816 Constants */

#define ISO7816_SW_CLA_NOT_SUPPORTED                            0x6E00
#define ISO7816_SW_CMD_NOT_ALLOWED                              0x6986
#define ISO7816_SW_CMD_SUCCESSFULLY_EXECUTED_THERE_IS_REMINDER  0x6100
#define ISO7816_SW_CONDITIONS_NOT_SATISFIED                     0x6985
#define ISO7816_SW_DATA_INVALID                                 0x6984
#define ISO7816_SW_FILE_NOT_FOUND                               0x6A82
#define ISO7816_SW_FUNC_NOT_SUPPORTED                           0x6A81
#define ISO7816_SW_INCORRECT_LENGTH                             0x6C00
#define ISO7816_SW_INCORRECT_P1_OR_P2                           0x6B00
#define ISO7816_SW_INCORRECT_P1P2                               0x6A86
#define ISO7816_SW_INS_NOT_SUPPORTED                            0x6D00
#define ISO7816_SW_INSUFFICIENT_MEMORY_SPACE                    0x6A84
#define ISO7816_SW_LC_INCONSISTENT_WITH_P1P2                    0x6A87
#define ISO7816_SW_LOGICAL_CHANNEL_NOT_SUPPORTED                0x6881
#define ISO7816_SW_NO_ERROR                                     0x9000
#define ISO7816_SW_NO_INFO_GIVEN                                0x6400
#define ISO7816_SW_RECORD_NOT_FOUND                             0x6A83
#define ISO7816_SW_REFERENCED_DATA_NOT_FOUND                    0x6A88
#define ISO7816_SW_SDAD_COMPUTATION_ERROR                       0x9486
#define ISO7816_SW_SECURITY_STATUS_NOT_SATISFIED                0x6982
#define ISO7816_SW_SELECTED_FILE_INVALIDATED                    0x6283
#define ISO7816_SW_UNKNOWN_ERROR_RESPONSE                       0x6F00
#define ISO7816_SW_WARN_MEM_CHANGED                             0x6300
#define ISO7816_SW_MORE_DATA                                    0x6310
#define ISO7816_SW_WARN_MEM_UNCHANGED                           0x6200
#define ISO7816_SW_WRONG_DATA                                   0x6A80
#define ISO7816_SW_WRONG_LENGTH                                 0x6700

/**********************************************************************/

#define SCP03LIB_MAX_PLAIN_APDU_DATA_SIZE (248U)
#define SCP03LIB_MAX_ENCRYPTED_APDU_DATA_SIZE (239U)
#define SCP03LIB_MAX_CPDU_SIZE (SCP03LIB_MAX_ENCRYPTED_APDU_DATA_SIZE + 6U)

#endif // _DK_CONSTANTS_H_
