{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-- |
-- Module      : Crypto.Cipher.AES.Primitive
-- License     : BSD-style
-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
-- Stability   : stable
-- Portability : good
--
module Crypto.Cipher.AES.Primitive
    (
    -- * Block cipher data types
      AES

    -- * Authenticated encryption block cipher types
    , AESGCM
    , AESOCB

    -- * Creation
    , initAES

    -- * Miscellanea
    , genCTR
    , genCounter

    -- * Encryption
    , encryptECB
    , encryptCBC
    , encryptCTR
    , encryptXTS

    -- * Decryption
    , decryptECB
    , decryptCBC
    , decryptCTR
    , decryptXTS

    -- * CTR with 32-bit wrapping
    , combineC32

    -- * Incremental GCM
    , gcmMode
    , gcmInit

    -- * Incremental OCB
    , ocbMode
    , ocbInit

    -- * CCM
    , ccmMode
    , ccmInit
    ) where

import           Data.Word
import           Foreign.Ptr
import           Foreign.C.Types
import           Foreign.C.String

import           Crypto.Error
import           Crypto.Cipher.Types
import           Crypto.Cipher.Types.Block (IV(..))
import           Crypto.Internal.Compat
import           Crypto.Internal.Imports
import           Crypto.Internal.ByteArray (ByteArray, ByteArrayAccess, ScrubbedBytes, withByteArray)
import qualified Crypto.Internal.ByteArray as B

instance Cipher AES where
    cipherName :: AES -> String
cipherName    AES
_ = String
"AES"
    cipherKeySize :: AES -> KeySizeSpecifier
cipherKeySize AES
_ = [Int] -> KeySizeSpecifier
KeySizeEnum [Int
16,Int
24,Int
32]
    cipherInit :: forall key. ByteArray key => key -> CryptoFailable AES
cipherInit key
k    = key -> CryptoFailable AES
forall key. ByteArrayAccess key => key -> CryptoFailable AES
initAES key
k

instance BlockCipher AES where
    blockSize :: AES -> Int
blockSize AES
_ = Int
16
    ecbEncrypt :: forall ba. ByteArray ba => AES -> ba -> ba
ecbEncrypt = AES -> ba -> ba
forall ba. ByteArray ba => AES -> ba -> ba
encryptECB
    ecbDecrypt :: forall ba. ByteArray ba => AES -> ba -> ba
ecbDecrypt = AES -> ba -> ba
forall ba. ByteArray ba => AES -> ba -> ba
decryptECB
    cbcEncrypt :: forall ba. ByteArray ba => AES -> IV AES -> ba -> ba
cbcEncrypt = AES -> IV AES -> ba -> ba
forall ba. ByteArray ba => AES -> IV AES -> ba -> ba
encryptCBC
    cbcDecrypt :: forall ba. ByteArray ba => AES -> IV AES -> ba -> ba
cbcDecrypt = AES -> IV AES -> ba -> ba
forall ba. ByteArray ba => AES -> IV AES -> ba -> ba
decryptCBC
    ctrCombine :: forall ba. ByteArray ba => AES -> IV AES -> ba -> ba
ctrCombine = AES -> IV AES -> ba -> ba
forall ba. ByteArray ba => AES -> IV AES -> ba -> ba
encryptCTR
    aeadInit :: forall iv.
ByteArrayAccess iv =>
AEADMode -> AES -> iv -> CryptoFailable (AEAD AES)
aeadInit AEADMode
AEAD_GCM AES
aes iv
iv = AEAD AES -> CryptoFailable (AEAD AES)
forall a. a -> CryptoFailable a
CryptoPassed (AEAD AES -> CryptoFailable (AEAD AES))
-> AEAD AES -> CryptoFailable (AEAD AES)
forall a b. (a -> b) -> a -> b
$ AEADModeImpl AESGCM -> AESGCM -> AEAD AES
forall cipher st. AEADModeImpl st -> st -> AEAD cipher
AEAD (AES -> AEADModeImpl AESGCM
gcmMode AES
aes) (AES -> iv -> AESGCM
forall iv. ByteArrayAccess iv => AES -> iv -> AESGCM
gcmInit AES
aes iv
iv)
    aeadInit AEADMode
AEAD_OCB AES
aes iv
iv = AEAD AES -> CryptoFailable (AEAD AES)
forall a. a -> CryptoFailable a
CryptoPassed (AEAD AES -> CryptoFailable (AEAD AES))
-> AEAD AES -> CryptoFailable (AEAD AES)
forall a b. (a -> b) -> a -> b
$ AEADModeImpl AESOCB -> AESOCB -> AEAD AES
forall cipher st. AEADModeImpl st -> st -> AEAD cipher
AEAD (AES -> AEADModeImpl AESOCB
ocbMode AES
aes) (AES -> iv -> AESOCB
forall iv. ByteArrayAccess iv => AES -> iv -> AESOCB
ocbInit AES
aes iv
iv)
    aeadInit (AEAD_CCM Int
n CCM_M
m CCM_L
l) AES
aes iv
iv = AEADModeImpl AESCCM -> AESCCM -> AEAD AES
forall cipher st. AEADModeImpl st -> st -> AEAD cipher
AEAD (AES -> AEADModeImpl AESCCM
ccmMode AES
aes) (AESCCM -> AEAD AES)
-> CryptoFailable AESCCM -> CryptoFailable (AEAD AES)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> AES -> iv -> Int -> CCM_M -> CCM_L -> CryptoFailable AESCCM
forall iv.
ByteArrayAccess iv =>
AES -> iv -> Int -> CCM_M -> CCM_L -> CryptoFailable AESCCM
ccmInit AES
aes iv
iv Int
n CCM_M
m CCM_L
l
    aeadInit AEADMode
_        AES
_   iv
_  = CryptoError -> CryptoFailable (AEAD AES)
forall a. CryptoError -> CryptoFailable a
CryptoFailed CryptoError
CryptoError_AEADModeNotSupported
instance BlockCipher128 AES where
    xtsEncrypt :: forall ba.
ByteArray ba =>
(AES, AES) -> IV AES -> DataUnitOffset -> ba -> ba
xtsEncrypt = (AES, AES) -> IV AES -> DataUnitOffset -> ba -> ba
forall ba.
ByteArray ba =>
(AES, AES) -> IV AES -> DataUnitOffset -> ba -> ba
encryptXTS
    xtsDecrypt :: forall ba.
ByteArray ba =>
(AES, AES) -> IV AES -> DataUnitOffset -> ba -> ba
xtsDecrypt = (AES, AES) -> IV AES -> DataUnitOffset -> ba -> ba
forall ba.
ByteArray ba =>
(AES, AES) -> IV AES -> DataUnitOffset -> ba -> ba
decryptXTS

-- | Create an AES AEAD implementation for GCM
gcmMode :: AES -> AEADModeImpl AESGCM
gcmMode :: AES -> AEADModeImpl AESGCM
gcmMode AES
aes = AEADModeImpl
    { aeadImplAppendHeader :: forall ba. ByteArrayAccess ba => AESGCM -> ba -> AESGCM
aeadImplAppendHeader = AESGCM -> ba -> AESGCM
forall ba. ByteArrayAccess ba => AESGCM -> ba -> AESGCM
gcmAppendAAD
    , aeadImplEncrypt :: forall ba. ByteArray ba => AESGCM -> ba -> (ba, AESGCM)
aeadImplEncrypt      = AES -> AESGCM -> ba -> (ba, AESGCM)
forall ba. ByteArray ba => AES -> AESGCM -> ba -> (ba, AESGCM)
gcmAppendEncrypt AES
aes
    , aeadImplDecrypt :: forall ba. ByteArray ba => AESGCM -> ba -> (ba, AESGCM)
aeadImplDecrypt      = AES -> AESGCM -> ba -> (ba, AESGCM)
forall ba. ByteArray ba => AES -> AESGCM -> ba -> (ba, AESGCM)
gcmAppendDecrypt AES
aes
    , aeadImplFinalize :: AESGCM -> Int -> AuthTag
aeadImplFinalize     = AES -> AESGCM -> Int -> AuthTag
gcmFinish AES
aes
    }

-- | Create an AES AEAD implementation for OCB
ocbMode :: AES -> AEADModeImpl AESOCB
ocbMode :: AES -> AEADModeImpl AESOCB
ocbMode AES
aes = AEADModeImpl
    { aeadImplAppendHeader :: forall ba. ByteArrayAccess ba => AESOCB -> ba -> AESOCB
aeadImplAppendHeader = AES -> AESOCB -> ba -> AESOCB
forall aad. ByteArrayAccess aad => AES -> AESOCB -> aad -> AESOCB
ocbAppendAAD AES
aes
    , aeadImplEncrypt :: forall ba. ByteArray ba => AESOCB -> ba -> (ba, AESOCB)
aeadImplEncrypt      = AES -> AESOCB -> ba -> (ba, AESOCB)
forall ba. ByteArray ba => AES -> AESOCB -> ba -> (ba, AESOCB)
ocbAppendEncrypt AES
aes
    , aeadImplDecrypt :: forall ba. ByteArray ba => AESOCB -> ba -> (ba, AESOCB)
aeadImplDecrypt      = AES -> AESOCB -> ba -> (ba, AESOCB)
forall ba. ByteArray ba => AES -> AESOCB -> ba -> (ba, AESOCB)
ocbAppendDecrypt AES
aes
    , aeadImplFinalize :: AESOCB -> Int -> AuthTag
aeadImplFinalize     = AES -> AESOCB -> Int -> AuthTag
ocbFinish AES
aes
    }

-- | Create an AES AEAD implementation for CCM
ccmMode :: AES -> AEADModeImpl AESCCM
ccmMode :: AES -> AEADModeImpl AESCCM
ccmMode AES
aes = AEADModeImpl
    { aeadImplAppendHeader :: forall ba. ByteArrayAccess ba => AESCCM -> ba -> AESCCM
aeadImplAppendHeader = AES -> AESCCM -> ba -> AESCCM
forall aad. ByteArrayAccess aad => AES -> AESCCM -> aad -> AESCCM
ccmAppendAAD AES
aes
    , aeadImplEncrypt :: forall ba. ByteArray ba => AESCCM -> ba -> (ba, AESCCM)
aeadImplEncrypt      = AES -> AESCCM -> ba -> (ba, AESCCM)
forall ba. ByteArray ba => AES -> AESCCM -> ba -> (ba, AESCCM)
ccmEncrypt AES
aes
    , aeadImplDecrypt :: forall ba. ByteArray ba => AESCCM -> ba -> (ba, AESCCM)
aeadImplDecrypt      = AES -> AESCCM -> ba -> (ba, AESCCM)
forall ba. ByteArray ba => AES -> AESCCM -> ba -> (ba, AESCCM)
ccmDecrypt AES
aes
    , aeadImplFinalize :: AESCCM -> Int -> AuthTag
aeadImplFinalize     = AES -> AESCCM -> Int -> AuthTag
ccmFinish AES
aes
    }


-- | AES Context (pre-processed key)
newtype AES = AES ScrubbedBytes
    deriving (AES -> ()
(AES -> ()) -> NFData AES
forall a. (a -> ()) -> NFData a
$crnf :: AES -> ()
rnf :: AES -> ()
NFData)

-- | AESGCM State
newtype AESGCM = AESGCM ScrubbedBytes
    deriving (AESGCM -> ()
(AESGCM -> ()) -> NFData AESGCM
forall a. (a -> ()) -> NFData a
$crnf :: AESGCM -> ()
rnf :: AESGCM -> ()
NFData)

-- | AESOCB State
newtype AESOCB = AESOCB ScrubbedBytes
    deriving (AESOCB -> ()
(AESOCB -> ()) -> NFData AESOCB
forall a. (a -> ()) -> NFData a
$crnf :: AESOCB -> ()
rnf :: AESOCB -> ()
NFData)

-- | AESCCM State
newtype AESCCM = AESCCM ScrubbedBytes
    deriving (AESCCM -> ()
(AESCCM -> ()) -> NFData AESCCM
forall a. (a -> ()) -> NFData a
$crnf :: AESCCM -> ()
rnf :: AESCCM -> ()
NFData)

sizeGCM :: Int
sizeGCM :: Int
sizeGCM = Int
320

sizeOCB :: Int
sizeOCB :: Int
sizeOCB = Int
160

sizeCCM :: Int
sizeCCM :: Int
sizeCCM = Int
80

keyToPtr :: AES -> (Ptr AES -> IO a) -> IO a
keyToPtr :: forall a. AES -> (Ptr AES -> IO a) -> IO a
keyToPtr (AES ScrubbedBytes
b) Ptr AES -> IO a
f = ScrubbedBytes -> (Ptr Any -> IO a) -> IO a
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
forall p a. ScrubbedBytes -> (Ptr p -> IO a) -> IO a
withByteArray ScrubbedBytes
b (Ptr AES -> IO a
f (Ptr AES -> IO a) -> (Ptr Any -> Ptr AES) -> Ptr Any -> IO a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Ptr Any -> Ptr AES
forall a b. Ptr a -> Ptr b
castPtr)

ivToPtr :: ByteArrayAccess iv => iv -> (Ptr Word8 -> IO a) -> IO a
ivToPtr :: forall iv a.
ByteArrayAccess iv =>
iv -> (Ptr Word8 -> IO a) -> IO a
ivToPtr iv
iv Ptr Word8 -> IO a
f = iv -> (Ptr Any -> IO a) -> IO a
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
forall p a. iv -> (Ptr p -> IO a) -> IO a
withByteArray iv
iv (Ptr Word8 -> IO a
f (Ptr Word8 -> IO a) -> (Ptr Any -> Ptr Word8) -> Ptr Any -> IO a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Ptr Any -> Ptr Word8
forall a b. Ptr a -> Ptr b
castPtr)


ivCopyPtr :: IV AES -> (Ptr Word8 -> IO a) -> IO (a, IV AES)
ivCopyPtr :: forall a. IV AES -> (Ptr Word8 -> IO a) -> IO (a, IV AES)
ivCopyPtr (IV byteArray
iv) Ptr Word8 -> IO a
f = (\(a
x,byteArray
y) -> (a
x, byteArray -> IV AES
forall c byteArray. ByteArray byteArray => byteArray -> IV c
IV byteArray
y)) ((a, byteArray) -> (a, IV AES))
-> IO (a, byteArray) -> IO (a, IV AES)
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` byteArray -> (Ptr Word8 -> IO a) -> IO (a, byteArray)
forall ba a.
ByteArray ba =>
ba -> (Ptr Word8 -> IO a) -> IO (a, ba)
copyAndModify byteArray
iv Ptr Word8 -> IO a
f
  where
    copyAndModify :: ByteArray ba => ba -> (Ptr Word8 -> IO a) -> IO (a, ba)
    copyAndModify :: forall ba a.
ByteArray ba =>
ba -> (Ptr Word8 -> IO a) -> IO (a, ba)
copyAndModify ba
ba Ptr Word8 -> IO a
f' = ba -> (Ptr Word8 -> IO a) -> IO (a, ba)
forall bs1 bs2 p a.
(ByteArrayAccess bs1, ByteArray bs2) =>
bs1 -> (Ptr p -> IO a) -> IO (a, bs2)
B.copyRet ba
ba Ptr Word8 -> IO a
f'

withKeyAndIV :: ByteArrayAccess iv => AES -> iv -> (Ptr AES -> Ptr Word8 -> IO a) -> IO a
withKeyAndIV :: forall iv a.
ByteArrayAccess iv =>
AES -> iv -> (Ptr AES -> Ptr Word8 -> IO a) -> IO a
withKeyAndIV AES
ctx iv
iv Ptr AES -> Ptr Word8 -> IO a
f = AES -> (Ptr AES -> IO a) -> IO a
forall a. AES -> (Ptr AES -> IO a) -> IO a
keyToPtr AES
ctx ((Ptr AES -> IO a) -> IO a) -> (Ptr AES -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \Ptr AES
kptr -> iv -> (Ptr Word8 -> IO a) -> IO a
forall iv a.
ByteArrayAccess iv =>
iv -> (Ptr Word8 -> IO a) -> IO a
ivToPtr iv
iv ((Ptr Word8 -> IO a) -> IO a) -> (Ptr Word8 -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
ivp -> Ptr AES -> Ptr Word8 -> IO a
f Ptr AES
kptr Ptr Word8
ivp

withKey2AndIV :: ByteArrayAccess iv => AES -> AES -> iv -> (Ptr AES -> Ptr AES -> Ptr Word8 -> IO a) -> IO a
withKey2AndIV :: forall iv a.
ByteArrayAccess iv =>
AES
-> AES -> iv -> (Ptr AES -> Ptr AES -> Ptr Word8 -> IO a) -> IO a
withKey2AndIV AES
key1 AES
key2 iv
iv Ptr AES -> Ptr AES -> Ptr Word8 -> IO a
f =
    AES -> (Ptr AES -> IO a) -> IO a
forall a. AES -> (Ptr AES -> IO a) -> IO a
keyToPtr AES
key1 ((Ptr AES -> IO a) -> IO a) -> (Ptr AES -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \Ptr AES
kptr1 -> AES -> (Ptr AES -> IO a) -> IO a
forall a. AES -> (Ptr AES -> IO a) -> IO a
keyToPtr AES
key2 ((Ptr AES -> IO a) -> IO a) -> (Ptr AES -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \Ptr AES
kptr2 -> iv -> (Ptr Word8 -> IO a) -> IO a
forall iv a.
ByteArrayAccess iv =>
iv -> (Ptr Word8 -> IO a) -> IO a
ivToPtr iv
iv ((Ptr Word8 -> IO a) -> IO a) -> (Ptr Word8 -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
ivp -> Ptr AES -> Ptr AES -> Ptr Word8 -> IO a
f Ptr AES
kptr1 Ptr AES
kptr2 Ptr Word8
ivp

withGCMKeyAndCopySt :: AES -> AESGCM -> (Ptr AESGCM -> Ptr AES -> IO a) -> IO (a, AESGCM)
withGCMKeyAndCopySt :: forall a.
AES -> AESGCM -> (Ptr AESGCM -> Ptr AES -> IO a) -> IO (a, AESGCM)
withGCMKeyAndCopySt AES
aes (AESGCM ScrubbedBytes
gcmSt) Ptr AESGCM -> Ptr AES -> IO a
f =
    AES -> (Ptr AES -> IO (a, AESGCM)) -> IO (a, AESGCM)
forall a. AES -> (Ptr AES -> IO a) -> IO a
keyToPtr AES
aes ((Ptr AES -> IO (a, AESGCM)) -> IO (a, AESGCM))
-> (Ptr AES -> IO (a, AESGCM)) -> IO (a, AESGCM)
forall a b. (a -> b) -> a -> b
$ \Ptr AES
aesPtr -> do
        ScrubbedBytes
newSt <- ScrubbedBytes -> (Ptr Any -> IO ()) -> IO ScrubbedBytes
forall bs1 bs2 p.
(ByteArrayAccess bs1, ByteArray bs2) =>
bs1 -> (Ptr p -> IO ()) -> IO bs2
B.copy ScrubbedBytes
gcmSt (\Ptr Any
_ -> () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ())
        a
a     <- ScrubbedBytes -> (Ptr Any -> IO a) -> IO a
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
forall p a. ScrubbedBytes -> (Ptr p -> IO a) -> IO a
withByteArray ScrubbedBytes
newSt ((Ptr Any -> IO a) -> IO a) -> (Ptr Any -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \Ptr Any
gcmStPtr -> Ptr AESGCM -> Ptr AES -> IO a
f (Ptr Any -> Ptr AESGCM
forall a b. Ptr a -> Ptr b
castPtr Ptr Any
gcmStPtr) Ptr AES
aesPtr
        (a, AESGCM) -> IO (a, AESGCM)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (a
a, ScrubbedBytes -> AESGCM
AESGCM ScrubbedBytes
newSt)

withNewGCMSt :: AESGCM -> (Ptr AESGCM -> IO ()) -> IO AESGCM
withNewGCMSt :: AESGCM -> (Ptr AESGCM -> IO ()) -> IO AESGCM
withNewGCMSt (AESGCM ScrubbedBytes
gcmSt) Ptr AESGCM -> IO ()
f = ScrubbedBytes -> (Ptr Any -> IO ()) -> IO ScrubbedBytes
forall bs1 bs2 p.
(ByteArrayAccess bs1, ByteArray bs2) =>
bs1 -> (Ptr p -> IO ()) -> IO bs2
B.copy ScrubbedBytes
gcmSt (Ptr AESGCM -> IO ()
f (Ptr AESGCM -> IO ())
-> (Ptr Any -> Ptr AESGCM) -> Ptr Any -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Ptr Any -> Ptr AESGCM
forall a b. Ptr a -> Ptr b
castPtr) IO ScrubbedBytes -> (ScrubbedBytes -> IO AESGCM) -> IO AESGCM
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \ScrubbedBytes
sm2 -> AESGCM -> IO AESGCM
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (ScrubbedBytes -> AESGCM
AESGCM ScrubbedBytes
sm2)

withOCBKeyAndCopySt :: AES -> AESOCB -> (Ptr AESOCB -> Ptr AES -> IO a) -> IO (a, AESOCB)
withOCBKeyAndCopySt :: forall a.
AES -> AESOCB -> (Ptr AESOCB -> Ptr AES -> IO a) -> IO (a, AESOCB)
withOCBKeyAndCopySt AES
aes (AESOCB ScrubbedBytes
gcmSt) Ptr AESOCB -> Ptr AES -> IO a
f =
    AES -> (Ptr AES -> IO (a, AESOCB)) -> IO (a, AESOCB)
forall a. AES -> (Ptr AES -> IO a) -> IO a
keyToPtr AES
aes ((Ptr AES -> IO (a, AESOCB)) -> IO (a, AESOCB))
-> (Ptr AES -> IO (a, AESOCB)) -> IO (a, AESOCB)
forall a b. (a -> b) -> a -> b
$ \Ptr AES
aesPtr -> do
        ScrubbedBytes
newSt <- ScrubbedBytes -> (Ptr Any -> IO ()) -> IO ScrubbedBytes
forall bs1 bs2 p.
(ByteArrayAccess bs1, ByteArray bs2) =>
bs1 -> (Ptr p -> IO ()) -> IO bs2
B.copy ScrubbedBytes
gcmSt (\Ptr Any
_ -> () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ())
        a
a     <- ScrubbedBytes -> (Ptr Any -> IO a) -> IO a
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
forall p a. ScrubbedBytes -> (Ptr p -> IO a) -> IO a
withByteArray ScrubbedBytes
newSt ((Ptr Any -> IO a) -> IO a) -> (Ptr Any -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \Ptr Any
gcmStPtr -> Ptr AESOCB -> Ptr AES -> IO a
f (Ptr Any -> Ptr AESOCB
forall a b. Ptr a -> Ptr b
castPtr Ptr Any
gcmStPtr) Ptr AES
aesPtr
        (a, AESOCB) -> IO (a, AESOCB)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (a
a, ScrubbedBytes -> AESOCB
AESOCB ScrubbedBytes
newSt)

withCCMKeyAndCopySt :: AES -> AESCCM -> (Ptr AESCCM -> Ptr AES -> IO a) -> IO (a, AESCCM)
withCCMKeyAndCopySt :: forall a.
AES -> AESCCM -> (Ptr AESCCM -> Ptr AES -> IO a) -> IO (a, AESCCM)
withCCMKeyAndCopySt AES
aes (AESCCM ScrubbedBytes
ccmSt) Ptr AESCCM -> Ptr AES -> IO a
f =
    AES -> (Ptr AES -> IO (a, AESCCM)) -> IO (a, AESCCM)
forall a. AES -> (Ptr AES -> IO a) -> IO a
keyToPtr AES
aes ((Ptr AES -> IO (a, AESCCM)) -> IO (a, AESCCM))
-> (Ptr AES -> IO (a, AESCCM)) -> IO (a, AESCCM)
forall a b. (a -> b) -> a -> b
$ \Ptr AES
aesPtr -> do
        ScrubbedBytes
newSt <- ScrubbedBytes -> (Ptr Any -> IO ()) -> IO ScrubbedBytes
forall bs1 bs2 p.
(ByteArrayAccess bs1, ByteArray bs2) =>
bs1 -> (Ptr p -> IO ()) -> IO bs2
B.copy ScrubbedBytes
ccmSt (\Ptr Any
_ -> () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ())
        a
a     <- ScrubbedBytes -> (Ptr Any -> IO a) -> IO a
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
forall p a. ScrubbedBytes -> (Ptr p -> IO a) -> IO a
withByteArray ScrubbedBytes
newSt ((Ptr Any -> IO a) -> IO a) -> (Ptr Any -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \Ptr Any
ccmStPtr -> Ptr AESCCM -> Ptr AES -> IO a
f (Ptr Any -> Ptr AESCCM
forall a b. Ptr a -> Ptr b
castPtr Ptr Any
ccmStPtr) Ptr AES
aesPtr
        (a, AESCCM) -> IO (a, AESCCM)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (a
a, ScrubbedBytes -> AESCCM
AESCCM ScrubbedBytes
newSt)

-- | Initialize a new context with a key
--
-- Key needs to be of length 16, 24 or 32 bytes. Any other values will return failure
initAES :: ByteArrayAccess key => key -> CryptoFailable AES
initAES :: forall key. ByteArrayAccess key => key -> CryptoFailable AES
initAES key
k
    | Int
len Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
16 = AES -> CryptoFailable AES
forall a. a -> CryptoFailable a
CryptoPassed (AES -> CryptoFailable AES) -> AES -> CryptoFailable AES
forall a b. (a -> b) -> a -> b
$ Int -> AES
initWithRounds Int
10
    | Int
len Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
24 = AES -> CryptoFailable AES
forall a. a -> CryptoFailable a
CryptoPassed (AES -> CryptoFailable AES) -> AES -> CryptoFailable AES
forall a b. (a -> b) -> a -> b
$ Int -> AES
initWithRounds Int
12
    | Int
len Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
32 = AES -> CryptoFailable AES
forall a. a -> CryptoFailable a
CryptoPassed (AES -> CryptoFailable AES) -> AES -> CryptoFailable AES
forall a b. (a -> b) -> a -> b
$ Int -> AES
initWithRounds Int
14
    | Bool
otherwise = CryptoError -> CryptoFailable AES
forall a. CryptoError -> CryptoFailable a
CryptoFailed CryptoError
CryptoError_KeySizeInvalid
  where len :: Int
len = key -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length key
k
        initWithRounds :: Int -> AES
initWithRounds Int
nbR = ScrubbedBytes -> AES
AES (ScrubbedBytes -> AES) -> ScrubbedBytes -> AES
forall a b. (a -> b) -> a -> b
$ Int -> (Ptr Any -> IO ()) -> ScrubbedBytes
forall a p. ByteArray a => Int -> (Ptr p -> IO ()) -> a
B.allocAndFreeze (Int
16Int -> Int -> Int
forall a. Num a => a -> a -> a
+Int
2Int -> Int -> Int
forall a. Num a => a -> a -> a
*Int
2Int -> Int -> Int
forall a. Num a => a -> a -> a
*Int
16Int -> Int -> Int
forall a. Num a => a -> a -> a
*Int
nbR) Ptr Any -> IO ()
forall {a}. Ptr a -> IO ()
aesInit
        aesInit :: Ptr a -> IO ()
aesInit Ptr a
ptr = key -> (Ptr Any -> IO ()) -> IO ()
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
forall p a. key -> (Ptr p -> IO a) -> IO a
withByteArray key
k ((Ptr Any -> IO ()) -> IO ()) -> (Ptr Any -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr Any
ikey ->
            Ptr AES -> CString -> CUInt -> IO ()
c_aes_init (Ptr a -> Ptr AES
forall a b. Ptr a -> Ptr b
castPtr Ptr a
ptr) (Ptr Any -> CString
forall a b. Ptr a -> Ptr b
castPtr Ptr Any
ikey) (Int -> CUInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
len)

-- | encrypt using Electronic Code Book (ECB)
{-# NOINLINE encryptECB #-}
encryptECB :: ByteArray ba => AES -> ba -> ba
encryptECB :: forall ba. ByteArray ba => AES -> ba -> ba
encryptECB = (CString -> Ptr AES -> CString -> CUInt -> IO ())
-> AES -> ba -> ba
forall ba b.
ByteArray ba =>
(Ptr b -> Ptr AES -> CString -> CUInt -> IO ()) -> AES -> ba -> ba
doECB CString -> Ptr AES -> CString -> CUInt -> IO ()
c_aes_encrypt_ecb

-- | encrypt using Cipher Block Chaining (CBC)
{-# NOINLINE encryptCBC #-}
encryptCBC :: ByteArray ba
           => AES        -- ^ AES Context
           -> IV AES     -- ^ Initial vector of AES block size
           -> ba         -- ^ plaintext
           -> ba         -- ^ ciphertext
encryptCBC :: forall ba. ByteArray ba => AES -> IV AES -> ba -> ba
encryptCBC = (CString -> Ptr AES -> Ptr Word8 -> CString -> CUInt -> IO ())
-> AES -> IV AES -> ba -> ba
forall ba b.
ByteArray ba =>
(Ptr b -> Ptr AES -> Ptr Word8 -> CString -> CUInt -> IO ())
-> AES -> IV AES -> ba -> ba
doCBC CString -> Ptr AES -> Ptr Word8 -> CString -> CUInt -> IO ()
c_aes_encrypt_cbc

-- | generate a counter mode pad. this is generally xor-ed to an input
-- to make the standard counter mode block operations.
--
-- if the length requested is not a multiple of the block cipher size,
-- more data will be returned, so that the returned bytearray is
-- a multiple of the block cipher size.
{-# NOINLINE genCTR #-}
genCTR :: ByteArray ba
       => AES    -- ^ Cipher Key.
       -> IV AES -- ^ usually a 128 bit integer.
       -> Int    -- ^ length of bytes required.
       -> ba
genCTR :: forall ba. ByteArray ba => AES -> IV AES -> Int -> ba
genCTR AES
ctx (IV byteArray
iv) Int
len
    | Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0  = ba
forall a. ByteArray a => a
B.empty
    | Bool
otherwise = Int -> (Ptr Any -> IO ()) -> ba
forall a p. ByteArray a => Int -> (Ptr p -> IO ()) -> a
B.allocAndFreeze (Int
nbBlocks Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
16) Ptr Any -> IO ()
forall {a}. Ptr a -> IO ()
generate
  where generate :: Ptr a -> IO ()
generate Ptr a
o = AES -> byteArray -> (Ptr AES -> Ptr Word8 -> IO ()) -> IO ()
forall iv a.
ByteArrayAccess iv =>
AES -> iv -> (Ptr AES -> Ptr Word8 -> IO a) -> IO a
withKeyAndIV AES
ctx byteArray
iv ((Ptr AES -> Ptr Word8 -> IO ()) -> IO ())
-> (Ptr AES -> Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr AES
k Ptr Word8
i -> CString -> Ptr AES -> Ptr Word8 -> CUInt -> IO ()
c_aes_gen_ctr (Ptr a -> CString
forall a b. Ptr a -> Ptr b
castPtr Ptr a
o) Ptr AES
k Ptr Word8
i (Int -> CUInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
nbBlocks)
        (Int
nbBlocks',Int
r) = Int
len Int -> Int -> (Int, Int)
forall a. Integral a => a -> a -> (a, a)
`quotRem` Int
16
        nbBlocks :: Int
nbBlocks = if Int
r Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 then Int
nbBlocks' else Int
nbBlocks' Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1

-- | generate a counter mode pad. this is generally xor-ed to an input
-- to make the standard counter mode block operations.
--
-- if the length requested is not a multiple of the block cipher size,
-- more data will be returned, so that the returned bytearray is
-- a multiple of the block cipher size.
--
-- Similiar to 'genCTR' but also return the next IV for continuation
{-# NOINLINE genCounter #-}
genCounter :: ByteArray ba
           => AES
           -> IV AES
           -> Int
           -> (ba, IV AES)
genCounter :: forall ba. ByteArray ba => AES -> IV AES -> Int -> (ba, IV AES)
genCounter AES
ctx IV AES
iv Int
len
    | Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0  = (ba
forall a. ByteArray a => a
B.empty, IV AES
iv)
    | Bool
otherwise = IO (ba, IV AES) -> (ba, IV AES)
forall a. IO a -> a
unsafeDoIO (IO (ba, IV AES) -> (ba, IV AES))
-> IO (ba, IV AES) -> (ba, IV AES)
forall a b. (a -> b) -> a -> b
$
        AES -> (Ptr AES -> IO (ba, IV AES)) -> IO (ba, IV AES)
forall a. AES -> (Ptr AES -> IO a) -> IO a
keyToPtr AES
ctx ((Ptr AES -> IO (ba, IV AES)) -> IO (ba, IV AES))
-> (Ptr AES -> IO (ba, IV AES)) -> IO (ba, IV AES)
forall a b. (a -> b) -> a -> b
$ \Ptr AES
k ->
        IV AES -> (Ptr Word8 -> IO ba) -> IO (ba, IV AES)
forall a. IV AES -> (Ptr Word8 -> IO a) -> IO (a, IV AES)
ivCopyPtr IV AES
iv ((Ptr Word8 -> IO ba) -> IO (ba, IV AES))
-> (Ptr Word8 -> IO ba) -> IO (ba, IV AES)
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
i ->
        Int -> (Ptr Any -> IO ()) -> IO ba
forall ba p. ByteArray ba => Int -> (Ptr p -> IO ()) -> IO ba
B.alloc Int
outputLength ((Ptr Any -> IO ()) -> IO ba) -> (Ptr Any -> IO ()) -> IO ba
forall a b. (a -> b) -> a -> b
$ \Ptr Any
o -> do
            CString -> Ptr AES -> Ptr Word8 -> CUInt -> IO ()
c_aes_gen_ctr_cont (Ptr Any -> CString
forall a b. Ptr a -> Ptr b
castPtr Ptr Any
o) Ptr AES
k Ptr Word8
i (Int -> CUInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
nbBlocks)
  where
        (Int
nbBlocks',Int
r) = Int
len Int -> Int -> (Int, Int)
forall a. Integral a => a -> a -> (a, a)
`quotRem` Int
16
        nbBlocks :: Int
nbBlocks = if Int
r Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 then Int
nbBlocks' else Int
nbBlocks' Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1
        outputLength :: Int
outputLength = Int
nbBlocks Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
16

{- TODO: when genCTR has same AESIV requirements for IV, add the following rules:
 - RULES "snd . genCounter" forall ctx iv len .  snd (genCounter ctx iv len) = genCTR ctx iv len
 -}

-- | encrypt using Counter mode (CTR)
--
-- in CTR mode encryption and decryption is the same operation.
{-# NOINLINE encryptCTR #-}
encryptCTR :: ByteArray ba
           => AES        -- ^ AES Context
           -> IV AES     -- ^ initial vector of AES block size (usually representing a 128 bit integer)
           -> ba         -- ^ plaintext input
           -> ba         -- ^ ciphertext output
encryptCTR :: forall ba. ByteArray ba => AES -> IV AES -> ba -> ba
encryptCTR AES
ctx IV AES
iv ba
input
    | Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0          = ba
forall a. ByteArray a => a
B.empty
    | IV AES -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length IV AES
iv Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
16 = String -> ba
forall a. HasCallStack => String -> a
error (String -> ba) -> String -> ba
forall a b. (a -> b) -> a -> b
$ String
"AES error: IV length must be block size (16). Its length is: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ (Int -> String
forall a. Show a => a -> String
show (Int -> String) -> Int -> String
forall a b. (a -> b) -> a -> b
$ IV AES -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length IV AES
iv)
    | Bool
otherwise = Int -> (Ptr Any -> IO ()) -> ba
forall a p. ByteArray a => Int -> (Ptr p -> IO ()) -> a
B.allocAndFreeze Int
len Ptr Any -> IO ()
forall {a}. Ptr a -> IO ()
doEncrypt
  where doEncrypt :: Ptr a -> IO ()
doEncrypt Ptr a
o = AES -> IV AES -> (Ptr AES -> Ptr Word8 -> IO ()) -> IO ()
forall iv a.
ByteArrayAccess iv =>
AES -> iv -> (Ptr AES -> Ptr Word8 -> IO a) -> IO a
withKeyAndIV AES
ctx IV AES
iv ((Ptr AES -> Ptr Word8 -> IO ()) -> IO ())
-> (Ptr AES -> Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr AES
k Ptr Word8
v -> ba -> (CString -> IO ()) -> IO ()
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
forall p a. ba -> (Ptr p -> IO a) -> IO a
withByteArray ba
input ((CString -> IO ()) -> IO ()) -> (CString -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \CString
i ->
                      CString -> Ptr AES -> Ptr Word8 -> CString -> CUInt -> IO ()
c_aes_encrypt_ctr (Ptr a -> CString
forall a b. Ptr a -> Ptr b
castPtr Ptr a
o) Ptr AES
k Ptr Word8
v CString
i (Int -> CUInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
len)
        len :: Int
len = ba -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length ba
input

-- | encrypt using XTS
--
-- the first key is the normal block encryption key
-- the second key is used for the initial block tweak
{-# NOINLINE encryptXTS #-}
encryptXTS :: ByteArray ba
           => (AES,AES)  -- ^ AES cipher and tweak context
           -> IV AES     -- ^ a 128 bits IV, typically a sector or a block offset in XTS
           -> Word32     -- ^ number of rounds to skip, also seen a 16 byte offset in the sector or block.
           -> ba         -- ^ input to encrypt
           -> ba         -- ^ output encrypted
encryptXTS :: forall ba.
ByteArray ba =>
(AES, AES) -> IV AES -> DataUnitOffset -> ba -> ba
encryptXTS = (CString
 -> Ptr AES
 -> Ptr AES
 -> Ptr Word8
 -> CUInt
 -> CString
 -> CUInt
 -> IO ())
-> (AES, AES) -> IV AES -> DataUnitOffset -> ba -> ba
forall ba b.
ByteArray ba =>
(Ptr b
 -> Ptr AES
 -> Ptr AES
 -> Ptr Word8
 -> CUInt
 -> CString
 -> CUInt
 -> IO ())
-> (AES, AES) -> IV AES -> DataUnitOffset -> ba -> ba
doXTS CString
-> Ptr AES
-> Ptr AES
-> Ptr Word8
-> CUInt
-> CString
-> CUInt
-> IO ()
c_aes_encrypt_xts

-- | decrypt using Electronic Code Book (ECB)
{-# NOINLINE decryptECB #-}
decryptECB :: ByteArray ba => AES -> ba -> ba
decryptECB :: forall ba. ByteArray ba => AES -> ba -> ba
decryptECB = (CString -> Ptr AES -> CString -> CUInt -> IO ())
-> AES -> ba -> ba
forall ba b.
ByteArray ba =>
(Ptr b -> Ptr AES -> CString -> CUInt -> IO ()) -> AES -> ba -> ba
doECB CString -> Ptr AES -> CString -> CUInt -> IO ()
c_aes_decrypt_ecb

-- | decrypt using Cipher block chaining (CBC)
{-# NOINLINE decryptCBC #-}
decryptCBC :: ByteArray ba => AES -> IV AES -> ba -> ba
decryptCBC :: forall ba. ByteArray ba => AES -> IV AES -> ba -> ba
decryptCBC = (CString -> Ptr AES -> Ptr Word8 -> CString -> CUInt -> IO ())
-> AES -> IV AES -> ba -> ba
forall ba b.
ByteArray ba =>
(Ptr b -> Ptr AES -> Ptr Word8 -> CString -> CUInt -> IO ())
-> AES -> IV AES -> ba -> ba
doCBC CString -> Ptr AES -> Ptr Word8 -> CString -> CUInt -> IO ()
c_aes_decrypt_cbc

-- | decrypt using Counter mode (CTR).
--
-- in CTR mode encryption and decryption is the same operation.
decryptCTR :: ByteArray ba
           => AES        -- ^ AES Context
           -> IV AES     -- ^ initial vector, usually representing a 128 bit integer
           -> ba         -- ^ ciphertext input
           -> ba         -- ^ plaintext output
decryptCTR :: forall ba. ByteArray ba => AES -> IV AES -> ba -> ba
decryptCTR = AES -> IV AES -> ba -> ba
forall ba. ByteArray ba => AES -> IV AES -> ba -> ba
encryptCTR

-- | decrypt using XTS
{-# NOINLINE decryptXTS #-}
decryptXTS :: ByteArray ba
           => (AES,AES)  -- ^ AES cipher and tweak context
           -> IV AES     -- ^ a 128 bits IV, typically a sector or a block offset in XTS
           -> Word32     -- ^ number of rounds to skip, also seen a 16 byte offset in the sector or block.
           -> ba         -- ^ input to decrypt
           -> ba         -- ^ output decrypted
decryptXTS :: forall ba.
ByteArray ba =>
(AES, AES) -> IV AES -> DataUnitOffset -> ba -> ba
decryptXTS = (CString
 -> Ptr AES
 -> Ptr AES
 -> Ptr Word8
 -> CUInt
 -> CString
 -> CUInt
 -> IO ())
-> (AES, AES) -> IV AES -> DataUnitOffset -> ba -> ba
forall ba b.
ByteArray ba =>
(Ptr b
 -> Ptr AES
 -> Ptr AES
 -> Ptr Word8
 -> CUInt
 -> CString
 -> CUInt
 -> IO ())
-> (AES, AES) -> IV AES -> DataUnitOffset -> ba -> ba
doXTS CString
-> Ptr AES
-> Ptr AES
-> Ptr Word8
-> CUInt
-> CString
-> CUInt
-> IO ()
c_aes_decrypt_xts

-- | encrypt/decrypt using Counter mode (32-bit wrapping used in AES-GCM-SIV)
{-# NOINLINE combineC32 #-}
combineC32 :: ByteArray ba
           => AES        -- ^ AES Context
           -> IV AES     -- ^ initial vector of AES block size (usually representing a 128 bit integer)
           -> ba         -- ^ plaintext input
           -> ba         -- ^ ciphertext output
combineC32 :: forall ba. ByteArray ba => AES -> IV AES -> ba -> ba
combineC32 AES
ctx IV AES
iv ba
input
    | Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0          = ba
forall a. ByteArray a => a
B.empty
    | IV AES -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length IV AES
iv Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
16 = String -> ba
forall a. HasCallStack => String -> a
error (String -> ba) -> String -> ba
forall a b. (a -> b) -> a -> b
$ String
"AES error: IV length must be block size (16). Its length is: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show (IV AES -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length IV AES
iv)
    | Bool
otherwise = Int -> (Ptr Any -> IO ()) -> ba
forall a p. ByteArray a => Int -> (Ptr p -> IO ()) -> a
B.allocAndFreeze Int
len Ptr Any -> IO ()
forall {a}. Ptr a -> IO ()
doEncrypt
  where doEncrypt :: Ptr a -> IO ()
doEncrypt Ptr a
o = AES -> IV AES -> (Ptr AES -> Ptr Word8 -> IO ()) -> IO ()
forall iv a.
ByteArrayAccess iv =>
AES -> iv -> (Ptr AES -> Ptr Word8 -> IO a) -> IO a
withKeyAndIV AES
ctx IV AES
iv ((Ptr AES -> Ptr Word8 -> IO ()) -> IO ())
-> (Ptr AES -> Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr AES
k Ptr Word8
v -> ba -> (CString -> IO ()) -> IO ()
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
forall p a. ba -> (Ptr p -> IO a) -> IO a
withByteArray ba
input ((CString -> IO ()) -> IO ()) -> (CString -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \CString
i ->
                      CString -> Ptr AES -> Ptr Word8 -> CString -> CUInt -> IO ()
c_aes_encrypt_c32 (Ptr a -> CString
forall a b. Ptr a -> Ptr b
castPtr Ptr a
o) Ptr AES
k Ptr Word8
v CString
i (Int -> CUInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
len)
        len :: Int
len = ba -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length ba
input

{-# INLINE doECB #-}
doECB :: ByteArray ba
      => (Ptr b -> Ptr AES -> CString -> CUInt -> IO ())
      -> AES -> ba -> ba
doECB :: forall ba b.
ByteArray ba =>
(Ptr b -> Ptr AES -> CString -> CUInt -> IO ()) -> AES -> ba -> ba
doECB Ptr b -> Ptr AES -> CString -> CUInt -> IO ()
f AES
ctx ba
input
    | Int
len Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0     = ba
forall a. ByteArray a => a
B.empty
    | Int
r Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
0       = String -> ba
forall a. HasCallStack => String -> a
error (String -> ba) -> String -> ba
forall a b. (a -> b) -> a -> b
$ String
"Encryption error: input length must be a multiple of block size (16). Its length is: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ (Int -> String
forall a. Show a => a -> String
show Int
len)
    | Bool
otherwise    =
        Int -> (Ptr Any -> IO ()) -> ba
forall a p. ByteArray a => Int -> (Ptr p -> IO ()) -> a
B.allocAndFreeze Int
len ((Ptr Any -> IO ()) -> ba) -> (Ptr Any -> IO ()) -> ba
forall a b. (a -> b) -> a -> b
$ \Ptr Any
o ->
        AES -> (Ptr AES -> IO ()) -> IO ()
forall a. AES -> (Ptr AES -> IO a) -> IO a
keyToPtr AES
ctx         ((Ptr AES -> IO ()) -> IO ()) -> (Ptr AES -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr AES
k ->
        ba -> (CString -> IO ()) -> IO ()
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
forall p a. ba -> (Ptr p -> IO a) -> IO a
withByteArray ba
input  ((CString -> IO ()) -> IO ()) -> (CString -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \CString
i ->
            Ptr b -> Ptr AES -> CString -> CUInt -> IO ()
f (Ptr Any -> Ptr b
forall a b. Ptr a -> Ptr b
castPtr Ptr Any
o) Ptr AES
k CString
i (Int -> CUInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
nbBlocks)
  where (Int
nbBlocks, Int
r) = Int
len Int -> Int -> (Int, Int)
forall a. Integral a => a -> a -> (a, a)
`quotRem` Int
16
        len :: Int
len           = ba -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length ba
input

{-# INLINE doCBC #-}
doCBC :: ByteArray ba
      => (Ptr b -> Ptr AES -> Ptr Word8 -> CString -> CUInt -> IO ())
      -> AES -> IV AES -> ba -> ba
doCBC :: forall ba b.
ByteArray ba =>
(Ptr b -> Ptr AES -> Ptr Word8 -> CString -> CUInt -> IO ())
-> AES -> IV AES -> ba -> ba
doCBC Ptr b -> Ptr AES -> Ptr Word8 -> CString -> CUInt -> IO ()
f AES
ctx (IV byteArray
iv) ba
input
    | Int
len Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0  = ba
forall a. ByteArray a => a
B.empty
    | Int
r Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
0    = String -> ba
forall a. HasCallStack => String -> a
error (String -> ba) -> String -> ba
forall a b. (a -> b) -> a -> b
$ String
"Encryption error: input length must be a multiple of block size (16). Its length is: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ (Int -> String
forall a. Show a => a -> String
show Int
len)
    | Bool
otherwise = Int -> (Ptr Any -> IO ()) -> ba
forall a p. ByteArray a => Int -> (Ptr p -> IO ()) -> a
B.allocAndFreeze Int
len ((Ptr Any -> IO ()) -> ba) -> (Ptr Any -> IO ()) -> ba
forall a b. (a -> b) -> a -> b
$ \Ptr Any
o ->
                  AES -> byteArray -> (Ptr AES -> Ptr Word8 -> IO ()) -> IO ()
forall iv a.
ByteArrayAccess iv =>
AES -> iv -> (Ptr AES -> Ptr Word8 -> IO a) -> IO a
withKeyAndIV AES
ctx byteArray
iv ((Ptr AES -> Ptr Word8 -> IO ()) -> IO ())
-> (Ptr AES -> Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr AES
k Ptr Word8
v ->
                  ba -> (CString -> IO ()) -> IO ()
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
forall p a. ba -> (Ptr p -> IO a) -> IO a
withByteArray ba
input ((CString -> IO ()) -> IO ()) -> (CString -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \CString
i ->
                  Ptr b -> Ptr AES -> Ptr Word8 -> CString -> CUInt -> IO ()
f (Ptr Any -> Ptr b
forall a b. Ptr a -> Ptr b
castPtr Ptr Any
o) Ptr AES
k Ptr Word8
v CString
i (Int -> CUInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
nbBlocks)
  where (Int
nbBlocks, Int
r) = Int
len Int -> Int -> (Int, Int)
forall a. Integral a => a -> a -> (a, a)
`quotRem` Int
16
        len :: Int
len           = ba -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length ba
input

{-# INLINE doXTS #-}
doXTS :: ByteArray ba
      => (Ptr b -> Ptr AES -> Ptr AES -> Ptr Word8 -> CUInt -> CString -> CUInt -> IO ())
      -> (AES, AES)
      -> IV AES
      -> Word32
      -> ba
      -> ba
doXTS :: forall ba b.
ByteArray ba =>
(Ptr b
 -> Ptr AES
 -> Ptr AES
 -> Ptr Word8
 -> CUInt
 -> CString
 -> CUInt
 -> IO ())
-> (AES, AES) -> IV AES -> DataUnitOffset -> ba -> ba
doXTS Ptr b
-> Ptr AES
-> Ptr AES
-> Ptr Word8
-> CUInt
-> CString
-> CUInt
-> IO ()
f (AES
key1,AES
key2) IV AES
iv DataUnitOffset
spoint ba
input
    | Int
len Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0  = ba
forall a. ByteArray a => a
B.empty
    | Int
r Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
0    = String -> ba
forall a. HasCallStack => String -> a
error (String -> ba) -> String -> ba
forall a b. (a -> b) -> a -> b
$ String
"Encryption error: input length must be a multiple of block size (16) for now. Its length is: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ (Int -> String
forall a. Show a => a -> String
show Int
len)
    | Bool
otherwise = Int -> (Ptr Any -> IO ()) -> ba
forall a p. ByteArray a => Int -> (Ptr p -> IO ()) -> a
B.allocAndFreeze Int
len ((Ptr Any -> IO ()) -> ba) -> (Ptr Any -> IO ()) -> ba
forall a b. (a -> b) -> a -> b
$ \Ptr Any
o -> AES
-> AES
-> IV AES
-> (Ptr AES -> Ptr AES -> Ptr Word8 -> IO ())
-> IO ()
forall iv a.
ByteArrayAccess iv =>
AES
-> AES -> iv -> (Ptr AES -> Ptr AES -> Ptr Word8 -> IO a) -> IO a
withKey2AndIV AES
key1 AES
key2 IV AES
iv ((Ptr AES -> Ptr AES -> Ptr Word8 -> IO ()) -> IO ())
-> (Ptr AES -> Ptr AES -> Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr AES
k1 Ptr AES
k2 Ptr Word8
v -> ba -> (CString -> IO ()) -> IO ()
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
forall p a. ba -> (Ptr p -> IO a) -> IO a
withByteArray ba
input ((CString -> IO ()) -> IO ()) -> (CString -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \CString
i ->
            Ptr b
-> Ptr AES
-> Ptr AES
-> Ptr Word8
-> CUInt
-> CString
-> CUInt
-> IO ()
f (Ptr Any -> Ptr b
forall a b. Ptr a -> Ptr b
castPtr Ptr Any
o) Ptr AES
k1 Ptr AES
k2 Ptr Word8
v (DataUnitOffset -> CUInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral DataUnitOffset
spoint) CString
i (Int -> CUInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
nbBlocks)
  where (Int
nbBlocks, Int
r) = Int
len Int -> Int -> (Int, Int)
forall a. Integral a => a -> a -> (a, a)
`quotRem` Int
16
        len :: Int
len           = ba -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length ba
input

------------------------------------------------------------------------
-- GCM
------------------------------------------------------------------------

-- | initialize a gcm context
{-# NOINLINE gcmInit #-}
gcmInit :: ByteArrayAccess iv => AES -> iv -> AESGCM
gcmInit :: forall iv. ByteArrayAccess iv => AES -> iv -> AESGCM
gcmInit AES
ctx iv
iv = IO AESGCM -> AESGCM
forall a. IO a -> a
unsafeDoIO (IO AESGCM -> AESGCM) -> IO AESGCM -> AESGCM
forall a b. (a -> b) -> a -> b
$ do
    ScrubbedBytes
sm <- Int -> (Ptr Any -> IO ()) -> IO ScrubbedBytes
forall ba p. ByteArray ba => Int -> (Ptr p -> IO ()) -> IO ba
B.alloc Int
sizeGCM ((Ptr Any -> IO ()) -> IO ScrubbedBytes)
-> (Ptr Any -> IO ()) -> IO ScrubbedBytes
forall a b. (a -> b) -> a -> b
$ \Ptr Any
gcmStPtr ->
            AES -> iv -> (Ptr AES -> Ptr Word8 -> IO ()) -> IO ()
forall iv a.
ByteArrayAccess iv =>
AES -> iv -> (Ptr AES -> Ptr Word8 -> IO a) -> IO a
withKeyAndIV AES
ctx iv
iv ((Ptr AES -> Ptr Word8 -> IO ()) -> IO ())
-> (Ptr AES -> Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr AES
k Ptr Word8
v ->
            Ptr AESGCM -> Ptr AES -> Ptr Word8 -> CUInt -> IO ()
c_aes_gcm_init (Ptr Any -> Ptr AESGCM
forall a b. Ptr a -> Ptr b
castPtr Ptr Any
gcmStPtr) Ptr AES
k Ptr Word8
v (Int -> CUInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> CUInt) -> Int -> CUInt
forall a b. (a -> b) -> a -> b
$ iv -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length iv
iv)
    AESGCM -> IO AESGCM
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (AESGCM -> IO AESGCM) -> AESGCM -> IO AESGCM
forall a b. (a -> b) -> a -> b
$ ScrubbedBytes -> AESGCM
AESGCM ScrubbedBytes
sm

-- | append data which is only going to be authenticated to the GCM context.
--
-- needs to happen after initialization and before appending encryption/decryption data.
{-# NOINLINE gcmAppendAAD #-}
gcmAppendAAD :: ByteArrayAccess aad => AESGCM -> aad -> AESGCM
gcmAppendAAD :: forall ba. ByteArrayAccess ba => AESGCM -> ba -> AESGCM
gcmAppendAAD AESGCM
gcmSt aad
input = IO AESGCM -> AESGCM
forall a. IO a -> a
unsafeDoIO IO AESGCM
doAppend
  where doAppend :: IO AESGCM
doAppend =
            AESGCM -> (Ptr AESGCM -> IO ()) -> IO AESGCM
withNewGCMSt AESGCM
gcmSt ((Ptr AESGCM -> IO ()) -> IO AESGCM)
-> (Ptr AESGCM -> IO ()) -> IO AESGCM
forall a b. (a -> b) -> a -> b
$ \Ptr AESGCM
gcmStPtr ->
            aad -> (CString -> IO ()) -> IO ()
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
forall p a. aad -> (Ptr p -> IO a) -> IO a
withByteArray aad
input ((CString -> IO ()) -> IO ()) -> (CString -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \CString
i ->
            Ptr AESGCM -> CString -> CUInt -> IO ()
c_aes_gcm_aad Ptr AESGCM
gcmStPtr CString
i (Int -> CUInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> CUInt) -> Int -> CUInt
forall a b. (a -> b) -> a -> b
$ aad -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length aad
input)

-- | append data to encrypt and append to the GCM context
--
-- the bytearray needs to be a multiple of AES block size, unless it's the last call to this function.
-- needs to happen after AAD appending, or after initialization if no AAD data.
{-# NOINLINE gcmAppendEncrypt #-}
gcmAppendEncrypt :: ByteArray ba => AES -> AESGCM -> ba -> (ba, AESGCM)
gcmAppendEncrypt :: forall ba. ByteArray ba => AES -> AESGCM -> ba -> (ba, AESGCM)
gcmAppendEncrypt AES
ctx AESGCM
gcm ba
input = IO (ba, AESGCM) -> (ba, AESGCM)
forall a. IO a -> a
unsafeDoIO (IO (ba, AESGCM) -> (ba, AESGCM))
-> IO (ba, AESGCM) -> (ba, AESGCM)
forall a b. (a -> b) -> a -> b
$ AES
-> AESGCM -> (Ptr AESGCM -> Ptr AES -> IO ba) -> IO (ba, AESGCM)
forall a.
AES -> AESGCM -> (Ptr AESGCM -> Ptr AES -> IO a) -> IO (a, AESGCM)
withGCMKeyAndCopySt AES
ctx AESGCM
gcm Ptr AESGCM -> Ptr AES -> IO ba
forall {ba}. ByteArray ba => Ptr AESGCM -> Ptr AES -> IO ba
doEnc
  where len :: Int
len = ba -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length ba
input
        doEnc :: Ptr AESGCM -> Ptr AES -> IO ba
doEnc Ptr AESGCM
gcmStPtr Ptr AES
aesPtr =
            Int -> (Ptr Any -> IO ()) -> IO ba
forall ba p. ByteArray ba => Int -> (Ptr p -> IO ()) -> IO ba
B.alloc Int
len ((Ptr Any -> IO ()) -> IO ba) -> (Ptr Any -> IO ()) -> IO ba
forall a b. (a -> b) -> a -> b
$ \Ptr Any
o ->
            ba -> (CString -> IO ()) -> IO ()
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
forall p a. ba -> (Ptr p -> IO a) -> IO a
withByteArray ba
input ((CString -> IO ()) -> IO ()) -> (CString -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \CString
i ->
            CString -> Ptr AESGCM -> Ptr AES -> CString -> CUInt -> IO ()
c_aes_gcm_encrypt (Ptr Any -> CString
forall a b. Ptr a -> Ptr b
castPtr Ptr Any
o) Ptr AESGCM
gcmStPtr Ptr AES
aesPtr CString
i (Int -> CUInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
len)

-- | append data to decrypt and append to the GCM context
--
-- the bytearray needs to be a multiple of AES block size, unless it's the last call to this function.
-- needs to happen after AAD appending, or after initialization if no AAD data.
{-# NOINLINE gcmAppendDecrypt #-}
gcmAppendDecrypt :: ByteArray ba => AES -> AESGCM -> ba -> (ba, AESGCM)
gcmAppendDecrypt :: forall ba. ByteArray ba => AES -> AESGCM -> ba -> (ba, AESGCM)
gcmAppendDecrypt AES
ctx AESGCM
gcm ba
input = IO (ba, AESGCM) -> (ba, AESGCM)
forall a. IO a -> a
unsafeDoIO (IO (ba, AESGCM) -> (ba, AESGCM))
-> IO (ba, AESGCM) -> (ba, AESGCM)
forall a b. (a -> b) -> a -> b
$ AES
-> AESGCM -> (Ptr AESGCM -> Ptr AES -> IO ba) -> IO (ba, AESGCM)
forall a.
AES -> AESGCM -> (Ptr AESGCM -> Ptr AES -> IO a) -> IO (a, AESGCM)
withGCMKeyAndCopySt AES
ctx AESGCM
gcm Ptr AESGCM -> Ptr AES -> IO ba
forall {ba}. ByteArray ba => Ptr AESGCM -> Ptr AES -> IO ba
doDec
  where len :: Int
len = ba -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length ba
input
        doDec :: Ptr AESGCM -> Ptr AES -> IO ba
doDec Ptr AESGCM
gcmStPtr Ptr AES
aesPtr =
            Int -> (Ptr Any -> IO ()) -> IO ba
forall ba p. ByteArray ba => Int -> (Ptr p -> IO ()) -> IO ba
B.alloc Int
len ((Ptr Any -> IO ()) -> IO ba) -> (Ptr Any -> IO ()) -> IO ba
forall a b. (a -> b) -> a -> b
$ \Ptr Any
o ->
            ba -> (CString -> IO ()) -> IO ()
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
forall p a. ba -> (Ptr p -> IO a) -> IO a
withByteArray ba
input ((CString -> IO ()) -> IO ()) -> (CString -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \CString
i ->
            CString -> Ptr AESGCM -> Ptr AES -> CString -> CUInt -> IO ()
c_aes_gcm_decrypt (Ptr Any -> CString
forall a b. Ptr a -> Ptr b
castPtr Ptr Any
o) Ptr AESGCM
gcmStPtr Ptr AES
aesPtr CString
i (Int -> CUInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
len)

-- | Generate the Tag from GCM context
{-# NOINLINE gcmFinish #-}
gcmFinish :: AES -> AESGCM -> Int -> AuthTag
gcmFinish :: AES -> AESGCM -> Int -> AuthTag
gcmFinish AES
ctx AESGCM
gcm Int
taglen = Bytes -> AuthTag
AuthTag (Bytes -> AuthTag) -> Bytes -> AuthTag
forall a b. (a -> b) -> a -> b
$ Int -> Bytes -> Bytes
forall bs. ByteArray bs => Int -> bs -> bs
B.take Int
taglen Bytes
computeTag
  where computeTag :: Bytes
computeTag = Int -> (Ptr Any -> IO ()) -> Bytes
forall a p. ByteArray a => Int -> (Ptr p -> IO ()) -> a
B.allocAndFreeze Int
16 ((Ptr Any -> IO ()) -> Bytes) -> (Ptr Any -> IO ()) -> Bytes
forall a b. (a -> b) -> a -> b
$ \Ptr Any
t ->
                        AES
-> AESGCM -> (Ptr AESGCM -> Ptr AES -> IO ()) -> IO ((), AESGCM)
forall a.
AES -> AESGCM -> (Ptr AESGCM -> Ptr AES -> IO a) -> IO (a, AESGCM)
withGCMKeyAndCopySt AES
ctx AESGCM
gcm (CString -> Ptr AESGCM -> Ptr AES -> IO ()
c_aes_gcm_finish (Ptr Any -> CString
forall a b. Ptr a -> Ptr b
castPtr Ptr Any
t)) IO ((), AESGCM) -> IO () -> IO ()
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()

------------------------------------------------------------------------
-- OCB v3
------------------------------------------------------------------------

-- | initialize an ocb context
{-# NOINLINE ocbInit #-}
ocbInit :: ByteArrayAccess iv => AES -> iv -> AESOCB
ocbInit :: forall iv. ByteArrayAccess iv => AES -> iv -> AESOCB
ocbInit AES
ctx iv
iv = IO AESOCB -> AESOCB
forall a. IO a -> a
unsafeDoIO (IO AESOCB -> AESOCB) -> IO AESOCB -> AESOCB
forall a b. (a -> b) -> a -> b
$ do
    ScrubbedBytes
sm <- Int -> (Ptr Any -> IO ()) -> IO ScrubbedBytes
forall ba p. ByteArray ba => Int -> (Ptr p -> IO ()) -> IO ba
B.alloc Int
sizeOCB ((Ptr Any -> IO ()) -> IO ScrubbedBytes)
-> (Ptr Any -> IO ()) -> IO ScrubbedBytes
forall a b. (a -> b) -> a -> b
$ \Ptr Any
ocbStPtr ->
            AES -> iv -> (Ptr AES -> Ptr Word8 -> IO ()) -> IO ()
forall iv a.
ByteArrayAccess iv =>
AES -> iv -> (Ptr AES -> Ptr Word8 -> IO a) -> IO a
withKeyAndIV AES
ctx iv
iv ((Ptr AES -> Ptr Word8 -> IO ()) -> IO ())
-> (Ptr AES -> Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr AES
k Ptr Word8
v ->
            Ptr AESOCB -> Ptr AES -> Ptr Word8 -> CUInt -> IO ()
c_aes_ocb_init (Ptr Any -> Ptr AESOCB
forall a b. Ptr a -> Ptr b
castPtr Ptr Any
ocbStPtr) Ptr AES
k Ptr Word8
v (Int -> CUInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> CUInt) -> Int -> CUInt
forall a b. (a -> b) -> a -> b
$ iv -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length iv
iv)
    AESOCB -> IO AESOCB
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (AESOCB -> IO AESOCB) -> AESOCB -> IO AESOCB
forall a b. (a -> b) -> a -> b
$ ScrubbedBytes -> AESOCB
AESOCB ScrubbedBytes
sm

-- | append data which is going to just be authenticated to the OCB context.
--
-- need to happen after initialization and before appending encryption/decryption data.
{-# NOINLINE ocbAppendAAD #-}
ocbAppendAAD :: ByteArrayAccess aad => AES -> AESOCB -> aad -> AESOCB
ocbAppendAAD :: forall aad. ByteArrayAccess aad => AES -> AESOCB -> aad -> AESOCB
ocbAppendAAD AES
ctx AESOCB
ocb aad
input = IO AESOCB -> AESOCB
forall a. IO a -> a
unsafeDoIO (((), AESOCB) -> AESOCB
forall a b. (a, b) -> b
snd (((), AESOCB) -> AESOCB) -> IO ((), AESOCB) -> IO AESOCB
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` AES
-> AESOCB -> (Ptr AESOCB -> Ptr AES -> IO ()) -> IO ((), AESOCB)
forall a.
AES -> AESOCB -> (Ptr AESOCB -> Ptr AES -> IO a) -> IO (a, AESOCB)
withOCBKeyAndCopySt AES
ctx AESOCB
ocb Ptr AESOCB -> Ptr AES -> IO ()
doAppend)
  where doAppend :: Ptr AESOCB -> Ptr AES -> IO ()
doAppend Ptr AESOCB
ocbStPtr Ptr AES
aesPtr =
            aad -> (CString -> IO ()) -> IO ()
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
forall p a. aad -> (Ptr p -> IO a) -> IO a
withByteArray aad
input ((CString -> IO ()) -> IO ()) -> (CString -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \CString
i ->
            Ptr AESOCB -> Ptr AES -> CString -> CUInt -> IO ()
c_aes_ocb_aad Ptr AESOCB
ocbStPtr Ptr AES
aesPtr CString
i (Int -> CUInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> CUInt) -> Int -> CUInt
forall a b. (a -> b) -> a -> b
$ aad -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length aad
input)

-- | append data to encrypt and append to the OCB context
--
-- the bytearray needs to be a multiple of the AES block size, unless it's the last call to this function.
-- need to happen after AAD appending, or after initialization if no AAD data.
{-# NOINLINE ocbAppendEncrypt #-}
ocbAppendEncrypt :: ByteArray ba => AES -> AESOCB -> ba -> (ba, AESOCB)
ocbAppendEncrypt :: forall ba. ByteArray ba => AES -> AESOCB -> ba -> (ba, AESOCB)
ocbAppendEncrypt AES
ctx AESOCB
ocb ba
input = IO (ba, AESOCB) -> (ba, AESOCB)
forall a. IO a -> a
unsafeDoIO (IO (ba, AESOCB) -> (ba, AESOCB))
-> IO (ba, AESOCB) -> (ba, AESOCB)
forall a b. (a -> b) -> a -> b
$ AES
-> AESOCB -> (Ptr AESOCB -> Ptr AES -> IO ba) -> IO (ba, AESOCB)
forall a.
AES -> AESOCB -> (Ptr AESOCB -> Ptr AES -> IO a) -> IO (a, AESOCB)
withOCBKeyAndCopySt AES
ctx AESOCB
ocb Ptr AESOCB -> Ptr AES -> IO ba
forall {ba}. ByteArray ba => Ptr AESOCB -> Ptr AES -> IO ba
doEnc
  where len :: Int
len = ba -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length ba
input
        doEnc :: Ptr AESOCB -> Ptr AES -> IO ba
doEnc Ptr AESOCB
ocbStPtr Ptr AES
aesPtr =
            Int -> (Ptr Any -> IO ()) -> IO ba
forall ba p. ByteArray ba => Int -> (Ptr p -> IO ()) -> IO ba
B.alloc Int
len ((Ptr Any -> IO ()) -> IO ba) -> (Ptr Any -> IO ()) -> IO ba
forall a b. (a -> b) -> a -> b
$ \Ptr Any
o ->
            ba -> (CString -> IO ()) -> IO ()
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
forall p a. ba -> (Ptr p -> IO a) -> IO a
withByteArray ba
input ((CString -> IO ()) -> IO ()) -> (CString -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \CString
i ->
            CString -> Ptr AESOCB -> Ptr AES -> CString -> CUInt -> IO ()
c_aes_ocb_encrypt (Ptr Any -> CString
forall a b. Ptr a -> Ptr b
castPtr Ptr Any
o) Ptr AESOCB
ocbStPtr Ptr AES
aesPtr CString
i (Int -> CUInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
len)

-- | append data to decrypt and append to the OCB context
--
-- the bytearray needs to be a multiple of the AES block size, unless it's the last call to this function.
-- need to happen after AAD appending, or after initialization if no AAD data.
{-# NOINLINE ocbAppendDecrypt #-}
ocbAppendDecrypt :: ByteArray ba => AES -> AESOCB -> ba -> (ba, AESOCB)
ocbAppendDecrypt :: forall ba. ByteArray ba => AES -> AESOCB -> ba -> (ba, AESOCB)
ocbAppendDecrypt AES
ctx AESOCB
ocb ba
input = IO (ba, AESOCB) -> (ba, AESOCB)
forall a. IO a -> a
unsafeDoIO (IO (ba, AESOCB) -> (ba, AESOCB))
-> IO (ba, AESOCB) -> (ba, AESOCB)
forall a b. (a -> b) -> a -> b
$ AES
-> AESOCB -> (Ptr AESOCB -> Ptr AES -> IO ba) -> IO (ba, AESOCB)
forall a.
AES -> AESOCB -> (Ptr AESOCB -> Ptr AES -> IO a) -> IO (a, AESOCB)
withOCBKeyAndCopySt AES
ctx AESOCB
ocb Ptr AESOCB -> Ptr AES -> IO ba
forall {ba}. ByteArray ba => Ptr AESOCB -> Ptr AES -> IO ba
doDec
  where len :: Int
len = ba -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length ba
input
        doDec :: Ptr AESOCB -> Ptr AES -> IO ba
doDec Ptr AESOCB
ocbStPtr Ptr AES
aesPtr =
            Int -> (Ptr Any -> IO ()) -> IO ba
forall ba p. ByteArray ba => Int -> (Ptr p -> IO ()) -> IO ba
B.alloc Int
len ((Ptr Any -> IO ()) -> IO ba) -> (Ptr Any -> IO ()) -> IO ba
forall a b. (a -> b) -> a -> b
$ \Ptr Any
o ->
            ba -> (CString -> IO ()) -> IO ()
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
forall p a. ba -> (Ptr p -> IO a) -> IO a
withByteArray ba
input ((CString -> IO ()) -> IO ()) -> (CString -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \CString
i ->
            CString -> Ptr AESOCB -> Ptr AES -> CString -> CUInt -> IO ()
c_aes_ocb_decrypt (Ptr Any -> CString
forall a b. Ptr a -> Ptr b
castPtr Ptr Any
o) Ptr AESOCB
ocbStPtr Ptr AES
aesPtr CString
i (Int -> CUInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
len)

-- | Generate the Tag from OCB context
{-# NOINLINE ocbFinish #-}
ocbFinish :: AES -> AESOCB -> Int -> AuthTag
ocbFinish :: AES -> AESOCB -> Int -> AuthTag
ocbFinish AES
ctx AESOCB
ocb Int
taglen = Bytes -> AuthTag
AuthTag (Bytes -> AuthTag) -> Bytes -> AuthTag
forall a b. (a -> b) -> a -> b
$ Int -> Bytes -> Bytes
forall bs. ByteArray bs => Int -> bs -> bs
B.take Int
taglen Bytes
computeTag
  where computeTag :: Bytes
computeTag = Int -> (Ptr Any -> IO ()) -> Bytes
forall a p. ByteArray a => Int -> (Ptr p -> IO ()) -> a
B.allocAndFreeze Int
16 ((Ptr Any -> IO ()) -> Bytes) -> (Ptr Any -> IO ()) -> Bytes
forall a b. (a -> b) -> a -> b
$ \Ptr Any
t ->
                        AES
-> AESOCB -> (Ptr AESOCB -> Ptr AES -> IO ()) -> IO ((), AESOCB)
forall a.
AES -> AESOCB -> (Ptr AESOCB -> Ptr AES -> IO a) -> IO (a, AESOCB)
withOCBKeyAndCopySt AES
ctx AESOCB
ocb (CString -> Ptr AESOCB -> Ptr AES -> IO ()
c_aes_ocb_finish (Ptr Any -> CString
forall a b. Ptr a -> Ptr b
castPtr Ptr Any
t)) IO ((), AESOCB) -> IO () -> IO ()
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()

ccmGetM :: CCM_M -> Int
ccmGetL :: CCM_L -> Int
ccmGetM :: CCM_M -> Int
ccmGetM CCM_M
m = case CCM_M
m of
  CCM_M
CCM_M4 -> Int
4
  CCM_M
CCM_M6 -> Int
6
  CCM_M
CCM_M8 -> Int
8
  CCM_M
CCM_M10 -> Int
10
  CCM_M
CCM_M12 -> Int
12
  CCM_M
CCM_M14 -> Int
14
  CCM_M
CCM_M16 -> Int
16

ccmGetL :: CCM_L -> Int
ccmGetL CCM_L
l = case CCM_L
l of
  CCM_L
CCM_L2 -> Int
2
  CCM_L
CCM_L3 -> Int
3
  CCM_L
CCM_L4 -> Int
4

-- | initialize a ccm context
{-# NOINLINE ccmInit #-}
ccmInit :: ByteArrayAccess iv => AES -> iv -> Int -> CCM_M -> CCM_L -> CryptoFailable AESCCM
ccmInit :: forall iv.
ByteArrayAccess iv =>
AES -> iv -> Int -> CCM_M -> CCM_L -> CryptoFailable AESCCM
ccmInit AES
ctx iv
iv Int
n CCM_M
m CCM_L
l
    | Int
15 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
li Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= iv -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length iv
iv = CryptoError -> CryptoFailable AESCCM
forall a. CryptoError -> CryptoFailable a
CryptoFailed CryptoError
CryptoError_IvSizeInvalid
    | Bool
otherwise = IO (CryptoFailable AESCCM) -> CryptoFailable AESCCM
forall a. IO a -> a
unsafeDoIO (IO (CryptoFailable AESCCM) -> CryptoFailable AESCCM)
-> IO (CryptoFailable AESCCM) -> CryptoFailable AESCCM
forall a b. (a -> b) -> a -> b
$ do
          ScrubbedBytes
sm <- Int -> (Ptr Any -> IO ()) -> IO ScrubbedBytes
forall ba p. ByteArray ba => Int -> (Ptr p -> IO ()) -> IO ba
B.alloc Int
sizeCCM ((Ptr Any -> IO ()) -> IO ScrubbedBytes)
-> (Ptr Any -> IO ()) -> IO ScrubbedBytes
forall a b. (a -> b) -> a -> b
$ \Ptr Any
ccmStPtr ->
            AES -> iv -> (Ptr AES -> Ptr Word8 -> IO ()) -> IO ()
forall iv a.
ByteArrayAccess iv =>
AES -> iv -> (Ptr AES -> Ptr Word8 -> IO a) -> IO a
withKeyAndIV AES
ctx iv
iv ((Ptr AES -> Ptr Word8 -> IO ()) -> IO ())
-> (Ptr AES -> Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr AES
k Ptr Word8
v ->
            Ptr AESCCM
-> Ptr AES -> Ptr Word8 -> CUInt -> CUInt -> CInt -> CInt -> IO ()
c_aes_ccm_init (Ptr Any -> Ptr AESCCM
forall a b. Ptr a -> Ptr b
castPtr Ptr Any
ccmStPtr) Ptr AES
k Ptr Word8
v (Int -> CUInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> CUInt) -> Int -> CUInt
forall a b. (a -> b) -> a -> b
$ iv -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length iv
iv) (Int -> CUInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n) (Int -> CInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
mi) (Int -> CInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
li)
          CryptoFailable AESCCM -> IO (CryptoFailable AESCCM)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (CryptoFailable AESCCM -> IO (CryptoFailable AESCCM))
-> CryptoFailable AESCCM -> IO (CryptoFailable AESCCM)
forall a b. (a -> b) -> a -> b
$ AESCCM -> CryptoFailable AESCCM
forall a. a -> CryptoFailable a
CryptoPassed (ScrubbedBytes -> AESCCM
AESCCM ScrubbedBytes
sm)
  where
    mi :: Int
mi = CCM_M -> Int
ccmGetM CCM_M
m
    li :: Int
li = CCM_L -> Int
ccmGetL CCM_L
l

-- | append data which is only going to be authenticated to the CCM context.
--
-- needs to happen after initialization and before appending encryption/decryption data.
{-# NOINLINE ccmAppendAAD #-}
ccmAppendAAD :: ByteArrayAccess aad => AES -> AESCCM -> aad -> AESCCM
ccmAppendAAD :: forall aad. ByteArrayAccess aad => AES -> AESCCM -> aad -> AESCCM
ccmAppendAAD AES
ctx AESCCM
ccm aad
input = IO AESCCM -> AESCCM
forall a. IO a -> a
unsafeDoIO (IO AESCCM -> AESCCM) -> IO AESCCM -> AESCCM
forall a b. (a -> b) -> a -> b
$ ((), AESCCM) -> AESCCM
forall a b. (a, b) -> b
snd (((), AESCCM) -> AESCCM) -> IO ((), AESCCM) -> IO AESCCM
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> AES
-> AESCCM -> (Ptr AESCCM -> Ptr AES -> IO ()) -> IO ((), AESCCM)
forall a.
AES -> AESCCM -> (Ptr AESCCM -> Ptr AES -> IO a) -> IO (a, AESCCM)
withCCMKeyAndCopySt AES
ctx AESCCM
ccm Ptr AESCCM -> Ptr AES -> IO ()
doAppend
  where doAppend :: Ptr AESCCM -> Ptr AES -> IO ()
doAppend Ptr AESCCM
ccmStPtr Ptr AES
aesPtr =
            aad -> (CString -> IO ()) -> IO ()
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
forall p a. aad -> (Ptr p -> IO a) -> IO a
withByteArray aad
input ((CString -> IO ()) -> IO ()) -> (CString -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \CString
i -> Ptr AESCCM -> Ptr AES -> CString -> CUInt -> IO ()
c_aes_ccm_aad Ptr AESCCM
ccmStPtr Ptr AES
aesPtr CString
i (Int -> CUInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> CUInt) -> Int -> CUInt
forall a b. (a -> b) -> a -> b
$ aad -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length aad
input)

-- | append data to encrypt and append to the CCM context
--
-- the bytearray needs to be a multiple of AES block size, unless it's the last call to this function.
-- needs to happen after AAD appending, or after initialization if no AAD data.
{-# NOINLINE ccmEncrypt #-}
ccmEncrypt :: ByteArray ba => AES -> AESCCM -> ba -> (ba, AESCCM)
ccmEncrypt :: forall ba. ByteArray ba => AES -> AESCCM -> ba -> (ba, AESCCM)
ccmEncrypt AES
ctx AESCCM
ccm ba
input = IO (ba, AESCCM) -> (ba, AESCCM)
forall a. IO a -> a
unsafeDoIO (IO (ba, AESCCM) -> (ba, AESCCM))
-> IO (ba, AESCCM) -> (ba, AESCCM)
forall a b. (a -> b) -> a -> b
$ AES
-> AESCCM -> (Ptr AESCCM -> Ptr AES -> IO ba) -> IO (ba, AESCCM)
forall a.
AES -> AESCCM -> (Ptr AESCCM -> Ptr AES -> IO a) -> IO (a, AESCCM)
withCCMKeyAndCopySt AES
ctx AESCCM
ccm Ptr AESCCM -> Ptr AES -> IO ba
forall {ba}. ByteArray ba => Ptr AESCCM -> Ptr AES -> IO ba
cbcmacAndIv
  where len :: Int
len = ba -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length ba
input
        cbcmacAndIv :: Ptr AESCCM -> Ptr AES -> IO ba
cbcmacAndIv Ptr AESCCM
ccmStPtr Ptr AES
aesPtr =
            Int -> (Ptr Any -> IO ()) -> IO ba
forall ba p. ByteArray ba => Int -> (Ptr p -> IO ()) -> IO ba
B.alloc Int
len ((Ptr Any -> IO ()) -> IO ba) -> (Ptr Any -> IO ()) -> IO ba
forall a b. (a -> b) -> a -> b
$ \Ptr Any
o ->
            ba -> (CString -> IO ()) -> IO ()
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
forall p a. ba -> (Ptr p -> IO a) -> IO a
withByteArray ba
input ((CString -> IO ()) -> IO ()) -> (CString -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \CString
i ->
            CString -> Ptr AESCCM -> Ptr AES -> CString -> CUInt -> IO ()
c_aes_ccm_encrypt (Ptr Any -> CString
forall a b. Ptr a -> Ptr b
castPtr Ptr Any
o) Ptr AESCCM
ccmStPtr Ptr AES
aesPtr CString
i (Int -> CUInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
len)

-- | append data to decrypt and append to the CCM context
--
-- the bytearray needs to be a multiple of AES block size, unless it's the last call to this function.
-- needs to happen after AAD appending, or after initialization if no AAD data.
{-# NOINLINE ccmDecrypt #-}
ccmDecrypt :: ByteArray ba => AES -> AESCCM -> ba -> (ba, AESCCM)
ccmDecrypt :: forall ba. ByteArray ba => AES -> AESCCM -> ba -> (ba, AESCCM)
ccmDecrypt AES
ctx AESCCM
ccm ba
input = IO (ba, AESCCM) -> (ba, AESCCM)
forall a. IO a -> a
unsafeDoIO (IO (ba, AESCCM) -> (ba, AESCCM))
-> IO (ba, AESCCM) -> (ba, AESCCM)
forall a b. (a -> b) -> a -> b
$ AES
-> AESCCM -> (Ptr AESCCM -> Ptr AES -> IO ba) -> IO (ba, AESCCM)
forall a.
AES -> AESCCM -> (Ptr AESCCM -> Ptr AES -> IO a) -> IO (a, AESCCM)
withCCMKeyAndCopySt AES
ctx AESCCM
ccm Ptr AESCCM -> Ptr AES -> IO ba
forall {ba}. ByteArray ba => Ptr AESCCM -> Ptr AES -> IO ba
cbcmacAndIv
  where len :: Int
len = ba -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length ba
input
        cbcmacAndIv :: Ptr AESCCM -> Ptr AES -> IO ba
cbcmacAndIv Ptr AESCCM
ccmStPtr Ptr AES
aesPtr =
            Int -> (Ptr Any -> IO ()) -> IO ba
forall ba p. ByteArray ba => Int -> (Ptr p -> IO ()) -> IO ba
B.alloc Int
len ((Ptr Any -> IO ()) -> IO ba) -> (Ptr Any -> IO ()) -> IO ba
forall a b. (a -> b) -> a -> b
$ \Ptr Any
o ->
            ba -> (CString -> IO ()) -> IO ()
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
forall p a. ba -> (Ptr p -> IO a) -> IO a
withByteArray ba
input ((CString -> IO ()) -> IO ()) -> (CString -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \CString
i ->
            CString -> Ptr AESCCM -> Ptr AES -> CString -> CUInt -> IO ()
c_aes_ccm_decrypt (Ptr Any -> CString
forall a b. Ptr a -> Ptr b
castPtr Ptr Any
o) Ptr AESCCM
ccmStPtr Ptr AES
aesPtr CString
i (Int -> CUInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
len)

-- | Generate the Tag from CCM context
{-# NOINLINE ccmFinish #-}
ccmFinish :: AES -> AESCCM -> Int -> AuthTag
ccmFinish :: AES -> AESCCM -> Int -> AuthTag
ccmFinish AES
ctx AESCCM
ccm Int
taglen = Bytes -> AuthTag
AuthTag (Bytes -> AuthTag) -> Bytes -> AuthTag
forall a b. (a -> b) -> a -> b
$ Int -> Bytes -> Bytes
forall bs. ByteArray bs => Int -> bs -> bs
B.take Int
taglen Bytes
computeTag
  where computeTag :: Bytes
computeTag = Int -> (Ptr Any -> IO ()) -> Bytes
forall a p. ByteArray a => Int -> (Ptr p -> IO ()) -> a
B.allocAndFreeze Int
16 ((Ptr Any -> IO ()) -> Bytes) -> (Ptr Any -> IO ()) -> Bytes
forall a b. (a -> b) -> a -> b
$ \Ptr Any
t ->
                        AES
-> AESCCM -> (Ptr AESCCM -> Ptr AES -> IO ()) -> IO ((), AESCCM)
forall a.
AES -> AESCCM -> (Ptr AESCCM -> Ptr AES -> IO a) -> IO (a, AESCCM)
withCCMKeyAndCopySt AES
ctx AESCCM
ccm (CString -> Ptr AESCCM -> Ptr AES -> IO ()
c_aes_ccm_finish (Ptr Any -> CString
forall a b. Ptr a -> Ptr b
castPtr Ptr Any
t)) IO ((), AESCCM) -> IO () -> IO ()
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()

------------------------------------------------------------------------
foreign import ccall "cryptonite_aes.h cryptonite_aes_initkey"
    c_aes_init :: Ptr AES -> CString -> CUInt -> IO ()

foreign import ccall "cryptonite_aes.h cryptonite_aes_encrypt_ecb"
    c_aes_encrypt_ecb :: CString -> Ptr AES -> CString -> CUInt -> IO ()

foreign import ccall "cryptonite_aes.h cryptonite_aes_decrypt_ecb"
    c_aes_decrypt_ecb :: CString -> Ptr AES -> CString -> CUInt -> IO ()

foreign import ccall "cryptonite_aes.h cryptonite_aes_encrypt_cbc"
    c_aes_encrypt_cbc :: CString -> Ptr AES -> Ptr Word8 -> CString -> CUInt -> IO ()

foreign import ccall "cryptonite_aes.h cryptonite_aes_decrypt_cbc"
    c_aes_decrypt_cbc :: CString -> Ptr AES -> Ptr Word8 -> CString -> CUInt -> IO ()

foreign import ccall "cryptonite_aes.h cryptonite_aes_encrypt_xts"
    c_aes_encrypt_xts :: CString -> Ptr AES -> Ptr AES -> Ptr Word8 -> CUInt -> CString -> CUInt -> IO ()

foreign import ccall "cryptonite_aes.h cryptonite_aes_decrypt_xts"
    c_aes_decrypt_xts :: CString -> Ptr AES -> Ptr AES -> Ptr Word8 -> CUInt -> CString -> CUInt -> IO ()

foreign import ccall "cryptonite_aes.h cryptonite_aes_gen_ctr"
    c_aes_gen_ctr :: CString -> Ptr AES -> Ptr Word8 -> CUInt -> IO ()

foreign import ccall unsafe "cryptonite_aes.h cryptonite_aes_gen_ctr_cont"
    c_aes_gen_ctr_cont :: CString -> Ptr AES -> Ptr Word8 -> CUInt -> IO ()

foreign import ccall "cryptonite_aes.h cryptonite_aes_encrypt_ctr"
    c_aes_encrypt_ctr :: CString -> Ptr AES -> Ptr Word8 -> CString -> CUInt -> IO ()

foreign import ccall "cryptonite_aes.h cryptonite_aes_encrypt_c32"
    c_aes_encrypt_c32 :: CString -> Ptr AES -> Ptr Word8 -> CString -> CUInt -> IO ()

foreign import ccall "cryptonite_aes.h cryptonite_aes_gcm_init"
    c_aes_gcm_init :: Ptr AESGCM -> Ptr AES -> Ptr Word8 -> CUInt -> IO ()

foreign import ccall "cryptonite_aes.h cryptonite_aes_gcm_aad"
    c_aes_gcm_aad :: Ptr AESGCM -> CString -> CUInt -> IO ()

foreign import ccall "cryptonite_aes.h cryptonite_aes_gcm_encrypt"
    c_aes_gcm_encrypt :: CString -> Ptr AESGCM -> Ptr AES -> CString -> CUInt -> IO ()

foreign import ccall "cryptonite_aes.h cryptonite_aes_gcm_decrypt"
    c_aes_gcm_decrypt :: CString -> Ptr AESGCM -> Ptr AES -> CString -> CUInt -> IO ()

foreign import ccall "cryptonite_aes.h cryptonite_aes_gcm_finish"
    c_aes_gcm_finish :: CString -> Ptr AESGCM -> Ptr AES -> IO ()

foreign import ccall "cryptonite_aes.h cryptonite_aes_ocb_init"
    c_aes_ocb_init :: Ptr AESOCB -> Ptr AES -> Ptr Word8 -> CUInt -> IO ()

foreign import ccall "cryptonite_aes.h cryptonite_aes_ocb_aad"
    c_aes_ocb_aad :: Ptr AESOCB -> Ptr AES -> CString -> CUInt -> IO ()

foreign import ccall "cryptonite_aes.h cryptonite_aes_ocb_encrypt"
    c_aes_ocb_encrypt :: CString -> Ptr AESOCB -> Ptr AES -> CString -> CUInt -> IO ()

foreign import ccall "cryptonite_aes.h cryptonite_aes_ocb_decrypt"
    c_aes_ocb_decrypt :: CString -> Ptr AESOCB -> Ptr AES -> CString -> CUInt -> IO ()

foreign import ccall "cryptonite_aes.h cryptonite_aes_ocb_finish"
    c_aes_ocb_finish :: CString -> Ptr AESOCB -> Ptr AES -> IO ()

foreign import ccall "cryptonite_aes.h cryptonite_aes_ccm_init"
    c_aes_ccm_init :: Ptr AESCCM -> Ptr AES -> Ptr Word8 -> CUInt -> CUInt -> CInt -> CInt -> IO ()

foreign import ccall "cryptonite_aes.h cryptonite_aes_ccm_aad"
    c_aes_ccm_aad :: Ptr AESCCM -> Ptr AES -> CString -> CUInt -> IO ()

foreign import ccall "cryptonite_aes.h cryptonite_aes_ccm_encrypt"
    c_aes_ccm_encrypt :: CString -> Ptr AESCCM -> Ptr AES -> CString -> CUInt -> IO ()

foreign import ccall "cryptonite_aes.h cryptonite_aes_ccm_decrypt"
    c_aes_ccm_decrypt :: CString -> Ptr AESCCM -> Ptr AES -> CString -> CUInt -> IO ()

foreign import ccall "cryptonite_aes.h cryptonite_aes_ccm_finish"
    c_aes_ccm_finish :: CString -> Ptr AESCCM -> Ptr AES -> IO ()