    -- |
    -- 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 Data.ByteString (ByteString)
    import qualified Data.ByteString as B
    import Data.Byteable
    import Crypto.Cipher.Types.Base
    import Crypto.Cipher.Types.Block

    -- | Append associated data into the AEAD state
    aeadAppendHeader :: BlockCipher a => AEAD a -> ByteString -> AEAD a
    aeadAppendHeader :: forall a. BlockCipher a => AEAD a -> ByteString -> AEAD a
    aeadAppendHeader (AEAD a
    cipher (AEADState st
    state)) ByteString
    bs =
        a -> AEADState a -> AEAD a
    forall cipher. cipher -> AEADState cipher -> AEAD cipher
    AEAD a
    cipher (AEADState a -> AEAD a) -> AEADState a -> AEAD a
    forall a b. (a -> b) -> a -> b
    $ st -> AEADState a
    forall cipher st. AEADModeImpl cipher st => st -> AEADState cipher
    AEADState (a -> st -> ByteString -> st
    forall cipher state.
    AEADModeImpl cipher state =>
    cipher -> state -> ByteString -> state
    aeadStateAppendHeader a
    cipher st
    state ByteString
    bs)

    -- | Encrypt input and append into the AEAD state
    aeadEncrypt :: BlockCipher a => AEAD a -> ByteString -> (ByteString, AEAD a)
    aeadEncrypt :: forall a.
    BlockCipher a =>
    AEAD a -> ByteString -> (ByteString, AEAD a)
    aeadEncrypt (AEAD a
    cipher (AEADState st
    state)) ByteString
    input = (ByteString
    output, a -> AEADState a -> AEAD a
    forall cipher. cipher -> AEADState cipher -> AEAD cipher
    AEAD a
    cipher (st -> AEADState a
    forall cipher st. AEADModeImpl cipher st => st -> AEADState cipher
    AEADState st
    nst))
      where (ByteString
    output, st
    nst) = a -> st -> ByteString -> (ByteString, st)
    forall cipher state.
    AEADModeImpl cipher state =>
    cipher -> state -> ByteString -> (ByteString, state)
    aeadStateEncrypt a
    cipher st
    state ByteString
    input

    -- | Decrypt input and append into the AEAD state
    aeadDecrypt :: BlockCipher a => AEAD a -> ByteString -> (ByteString, AEAD a)
    aeadDecrypt :: forall a.
    BlockCipher a =>
    AEAD a -> ByteString -> (ByteString, AEAD a)
    aeadDecrypt (AEAD a
    cipher (AEADState st
    state)) ByteString
    input = (ByteString
    output, a -> AEADState a -> AEAD a
    forall cipher. cipher -> AEADState cipher -> AEAD cipher
    AEAD a
    cipher (st -> AEADState a
    forall cipher st. AEADModeImpl cipher st => st -> AEADState cipher
    AEADState st
    nst))
      where (ByteString
    output, st
    nst) = a -> st -> ByteString -> (ByteString, st)
    forall cipher state.
    AEADModeImpl cipher state =>
    cipher -> state -> ByteString -> (ByteString, state)
    aeadStateDecrypt a
    cipher st
    state ByteString
    input

    -- | Finalize the AEAD state and create an authentification tag
    aeadFinalize :: BlockCipher a => AEAD a -> Int -> AuthTag
    aeadFinalize :: forall a. BlockCipher a => AEAD a -> Int -> AuthTag
    aeadFinalize (AEAD a
    cipher (AEADState st
    state)) Int
    len =
        a -> st -> Int -> AuthTag
    forall cipher state.
    AEADModeImpl cipher state =>
    cipher -> state -> Int -> AuthTag
    aeadStateFinalize a
    cipher st
    state Int
    len

    -- | Simple AEAD encryption
    aeadSimpleEncrypt :: BlockCipher a
                      => AEAD a        -- ^ A new AEAD Context
                      -> B.ByteString  -- ^ Optional Authentified Header
                      -> B.ByteString  -- ^ Optional Plaintext
                      -> Int           -- ^ Tag length
                      -> (AuthTag, B.ByteString) -- ^ Authentification tag and ciphertext
    aeadSimpleEncrypt :: forall a.
    BlockCipher a =>
    AEAD a -> ByteString -> ByteString -> Int -> (AuthTag, ByteString)
    aeadSimpleEncrypt AEAD a
    aeadIni ByteString
    header ByteString
    input Int
    taglen = (AuthTag
    tag, ByteString
    output)
      where aead :: AEAD a
    aead                = AEAD a -> ByteString -> AEAD a
    forall a. BlockCipher a => AEAD a -> ByteString -> AEAD a
    aeadAppendHeader AEAD a
    aeadIni ByteString
    header
            (ByteString
    output, AEAD a
    aeadFinal) = AEAD a -> ByteString -> (ByteString, AEAD a)
    forall a.
    BlockCipher a =>
    AEAD a -> ByteString -> (ByteString, AEAD a)
    aeadEncrypt AEAD a
    aead ByteString
    input
            tag :: AuthTag
    tag                 = AEAD a -> Int -> AuthTag
    forall a. BlockCipher a => AEAD a -> Int -> AuthTag
    aeadFinalize AEAD a
    aeadFinal Int
    taglen

    -- | Simple AEAD decryption
    aeadSimpleDecrypt :: BlockCipher a
                      => AEAD a        -- ^ A new AEAD Context
                      -> B.ByteString  -- ^ Optional Authentified Header
                      -> B.ByteString  -- ^ Optional Plaintext
                      -> AuthTag       -- ^ Tag length
                      -> Maybe B.ByteString -- ^ Plaintext
    aeadSimpleDecrypt :: forall a.
    BlockCipher a =>
    AEAD a -> ByteString -> ByteString -> AuthTag -> Maybe ByteString
    aeadSimpleDecrypt AEAD a
    aeadIni ByteString
    header ByteString
    input AuthTag
    authTag
        | AuthTag
    tag AuthTag -> AuthTag -> Bool
    forall a. Eq a => a -> a -> Bool
    == AuthTag
    authTag = ByteString -> Maybe ByteString
    forall a. a -> Maybe a
    Just ByteString
    output
        | Bool
    otherwise      = Maybe ByteString
    forall a. Maybe a
    Nothing
      where aead :: AEAD a
    aead                = AEAD a -> ByteString -> AEAD a
    forall a. BlockCipher a => AEAD a -> ByteString -> AEAD a
    aeadAppendHeader AEAD a
    aeadIni ByteString
    header
            (ByteString
    output, AEAD a
    aeadFinal) = AEAD a -> ByteString -> (ByteString, AEAD a)
    forall a.
    BlockCipher a =>
    AEAD a -> ByteString -> (ByteString, AEAD a)
    aeadDecrypt AEAD a
    aead ByteString
    input
            tag :: AuthTag
    tag                 = AEAD a -> Int -> AuthTag
    forall a. BlockCipher a => AEAD a -> Int -> AuthTag
    aeadFinalize AEAD a
    aeadFinal (AuthTag -> Int
    forall a. Byteable a => a -> Int
    byteableLength AuthTag
    authTag)