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

    -- * IV
    , AESIV
    , aesIV_

    -- * Authenticated encryption block cipher types
    , AESGCM

    -- * creation
    , initAES
    , initKey

    -- * misc
    , genCTR
    , genCounter

    -- * encryption
    , encryptECB
    , encryptCBC
    , encryptCTR
    , encryptXTS
    , encryptGCM
    , encryptOCB

    -- * decryption
    , decryptECB
    , decryptCBC
    , decryptCTR
    , decryptXTS
    , decryptGCM
    , decryptOCB
    ) where

import Data.Word
import Foreign.Ptr
import Foreign.ForeignPtr
import Foreign.C.Types
import Foreign.C.String
import Data.ByteString.Internal
import Data.ByteString.Unsafe
import Data.Byteable
import qualified Data.ByteString as B
import qualified Data.ByteString.Internal as B (ByteString(PS), mallocByteString, memcpy)
import System.IO.Unsafe (unsafePerformIO)

import Crypto.Cipher.Types
import Data.SecureMem

-- | AES Context (pre-processed key)
newtype AES = AES SecureMem

-- | AES with 128 bit key
newtype AES128 = AES128 AES

-- | AES with 192 bit key
newtype AES192 = AES192 AES

-- | AES with 256 bit key
newtype AES256 = AES256 AES

-- | AES IV is always 16 bytes
newtype AESIV = AESIV ByteString
    deriving (Int -> AESIV -> ShowS
[AESIV] -> ShowS
AESIV -> String
(Int -> AESIV -> ShowS)
-> (AESIV -> String) -> ([AESIV] -> ShowS) -> Show AESIV
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> AESIV -> ShowS
showsPrec :: Int -> AESIV -> ShowS
$cshow :: AESIV -> String
show :: AESIV -> String
$cshowList :: [AESIV] -> ShowS
showList :: [AESIV] -> ShowS
Show,AESIV -> AESIV -> Bool
(AESIV -> AESIV -> Bool) -> (AESIV -> AESIV -> Bool) -> Eq AESIV
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: AESIV -> AESIV -> Bool
== :: AESIV -> AESIV -> Bool
$c/= :: AESIV -> AESIV -> Bool
/= :: AESIV -> AESIV -> Bool
Eq,AESIV -> Int
AESIV -> ByteString
(AESIV -> ByteString)
-> (AESIV -> Int)
-> (forall b. AESIV -> (Ptr Word8 -> IO b) -> IO b)
-> Byteable AESIV
forall b. AESIV -> (Ptr Word8 -> IO b) -> IO b
forall a.
(a -> ByteString)
-> (a -> Int)
-> (forall b. a -> (Ptr Word8 -> IO b) -> IO b)
-> Byteable a
$ctoBytes :: AESIV -> ByteString
toBytes :: AESIV -> ByteString
$cbyteableLength :: AESIV -> Int
byteableLength :: AESIV -> Int
$cwithBytePtr :: forall b. AESIV -> (Ptr Word8 -> IO b) -> IO b
withBytePtr :: forall b. AESIV -> (Ptr Word8 -> IO b) -> IO b
Byteable)

-- | convert a bytestring to an AESIV
aesIV_ :: ByteString -> AESIV
aesIV_ :: ByteString -> AESIV
aesIV_ ByteString
iv
    | ByteString -> Int
B.length ByteString
iv Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
16 = String -> AESIV
forall a. HasCallStack => String -> a
error (String -> AESIV) -> String -> AESIV
forall a b. (a -> b) -> a -> b
$ String
"AES error: IV length must be block size (16). Its length is: " String -> ShowS
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
$ ByteString -> Int
B.length ByteString
iv)
    | Bool
otherwise         = ByteString -> AESIV
AESIV ByteString
iv

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 :: Key AES -> AES
cipherInit Key AES
k    = Key AES -> AES
forall b. Byteable b => b -> AES
initAES Key AES
k

instance Cipher AES128 where
    cipherName :: AES128 -> String
cipherName    AES128
_ = String
"AES128"
    cipherKeySize :: AES128 -> KeySizeSpecifier
cipherKeySize AES128
_ = Int -> KeySizeSpecifier
KeySizeFixed Int
16
    cipherInit :: Key AES128 -> AES128
cipherInit Key AES128
k    = AES -> AES128
AES128 (AES -> AES128) -> AES -> AES128
forall a b. (a -> b) -> a -> b
$ Key AES128 -> AES
forall b. Byteable b => b -> AES
initAES Key AES128
k

instance Cipher AES192 where
    cipherName :: AES192 -> String
cipherName    AES192
_ = String
"AES192"
    cipherKeySize :: AES192 -> KeySizeSpecifier
cipherKeySize AES192
_ = Int -> KeySizeSpecifier
KeySizeFixed Int
24
    cipherInit :: Key AES192 -> AES192
cipherInit Key AES192
k    = AES -> AES192
AES192 (AES -> AES192) -> AES -> AES192
forall a b. (a -> b) -> a -> b
$ Key AES192 -> AES
forall b. Byteable b => b -> AES
initAES Key AES192
k

instance Cipher AES256 where
    cipherName :: AES256 -> String
cipherName    AES256
_ = String
"AES256"
    cipherKeySize :: AES256 -> KeySizeSpecifier
cipherKeySize AES256
_ = Int -> KeySizeSpecifier
KeySizeFixed Int
32
    cipherInit :: Key AES256 -> AES256
cipherInit Key AES256
k    = AES -> AES256
AES256 (AES -> AES256) -> AES -> AES256
forall a b. (a -> b) -> a -> b
$ Key AES256 -> AES
forall b. Byteable b => b -> AES
initAES Key AES256
k

instance BlockCipher AES where
    blockSize :: AES -> Int
blockSize AES
_ = Int
16
    ecbEncrypt :: AES -> ByteString -> ByteString
ecbEncrypt = AES -> ByteString -> ByteString
encryptECB
    ecbDecrypt :: AES -> ByteString -> ByteString
ecbDecrypt = AES -> ByteString -> ByteString
decryptECB
    cbcEncrypt :: AES -> IV AES -> ByteString -> ByteString
cbcEncrypt = AES -> IV AES -> ByteString -> ByteString
forall iv. Byteable iv => AES -> iv -> ByteString -> ByteString
encryptCBC
    cbcDecrypt :: AES -> IV AES -> ByteString -> ByteString
cbcDecrypt = AES -> IV AES -> ByteString -> ByteString
forall iv. Byteable iv => AES -> iv -> ByteString -> ByteString
decryptCBC
    ctrCombine :: AES -> IV AES -> ByteString -> ByteString
ctrCombine = AES -> IV AES -> ByteString -> ByteString
forall iv. Byteable iv => AES -> iv -> ByteString -> ByteString
encryptCTR
    xtsEncrypt :: (AES, AES) -> IV AES -> DataUnitOffset -> ByteString -> ByteString
xtsEncrypt = (AES, AES) -> IV AES -> DataUnitOffset -> ByteString -> ByteString
forall iv.
Byteable iv =>
(AES, AES) -> iv -> DataUnitOffset -> ByteString -> ByteString
encryptXTS
    xtsDecrypt :: (AES, AES) -> IV AES -> DataUnitOffset -> ByteString -> ByteString
xtsDecrypt = (AES, AES) -> IV AES -> DataUnitOffset -> ByteString -> ByteString
forall iv.
Byteable iv =>
(AES, AES) -> iv -> DataUnitOffset -> ByteString -> ByteString
decryptXTS
    aeadInit :: forall iv. Byteable iv => AEADMode -> AES -> iv -> Maybe (AEAD AES)
aeadInit AEADMode
AEAD_GCM AES
aes iv
iv = AEAD AES -> Maybe (AEAD AES)
forall a. a -> Maybe a
Just (AEAD AES -> Maybe (AEAD AES)) -> AEAD AES -> Maybe (AEAD AES)
forall a b. (a -> b) -> a -> b
$ AES -> AEADState AES -> AEAD AES
forall cipher. cipher -> AEADState cipher -> AEAD cipher
AEAD AES
aes (AEADState AES -> AEAD AES) -> AEADState AES -> AEAD AES
forall a b. (a -> b) -> a -> b
$ AESGCM -> AEADState AES
forall cipher st. AEADModeImpl cipher st => st -> AEADState cipher
AEADState (AESGCM -> AEADState AES) -> AESGCM -> AEADState AES
forall a b. (a -> b) -> a -> b
$ AES -> iv -> AESGCM
forall iv. Byteable iv => AES -> iv -> AESGCM
gcmInit AES
aes iv
iv
    aeadInit AEADMode
AEAD_OCB AES
aes iv
iv = AEAD AES -> Maybe (AEAD AES)
forall a. a -> Maybe a
Just (AEAD AES -> Maybe (AEAD AES)) -> AEAD AES -> Maybe (AEAD AES)
forall a b. (a -> b) -> a -> b
$ AES -> AEADState AES -> AEAD AES
forall cipher. cipher -> AEADState cipher -> AEAD cipher
AEAD AES
aes (AEADState AES -> AEAD AES) -> AEADState AES -> AEAD AES
forall a b. (a -> b) -> a -> b
$ AESOCB -> AEADState AES
forall cipher st. AEADModeImpl cipher st => st -> AEADState cipher
AEADState (AESOCB -> AEADState AES) -> AESOCB -> AEADState AES
forall a b. (a -> b) -> a -> b
$ AES -> iv -> AESOCB
forall iv. Byteable iv => AES -> iv -> AESOCB
ocbInit AES
aes iv
iv
    aeadInit AEADMode
_        AES
_    iv
_ = Maybe (AEAD AES)
forall a. Maybe a
Nothing

instance AEADModeImpl AES AESGCM where
    aeadStateAppendHeader :: AES -> AESGCM -> ByteString -> AESGCM
aeadStateAppendHeader AES
_ = AESGCM -> ByteString -> AESGCM
gcmAppendAAD
    aeadStateEncrypt :: AES -> AESGCM -> ByteString -> (ByteString, AESGCM)
aeadStateEncrypt = AES -> AESGCM -> ByteString -> (ByteString, AESGCM)
gcmAppendEncrypt
    aeadStateDecrypt :: AES -> AESGCM -> ByteString -> (ByteString, AESGCM)
aeadStateDecrypt = AES -> AESGCM -> ByteString -> (ByteString, AESGCM)
gcmAppendDecrypt
    aeadStateFinalize :: AES -> AESGCM -> Int -> AuthTag
aeadStateFinalize = AES -> AESGCM -> Int -> AuthTag
gcmFinish

instance AEADModeImpl AES AESOCB where
    aeadStateAppendHeader :: AES -> AESOCB -> ByteString -> AESOCB
aeadStateAppendHeader = AES -> AESOCB -> ByteString -> AESOCB
ocbAppendAAD
    aeadStateEncrypt :: AES -> AESOCB -> ByteString -> (ByteString, AESOCB)
aeadStateEncrypt = AES -> AESOCB -> ByteString -> (ByteString, AESOCB)
ocbAppendEncrypt
    aeadStateDecrypt :: AES -> AESOCB -> ByteString -> (ByteString, AESOCB)
aeadStateDecrypt = AES -> AESOCB -> ByteString -> (ByteString, AESOCB)
ocbAppendDecrypt
    aeadStateFinalize :: AES -> AESOCB -> Int -> AuthTag
aeadStateFinalize = AES -> AESOCB -> Int -> AuthTag
ocbFinish

#define INSTANCE_BLOCKCIPHER(CSTR) \
instance BlockCipher CSTR where \
    { blockSize _ = 16 \
    ; ecbEncrypt (CSTR aes) = encryptECB aes \
    ; ecbDecrypt (CSTR aes) = decryptECB aes \
    ; cbcEncrypt (CSTR aes) = encryptCBC aes \
    ; cbcDecrypt (CSTR aes) = decryptCBC aes \
    ; ctrCombine (CSTR aes) = encryptCTR aes \
    ; xtsEncrypt (CSTR aes1, CSTR aes2) = encryptXTS (aes1,aes2) \
    ; xtsDecrypt (CSTR aes1, CSTR aes2) = decryptXTS (aes1,aes2) \
    ; aeadInit AEAD_GCM cipher@(CSTR aes) iv = Just $ AEAD cipher $ AEADState $ gcmInit aes iv \
    ; aeadInit AEAD_OCB cipher@(CSTR aes) iv = Just $ AEAD cipher $ AEADState $ ocbInit aes iv \
    ; aeadInit _        _                  _ = Nothing \
    }; \
\
instance AEADModeImpl CSTR AESGCM where \
    { aeadStateAppendHeader (CSTR _) gcmState bs = gcmAppendAAD gcmState bs \
    ; aeadStateEncrypt (CSTR aes) gcmState input = gcmAppendEncrypt aes gcmState input \
    ; aeadStateDecrypt (CSTR aes) gcmState input = gcmAppendDecrypt aes gcmState input \
    ; aeadStateFinalize (CSTR aes) gcmState len  = gcmFinish aes gcmState len \
    }; \
\
instance AEADModeImpl CSTR AESOCB where \
    { aeadStateAppendHeader (CSTR aes) ocbState bs = ocbAppendAAD aes ocbState bs \
    ; aeadStateEncrypt (CSTR aes) ocbState input = ocbAppendEncrypt aes ocbState input \
    ; aeadStateDecrypt (CSTR aes) ocbState input = ocbAppendDecrypt aes ocbState input \
    ; aeadStateFinalize (CSTR aes) ocbState len  = ocbFinish aes ocbState len \
    }

INSTANCE_BLOCKCIPHER(AES128)
INSTANCE_BLOCKCIPHER(AES192)
INSTANCE_BLOCKCIPHER(AES256)

-- | AESGCM State
newtype AESGCM = AESGCM SecureMem

-- | AESOCB State
newtype AESOCB = AESOCB SecureMem

sizeGCM :: Int
sizeGCM :: Int
sizeGCM = Int
80

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

keyToPtr :: AES -> (Ptr AES -> IO a) -> IO a
keyToPtr :: forall a. AES -> (Ptr AES -> IO a) -> IO a
keyToPtr (AES SecureMem
b) Ptr AES -> IO a
f = SecureMem -> (Ptr Word8 -> IO a) -> IO a
forall b. SecureMem -> (Ptr Word8 -> IO b) -> IO b
withSecureMemPtr SecureMem
b (Ptr AES -> IO a
f (Ptr AES -> IO a) -> (Ptr Word8 -> Ptr AES) -> Ptr Word8 -> IO a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Ptr Word8 -> Ptr AES
forall a b. Ptr a -> Ptr b
castPtr)

ivToPtr :: Byteable iv => iv -> (Ptr Word8 -> IO a) -> IO a
ivToPtr :: forall iv a. Byteable iv => iv -> (Ptr Word8 -> IO a) -> IO a
ivToPtr iv
iv Ptr Word8 -> IO a
f = iv -> (Ptr Word8 -> IO a) -> IO a
forall b. iv -> (Ptr Word8 -> IO b) -> IO b
forall a b. Byteable a => a -> (Ptr Word8 -> IO b) -> IO b
withBytePtr iv
iv (Ptr Word8 -> IO a
f (Ptr Word8 -> IO a)
-> (Ptr Word8 -> Ptr Word8) -> Ptr Word8 -> IO a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Ptr Word8 -> Ptr Word8
forall a b. Ptr a -> Ptr b
castPtr)

ivCopyPtr :: AESIV -> (Ptr Word8 -> IO ()) -> IO AESIV
ivCopyPtr :: AESIV -> (Ptr Word8 -> IO ()) -> IO AESIV
ivCopyPtr (AESIV ByteString
iv) Ptr Word8 -> IO ()
f = do
    ByteString
newIV <- Int -> (Ptr Word8 -> IO ()) -> IO ByteString
create Int
16 ((Ptr Word8 -> IO ()) -> IO ByteString)
-> (Ptr Word8 -> IO ()) -> IO ByteString
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
newPtr -> do
                ByteString -> (Ptr Word8 -> IO ()) -> IO ()
forall b. ByteString -> (Ptr Word8 -> IO b) -> IO b
forall a b. Byteable a => a -> (Ptr Word8 -> IO b) -> IO b
withBytePtr ByteString
iv ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
ivPtr -> Ptr Word8 -> Ptr Word8 -> Int -> IO ()
B.memcpy Ptr Word8
newPtr Ptr Word8
ivPtr Int
16
    ByteString -> (Ptr Word8 -> IO ()) -> IO ()
forall b. ByteString -> (Ptr Word8 -> IO b) -> IO b
forall a b. Byteable a => a -> (Ptr Word8 -> IO b) -> IO b
withBytePtr ByteString
newIV ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ Ptr Word8 -> IO ()
f
    AESIV -> IO AESIV
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (AESIV -> IO AESIV) -> AESIV -> IO AESIV
forall a b. (a -> b) -> a -> b
$! ByteString -> AESIV
AESIV ByteString
newIV

withKeyAndIV :: Byteable iv => AES -> iv -> (Ptr AES -> Ptr Word8 -> IO a) -> IO a
withKeyAndIV :: forall iv a.
Byteable 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. Byteable 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 :: Byteable iv => AES -> AES -> iv -> (Ptr AES -> Ptr AES -> Ptr Word8 -> IO a) -> IO a
withKey2AndIV :: forall iv a.
Byteable 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. Byteable 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 SecureMem
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
        SecureMem
newSt <- SecureMem -> IO SecureMem
secureMemCopy SecureMem
gcmSt
        a
a     <- SecureMem -> (Ptr Word8 -> IO a) -> IO a
forall b. SecureMem -> (Ptr Word8 -> IO b) -> IO b
withSecureMemPtr SecureMem
newSt ((Ptr Word8 -> IO a) -> IO a) -> (Ptr Word8 -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
gcmStPtr -> Ptr AESGCM -> Ptr AES -> IO a
f (Ptr Word8 -> Ptr AESGCM
forall a b. Ptr a -> Ptr b
castPtr Ptr Word8
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, SecureMem -> AESGCM
AESGCM SecureMem
newSt)

withNewGCMSt :: AESGCM -> (Ptr AESGCM -> IO ()) -> IO AESGCM
withNewGCMSt :: AESGCM -> (Ptr AESGCM -> IO ()) -> IO AESGCM
withNewGCMSt (AESGCM SecureMem
gcmSt) Ptr AESGCM -> IO ()
f = SecureMem -> (Ptr Word8 -> IO ()) -> IO SecureMem
withSecureMemCopy SecureMem
gcmSt (Ptr AESGCM -> IO ()
f (Ptr AESGCM -> IO ())
-> (Ptr Word8 -> Ptr AESGCM) -> Ptr Word8 -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Ptr Word8 -> Ptr AESGCM
forall a b. Ptr a -> Ptr b
castPtr) IO SecureMem -> (SecureMem -> 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
>>= \SecureMem
sm2 -> AESGCM -> IO AESGCM
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (SecureMem -> AESGCM
AESGCM SecureMem
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 SecureMem
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
        SecureMem
newSt <- SecureMem -> IO SecureMem
secureMemCopy SecureMem
gcmSt
        a
a     <- SecureMem -> (Ptr Word8 -> IO a) -> IO a
forall b. SecureMem -> (Ptr Word8 -> IO b) -> IO b
withSecureMemPtr SecureMem
newSt ((Ptr Word8 -> IO a) -> IO a) -> (Ptr Word8 -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
gcmStPtr -> Ptr AESOCB -> Ptr AES -> IO a
f (Ptr Word8 -> Ptr AESOCB
forall a b. Ptr a -> Ptr b
castPtr Ptr Word8
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, SecureMem -> AESOCB
AESOCB SecureMem
newSt)

-- | Initialize a new context with a key
--
-- Key need to be of length 16, 24 or 32 bytes. any other values will cause undefined behavior
initAES :: Byteable b => b -> AES
initAES :: forall b. Byteable b => b -> AES
initAES b
k
    | Int
len Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
16 = Int -> AES
initWithRounds Int
10
    | Int
len Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
24 = Int -> AES
initWithRounds Int
12
    | Int
len Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
32 = Int -> AES
initWithRounds Int
14
    | Bool
otherwise = String -> AES
forall a. HasCallStack => String -> a
error String
"AES: not a valid key length (valid=16,24,32)"
  where len :: Int
len = b -> Int
forall a. Byteable a => a -> Int
byteableLength b
k
        initWithRounds :: Int -> AES
initWithRounds Int
nbR = SecureMem -> AES
AES (SecureMem -> AES) -> SecureMem -> AES
forall a b. (a -> b) -> a -> b
$ Int -> (Ptr Word8 -> IO ()) -> SecureMem
unsafeCreateSecureMem (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 Word8 -> IO ()
forall {a}. Ptr a -> IO ()
aesInit
        aesInit :: Ptr a -> IO ()
aesInit Ptr a
ptr = b -> (Ptr Word8 -> IO ()) -> IO ()
forall b. b -> (Ptr Word8 -> IO b) -> IO b
forall a b. Byteable a => a -> (Ptr Word8 -> IO b) -> IO b
withBytePtr b
k ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
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 Word8 -> CString
forall a b. Ptr a -> Ptr b
castPtr Ptr Word8
ikey) (Int -> CUInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
len)

{-# DEPRECATED initKey "use initAES" #-}
initKey :: Byteable b => b -> AES
initKey :: forall b. Byteable b => b -> AES
initKey = b -> AES
forall b. Byteable b => b -> AES
initAES

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

-- | encrypt using Cipher Block Chaining (CBC)
{-# NOINLINE encryptCBC #-}
encryptCBC :: Byteable iv
           => AES        -- ^ AES Context
           -> iv         -- ^ Initial vector of AES block size
           -> ByteString -- ^ plaintext
           -> ByteString -- ^ ciphertext
encryptCBC :: forall iv. Byteable iv => AES -> iv -> ByteString -> ByteString
encryptCBC = (CString -> Ptr AES -> Ptr Word8 -> CString -> CUInt -> IO ())
-> AES -> iv -> ByteString -> ByteString
forall iv b.
Byteable iv =>
(Ptr b -> Ptr AES -> Ptr Word8 -> CString -> CUInt -> IO ())
-> AES -> iv -> ByteString -> ByteString
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 bytestring is
-- a multiple of the block cipher size.
{-# NOINLINE genCTR #-}
genCTR :: Byteable iv
       => AES -- ^ Cipher Key.
       -> iv  -- ^ usually a 128 bit integer.
       -> Int -- ^ length of bytes required.
       -> ByteString
genCTR :: forall iv. Byteable iv => AES -> iv -> Int -> ByteString
genCTR AES
ctx iv
iv Int
len
    | Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0  = ByteString
B.empty
    | iv -> Int
forall a. Byteable a => a -> Int
byteableLength iv
iv Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
16 = String -> ByteString
forall a. HasCallStack => String -> a
error (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ String
"AES error: IV length must be block size (16). Its length is: " String -> ShowS
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 -> Int
forall a. Byteable a => a -> Int
byteableLength iv
iv)
    | Bool
otherwise = Int -> (Ptr Word8 -> IO ()) -> ByteString
unsafeCreate (Int
nbBlocks Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
16) Ptr Word8 -> IO ()
forall {a}. Ptr a -> IO ()
generate
  where generate :: Ptr a -> IO ()
generate Ptr a
o = AES -> iv -> (Ptr AES -> Ptr Word8 -> IO ()) -> IO ()
forall iv a.
Byteable 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
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 bytestring is
-- a multiple of the block cipher size.
--
-- Similiar to 'genCTR' but also return the next IV for continuation
{-# NOINLINE genCounter #-}
genCounter :: AES
           -> AESIV
           -> Int
           -> (ByteString, AESIV)
genCounter :: AES -> AESIV -> Int -> (ByteString, AESIV)
genCounter AES
ctx AESIV
iv Int
len
    | Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0  = (ByteString
B.empty, AESIV
iv)
    | Bool
otherwise = IO (ByteString, AESIV) -> (ByteString, AESIV)
forall a. IO a -> a
unsafePerformIO (IO (ByteString, AESIV) -> (ByteString, AESIV))
-> IO (ByteString, AESIV) -> (ByteString, AESIV)
forall a b. (a -> b) -> a -> b
$ do
        ForeignPtr Word8
fptr  <- Int -> IO (ForeignPtr Word8)
forall a. Int -> IO (ForeignPtr a)
B.mallocByteString Int
outputLength
        AESIV
newIv <- ForeignPtr Word8 -> (Ptr Word8 -> IO AESIV) -> IO AESIV
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr Word8
fptr ((Ptr Word8 -> IO AESIV) -> IO AESIV)
-> (Ptr Word8 -> IO AESIV) -> IO AESIV
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
o ->
                    AES -> (Ptr AES -> IO AESIV) -> IO AESIV
forall a. AES -> (Ptr AES -> IO a) -> IO a
keyToPtr AES
ctx ((Ptr AES -> IO AESIV) -> IO AESIV)
-> (Ptr AES -> IO AESIV) -> IO AESIV
forall a b. (a -> b) -> a -> b
$ \Ptr AES
k ->
                    AESIV -> (Ptr Word8 -> IO ()) -> IO AESIV
ivCopyPtr AESIV
iv ((Ptr Word8 -> IO ()) -> IO AESIV)
-> (Ptr Word8 -> IO ()) -> IO AESIV
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
i -> do
                        CString -> Ptr AES -> Ptr Word8 -> CUInt -> IO ()
c_aes_gen_ctr_cont (Ptr Word8 -> CString
forall a b. Ptr a -> Ptr b
castPtr Ptr Word8
o) Ptr AES
k Ptr Word8
i (Int -> CUInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
nbBlocks)
        let !out :: ByteString
out = ForeignPtr Word8 -> Int -> Int -> ByteString
B.PS ForeignPtr Word8
fptr Int
0 Int
outputLength
        (ByteString, AESIV) -> IO (ByteString, AESIV)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ((ByteString, AESIV) -> IO (ByteString, AESIV))
-> (ByteString, AESIV) -> IO (ByteString, AESIV)
forall a b. (a -> b) -> a -> b
$! (ByteString
out ByteString -> (ByteString, AESIV) -> (ByteString, AESIV)
forall a b. a -> b -> b
`seq` AESIV
newIv AESIV -> (ByteString, AESIV) -> (ByteString, AESIV)
forall a b. a -> b -> b
`seq` (ByteString
out, AESIV
newIv))
  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 :: Byteable iv
           => AES        -- ^ AES Context
           -> iv         -- ^ initial vector of AES block size (usually representing a 128 bit integer)
           -> ByteString -- ^ plaintext input
           -> ByteString -- ^ ciphertext output
encryptCTR :: forall iv. Byteable iv => AES -> iv -> ByteString -> ByteString
encryptCTR AES
ctx iv
iv ByteString
input
    | Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0  = ByteString
B.empty
    | iv -> Int
forall a. Byteable a => a -> Int
byteableLength iv
iv Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
16 = String -> ByteString
forall a. HasCallStack => String -> a
error (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ String
"AES error: IV length must be block size (16). Its length is: " String -> ShowS
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 -> Int
forall a. Byteable a => a -> Int
byteableLength iv
iv)
    | Bool
otherwise = Int -> (Ptr Word8 -> IO ()) -> ByteString
unsafeCreate Int
len Ptr Word8 -> IO ()
forall {a}. Ptr a -> IO ()
doEncrypt
  where doEncrypt :: Ptr a -> IO ()
doEncrypt Ptr a
o = AES -> iv -> (Ptr AES -> Ptr Word8 -> IO ()) -> IO ()
forall iv a.
Byteable 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 -> ByteString -> (CString -> IO ()) -> IO ()
forall a. ByteString -> (CString -> IO a) -> IO a
unsafeUseAsCString ByteString
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 = ByteString -> Int
B.length ByteString
input

-- | encrypt using Galois counter mode (GCM)
-- return the encrypted bytestring and the tag associated
--
-- note: encrypted data is identical to CTR mode in GCM, however
-- a tag is also computed.
{-# NOINLINE encryptGCM #-}
encryptGCM :: Byteable iv
           => AES        -- ^ AES Context
           -> iv         -- ^ IV initial vector of any size
           -> ByteString -- ^ data to authenticate (AAD)
           -> ByteString -- ^ data to encrypt
           -> (ByteString, AuthTag) -- ^ ciphertext and tag
encryptGCM :: forall iv.
Byteable iv =>
AES -> iv -> ByteString -> ByteString -> (ByteString, AuthTag)
encryptGCM = (AES -> AESGCM -> ByteString -> (ByteString, AESGCM))
-> AES -> iv -> ByteString -> ByteString -> (ByteString, AuthTag)
forall iv.
Byteable iv =>
(AES -> AESGCM -> ByteString -> (ByteString, AESGCM))
-> AES -> iv -> ByteString -> ByteString -> (ByteString, AuthTag)
doGCM AES -> AESGCM -> ByteString -> (ByteString, AESGCM)
gcmAppendEncrypt

-- | encrypt using OCB v3
-- return the encrypted bytestring and the tag associated
{-# NOINLINE encryptOCB #-}
encryptOCB :: Byteable iv
           => AES        -- ^ AES Context
           -> iv         -- ^ IV initial vector of any size
           -> ByteString -- ^ data to authenticate (AAD)
           -> ByteString -- ^ data to encrypt
           -> (ByteString, AuthTag) -- ^ ciphertext and tag
encryptOCB :: forall iv.
Byteable iv =>
AES -> iv -> ByteString -> ByteString -> (ByteString, AuthTag)
encryptOCB = (AES -> AESOCB -> ByteString -> (ByteString, AESOCB))
-> AES -> iv -> ByteString -> ByteString -> (ByteString, AuthTag)
forall iv.
Byteable iv =>
(AES -> AESOCB -> ByteString -> (ByteString, AESOCB))
-> AES -> iv -> ByteString -> ByteString -> (ByteString, AuthTag)
doOCB AES -> AESOCB -> ByteString -> (ByteString, AESOCB)
ocbAppendEncrypt

-- | 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 :: Byteable iv
           => (AES,AES)  -- ^ AES cipher and tweak context
           -> iv         -- ^ 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.
           -> ByteString -- ^ input to encrypt
           -> ByteString -- ^ output encrypted
encryptXTS :: forall iv.
Byteable iv =>
(AES, AES) -> iv -> DataUnitOffset -> ByteString -> ByteString
encryptXTS = (CString
 -> Ptr AES
 -> Ptr AES
 -> Ptr Word8
 -> CUInt
 -> CString
 -> CUInt
 -> IO ())
-> (AES, AES) -> iv -> DataUnitOffset -> ByteString -> ByteString
forall iv b.
Byteable iv =>
(Ptr b
 -> Ptr AES
 -> Ptr AES
 -> Ptr Word8
 -> CUInt
 -> CString
 -> CUInt
 -> IO ())
-> (AES, AES) -> iv -> DataUnitOffset -> ByteString -> ByteString
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 :: AES -> ByteString -> ByteString
decryptECB :: AES -> ByteString -> ByteString
decryptECB = (CString -> Ptr AES -> CString -> CUInt -> IO ())
-> AES -> ByteString -> ByteString
forall b.
(Ptr b -> Ptr AES -> CString -> CUInt -> IO ())
-> AES -> ByteString -> ByteString
doECB CString -> Ptr AES -> CString -> CUInt -> IO ()
c_aes_decrypt_ecb

-- | decrypt using Cipher block chaining (CBC)
{-# NOINLINE decryptCBC #-}
decryptCBC :: Byteable iv => AES -> iv -> ByteString -> ByteString
decryptCBC :: forall iv. Byteable iv => AES -> iv -> ByteString -> ByteString
decryptCBC = (CString -> Ptr AES -> Ptr Word8 -> CString -> CUInt -> IO ())
-> AES -> iv -> ByteString -> ByteString
forall iv b.
Byteable iv =>
(Ptr b -> Ptr AES -> Ptr Word8 -> CString -> CUInt -> IO ())
-> AES -> iv -> ByteString -> ByteString
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 :: Byteable iv
           => AES        -- ^ AES Context
           -> iv         -- ^ initial vector, usually representing a 128 bit integer
           -> ByteString -- ^ ciphertext input
           -> ByteString -- ^ plaintext output
decryptCTR :: forall iv. Byteable iv => AES -> iv -> ByteString -> ByteString
decryptCTR = AES -> iv -> ByteString -> ByteString
forall iv. Byteable iv => AES -> iv -> ByteString -> ByteString
encryptCTR

-- | decrypt using XTS
{-# NOINLINE decryptXTS #-}
decryptXTS :: Byteable iv
           => (AES,AES)  -- ^ AES cipher and tweak context
           -> iv         -- ^ 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.
           -> ByteString -- ^ input to decrypt
           -> ByteString -- ^ output decrypted
decryptXTS :: forall iv.
Byteable iv =>
(AES, AES) -> iv -> DataUnitOffset -> ByteString -> ByteString
decryptXTS = (CString
 -> Ptr AES
 -> Ptr AES
 -> Ptr Word8
 -> CUInt
 -> CString
 -> CUInt
 -> IO ())
-> (AES, AES) -> iv -> DataUnitOffset -> ByteString -> ByteString
forall iv b.
Byteable iv =>
(Ptr b
 -> Ptr AES
 -> Ptr AES
 -> Ptr Word8
 -> CUInt
 -> CString
 -> CUInt
 -> IO ())
-> (AES, AES) -> iv -> DataUnitOffset -> ByteString -> ByteString
doXTS CString
-> Ptr AES
-> Ptr AES
-> Ptr Word8
-> CUInt
-> CString
-> CUInt
-> IO ()
c_aes_decrypt_xts

-- | decrypt using Galois Counter Mode (GCM)
{-# NOINLINE decryptGCM #-}
decryptGCM :: Byteable iv
           => AES        -- ^ Key
           -> iv         -- ^ IV initial vector of any size
           -> ByteString -- ^ data to authenticate (AAD)
           -> ByteString -- ^ data to decrypt
           -> (ByteString, AuthTag) -- ^ plaintext and tag
decryptGCM :: forall iv.
Byteable iv =>
AES -> iv -> ByteString -> ByteString -> (ByteString, AuthTag)
decryptGCM = (AES -> AESGCM -> ByteString -> (ByteString, AESGCM))
-> AES -> iv -> ByteString -> ByteString -> (ByteString, AuthTag)
forall iv.
Byteable iv =>
(AES -> AESGCM -> ByteString -> (ByteString, AESGCM))
-> AES -> iv -> ByteString -> ByteString -> (ByteString, AuthTag)
doGCM AES -> AESGCM -> ByteString -> (ByteString, AESGCM)
gcmAppendDecrypt

-- | decrypt using Offset Codebook Mode (OCB)
{-# NOINLINE decryptOCB #-}
decryptOCB :: Byteable iv
           => AES        -- ^ Key
           -> iv         -- ^ IV initial vector of any size
           -> ByteString -- ^ data to authenticate (AAD)
           -> ByteString -- ^ data to decrypt
           -> (ByteString, AuthTag) -- ^ plaintext and tag
decryptOCB :: forall iv.
Byteable iv =>
AES -> iv -> ByteString -> ByteString -> (ByteString, AuthTag)
decryptOCB = (AES -> AESOCB -> ByteString -> (ByteString, AESOCB))
-> AES -> iv -> ByteString -> ByteString -> (ByteString, AuthTag)
forall iv.
Byteable iv =>
(AES -> AESOCB -> ByteString -> (ByteString, AESOCB))
-> AES -> iv -> ByteString -> ByteString -> (ByteString, AuthTag)
doOCB AES -> AESOCB -> ByteString -> (ByteString, AESOCB)
ocbAppendDecrypt

{-# INLINE doECB #-}
doECB :: (Ptr b -> Ptr AES -> CString -> CUInt -> IO ())
      -> AES -> ByteString -> ByteString
doECB :: forall b.
(Ptr b -> Ptr AES -> CString -> CUInt -> IO ())
-> AES -> ByteString -> ByteString
doECB Ptr b -> Ptr AES -> CString -> CUInt -> IO ()
f AES
ctx ByteString
input
    | Int
r Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
0    = String -> ByteString
forall a. HasCallStack => String -> a
error (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ String
"Encryption error: input length must be a multiple of block size (16). Its length is: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ (Int -> String
forall a. Show a => a -> String
show Int
len)
    | Bool
otherwise = Int -> (Ptr Word8 -> IO ()) -> ByteString
unsafeCreate Int
len ((Ptr Word8 -> IO ()) -> ByteString)
-> (Ptr Word8 -> IO ()) -> ByteString
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
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 ->
                  ByteString -> (CString -> IO ()) -> IO ()
forall a. ByteString -> (CString -> IO a) -> IO a
unsafeUseAsCString ByteString
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 Word8 -> Ptr b
forall a b. Ptr a -> Ptr b
castPtr Ptr Word8
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           = (ByteString -> Int
B.length ByteString
input)

{-# INLINE doCBC #-}
doCBC :: Byteable iv
      => (Ptr b -> Ptr AES -> Ptr Word8 -> CString -> CUInt -> IO ())
      -> AES -> iv -> ByteString -> ByteString
doCBC :: forall iv b.
Byteable iv =>
(Ptr b -> Ptr AES -> Ptr Word8 -> CString -> CUInt -> IO ())
-> AES -> iv -> ByteString -> ByteString
doCBC Ptr b -> Ptr AES -> Ptr Word8 -> CString -> CUInt -> IO ()
f AES
ctx iv
iv ByteString
input
    | Int
len Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0  = ByteString
B.empty
    | iv -> Int
forall a. Byteable a => a -> Int
byteableLength iv
iv Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
16 = String -> ByteString
forall a. HasCallStack => String -> a
error (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ String
"AES error: IV length must be block size (16). Its length is: " String -> ShowS
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 -> Int
forall a. Byteable a => a -> Int
byteableLength iv
iv)
    | Int
r Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
0    = String -> ByteString
forall a. HasCallStack => String -> a
error (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ String
"Encryption error: input length must be a multiple of block size (16). Its length is: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ (Int -> String
forall a. Show a => a -> String
show Int
len)
    | Bool
otherwise = Int -> (Ptr Word8 -> IO ()) -> ByteString
unsafeCreate Int
len ((Ptr Word8 -> IO ()) -> ByteString)
-> (Ptr Word8 -> IO ()) -> ByteString
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
o ->
                  AES -> iv -> (Ptr AES -> Ptr Word8 -> IO ()) -> IO ()
forall iv a.
Byteable 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 ->
                  ByteString -> (CString -> IO ()) -> IO ()
forall a. ByteString -> (CString -> IO a) -> IO a
unsafeUseAsCString ByteString
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 Word8 -> Ptr b
forall a b. Ptr a -> Ptr b
castPtr Ptr Word8
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           = ByteString -> Int
B.length ByteString
input

{-# INLINE doXTS #-}
doXTS :: Byteable iv
      => (Ptr b -> Ptr AES -> Ptr AES -> Ptr Word8 -> CUInt -> CString -> CUInt -> IO ())
      -> (AES, AES)
      -> iv
      -> Word32
      -> ByteString
      -> ByteString
doXTS :: forall iv b.
Byteable iv =>
(Ptr b
 -> Ptr AES
 -> Ptr AES
 -> Ptr Word8
 -> CUInt
 -> CString
 -> CUInt
 -> IO ())
-> (AES, AES) -> iv -> DataUnitOffset -> ByteString -> ByteString
doXTS Ptr b
-> Ptr AES
-> Ptr AES
-> Ptr Word8
-> CUInt
-> CString
-> CUInt
-> IO ()
f (AES
key1,AES
key2) iv
iv DataUnitOffset
spoint ByteString
input
    | Int
len Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0  = ByteString
B.empty
    | Int
r Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
0    = String -> ByteString
forall a. HasCallStack => String -> a
error (String -> ByteString) -> String -> ByteString
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 -> ShowS
forall a. [a] -> [a] -> [a]
++ (Int -> String
forall a. Show a => a -> String
show Int
len)
    | Bool
otherwise = Int -> (Ptr Word8 -> IO ()) -> ByteString
unsafeCreate Int
len ((Ptr Word8 -> IO ()) -> ByteString)
-> (Ptr Word8 -> IO ()) -> ByteString
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
o -> AES
-> AES -> iv -> (Ptr AES -> Ptr AES -> Ptr Word8 -> IO ()) -> IO ()
forall iv a.
Byteable 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 ()) -> 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 -> ByteString -> (CString -> IO ()) -> IO ()
forall a. ByteString -> (CString -> IO a) -> IO a
unsafeUseAsCString ByteString
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 Word8 -> Ptr b
forall a b. Ptr a -> Ptr b
castPtr Ptr Word8
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           = ByteString -> Int
B.length ByteString
input

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

{-# INLINE doGCM #-}
doGCM :: Byteable iv
      => (AES -> AESGCM -> ByteString -> (ByteString, AESGCM))
      -> AES
      -> iv
      -> ByteString
      -> ByteString
      -> (ByteString, AuthTag)
doGCM :: forall iv.
Byteable iv =>
(AES -> AESGCM -> ByteString -> (ByteString, AESGCM))
-> AES -> iv -> ByteString -> ByteString -> (ByteString, AuthTag)
doGCM AES -> AESGCM -> ByteString -> (ByteString, AESGCM)
f AES
ctx iv
iv ByteString
aad ByteString
input = (ByteString
output, AuthTag
tag)
  where tag :: AuthTag
tag             = AES -> AESGCM -> Int -> AuthTag
gcmFinish AES
ctx AESGCM
after Int
16
        (ByteString
output, AESGCM
after) = AES -> AESGCM -> ByteString -> (ByteString, AESGCM)
f AES
ctx AESGCM
afterAAD ByteString
input
        afterAAD :: AESGCM
afterAAD        = AESGCM -> ByteString -> AESGCM
gcmAppendAAD AESGCM
ini ByteString
aad
        ini :: AESGCM
ini             = AES -> iv -> AESGCM
forall iv. Byteable iv => AES -> iv -> AESGCM
gcmInit AES
ctx iv
iv

-- | initialize a gcm context
{-# NOINLINE gcmInit #-}
gcmInit :: Byteable iv => AES -> iv -> AESGCM
gcmInit :: forall iv. Byteable iv => AES -> iv -> AESGCM
gcmInit AES
ctx iv
iv = IO AESGCM -> AESGCM
forall a. IO a -> a
unsafePerformIO (IO AESGCM -> AESGCM) -> IO AESGCM -> AESGCM
forall a b. (a -> b) -> a -> b
$ do
    SecureMem
sm <- Int -> (Ptr Word8 -> IO ()) -> IO SecureMem
createSecureMem Int
sizeGCM ((Ptr Word8 -> IO ()) -> IO SecureMem)
-> (Ptr Word8 -> IO ()) -> IO SecureMem
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
gcmStPtr ->
            AES -> iv -> (Ptr AES -> Ptr Word8 -> IO ()) -> IO ()
forall iv a.
Byteable 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 Word8 -> Ptr AESGCM
forall a b. Ptr a -> Ptr b
castPtr Ptr Word8
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 a. Byteable a => a -> Int
byteableLength 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
$ SecureMem -> AESGCM
AESGCM SecureMem
sm

-- | append data which is going to just be authentified to the GCM context.
--
-- need to happen after initialization and before appending encryption/decryption data.
{-# NOINLINE gcmAppendAAD #-}
gcmAppendAAD :: AESGCM -> ByteString -> AESGCM
gcmAppendAAD :: AESGCM -> ByteString -> AESGCM
gcmAppendAAD AESGCM
gcmSt ByteString
input = IO AESGCM -> AESGCM
forall a. IO a -> a
unsafePerformIO 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 ->
            ByteString -> (CString -> IO ()) -> IO ()
forall a. ByteString -> (CString -> IO a) -> IO a
unsafeUseAsCString ByteString
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
$ ByteString -> Int
B.length ByteString
input)

-- | append data to encrypt and append to the GCM context
--
-- bytestring need to be multiple of 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 gcmAppendEncrypt #-}
gcmAppendEncrypt :: AES -> AESGCM -> ByteString -> (ByteString, AESGCM)
gcmAppendEncrypt :: AES -> AESGCM -> ByteString -> (ByteString, AESGCM)
gcmAppendEncrypt AES
ctx AESGCM
gcm ByteString
input = IO (ByteString, AESGCM) -> (ByteString, AESGCM)
forall a. IO a -> a
unsafePerformIO (IO (ByteString, AESGCM) -> (ByteString, AESGCM))
-> IO (ByteString, AESGCM) -> (ByteString, AESGCM)
forall a b. (a -> b) -> a -> b
$ AES
-> AESGCM
-> (Ptr AESGCM -> Ptr AES -> IO ByteString)
-> IO (ByteString, AESGCM)
forall a.
AES -> AESGCM -> (Ptr AESGCM -> Ptr AES -> IO a) -> IO (a, AESGCM)
withGCMKeyAndCopySt AES
ctx AESGCM
gcm Ptr AESGCM -> Ptr AES -> IO ByteString
doEnc
  where len :: Int
len = ByteString -> Int
B.length ByteString
input
        doEnc :: Ptr AESGCM -> Ptr AES -> IO ByteString
doEnc Ptr AESGCM
gcmStPtr Ptr AES
aesPtr =
            Int -> (Ptr Word8 -> IO ()) -> IO ByteString
create Int
len ((Ptr Word8 -> IO ()) -> IO ByteString)
-> (Ptr Word8 -> IO ()) -> IO ByteString
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
o ->
            ByteString -> (CString -> IO ()) -> IO ()
forall a. ByteString -> (CString -> IO a) -> IO a
unsafeUseAsCString ByteString
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 Word8 -> CString
forall a b. Ptr a -> Ptr b
castPtr Ptr Word8
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
--
-- bytestring need to be multiple of 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 gcmAppendDecrypt #-}
gcmAppendDecrypt :: AES -> AESGCM -> ByteString -> (ByteString, AESGCM)
gcmAppendDecrypt :: AES -> AESGCM -> ByteString -> (ByteString, AESGCM)
gcmAppendDecrypt AES
ctx AESGCM
gcm ByteString
input = IO (ByteString, AESGCM) -> (ByteString, AESGCM)
forall a. IO a -> a
unsafePerformIO (IO (ByteString, AESGCM) -> (ByteString, AESGCM))
-> IO (ByteString, AESGCM) -> (ByteString, AESGCM)
forall a b. (a -> b) -> a -> b
$ AES
-> AESGCM
-> (Ptr AESGCM -> Ptr AES -> IO ByteString)
-> IO (ByteString, AESGCM)
forall a.
AES -> AESGCM -> (Ptr AESGCM -> Ptr AES -> IO a) -> IO (a, AESGCM)
withGCMKeyAndCopySt AES
ctx AESGCM
gcm Ptr AESGCM -> Ptr AES -> IO ByteString
doDec
  where len :: Int
len = ByteString -> Int
B.length ByteString
input
        doDec :: Ptr AESGCM -> Ptr AES -> IO ByteString
doDec Ptr AESGCM
gcmStPtr Ptr AES
aesPtr =
            Int -> (Ptr Word8 -> IO ()) -> IO ByteString
create Int
len ((Ptr Word8 -> IO ()) -> IO ByteString)
-> (Ptr Word8 -> IO ()) -> IO ByteString
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
o ->
            ByteString -> (CString -> IO ()) -> IO ()
forall a. ByteString -> (CString -> IO a) -> IO a
unsafeUseAsCString ByteString
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 Word8 -> CString
forall a b. Ptr a -> Ptr b
castPtr Ptr Word8
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 = ByteString -> AuthTag
AuthTag (ByteString -> AuthTag) -> ByteString -> AuthTag
forall a b. (a -> b) -> a -> b
$ Int -> ByteString -> ByteString
B.take Int
taglen ByteString
computeTag
  where computeTag :: ByteString
computeTag = Int -> (Ptr Word8 -> IO ()) -> ByteString
unsafeCreate Int
16 ((Ptr Word8 -> IO ()) -> ByteString)
-> (Ptr Word8 -> IO ()) -> ByteString
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
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 Word8 -> CString
forall a b. Ptr a -> Ptr b
castPtr Ptr Word8
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
------------------------------------------------------------------------

{-# INLINE doOCB #-}
doOCB :: Byteable iv
      => (AES -> AESOCB -> ByteString -> (ByteString, AESOCB))
      -> AES
      -> iv
      -> ByteString
      -> ByteString
      -> (ByteString, AuthTag)
doOCB :: forall iv.
Byteable iv =>
(AES -> AESOCB -> ByteString -> (ByteString, AESOCB))
-> AES -> iv -> ByteString -> ByteString -> (ByteString, AuthTag)
doOCB AES -> AESOCB -> ByteString -> (ByteString, AESOCB)
f AES
ctx iv
iv ByteString
aad ByteString
input = (ByteString
output, AuthTag
tag)
  where tag :: AuthTag
tag             = AES -> AESOCB -> Int -> AuthTag
ocbFinish AES
ctx AESOCB
after Int
16
        (ByteString
output, AESOCB
after) = AES -> AESOCB -> ByteString -> (ByteString, AESOCB)
f AES
ctx AESOCB
afterAAD ByteString
input
        afterAAD :: AESOCB
afterAAD        = AES -> AESOCB -> ByteString -> AESOCB
ocbAppendAAD AES
ctx AESOCB
ini ByteString
aad
        ini :: AESOCB
ini             = AES -> iv -> AESOCB
forall iv. Byteable iv => AES -> iv -> AESOCB
ocbInit AES
ctx iv
iv

-- | initialize an ocb context
{-# NOINLINE ocbInit #-}
ocbInit :: Byteable iv => AES -> iv -> AESOCB
ocbInit :: forall iv. Byteable iv => AES -> iv -> AESOCB
ocbInit AES
ctx iv
iv = IO AESOCB -> AESOCB
forall a. IO a -> a
unsafePerformIO (IO AESOCB -> AESOCB) -> IO AESOCB -> AESOCB
forall a b. (a -> b) -> a -> b
$ do
    SecureMem
sm <- Int -> (Ptr Word8 -> IO ()) -> IO SecureMem
createSecureMem Int
sizeOCB ((Ptr Word8 -> IO ()) -> IO SecureMem)
-> (Ptr Word8 -> IO ()) -> IO SecureMem
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
ocbStPtr ->
            AES -> iv -> (Ptr AES -> Ptr Word8 -> IO ()) -> IO ()
forall iv a.
Byteable 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 Word8 -> Ptr AESOCB
forall a b. Ptr a -> Ptr b
castPtr Ptr Word8
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 a. Byteable a => a -> Int
byteableLength 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
$ SecureMem -> AESOCB
AESOCB SecureMem
sm

-- | append data which is going to just be authentified to the OCB context.
--
-- need to happen after initialization and before appending encryption/decryption data.
{-# NOINLINE ocbAppendAAD #-}
ocbAppendAAD :: AES -> AESOCB -> ByteString -> AESOCB
ocbAppendAAD :: AES -> AESOCB -> ByteString -> AESOCB
ocbAppendAAD AES
ctx AESOCB
ocb ByteString
input = IO AESOCB -> AESOCB
forall a. IO a -> a
unsafePerformIO (((), 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 =
            ByteString -> (CString -> IO ()) -> IO ()
forall a. ByteString -> (CString -> IO a) -> IO a
unsafeUseAsCString ByteString
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
$ ByteString -> Int
B.length ByteString
input)

-- | append data to encrypt and append to the OCB context
--
-- bytestring need to be multiple of 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 :: AES -> AESOCB -> ByteString -> (ByteString, AESOCB)
ocbAppendEncrypt :: AES -> AESOCB -> ByteString -> (ByteString, AESOCB)
ocbAppendEncrypt AES
ctx AESOCB
ocb ByteString
input = IO (ByteString, AESOCB) -> (ByteString, AESOCB)
forall a. IO a -> a
unsafePerformIO (IO (ByteString, AESOCB) -> (ByteString, AESOCB))
-> IO (ByteString, AESOCB) -> (ByteString, AESOCB)
forall a b. (a -> b) -> a -> b
$ AES
-> AESOCB
-> (Ptr AESOCB -> Ptr AES -> IO ByteString)
-> IO (ByteString, AESOCB)
forall a.
AES -> AESOCB -> (Ptr AESOCB -> Ptr AES -> IO a) -> IO (a, AESOCB)
withOCBKeyAndCopySt AES
ctx AESOCB
ocb Ptr AESOCB -> Ptr AES -> IO ByteString
doEnc
  where len :: Int
len = ByteString -> Int
B.length ByteString
input
        doEnc :: Ptr AESOCB -> Ptr AES -> IO ByteString
doEnc Ptr AESOCB
ocbStPtr Ptr AES
aesPtr =
            Int -> (Ptr Word8 -> IO ()) -> IO ByteString
create Int
len ((Ptr Word8 -> IO ()) -> IO ByteString)
-> (Ptr Word8 -> IO ()) -> IO ByteString
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
o ->
            ByteString -> (CString -> IO ()) -> IO ()
forall a. ByteString -> (CString -> IO a) -> IO a
unsafeUseAsCString ByteString
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 Word8 -> CString
forall a b. Ptr a -> Ptr b
castPtr Ptr Word8
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
--
-- bytestring need to be multiple of 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 :: AES -> AESOCB -> ByteString -> (ByteString, AESOCB)
ocbAppendDecrypt :: AES -> AESOCB -> ByteString -> (ByteString, AESOCB)
ocbAppendDecrypt AES
ctx AESOCB
ocb ByteString
input = IO (ByteString, AESOCB) -> (ByteString, AESOCB)
forall a. IO a -> a
unsafePerformIO (IO (ByteString, AESOCB) -> (ByteString, AESOCB))
-> IO (ByteString, AESOCB) -> (ByteString, AESOCB)
forall a b. (a -> b) -> a -> b
$ AES
-> AESOCB
-> (Ptr AESOCB -> Ptr AES -> IO ByteString)
-> IO (ByteString, AESOCB)
forall a.
AES -> AESOCB -> (Ptr AESOCB -> Ptr AES -> IO a) -> IO (a, AESOCB)
withOCBKeyAndCopySt AES
ctx AESOCB
ocb Ptr AESOCB -> Ptr AES -> IO ByteString
doDec
  where len :: Int
len = ByteString -> Int
B.length ByteString
input
        doDec :: Ptr AESOCB -> Ptr AES -> IO ByteString
doDec Ptr AESOCB
ocbStPtr Ptr AES
aesPtr =
            Int -> (Ptr Word8 -> IO ()) -> IO ByteString
create Int
len ((Ptr Word8 -> IO ()) -> IO ByteString)
-> (Ptr Word8 -> IO ()) -> IO ByteString
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
o ->
            ByteString -> (CString -> IO ()) -> IO ()
forall a. ByteString -> (CString -> IO a) -> IO a
unsafeUseAsCString ByteString
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 Word8 -> CString
forall a b. Ptr a -> Ptr b
castPtr Ptr Word8
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 = ByteString -> AuthTag
AuthTag (ByteString -> AuthTag) -> ByteString -> AuthTag
forall a b. (a -> b) -> a -> b
$ Int -> ByteString -> ByteString
B.take Int
taglen ByteString
computeTag
  where computeTag :: ByteString
computeTag = Int -> (Ptr Word8 -> IO ()) -> ByteString
unsafeCreate Int
16 ((Ptr Word8 -> IO ()) -> ByteString)
-> (Ptr Word8 -> IO ()) -> ByteString
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
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 Word8 -> CString
forall a b. Ptr a -> Ptr b
castPtr Ptr Word8
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 ()

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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