#pragma once

/// @file
/// @brief Определение функций API шифрования
///
/// @copyright Copyright 2019 InfoTeCS.

#include <stdint.h>
#include <stddef.h>

#if defined( _WIN32 )
#    define CipherApiExport
#else
#    if ( __GNUC__ >= 4 ) || defined( __clang__ )
#        define CipherApiExport __attribute__( ( visibility( "default" ) ) )
#    else
#        define CipherApiExport
#    endif
#endif

enum CypherApiVersion
{
    CIPHER_API_VERSION = 2
};

enum CryptoResult
{
    SUCCESS = 0,
    BUFFER_TOO_SMALL = 0x000A0001,
    BUFFER_IS_NULLPTR = 0x000A0002,
    ENCRYPT_ERROR = 0x000A0003,
    DECRYPT_ERROR = 0x000A0004,
    KEY_NOT_FOUND_ERROR = 0x000A0005,
    BUFFER_TOO_LARGE = 0x000A0006,
    CIPHER_SUITE_NOT_AVAILABLE = 0x000A0007,
    NOT_AVAILABLE = 0x000A000A,
};

///@brief Поддерживаемые наборы криптографических алгоритмов.
typedef enum
{
    csG28147_CFB = 0,
    csG3412_MAGMA = 1,
    csITCS_AES256 = 4,
    csG28147_CTR = 5,
    csTFIPS = 7,
    csG3412_KUZNYECHIK = 14,
} CipherSuite;

/// @brief Результат выполнения команды
typedef struct
{
    /// @brief Код возврата функций (0 - успешное завершение)
    uint32_t code;

    /// @brief Сообщение об ошибке (пустое при успешном завершении)
    /// @remarks Не требует освобождения памяти. Сообщение хранится до следующего вызова команды.
    const char* message;
} CipherApiReturnCode;

/// @brief Зашифровать данные для узла на криптонаборе csG28147_CFB (устарело, используйте EncryptBlobEx)
/// @param[in] targetNodeId - ID узла для которого производится шифрование
/// @param[in] in - Буфер с входными данными
/// @param[in] inSize - Размер буфера с входными данными
/// @param[out] out - Буфер с зашифрованными данными
/// @param[in,out] outSize - Размер буфера с зашифрованными данными
/// @remarks Размер входного буфера должен быть не меньше 16 байт, выходного - не меньше, чем размер входного + 12 байт
/// @return Результат выполнения команды
typedef CipherApiReturnCode ( *EncryptBlob )(
    uint32_t targetNodeId, uint8_t* in, size_t inSize, uint8_t* out, size_t* outSize );

/// @brief Расшифровать данные от узла на криптонаборе csG28147_CFB (устарело, используйте DecryptBlobEx)
/// @param[in] sourceNodeId - ID узла от которого производится расшифрование
/// @param[in] in - Буфер с входными данными
/// @param[in] inSize - Размер буфера с входными данными
/// @param[out] out - Буфер с расшифрованными данными
/// @param[in,out] outSize - Размер буфера с расшифрованными данными
/// @remarks Размер входного буфера должен быть не меньше 28 байт, выходного - не меньше, чем размер входного - 12 байт
/// @return Результат выполнения команды
typedef CipherApiReturnCode ( *DecryptBlob )(
    uint32_t sourceNodeId, uint8_t* in, size_t inSize, uint8_t* out, size_t* outSize );

/// @brief Проверить поддерживается ли указанный криптонабор
/// @param[in] cipherSuite - криптонабор
/// @return Результат выполнения команды
typedef CipherApiReturnCode ( *IsCipherSuiteSupported )( uint32_t cipherSuite );

/// @brief Зашифровать данные для узла с использованием указанного криптонабора
/// @param[in] cipherSuite - криптонабор
/// @param[in] targetNodeId - ID узла для которого производится шифрование
/// @param[in] in - Буфер с входными данными
/// @param[in] inSize - Размер буфера с входными данными
/// @param[out] out - Буфер с зашифрованными данными
/// @param[in,out] outSize - Размер буфера с зашифрованными данными
/// @remarks Размер входного буфера должен быть не меньше 16 байт, выходного - не меньше, чем размер входного + 16 байт
/// @return Результат выполнения команды
typedef CipherApiReturnCode ( *EncryptBlobEx )(
    uint32_t cipherSuite, uint32_t targetNodeId, uint8_t* in, size_t inSize, uint8_t* out, size_t* outSize );

/// @brief Расшифровать данные от узла с использованием указанного криптонабора
/// @param[in] cipherSuite - криптонабор
/// @param[in] sourceNodeId - ID узла от которого производится расшифрование
/// @param[in] in - Буфер с входными данными
/// @param[in] inSize - Размер буфера с входными данными
/// @param[out] out - Буфер с расшифрованными данными
/// @param[in,out] outSize - Размер буфера с расшифрованными данными
/// @remarks Размер входного буфера должен быть не меньше 28 байт, выходного - не меньше, чем размер входного - 16 байт
/// @return Результат выполнения команды
typedef CipherApiReturnCode ( *DecryptBlobEx )(
    uint32_t cipherSuite, uint32_t sourceNodeId, uint8_t* in, size_t inSize, uint8_t* out, size_t* outSize );

/// @brief Функции API шифрования (описание функций выше)
typedef struct
{
    // API_VERSION_1
    EncryptBlob encryptBlob;
    DecryptBlob decryptBlob;

    // API_VERSION_2
    IsCipherSuiteSupported isCipherSuiteSupported;
    EncryptBlobEx encryptBlobEx;
    DecryptBlobEx decryptBlobEx;
} ItcsCipherApi;

#ifdef __cplusplus
extern "C" {
#endif

/// @brief Получить текущую версию API шифрования
/// @remarks При обновлении версии API рекомендуется проверить совместимость, иначе работоспособность не гарантируется
/// @return Текущая версия API шифрования
CipherApiExport uint32_t GetCipherApiVersion();

/// @brief Получить указатель на структуру API шифрования
/// @return Указатель на структуру API шифрования
CipherApiExport ItcsCipherApi* GetCipherApi();

#ifdef __cplusplus
}
#endif
