{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE Rank2Types #-}

-- |
-- Module      : Crypto.Cipher.Types.AEAD
-- License     : BSD-style
-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
-- Stability   : Stable
-- Portability : Excellent
--
-- AEAD cipher basic types
module Crypto.Cipher.Types.AEAD where

import Crypto.Cipher.Types.Base
import Crypto.Internal.ByteArray (ByteArray, ByteArrayAccess)
import qualified Crypto.Internal.ByteArray as B
import Crypto.Internal.Imports

-- | AEAD Implementation
data AEADModeImpl st = AEADModeImpl
    { forall st.
AEADModeImpl st -> forall ba. ByteArrayAccess ba => st -> ba -> st
aeadImplAppendHeader :: forall ba. ByteArrayAccess ba => st -> ba -> st
    -- ^ Adding associated\/additional data to the AEAD context.
    , forall st.
AEADModeImpl st -> forall ba. ByteArray ba => st -> ba -> (ba, st)
aeadImplEncrypt :: forall ba. ByteArray ba => st -> ba -> (ba, st)
    -- ^ Encrypiting plaintext and update the AEAD context.
    , forall st.
AEADModeImpl st -> forall ba. ByteArray ba => st -> ba -> (ba, st)
aeadImplDecrypt :: forall ba. ByteArray ba => st -> ba -> (ba, st)
    -- ^ Decrypting ciphertext and update the AEAD context.
    , forall st. AEADModeImpl st -> st -> Int -> AuthTag
aeadImplFinalize :: st -> Int -> AuthTag
    -- ^ Finalizing the AEAD context and returning the authentication tag.
    }

-- | Algorithm and context for AEAD(Authenticated Encryption with Associated\/Additional Data)
data AEAD cipher = forall st. AEAD
    { ()
aeadModeImpl :: AEADModeImpl st
    , ()
aeadState :: !st
    }

-- | Adding associated\/additional data to the AEAD context.
aeadAppendHeader :: ByteArrayAccess aad => AEAD cipher -> aad -> AEAD cipher
aeadAppendHeader :: forall aad cipher.
ByteArrayAccess aad =>
AEAD cipher -> aad -> AEAD cipher
aeadAppendHeader (AEAD AEADModeImpl st
impl st
st) aad
aad = AEADModeImpl st -> st -> AEAD cipher
forall cipher st. AEADModeImpl st -> st -> AEAD cipher
AEAD AEADModeImpl st
impl (st -> AEAD cipher) -> st -> AEAD cipher
forall a b. (a -> b) -> a -> b
$ AEADModeImpl st -> forall ba. ByteArrayAccess ba => st -> ba -> st
forall st.
AEADModeImpl st -> forall ba. ByteArrayAccess ba => st -> ba -> st
aeadImplAppendHeader AEADModeImpl st
impl st
st aad
aad

-- | Encrypting plaintext  and update the AEAD context.
aeadEncrypt :: ByteArray ba => AEAD cipher -> ba -> (ba, AEAD cipher)
aeadEncrypt :: forall ba cipher.
ByteArray ba =>
AEAD cipher -> ba -> (ba, AEAD cipher)
aeadEncrypt (AEAD AEADModeImpl st
impl st
st) ba
ba = (st -> AEAD cipher) -> (ba, st) -> (ba, AEAD cipher)
forall b c d. (b -> c) -> (d, b) -> (d, c)
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (d, b) (d, c)
second (AEADModeImpl st -> st -> AEAD cipher
forall cipher st. AEADModeImpl st -> st -> AEAD cipher
AEAD AEADModeImpl st
impl) ((ba, st) -> (ba, AEAD cipher)) -> (ba, st) -> (ba, AEAD cipher)
forall a b. (a -> b) -> a -> b
$ AEADModeImpl st -> forall ba. ByteArray ba => st -> ba -> (ba, st)
forall st.
AEADModeImpl st -> forall ba. ByteArray ba => st -> ba -> (ba, st)
aeadImplEncrypt AEADModeImpl st
impl st
st ba
ba

-- | Decrypting ciphertext and update the AEAD context.
aeadDecrypt :: ByteArray ba => AEAD cipher -> ba -> (ba, AEAD cipher)
aeadDecrypt :: forall ba cipher.
ByteArray ba =>
AEAD cipher -> ba -> (ba, AEAD cipher)
aeadDecrypt (AEAD AEADModeImpl st
impl st
st) ba
ba = (st -> AEAD cipher) -> (ba, st) -> (ba, AEAD cipher)
forall b c d. (b -> c) -> (d, b) -> (d, c)
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (d, b) (d, c)
second (AEADModeImpl st -> st -> AEAD cipher
forall cipher st. AEADModeImpl st -> st -> AEAD cipher
AEAD AEADModeImpl st
impl) ((ba, st) -> (ba, AEAD cipher)) -> (ba, st) -> (ba, AEAD cipher)
forall a b. (a -> b) -> a -> b
$ AEADModeImpl st -> forall ba. ByteArray ba => st -> ba -> (ba, st)
forall st.
AEADModeImpl st -> forall ba. ByteArray ba => st -> ba -> (ba, st)
aeadImplDecrypt AEADModeImpl st
impl st
st ba
ba

-- | Finalizing the AEAD context and returning the authentication tag.
aeadFinalize :: AEAD cipher -> Int -> AuthTag
aeadFinalize :: forall cipher. AEAD cipher -> Int -> AuthTag
aeadFinalize (AEAD AEADModeImpl st
impl st
st) = AEADModeImpl st -> st -> Int -> AuthTag
forall st. AEADModeImpl st -> st -> Int -> AuthTag
aeadImplFinalize AEADModeImpl st
impl st
st

-- | Simple AEAD encryption.
aeadSimpleEncrypt
    :: (ByteArrayAccess aad, ByteArray ba)
    => AEAD a
    -- ^ An AEAD Context
    -> aad
    -- ^ Associated\/additional data
    -> ba
    -- ^ Plaintext
    -> Int
    -- ^ Tag length
    -> (AuthTag, ba)
    -- ^ Authentication tag and ciphertext
aeadSimpleEncrypt :: forall aad ba a.
(ByteArrayAccess aad, ByteArray ba) =>
AEAD a -> aad -> ba -> Int -> (AuthTag, ba)
aeadSimpleEncrypt AEAD a
aeadIni aad
header ba
input Int
taglen = (AuthTag
tag, ba
output)
  where
    aead :: AEAD a
aead = AEAD a -> aad -> AEAD a
forall aad cipher.
ByteArrayAccess aad =>
AEAD cipher -> aad -> AEAD cipher
aeadAppendHeader AEAD a
aeadIni aad
header
    (ba
output, AEAD a
aeadFinal) = AEAD a -> ba -> (ba, AEAD a)
forall ba cipher.
ByteArray ba =>
AEAD cipher -> ba -> (ba, AEAD cipher)
aeadEncrypt AEAD a
aead ba
input
    tag :: AuthTag
tag = AEAD a -> Int -> AuthTag
forall cipher. AEAD cipher -> Int -> AuthTag
aeadFinalize AEAD a
aeadFinal Int
taglen

-- | The shortest authentication tag any mode here produces, four bytes
-- (@CCM_M4@).  Modes that truncate their tag -- GCM and OCB3 -- will
-- compute one of whatever length they are asked for, down to nothing, so
-- 'aeadSimpleDecrypt' refuses a shorter tag than this rather than
-- authenticate fewer bytes than any supported mode ever emits.
minimumTagLength :: Int
minimumTagLength :: Int
minimumTagLength = Int
4

-- | Simple AEAD decryptio.
--
-- The number of bytes compared is the length of @authTag@.  That is the
-- caller's choice of tag length, so a caller reading a tag off the wire
-- must check its length against the one it expects: passing an
-- attacker-supplied tag straight in lets the attacker pick how much of it
-- is verified.  Tags shorter than 'minimumTagLength' are rejected
-- outright.
aeadSimpleDecrypt
    :: (ByteArrayAccess aad, ByteArray ba)
    => AEAD a
    -- ^ An AEAD Context
    -> aad
    -- ^ Associated\/additional data
    -> ba
    -- ^ Ciphertext
    -> AuthTag
    -- ^ The authentication tag
    -> Maybe ba
    -- ^ Plaintext
aeadSimpleDecrypt :: forall aad ba a.
(ByteArrayAccess aad, ByteArray ba) =>
AEAD a -> aad -> ba -> AuthTag -> Maybe ba
aeadSimpleDecrypt AEAD a
aeadIni aad
header ba
input AuthTag
authTag
    | AuthTag -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length AuthTag
authTag Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
minimumTagLength = Maybe ba
forall a. Maybe a
Nothing
    | AuthTag
tag AuthTag -> AuthTag -> Bool
forall a. Eq a => a -> a -> Bool
== AuthTag
authTag = ba -> Maybe ba
forall a. a -> Maybe a
Just ba
output
    | Bool
otherwise = Maybe ba
forall a. Maybe a
Nothing
  where
    aead :: AEAD a
aead = AEAD a -> aad -> AEAD a
forall aad cipher.
ByteArrayAccess aad =>
AEAD cipher -> aad -> AEAD cipher
aeadAppendHeader AEAD a
aeadIni aad
header
    (ba
output, AEAD a
aeadFinal) = AEAD a -> ba -> (ba, AEAD a)
forall ba cipher.
ByteArray ba =>
AEAD cipher -> ba -> (ba, AEAD cipher)
aeadDecrypt AEAD a
aead ba
input
    tag :: AuthTag
tag = AEAD a -> Int -> AuthTag
forall cipher. AEAD cipher -> Int -> AuthTag
aeadFinalize AEAD a
aeadFinal (AuthTag -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length AuthTag
authTag)

-- | Simple AEAD decryption with the tag length given by the caller.
--
-- 'aeadSimpleDecrypt' authenticates as many octets as the tag it is handed is
-- long.  That is the caller's choice only for as long as the tag is: one read
-- off the wire is the peer's, and an attacker who truncates it picks how much
-- of it gets verified, down to 'minimumTagLength'.
--
-- Here the length is a separate argument and a tag that is not exactly that
-- long is refused before anything is compared, so the peer cannot weaken the
-- check.  Prefer this wherever the tag is attacker reachable.
tryAeadSimpleDecrypt
    :: (ByteArrayAccess aad, ByteArray ba)
    => AEAD a
    -- ^ An AEAD Context
    -> aad
    -- ^ Associated\/additional data
    -> ba
    -- ^ Ciphertext
    -> Int
    -- ^ The tag length to authenticate, which the tag must match
    -> AuthTag
    -- ^ The authentication tag
    -> Maybe ba
    -- ^ Plaintext
tryAeadSimpleDecrypt :: forall aad ba a.
(ByteArrayAccess aad, ByteArray ba) =>
AEAD a -> aad -> ba -> Int -> AuthTag -> Maybe ba
tryAeadSimpleDecrypt AEAD a
aeadIni aad
header ba
input Int
taglen AuthTag
authTag
    | Int
taglen Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
minimumTagLength = Maybe ba
forall a. Maybe a
Nothing
    | AuthTag -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length AuthTag
authTag Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
taglen = Maybe ba
forall a. Maybe a
Nothing
    | AuthTag
tag AuthTag -> AuthTag -> Bool
forall a. Eq a => a -> a -> Bool
== AuthTag
authTag = ba -> Maybe ba
forall a. a -> Maybe a
Just ba
output
    | Bool
otherwise = Maybe ba
forall a. Maybe a
Nothing
  where
    aead :: AEAD a
aead = AEAD a -> aad -> AEAD a
forall aad cipher.
ByteArrayAccess aad =>
AEAD cipher -> aad -> AEAD cipher
aeadAppendHeader AEAD a
aeadIni aad
header
    (ba
output, AEAD a
aeadFinal) = AEAD a -> ba -> (ba, AEAD a)
forall ba cipher.
ByteArray ba =>
AEAD cipher -> ba -> (ba, AEAD cipher)
aeadDecrypt AEAD a
aead ba
input
    tag :: AuthTag
tag = AEAD a -> Int -> AuthTag
forall cipher. AEAD cipher -> Int -> AuthTag
aeadFinalize AEAD a
aeadFinal Int
taglen