module Crypto.Cipher.AES.GCM (
Context,
newContext,
encrypt,
decrypt,
decryptWithTag,
HeaderKey,
newHeaderKey,
encryptWithMask,
) where
import Crypto.Cipher.AES.Primitive (
AES,
AESGCMKey,
gcmFullDecrypt,
gcmFullDecryptTag,
gcmFullEncrypt,
gcmFullEncryptMask,
gcmKeyInit,
initAES,
)
import Crypto.Cipher.Types (AuthTag)
import Crypto.Cipher.Types.AEAD (minimumTagLength)
import Crypto.Error
import Crypto.Internal.ByteArray (ByteArray, ByteArrayAccess)
import qualified Crypto.Internal.ByteArray as B
import Data.Word (Word8)
import Foreign.Ptr (Ptr)
data Context = Context !AES !AESGCMKey
newContext :: ByteArrayAccess key => key -> CryptoFailable Context
newContext :: forall key. ByteArrayAccess key => key -> CryptoFailable Context
newContext key
k = do
AES
aes <- key -> CryptoFailable AES
forall key. ByteArrayAccess key => key -> CryptoFailable AES
initAES key
k
Context -> CryptoFailable Context
forall a. a -> CryptoFailable a
forall (m :: * -> *) a. Monad m => a -> m a
return (Context -> CryptoFailable Context)
-> Context -> CryptoFailable Context
forall a b. (a -> b) -> a -> b
$ AES -> AESGCMKey -> Context
Context AES
aes (AES -> AESGCMKey
gcmKeyInit AES
aes)
{-# INLINABLE encrypt #-}
encrypt
:: ( ByteArrayAccess nonce
, ByteArrayAccess aad
, ByteArrayAccess ba
, ByteArray output
)
=> Context
-> nonce
-> aad
-> ba
-> Int
-> output
encrypt :: forall nonce aad ba output.
(ByteArrayAccess nonce, ByteArrayAccess aad, ByteArrayAccess ba,
ByteArray output) =>
Context -> nonce -> aad -> ba -> Int -> output
encrypt (Context AES
aes AESGCMKey
gk) nonce
nonce aad
aad ba
input Int
taglen
| aad -> ba -> Bool
forall aad ba.
(ByteArrayAccess aad, ByteArrayAccess ba) =>
aad -> ba -> Bool
tooLongForC aad
aad ba
input =
CryptoFailable output -> output
forall a. CryptoFailable a -> a
throwCryptoError (CryptoError -> CryptoFailable output
forall a. CryptoError -> CryptoFailable a
CryptoFailed CryptoError
CryptoError_ParameterInvalid)
| nonce -> Bool
forall nonce. ByteArrayAccess nonce => nonce -> Bool
badNonce nonce
nonce =
CryptoFailable output -> output
forall a. CryptoFailable a -> a
throwCryptoError (CryptoError -> CryptoFailable output
forall a. CryptoError -> CryptoFailable a
CryptoFailed CryptoError
CryptoError_IvSizeInvalid)
| Int -> Bool
badTagLength Int
taglen =
CryptoFailable output -> output
forall a. CryptoFailable a -> a
throwCryptoError (CryptoError -> CryptoFailable output
forall a. CryptoError -> CryptoFailable a
CryptoFailed CryptoError
CryptoError_AuthenticationTagSizeInvalid)
| Bool
otherwise = AES -> AESGCMKey -> nonce -> aad -> ba -> Int -> output
forall iv aad ba output.
(ByteArrayAccess iv, ByteArrayAccess aad, ByteArrayAccess ba,
ByteArray output) =>
AES -> AESGCMKey -> iv -> aad -> ba -> Int -> output
gcmFullEncrypt AES
aes AESGCMKey
gk nonce
nonce aad
aad ba
input Int
taglen
{-# INLINABLE decrypt #-}
decrypt
:: (ByteArrayAccess nonce, ByteArrayAccess aad, ByteArray ba)
=> Context
-> nonce
-> aad
-> ba
-> Int
-> Maybe ba
decrypt :: forall nonce aad ba.
(ByteArrayAccess nonce, ByteArrayAccess aad, ByteArray ba) =>
Context -> nonce -> aad -> ba -> Int -> Maybe ba
decrypt (Context AES
aes AESGCMKey
gk) nonce
nonce aad
aad ba
input Int
taglen
| aad -> ba -> Bool
forall aad ba.
(ByteArrayAccess aad, ByteArrayAccess ba) =>
aad -> ba -> Bool
tooLongForC aad
aad ba
input = Maybe ba
forall a. Maybe a
Nothing
| nonce -> Bool
forall nonce. ByteArrayAccess nonce => nonce -> Bool
badNonce nonce
nonce Bool -> Bool -> Bool
|| Int -> Bool
badTagLength Int
taglen Bool -> Bool -> Bool
|| ba -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length ba
input Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
taglen = Maybe ba
forall a. Maybe a
Nothing
| Bool
otherwise = AES -> AESGCMKey -> nonce -> aad -> ba -> ba -> Maybe ba
forall iv aad ba tag output.
(ByteArrayAccess iv, ByteArrayAccess aad, ByteArrayAccess ba,
ByteArrayAccess tag, ByteArray output) =>
AES -> AESGCMKey -> iv -> aad -> ba -> tag -> Maybe output
gcmFullDecrypt AES
aes AESGCMKey
gk nonce
nonce aad
aad ba
body ba
tag
where
(ba
body, ba
tag) = Int -> ba -> (ba, ba)
forall bs. ByteArray bs => Int -> bs -> (bs, bs)
B.splitAt (ba -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length ba
input Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
taglen) ba
input
{-# INLINABLE decryptWithTag #-}
decryptWithTag
:: (ByteArrayAccess nonce, ByteArrayAccess aad, ByteArray ba)
=> Context
-> nonce
-> aad
-> ba
-> Int
-> (ba, AuthTag)
decryptWithTag :: forall nonce aad ba.
(ByteArrayAccess nonce, ByteArrayAccess aad, ByteArray ba) =>
Context -> nonce -> aad -> ba -> Int -> (ba, AuthTag)
decryptWithTag (Context AES
aes AESGCMKey
gk) nonce
nonce aad
aad ba
input Int
taglen
| aad -> ba -> Bool
forall aad ba.
(ByteArrayAccess aad, ByteArrayAccess ba) =>
aad -> ba -> Bool
tooLongForC aad
aad ba
input =
CryptoFailable (ba, AuthTag) -> (ba, AuthTag)
forall a. CryptoFailable a -> a
throwCryptoError (CryptoError -> CryptoFailable (ba, AuthTag)
forall a. CryptoError -> CryptoFailable a
CryptoFailed CryptoError
CryptoError_ParameterInvalid)
| nonce -> Bool
forall nonce. ByteArrayAccess nonce => nonce -> Bool
badNonce nonce
nonce =
CryptoFailable (ba, AuthTag) -> (ba, AuthTag)
forall a. CryptoFailable a -> a
throwCryptoError (CryptoError -> CryptoFailable (ba, AuthTag)
forall a. CryptoError -> CryptoFailable a
CryptoFailed CryptoError
CryptoError_IvSizeInvalid)
| Int -> Bool
badTagLength Int
taglen =
CryptoFailable (ba, AuthTag) -> (ba, AuthTag)
forall a. CryptoFailable a -> a
throwCryptoError (CryptoError -> CryptoFailable (ba, AuthTag)
forall a. CryptoError -> CryptoFailable a
CryptoFailed CryptoError
CryptoError_AuthenticationTagSizeInvalid)
| Bool
otherwise = AES -> AESGCMKey -> nonce -> aad -> ba -> Int -> (ba, AuthTag)
forall iv aad ba output.
(ByteArrayAccess iv, ByteArrayAccess aad, ByteArrayAccess ba,
ByteArray output) =>
AES -> AESGCMKey -> iv -> aad -> ba -> Int -> (output, AuthTag)
gcmFullDecryptTag AES
aes AESGCMKey
gk nonce
nonce aad
aad ba
input Int
taglen
newtype = AES
newHeaderKey :: ByteArrayAccess key => key -> CryptoFailable HeaderKey
key
k = AES -> HeaderKey
HeaderKey (AES -> HeaderKey)
-> CryptoFailable AES -> CryptoFailable HeaderKey
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> key -> CryptoFailable AES
forall key. ByteArrayAccess key => key -> CryptoFailable AES
initAES key
k
{-# INLINABLE encryptWithMask #-}
encryptWithMask
:: (ByteArrayAccess nonce, ByteArrayAccess aad, ByteArrayAccess ba)
=> Context
-> HeaderKey
-> nonce
-> aad
-> ba
-> Int
-> Int
-> Ptr Word8
-> Ptr Word8
-> IO Bool
encryptWithMask :: forall nonce aad ba.
(ByteArrayAccess nonce, ByteArrayAccess aad, ByteArrayAccess ba) =>
Context
-> HeaderKey
-> nonce
-> aad
-> ba
-> Int
-> Int
-> Ptr Word8
-> Ptr Word8
-> IO Bool
encryptWithMask (Context AES
aes AESGCMKey
gk) (HeaderKey AES
hp) nonce
nonce aad
aad ba
input Int
taglen Int
off Ptr Word8
outp Ptr Word8
maskp
| aad -> ba -> Bool
forall aad ba.
(ByteArrayAccess aad, ByteArrayAccess ba) =>
aad -> ba -> Bool
tooLongForC aad
aad ba
input = Bool -> IO Bool
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
| nonce -> Bool
forall nonce. ByteArrayAccess nonce => nonce -> Bool
badNonce nonce
nonce = Bool -> IO Bool
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
| Int
off Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0 Bool -> Bool -> Bool
|| Int -> Bool
badTagLength Int
taglen Bool -> Bool -> Bool
|| Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
16 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> ba -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length ba
input Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
taglen =
Bool -> IO Bool
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
| Bool
otherwise = do
AES
-> AESGCMKey
-> AES
-> nonce
-> aad
-> ba
-> Int
-> Int
-> Ptr Word8
-> Ptr Word8
-> IO ()
forall iv aad ba.
(ByteArrayAccess iv, ByteArrayAccess aad, ByteArrayAccess ba) =>
AES
-> AESGCMKey
-> AES
-> iv
-> aad
-> ba
-> Int
-> Int
-> Ptr Word8
-> Ptr Word8
-> IO ()
gcmFullEncryptMask AES
aes AESGCMKey
gk AES
hp nonce
nonce aad
aad ba
input Int
taglen Int
off Ptr Word8
outp Ptr Word8
maskp
Bool -> IO Bool
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
tooLongForC
:: (ByteArrayAccess aad, ByteArrayAccess ba) => aad -> ba -> Bool
tooLongForC :: forall aad ba.
(ByteArrayAccess aad, ByteArrayAccess ba) =>
aad -> ba -> Bool
tooLongForC aad
aad ba
input =
Int -> Bool
B.overCLength (aad -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length aad
aad) Bool -> Bool -> Bool
|| Int -> Bool
B.overCLength (ba -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length ba
input)
badNonce :: ByteArrayAccess nonce => nonce -> Bool
badNonce :: forall nonce. ByteArrayAccess nonce => nonce -> Bool
badNonce nonce
nonce = nonce -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length nonce
nonce Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0
badTagLength :: Int -> Bool
badTagLength :: Int -> Bool
badTagLength Int
t = Int
t Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
minimumTagLength Bool -> Bool -> Bool
|| Int
t Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
16