{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Crypto.Cipher.AESGCMSIV
( Nonce
, nonce
, generateNonce
, encrypt
, decrypt
) where
import Data.Bits
import Data.Word
import Foreign.C.Types
import Foreign.C.String
import Foreign.Ptr (Ptr, plusPtr)
import Foreign.Storable (peekElemOff, poke, pokeElemOff)
import Data.ByteArray
import qualified Data.ByteArray as B
import Data.Memory.Endian (toLE)
import Data.Memory.PtrMethods (memXor)
import Crypto.Cipher.AES.Primitive
import Crypto.Cipher.Types
import Crypto.Error
import Crypto.Internal.Compat (unsafeDoIO)
import Crypto.Random
newtype Nonce = Nonce Bytes deriving (Int -> Nonce -> ShowS
[Nonce] -> ShowS
Nonce -> String
(Int -> Nonce -> ShowS)
-> (Nonce -> String) -> ([Nonce] -> ShowS) -> Show Nonce
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Nonce -> ShowS
showsPrec :: Int -> Nonce -> ShowS
$cshow :: Nonce -> String
show :: Nonce -> String
$cshowList :: [Nonce] -> ShowS
showList :: [Nonce] -> ShowS
Show, Nonce -> Nonce -> Bool
(Nonce -> Nonce -> Bool) -> (Nonce -> Nonce -> Bool) -> Eq Nonce
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Nonce -> Nonce -> Bool
== :: Nonce -> Nonce -> Bool
$c/= :: Nonce -> Nonce -> Bool
/= :: Nonce -> Nonce -> Bool
Eq, Nonce -> Int
(Nonce -> Int)
-> (forall p a. Nonce -> (Ptr p -> IO a) -> IO a)
-> (forall p. Nonce -> Ptr p -> IO ())
-> ByteArrayAccess Nonce
forall p. Nonce -> Ptr p -> IO ()
forall ba.
(ba -> Int)
-> (forall p a. ba -> (Ptr p -> IO a) -> IO a)
-> (forall p. ba -> Ptr p -> IO ())
-> ByteArrayAccess ba
forall p a. Nonce -> (Ptr p -> IO a) -> IO a
$clength :: Nonce -> Int
length :: Nonce -> Int
$cwithByteArray :: forall p a. Nonce -> (Ptr p -> IO a) -> IO a
withByteArray :: forall p a. Nonce -> (Ptr p -> IO a) -> IO a
$ccopyByteArrayToPtr :: forall p. Nonce -> Ptr p -> IO ()
copyByteArrayToPtr :: forall p. Nonce -> Ptr p -> IO ()
ByteArrayAccess)
nonce :: ByteArrayAccess iv => iv -> CryptoFailable Nonce
nonce :: forall iv. ByteArrayAccess iv => iv -> CryptoFailable Nonce
nonce iv
iv
| iv -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length iv
iv Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
12 = Nonce -> CryptoFailable Nonce
forall a. a -> CryptoFailable a
CryptoPassed (Bytes -> Nonce
Nonce (Bytes -> Nonce) -> Bytes -> Nonce
forall a b. (a -> b) -> a -> b
$ iv -> Bytes
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
B.convert iv
iv)
| Bool
otherwise = CryptoError -> CryptoFailable Nonce
forall a. CryptoError -> CryptoFailable a
CryptoFailed CryptoError
CryptoError_IvSizeInvalid
generateNonce :: MonadRandom m => m Nonce
generateNonce :: forall (m :: * -> *). MonadRandom m => m Nonce
generateNonce = Bytes -> Nonce
Nonce (Bytes -> Nonce) -> m Bytes -> m Nonce
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Int -> m Bytes
forall byteArray. ByteArray byteArray => Int -> m byteArray
forall (m :: * -> *) byteArray.
(MonadRandom m, ByteArray byteArray) =>
Int -> m byteArray
getRandomBytes Int
12
newtype Polyval = Polyval Bytes
polyvalInit :: ScrubbedBytes -> IO Polyval
polyvalInit :: ScrubbedBytes -> IO Polyval
polyvalInit ScrubbedBytes
h = Bytes -> Polyval
Polyval (Bytes -> Polyval) -> IO Bytes -> IO Polyval
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO Bytes
doInit
where doInit :: IO Bytes
doInit = Int -> (Ptr Polyval -> IO ()) -> IO Bytes
forall ba p. ByteArray ba => Int -> (Ptr p -> IO ()) -> IO ba
B.alloc Int
272 ((Ptr Polyval -> IO ()) -> IO Bytes)
-> (Ptr Polyval -> IO ()) -> IO Bytes
forall a b. (a -> b) -> a -> b
$ \Ptr Polyval
pctx -> ScrubbedBytes -> (Ptr CChar -> IO ()) -> IO ()
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
forall p a. ScrubbedBytes -> (Ptr p -> IO a) -> IO a
B.withByteArray ScrubbedBytes
h ((Ptr CChar -> IO ()) -> IO ()) -> (Ptr CChar -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr CChar
ph ->
Ptr Polyval -> Ptr CChar -> IO ()
c_aes_polyval_init Ptr Polyval
pctx Ptr CChar
ph
polyvalUpdate :: ByteArrayAccess ba => Polyval -> ba -> IO ()
polyvalUpdate :: forall ba. ByteArrayAccess ba => Polyval -> ba -> IO ()
polyvalUpdate (Polyval Bytes
ctx) ba
bs = Bytes -> (Ptr Polyval -> IO ()) -> IO ()
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
forall p a. Bytes -> (Ptr p -> IO a) -> IO a
B.withByteArray Bytes
ctx ((Ptr Polyval -> IO ()) -> IO ())
-> (Ptr Polyval -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr Polyval
pctx ->
ba -> (Ptr CChar -> 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
B.withByteArray ba
bs ((Ptr CChar -> IO ()) -> IO ()) -> (Ptr CChar -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr CChar
pbs -> Ptr Polyval -> Ptr CChar -> CUInt -> IO ()
c_aes_polyval_update Ptr Polyval
pctx Ptr CChar
pbs CUInt
sz
where sz :: CUInt
sz = Int -> CUInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral (ba -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length ba
bs)
polyvalFinalize :: Polyval -> IO ScrubbedBytes
polyvalFinalize :: Polyval -> IO ScrubbedBytes
polyvalFinalize (Polyval Bytes
ctx) = Int -> (Ptr CChar -> IO ()) -> IO ScrubbedBytes
forall ba p. ByteArray ba => Int -> (Ptr p -> IO ()) -> IO ba
B.alloc Int
16 ((Ptr CChar -> IO ()) -> IO ScrubbedBytes)
-> (Ptr CChar -> IO ()) -> IO ScrubbedBytes
forall a b. (a -> b) -> a -> b
$ \Ptr CChar
dst ->
Bytes -> (Ptr Polyval -> IO ()) -> IO ()
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
forall p a. Bytes -> (Ptr p -> IO a) -> IO a
B.withByteArray Bytes
ctx ((Ptr Polyval -> IO ()) -> IO ())
-> (Ptr Polyval -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr Polyval
pctx -> Ptr Polyval -> Ptr CChar -> IO ()
c_aes_polyval_finalize Ptr Polyval
pctx Ptr CChar
dst
foreign import ccall unsafe "cryptonite_aes.h cryptonite_aes_polyval_init"
c_aes_polyval_init :: Ptr Polyval -> CString -> IO ()
foreign import ccall "cryptonite_aes.h cryptonite_aes_polyval_update"
c_aes_polyval_update :: Ptr Polyval -> CString -> CUInt -> IO ()
foreign import ccall unsafe "cryptonite_aes.h cryptonite_aes_polyval_finalize"
c_aes_polyval_finalize :: Ptr Polyval -> CString -> IO ()
le32iv :: Word32 -> Nonce -> Bytes
le32iv :: Word32 -> Nonce -> Bytes
le32iv Word32
n (Nonce Bytes
iv) = Int -> (Ptr (LE Word32) -> IO ()) -> Bytes
forall a p. ByteArray a => Int -> (Ptr p -> IO ()) -> a
B.allocAndFreeze Int
16 ((Ptr (LE Word32) -> IO ()) -> Bytes)
-> (Ptr (LE Word32) -> IO ()) -> Bytes
forall a b. (a -> b) -> a -> b
$ \Ptr (LE Word32)
ptr -> do
Ptr (LE Word32) -> LE Word32 -> IO ()
forall a. Storable a => Ptr a -> a -> IO ()
poke Ptr (LE Word32)
ptr (Word32 -> LE Word32
forall a. ByteSwap a => a -> LE a
toLE Word32
n)
Bytes -> Ptr Any -> IO ()
forall ba p. ByteArrayAccess ba => ba -> Ptr p -> IO ()
forall p. Bytes -> Ptr p -> IO ()
copyByteArrayToPtr Bytes
iv (Ptr (LE Word32)
ptr Ptr (LE Word32) -> Int -> Ptr Any
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
4)
deriveKeys :: BlockCipher128 aes => aes -> Nonce -> (ScrubbedBytes, AES)
deriveKeys :: forall aes.
BlockCipher128 aes =>
aes -> Nonce -> (ScrubbedBytes, AES)
deriveKeys aes
aes Nonce
iv =
case aes -> KeySizeSpecifier
forall cipher. Cipher cipher => cipher -> KeySizeSpecifier
cipherKeySize aes
aes of
KeySizeFixed Int
sz | Int
sz Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
8 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 ->
let mak :: ScrubbedBytes
mak = [Word32] -> ScrubbedBytes
buildKey [Word32
0 .. Word32
1]
key :: ScrubbedBytes
key = [Word32] -> ScrubbedBytes
buildKey [Word32
2 .. Int -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int
sz Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
8) Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
+ Word32
1]
mek :: AES
mek = CryptoFailable AES -> AES
forall a. CryptoFailable a -> a
throwCryptoError (ScrubbedBytes -> CryptoFailable AES
forall key. ByteArray key => key -> CryptoFailable AES
forall cipher key.
(Cipher cipher, ByteArray key) =>
key -> CryptoFailable cipher
cipherInit ScrubbedBytes
key)
in (ScrubbedBytes
mak, AES
mek)
KeySizeSpecifier
_ -> String -> (ScrubbedBytes, AES)
forall a. HasCallStack => String -> a
error String
"AESGCMSIV: invalid cipher"
where
idx :: Word32 -> View Bytes
idx Word32
n = aes -> Bytes -> Bytes
forall ba. ByteArray ba => aes -> ba -> ba
forall cipher ba.
(BlockCipher cipher, ByteArray ba) =>
cipher -> ba -> ba
ecbEncrypt aes
aes (Word32 -> Nonce -> Bytes
le32iv Word32
n Nonce
iv) Bytes -> Int -> View Bytes
forall bytes. ByteArrayAccess bytes => bytes -> Int -> View bytes
`takeView` Int
8
buildKey :: [Word32] -> ScrubbedBytes
buildKey = [View Bytes] -> ScrubbedBytes
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
[bin] -> bout
B.concat ([View Bytes] -> ScrubbedBytes)
-> ([Word32] -> [View Bytes]) -> [Word32] -> ScrubbedBytes
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Word32 -> View Bytes) -> [Word32] -> [View Bytes]
forall a b. (a -> b) -> [a] -> [b]
map Word32 -> View Bytes
idx
lengthInvalid :: ByteArrayAccess ba => ba -> Bool
lengthInvalid :: forall ba. ByteArrayAccess ba => ba -> Bool
lengthInvalid ba
bs
| Int -> Int
forall b. FiniteBits b => b -> Int
finiteBitSize Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
32 = Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
1 Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`unsafeShiftL` Int
32
| Bool
otherwise = Bool
False
where len :: Int
len = ba -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length ba
bs
encrypt :: (BlockCipher128 aes, ByteArrayAccess aad, ByteArray ba)
=> aes -> Nonce -> aad -> ba -> (AuthTag, ba)
encrypt :: forall aes aad ba.
(BlockCipher128 aes, ByteArrayAccess aad, ByteArray ba) =>
aes -> Nonce -> aad -> ba -> (AuthTag, ba)
encrypt aes
aes Nonce
iv aad
aad ba
plaintext
| aad -> Bool
forall ba. ByteArrayAccess ba => ba -> Bool
lengthInvalid aad
aad = String -> (AuthTag, ba)
forall a. HasCallStack => String -> a
error String
"AESGCMSIV: aad is too large"
| ba -> Bool
forall ba. ByteArrayAccess ba => ba -> Bool
lengthInvalid ba
plaintext = String -> (AuthTag, ba)
forall a. HasCallStack => String -> a
error String
"AESGCMSIV: plaintext is too large"
| Bool
otherwise = (Bytes -> AuthTag
AuthTag Bytes
tag, ba
ciphertext)
where
(ScrubbedBytes
mak, AES
mek) = aes -> Nonce -> (ScrubbedBytes, AES)
forall aes.
BlockCipher128 aes =>
aes -> Nonce -> (ScrubbedBytes, AES)
deriveKeys aes
aes Nonce
iv
ss :: ScrubbedBytes
ss = ScrubbedBytes -> aad -> ba -> ScrubbedBytes
forall aad ba.
(ByteArrayAccess aad, ByteArrayAccess ba) =>
ScrubbedBytes -> aad -> ba -> ScrubbedBytes
getSs ScrubbedBytes
mak aad
aad ba
plaintext
tag :: Bytes
tag = AES -> ScrubbedBytes -> Nonce -> Bytes
forall aes.
BlockCipher128 aes =>
aes -> ScrubbedBytes -> Nonce -> Bytes
buildTag AES
mek ScrubbedBytes
ss Nonce
iv
ciphertext :: ba
ciphertext = AES -> IV AES -> ba -> ba
forall ba. ByteArray ba => AES -> IV AES -> ba -> ba
combineC32 AES
mek (Bytes -> IV AES
transformTag Bytes
tag) ba
plaintext
decrypt :: (BlockCipher128 aes, ByteArrayAccess aad, ByteArray ba)
=> aes -> Nonce -> aad -> ba -> AuthTag -> Maybe ba
decrypt :: forall aes aad ba.
(BlockCipher128 aes, ByteArrayAccess aad, ByteArray ba) =>
aes -> Nonce -> aad -> ba -> AuthTag -> Maybe ba
decrypt aes
aes Nonce
iv aad
aad ba
ciphertext (AuthTag Bytes
tag)
| aad -> Bool
forall ba. ByteArrayAccess ba => ba -> Bool
lengthInvalid aad
aad = String -> Maybe ba
forall a. HasCallStack => String -> a
error String
"AESGCMSIV: aad is too large"
| ba -> Bool
forall ba. ByteArrayAccess ba => ba -> Bool
lengthInvalid ba
ciphertext = String -> Maybe ba
forall a. HasCallStack => String -> a
error String
"AESGCMSIV: ciphertext is too large"
| Bytes
tag Bytes -> Bytes -> Bool
forall bs1 bs2.
(ByteArrayAccess bs1, ByteArrayAccess bs2) =>
bs1 -> bs2 -> Bool
`constEq` AES -> ScrubbedBytes -> Nonce -> Bytes
forall aes.
BlockCipher128 aes =>
aes -> ScrubbedBytes -> Nonce -> Bytes
buildTag AES
mek ScrubbedBytes
ss Nonce
iv = ba -> Maybe ba
forall a. a -> Maybe a
Just ba
plaintext
| Bool
otherwise = Maybe ba
forall a. Maybe a
Nothing
where
(ScrubbedBytes
mak, AES
mek) = aes -> Nonce -> (ScrubbedBytes, AES)
forall aes.
BlockCipher128 aes =>
aes -> Nonce -> (ScrubbedBytes, AES)
deriveKeys aes
aes Nonce
iv
ss :: ScrubbedBytes
ss = ScrubbedBytes -> aad -> ba -> ScrubbedBytes
forall aad ba.
(ByteArrayAccess aad, ByteArrayAccess ba) =>
ScrubbedBytes -> aad -> ba -> ScrubbedBytes
getSs ScrubbedBytes
mak aad
aad ba
plaintext
plaintext :: ba
plaintext = AES -> IV AES -> ba -> ba
forall ba. ByteArray ba => AES -> IV AES -> ba -> ba
combineC32 AES
mek (Bytes -> IV AES
transformTag Bytes
tag) ba
ciphertext
getSs :: (ByteArrayAccess aad, ByteArrayAccess ba)
=> ScrubbedBytes -> aad -> ba -> ScrubbedBytes
getSs :: forall aad ba.
(ByteArrayAccess aad, ByteArrayAccess ba) =>
ScrubbedBytes -> aad -> ba -> ScrubbedBytes
getSs ScrubbedBytes
mak aad
aad ba
plaintext = IO ScrubbedBytes -> ScrubbedBytes
forall a. IO a -> a
unsafeDoIO (IO ScrubbedBytes -> ScrubbedBytes)
-> IO ScrubbedBytes -> ScrubbedBytes
forall a b. (a -> b) -> a -> b
$ do
Polyval
ctx <- ScrubbedBytes -> IO Polyval
polyvalInit ScrubbedBytes
mak
Polyval -> aad -> IO ()
forall ba. ByteArrayAccess ba => Polyval -> ba -> IO ()
polyvalUpdate Polyval
ctx aad
aad
Polyval -> ba -> IO ()
forall ba. ByteArrayAccess ba => Polyval -> ba -> IO ()
polyvalUpdate Polyval
ctx ba
plaintext
Polyval -> Bytes -> IO ()
forall ba. ByteArrayAccess ba => Polyval -> ba -> IO ()
polyvalUpdate Polyval
ctx (Bytes
lb :: Bytes)
Polyval -> IO ScrubbedBytes
polyvalFinalize Polyval
ctx
where
lb :: Bytes
lb = Int -> (Ptr (LE Word64) -> IO ()) -> Bytes
forall a p. ByteArray a => Int -> (Ptr p -> IO ()) -> a
B.allocAndFreeze Int
16 ((Ptr (LE Word64) -> IO ()) -> Bytes)
-> (Ptr (LE Word64) -> IO ()) -> Bytes
forall a b. (a -> b) -> a -> b
$ \Ptr (LE Word64)
ptr -> do
Ptr (LE Word64) -> Int -> LE Word64 -> IO ()
forall a. Storable a => Ptr a -> Int -> a -> IO ()
pokeElemOff Ptr (LE Word64)
ptr Int
0 (Int -> LE Word64
forall {a}. Integral a => a -> LE Word64
toLE64 (Int -> LE Word64) -> Int -> LE Word64
forall a b. (a -> b) -> a -> b
$ aad -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length aad
aad)
Ptr (LE Word64) -> Int -> LE Word64 -> IO ()
forall a. Storable a => Ptr a -> Int -> a -> IO ()
pokeElemOff Ptr (LE Word64)
ptr Int
1 (Int -> LE Word64
forall {a}. Integral a => a -> LE Word64
toLE64 (Int -> LE Word64) -> Int -> LE Word64
forall a b. (a -> b) -> a -> b
$ ba -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length ba
plaintext)
toLE64 :: a -> LE Word64
toLE64 a
x = Word64 -> LE Word64
forall a. ByteSwap a => a -> LE a
toLE (a -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
x Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
* Word64
8 :: Word64)
tagInput :: ScrubbedBytes -> Nonce -> Bytes
tagInput :: ScrubbedBytes -> Nonce -> Bytes
tagInput ScrubbedBytes
ss (Nonce Bytes
iv) =
ScrubbedBytes -> (Ptr Word8 -> IO ()) -> Bytes
forall bs1 bs2 p.
(ByteArrayAccess bs1, ByteArray bs2) =>
bs1 -> (Ptr p -> IO ()) -> bs2
B.copyAndFreeze ScrubbedBytes
ss ((Ptr Word8 -> IO ()) -> Bytes) -> (Ptr Word8 -> IO ()) -> Bytes
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
ptr ->
Bytes -> (Ptr Word8 -> IO ()) -> IO ()
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
forall p a. Bytes -> (Ptr p -> IO a) -> IO a
B.withByteArray Bytes
iv ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
ivPtr -> do
Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> Int -> IO ()
memXor Ptr Word8
ptr Ptr Word8
ptr Ptr Word8
ivPtr Int
12
Word8
b <- Ptr Word8 -> Int -> IO Word8
forall a. Storable a => Ptr a -> Int -> IO a
peekElemOff Ptr Word8
ptr Int
15
Ptr Word8 -> Int -> Word8 -> IO ()
forall a. Storable a => Ptr a -> Int -> a -> IO ()
pokeElemOff Ptr Word8
ptr Int
15 (Word8
b Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. (Word8
0x7f :: Word8))
buildTag :: BlockCipher128 aes => aes -> ScrubbedBytes -> Nonce -> Bytes
buildTag :: forall aes.
BlockCipher128 aes =>
aes -> ScrubbedBytes -> Nonce -> Bytes
buildTag aes
mek ScrubbedBytes
ss Nonce
iv = aes -> Bytes -> Bytes
forall ba. ByteArray ba => aes -> ba -> ba
forall cipher ba.
(BlockCipher cipher, ByteArray ba) =>
cipher -> ba -> ba
ecbEncrypt aes
mek (ScrubbedBytes -> Nonce -> Bytes
tagInput ScrubbedBytes
ss Nonce
iv)
transformTag :: Bytes -> IV AES
transformTag :: Bytes -> IV AES
transformTag Bytes
tag = Bytes -> IV AES
forall {c}. BlockCipher c => Bytes -> IV c
toIV (Bytes -> IV AES) -> Bytes -> IV AES
forall a b. (a -> b) -> a -> b
$ Bytes -> (Ptr Word8 -> IO ()) -> Bytes
forall bs1 bs2 p.
(ByteArrayAccess bs1, ByteArray bs2) =>
bs1 -> (Ptr p -> IO ()) -> bs2
B.copyAndFreeze Bytes
tag ((Ptr Word8 -> IO ()) -> Bytes) -> (Ptr Word8 -> IO ()) -> Bytes
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
ptr ->
Ptr Word8 -> Int -> IO Word8
forall a. Storable a => Ptr a -> Int -> IO a
peekElemOff Ptr Word8
ptr Int
15 IO Word8 -> (Word8 -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Ptr Word8 -> Int -> Word8 -> IO ()
forall a. Storable a => Ptr a -> Int -> a -> IO ()
pokeElemOff Ptr Word8
ptr Int
15 (Word8 -> IO ()) -> (Word8 -> Word8) -> Word8 -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. (Word8
0x80 :: Word8))
where toIV :: Bytes -> IV c
toIV Bytes
bs = let Just IV c
iv = Bytes -> Maybe (IV c)
forall b c. (ByteArrayAccess b, BlockCipher c) => b -> Maybe (IV c)
makeIV (Bytes
bs :: Bytes) in IV c
iv