{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE EmptyDataDecls #-}
module Crypto.OpenSSL.AES.Foreign where
#include <openssl/opensslv.h>
#include <openssl/evp.h>
#if OPENSSL_VERSION_NUMBER >= 0x10100000
#define OPENSSL_HAS_OPAQUE_EVP_CIPHER_CTX
#endif
#if OPENSSL_VERSION_NUMBER >= 0x10001000
#define OPENSSL_HAS_PBKDF2
#define OPENSSL_HAS_GCM
#endif
import Foreign.Marshal.Alloc
import Foreign.Ptr
import Foreign.ForeignPtr
import Foreign.C.Types
import Data.Word
#ifndef OPENSSL_HAS_OPAQUE_EVP_CIPHER_CTX
import qualified Data.Memory.PtrMethods as B (memSet)
#endif
gcmTagLength :: Int
gcmTagLength = 16
#ifndef OPENSSL_HAS_OPAQUE_EVP_CIPHER_CTX
sizeofEVP :: Int
sizeofEVP = (#const sizeof(EVP_CIPHER_CTX))
#endif
data ENGINE
data EVP_CIPHER
data EVP_CIPHER_CTX
type KeyBuf = Ptr Word8
type IvBuf = Ptr Word8
type DataBuf = Ptr Word8
type OutputOffset = Ptr CInt
type InputLength = CInt
compatNewEvpCipherCtx :: IO (ForeignPtr EVP_CIPHER_CTX)
compatNewEvpCipherCtx = do
#ifdef OPENSSL_HAS_OPAQUE_EVP_CIPHER_CTX
ptr <- ssl_c_cipher_ctx_new
newForeignPtr ssl_c_cipher_ctx_free ptr
#else
ptr <- mallocBytes sizeofEVP
B.memSet (castPtr ptr) 0 (fromIntegral sizeofEVP)
ssl_c_cipher_ctx_init ptr
newForeignPtr ssl_c_cipher_ctx_cleanup ptr
#endif
#ifdef OPENSSL_HAS_OPAQUE_EVP_CIPHER_CTX
foreign import ccall unsafe "EVP_CIPHER_CTX_new"
ssl_c_cipher_ctx_new :: IO (Ptr EVP_CIPHER_CTX)
#endif
#ifndef OPENSSL_HAS_OPAQUE_EVP_CIPHER_CTX
foreign import ccall unsafe "EVP_CIPHER_CTX_init"
ssl_c_cipher_ctx_init :: Ptr EVP_CIPHER_CTX -> IO ()
#endif
foreign import ccall unsafe "&EVP_CIPHER_CTX_free"
ssl_c_cipher_ctx_free :: FunPtr (Ptr EVP_CIPHER_CTX -> IO ())
#ifndef OPENSSL_HAS_OPAQUE_EVP_CIPHER_CTX
foreign import ccall unsafe "&EVP_CIPHER_CTX_cleanup"
ssl_c_cipher_ctx_cleanup :: FunPtr (Ptr EVP_CIPHER_CTX -> IO ())
#endif
foreign import ccall unsafe "EVP_CIPHER_CTX_ctrl"
ssl_c_cipher_ctx_ctrl :: Ptr EVP_CIPHER_CTX -> CInt -> CInt -> Ptr a -> IO CInt
foreign import ccall unsafe "EVP_CIPHER_CTX_set_padding"
ssl_c_cipher_ctx_set_padding :: Ptr EVP_CIPHER_CTX -> CInt -> IO CInt
foreign import ccall unsafe "EVP_CIPHER_CTX_set_key_length"
ssl_c_cipher_ctx_set_key_length :: Ptr EVP_CIPHER_CTX -> CInt -> IO CInt
foreign import ccall unsafe "EVP_EncryptInit_ex"
ssl_c_encryptinit_ex :: Ptr EVP_CIPHER_CTX -> Ptr EVP_CIPHER -> Ptr ENGINE -> KeyBuf -> IvBuf -> IO CInt
foreign import ccall unsafe "EVP_DecryptInit_ex"
ssl_c_decryptinit_ex :: Ptr EVP_CIPHER_CTX -> Ptr EVP_CIPHER -> Ptr ENGINE -> KeyBuf -> IvBuf -> IO CInt
foreign import ccall unsafe "EVP_EncryptUpdate"
ssl_c_encryptupdate :: Ptr EVP_CIPHER_CTX -> DataBuf -> OutputOffset -> DataBuf -> InputLength -> IO CInt
foreign import ccall unsafe "EVP_DecryptUpdate"
ssl_c_decryptupdate :: Ptr EVP_CIPHER_CTX -> DataBuf -> OutputOffset -> DataBuf -> InputLength -> IO CInt
foreign import ccall unsafe "EVP_EncryptFinal_ex"
ssl_c_encryptfinal_ex :: Ptr EVP_CIPHER_CTX -> DataBuf -> OutputOffset -> IO CInt
foreign import ccall unsafe "EVP_DecryptFinal_ex"
ssl_c_decryptfinal_ex :: Ptr EVP_CIPHER_CTX -> DataBuf -> OutputOffset -> IO CInt
#ifdef OPENSSL_HAS_GCM
foreign import ccall unsafe "EVP_aes_256_gcm"
ssl_c_aes_256_gcm :: IO (Ptr EVP_CIPHER)
#else
ssl_c_aes_256_gcm :: IO (Ptr EVP_CIPHER)
ssl_c_aes_256_gcm = return nullPtr
#endif
ctrl_GCM_SET_IVLEN, ctrl_GCM_GET_TAG, ctrl_GCM_SET_TAG :: CInt
#ifdef OPENSSL_HAS_GCM
ctrl_GCM_SET_IVLEN = (#const EVP_CTRL_GCM_SET_IVLEN)
ctrl_GCM_GET_TAG = (#const EVP_CTRL_GCM_GET_TAG)
ctrl_GCM_SET_TAG = (#const EVP_CTRL_GCM_SET_TAG)
#else
-- not sure if this is a good idea to hardcode it.
ctrl_GCM_SET_IVLEN = 0x9
ctrl_GCM_GET_TAG = 0x10
ctrl_GCM_SET_TAG = 0x11
#endif