/*---------------------------------------------------------------------------*/
/* cipher.h                                                                  */
/* copyright (c) innovaphone 2016                                            */
/*                                                                           */
/*---------------------------------------------------------------------------*/

NAMESPACE_BEGIN

enum cipher_t {
    CIPHER_UNDEFINED,
    CIPHER_DES,
    CIPHER_3DES,
    CIPHER_AES,
    CIPHER_RC2,
    CIPHER_RC4
};

#if (!defined(__ANDROID__) && !defined(_IOS_) && !defined(_VDI_PLUGIN_))
#ifdef  __i386
#   undef IA32_CRYPT_AESNI
#   define IA32_CRYPT_AESNI 1
#elif   __x86_64
#   undef   IA64_CRYPT_AESNI
#   define  IA64_CRYPT_AESNI 1
#endif
#endif

class Cipher {
protected:
    bool encrypt;
    cipher_t type;
#if defined ARMV7_CRYPT   
    __attribute__((aligned(16))) ulong64 encrypt_ctx[214], decrypt_ctx[214]; // max context size is aesbs_ctx, 4 + 12 alignment + 13 * (8 * 16) + 32
#else
            // fyi, context size requirement for (IA32_CRYPT_AESNI || IA64_CRYPT_AESNI) would be 512 bytes + 16 byte alignment
        ulong64 encrypt_ctx[129], decrypt_ctx[129];
#endif
public:
    Cipher();
    void Init(cipher_t type, const byte * key, int keyLen, bool encrypt = true, bool makekey = true);
    void Reset();

    void Block(const byte * in, byte * out);
    void Crypt(const byte * in, byte * out, int len);
    void CtrCrypt(const byte * in, byte * out, int len, byte * iv);
    void CfbCrypt(const byte * in, byte * out, int len, byte * iv);
    void CbcCrypt(const byte * in, byte * out, int len, byte * iv);
    int CtsCrypt(const byte * in, byte * out, int len, byte * iv);
    bool GcmCrypt(const byte * aad, int aad_len, const byte * in, byte * out, int len, byte * iv, byte * tag);
};

NAMESPACE_END
