#ifndef LCRYPT_PGP_HELPERS_H
#define LCRYPT_PGP_HELPERS_H

#include <stdint.h>
#include <stdlib.h>

#ifdef LCRYPT_CRYPT_ENGINE_GCRYPT
    #include <gcrypt.h>
    typedef gcry_mpi_t t_lcrypt_pgp_mpi;
#else
    #define LCRYPT_MPI_STATIC
    #define LCRYPT_CRYPT_ENGINE_NONE
#endif

#ifdef LCRYPT_MPI_STATIC
    #define LCRYPT_MPI_MAX_SIZE 256
    typedef struct {
        uint16_t len;
        uint8_t  bytes[LCRYPT_MPI_MAX_SIZE];
    } t_lcrypt_pgp_mpi;
#endif

typedef enum {
    LCRYPT_ERR_PGP_OK             = 0,
    LCRYPT_ERR_PGP_INVALID_FORMAT = -10000,
    LCRYPT_ERR_PGP_INSUF_DATA     = -10001,
    LCRYPT_ERR_PGP_UNSUP_FEATURE  = -10002,
    LCRYPT_ERR_PGP_MPI_UNSUP_SIZE = -10003,
    LCRYPT_ERR_PGP_UNSUP_ALGO     = -10004,
    LCRYPT_ERR_PGP_MEMORY_ALLOC   = -10005,
    LCRYPT_ERR_PGP_BAD_SIGN       = -10006,
    LCRYPT_ERR_PGP_INTERNAL       = -10007
} t_lcrypt_err;

typedef enum {
    PGP_PACKET_PUBKEY_ENCRYPTED_SESSION_KEY = 1,
    PGP_PACKET_SIGNATURE                    = 2,
    PGP_PACKET_SYMKEY_ENCRYPTED_SESSION_KEY = 3,
    PGP_PACKET_ONEPASS_SIGNATURE            = 4,
    PGP_PACKET_SECRET_KEY                   = 5,
    PGP_PACKET_PUBLIC_KEY                   = 6,
    PGP_PACKET_SECRET_SUBKEY                = 7,
    PGP_PACKET_COMPRESSED_DATA              = 8,
    PGP_PACKET_SYM_ENCRYPTED_DATA           = 9,
    PGP_PACKET_MARKER                       = 10,
    PGP_PACKET_LITERAL_DATA                 = 11,
    PGP_PACKET_TRUST                        = 12,
    PGP_PACKET_USER_ID                      = 13,
    PGP_PACKET_PUBLIC_SUBKEY                = 14,
    PGP_PACKET_USER_ATTRIBUTE               = 17,
    PGP_PACKET_SYM_ENCRYPTED_INTEGRITY_DATA = 18,
    PGP_PACKET_MODIFICATION_DETECTION_CODE  = 19
} t_pgp_packet_type;

typedef enum {
    PGP_PUBKEY_ALGO_RSA                     = 1,
    PGP_PUBKEY_ALGO_RSA_ENCRYPT_ONLY        = 2,
    PGP_PUBKEY_ALGO_RSA_SIGN_ONLY           = 3,
    PGP_PUBKEY_ALGO_ELGAMAL                 = 16,
    PGP_PUBKEY_ALGO_DSA                     = 17,
    PGP_PUBKEY_ALGO_ELLIPTIC_CURVE          = 18,
    PGP_PUBKEY_ALGO_ECDSA                   = 19,
    PGP_PUBKEY_ALGO_DIFFIE_HELLMAN          = 21
} t_pgp_pubkey_algo;

typedef enum {
    PGP_SYMKEY_ALGO_PLAIN       = 0,
    PGP_SYMKEY_ALGO_IDEA        = 1,
    PGP_SYMKEY_ALGO_TRIPLE_DES  = 2,
    PGP_SYMKEY_ALGO_CAST5       = 3,
    PGP_SYMKEY_ALGO_BLOWFISH    = 4,
    PGP_SYMKEY_ALGO_AES128      = 7,
    PGP_SYMKEY_ALGO_AES192      = 8,
    PGP_SYMKEY_ALGO_AES256      = 9,
    PGP_SYMKEY_ALGO_TSOFISH256  = 19
} t_pgp_symkey_algo;

typedef enum {
    PGP_COMPRESSION_ALGO_NONE   = 0,
    PGP_COMPRESSION_ALGO_ZIP    = 1,
    PGP_COMPRESSION_ALGO_ZLIB   = 2,
    PGP_COMPRESSION_ALGO_BZIP2  = 3
} t_pgp_compression_algo;

typedef enum {
    PGP_HASH_ALGO_MD5       = 1,
    PGP_HASH_ALGO_SHA1      = 2,
    PGP_HASH_ALGO_RIPEMD    = 3,
    PGP_HASH_ALGO_SHA256    = 8,
    PGP_HASH_ALGO_SHA384    = 9,
    PGP_HASH_ALGO_SHA512    = 10,
    PGP_HASH_ALGO_SHA224    = 11
} t_pgp_hash_algo;

typedef enum {
    PGP_SIGN_TYPE_BINARY_DOC    = 0,
    PGP_SIGN_TYPE_TEXT_DOC      = 1,
    PGP_SIGN_TYPE_STANDALONE    = 2,
    //PGP_SIGN_TYPE_

} t_pgp_sign_type;



typedef struct {
    t_pgp_packet_type type;
    uint32_t pkt_size;
    uint8_t hdr_size;
} t_lcrypt_pgp_hdr;


typedef struct {
    uint32_t creation_time;
    t_pgp_pubkey_algo algo;
    struct {
        t_lcrypt_pgp_mpi n;
        t_lcrypt_pgp_mpi e;
    } rsa;
} t_lcrypt_pgp_pubkey;

typedef struct {
    uint8_t  version;
    uint32_t creation_time;
    t_pgp_sign_type sign_type;
    t_pgp_pubkey_algo pubkey_algo;
    t_pgp_hash_algo hash_algo;

    uint16_t first_word;
    uint16_t hashed_data_len;
    uint8_t *hashed_data;
    uint8_t key_id[8];
    union {
        struct {
            t_lcrypt_pgp_mpi val;
        } rsa;
        struct {
            t_lcrypt_pgp_mpi r;
            t_lcrypt_pgp_mpi s;
        } dsa;
    };
} t_lcrypt_pgp_sign;

typedef struct {
    char type;
    uint8_t filename_len;
    const char *filename;
    uint32_t creation_date;
    const uint8_t *body;
    size_t body_len;
} t_lcrypt_pgp_data;


#ifdef __cplusplus
extern "C" {
#endif


typedef void (*t_lcrypt_progress_cb)(void *cb_data, size_t processed, size_t size);

t_lcrypt_err pgp_parse_packet_hdr(const uint8_t *msg, size_t size, t_lcrypt_pgp_hdr *hdr);
t_lcrypt_err pgp_public_key_parse(const uint8_t *msg, size_t size, t_lcrypt_pgp_pubkey *key);
void pgp_public_key_release(t_lcrypt_pgp_pubkey *key);
t_lcrypt_err pgp_sign_parse(const uint8_t *msg, size_t size,  t_lcrypt_pgp_sign *sign);
void pgp_sign_release(t_lcrypt_pgp_sign *sign);
t_lcrypt_err pgp_data_parse(const uint8_t *msg, size_t size, t_lcrypt_pgp_data *data);
#ifndef LCRYPT_CRYPT_ENGINE_NONE
t_lcrypt_err pgp_sign_check(const t_lcrypt_pgp_sign *sign, const t_lcrypt_pgp_pubkey *key,
                            const uint8_t *data, size_t data_size, t_lcrypt_progress_cb cb, void *cb_data);
#endif

#ifdef __cplusplus
}
#endif

#endif // LCRYPT_PGP_HELPERS_H
