{-|
Module      : Botan.Bindings.MAC
Description : Message Authentication Codes (MAC)
Copyright   : (c) Leo D, 2023
License     : BSD-3-Clause
Maintainer  : leo@apotheca.io
Stability   : experimental
Portability : POSIX

A Message Authentication Code algorithm computes a tag over a
message utilizing a shared secret key. Thus a valid tag confirms
the authenticity and integrity of the message. Only entities in
possession of the shared secret key are able to verify the tag.

Note

When combining a MAC with unauthenticated encryption mode, prefer
to first encrypt the message and then MAC the ciphertext. The
alternative is to MAC the plaintext, which depending on exact usage
can suffer serious security issues. For a detailed discussion of
this issue see the paper “The Order of Encryption and Authentication
for Protecting Communications” by Hugo Krawczyk

The Botan MAC computation is split into five stages.

- Instantiate the MAC algorithm.

- Set the secret key.

- Process IV.

- Process data.

- Finalize the MAC computation.
-}

{-# LANGUAGE CApiFFI #-}

module Botan.Bindings.MAC where

import Botan.Bindings.Prelude

-- | Opaque MAC struct
data {-# CTYPE "botan/ffi.h" "struct botan_mac_struct" #-} BotanMACStruct

-- | Botan MAC object
newtype {-# CTYPE "botan/ffi.h" "botan_mac_t" #-} BotanMAC
    = MkBotanMAC { BotanMAC -> Ptr BotanMACStruct
runBotanMAC :: Ptr BotanMACStruct }
        deriving newtype (BotanMAC -> BotanMAC -> Bool
(BotanMAC -> BotanMAC -> Bool)
-> (BotanMAC -> BotanMAC -> Bool) -> Eq BotanMAC
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: BotanMAC -> BotanMAC -> Bool
== :: BotanMAC -> BotanMAC -> Bool
$c/= :: BotanMAC -> BotanMAC -> Bool
/= :: BotanMAC -> BotanMAC -> Bool
Eq, Eq BotanMAC
Eq BotanMAC
-> (BotanMAC -> BotanMAC -> Ordering)
-> (BotanMAC -> BotanMAC -> Bool)
-> (BotanMAC -> BotanMAC -> Bool)
-> (BotanMAC -> BotanMAC -> Bool)
-> (BotanMAC -> BotanMAC -> Bool)
-> (BotanMAC -> BotanMAC -> BotanMAC)
-> (BotanMAC -> BotanMAC -> BotanMAC)
-> Ord BotanMAC
BotanMAC -> BotanMAC -> Bool
BotanMAC -> BotanMAC -> Ordering
BotanMAC -> BotanMAC -> BotanMAC
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: BotanMAC -> BotanMAC -> Ordering
compare :: BotanMAC -> BotanMAC -> Ordering
$c< :: BotanMAC -> BotanMAC -> Bool
< :: BotanMAC -> BotanMAC -> Bool
$c<= :: BotanMAC -> BotanMAC -> Bool
<= :: BotanMAC -> BotanMAC -> Bool
$c> :: BotanMAC -> BotanMAC -> Bool
> :: BotanMAC -> BotanMAC -> Bool
$c>= :: BotanMAC -> BotanMAC -> Bool
>= :: BotanMAC -> BotanMAC -> Bool
$cmax :: BotanMAC -> BotanMAC -> BotanMAC
max :: BotanMAC -> BotanMAC -> BotanMAC
$cmin :: BotanMAC -> BotanMAC -> BotanMAC
min :: BotanMAC -> BotanMAC -> BotanMAC
Ord, Ptr BotanMAC -> IO BotanMAC
Ptr BotanMAC -> Int -> IO BotanMAC
Ptr BotanMAC -> Int -> BotanMAC -> IO ()
Ptr BotanMAC -> BotanMAC -> IO ()
BotanMAC -> Int
(BotanMAC -> Int)
-> (BotanMAC -> Int)
-> (Ptr BotanMAC -> Int -> IO BotanMAC)
-> (Ptr BotanMAC -> Int -> BotanMAC -> IO ())
-> (forall b. Ptr b -> Int -> IO BotanMAC)
-> (forall b. Ptr b -> Int -> BotanMAC -> IO ())
-> (Ptr BotanMAC -> IO BotanMAC)
-> (Ptr BotanMAC -> BotanMAC -> IO ())
-> Storable BotanMAC
forall b. Ptr b -> Int -> IO BotanMAC
forall b. Ptr b -> Int -> BotanMAC -> IO ()
forall a.
(a -> Int)
-> (a -> Int)
-> (Ptr a -> Int -> IO a)
-> (Ptr a -> Int -> a -> IO ())
-> (forall b. Ptr b -> Int -> IO a)
-> (forall b. Ptr b -> Int -> a -> IO ())
-> (Ptr a -> IO a)
-> (Ptr a -> a -> IO ())
-> Storable a
$csizeOf :: BotanMAC -> Int
sizeOf :: BotanMAC -> Int
$calignment :: BotanMAC -> Int
alignment :: BotanMAC -> Int
$cpeekElemOff :: Ptr BotanMAC -> Int -> IO BotanMAC
peekElemOff :: Ptr BotanMAC -> Int -> IO BotanMAC
$cpokeElemOff :: Ptr BotanMAC -> Int -> BotanMAC -> IO ()
pokeElemOff :: Ptr BotanMAC -> Int -> BotanMAC -> IO ()
$cpeekByteOff :: forall b. Ptr b -> Int -> IO BotanMAC
peekByteOff :: forall b. Ptr b -> Int -> IO BotanMAC
$cpokeByteOff :: forall b. Ptr b -> Int -> BotanMAC -> IO ()
pokeByteOff :: forall b. Ptr b -> Int -> BotanMAC -> IO ()
$cpeek :: Ptr BotanMAC -> IO BotanMAC
peek :: Ptr BotanMAC -> IO BotanMAC
$cpoke :: Ptr BotanMAC -> BotanMAC -> IO ()
poke :: Ptr BotanMAC -> BotanMAC -> IO ()
Storable)

-- | Frees all resources of the MAC object
foreign import capi safe "botan/ffi.h &botan_mac_destroy"
    botan_mac_destroy
        :: FinalizerPtr BotanMACStruct

pattern BOTAN_MAC_CMAC
    ,   BOTAN_MAC_GMAC
    -- ,   BOTAN_MAC_CBC_MAC
    ,   BOTAN_MAC_HMAC
    -- ,   BOTAN_MAC_KMAC_128
    -- ,   BOTAN_MAC_KMAC_256
    ,   BOTAN_MAC_Poly1305
    ,   BOTAN_MAC_SipHash
    ,   BOTAN_MAC_X9_19_MAC
    ::  (Eq a, IsString a) => a

pattern $mBOTAN_MAC_CMAC :: forall {r} {a}.
(Eq a, IsString a) =>
a -> ((# #) -> r) -> ((# #) -> r) -> r
$bBOTAN_MAC_CMAC :: forall a. (Eq a, IsString a) => a
BOTAN_MAC_CMAC      = "CMAC"
pattern $mBOTAN_MAC_GMAC :: forall {r} {a}.
(Eq a, IsString a) =>
a -> ((# #) -> r) -> ((# #) -> r) -> r
$bBOTAN_MAC_GMAC :: forall a. (Eq a, IsString a) => a
BOTAN_MAC_GMAC      = "GMAC"
-- pattern BOTAN_MAC_CBC_MAC   = "CBC-MAC"
pattern $mBOTAN_MAC_HMAC :: forall {r} {a}.
(Eq a, IsString a) =>
a -> ((# #) -> r) -> ((# #) -> r) -> r
$bBOTAN_MAC_HMAC :: forall a. (Eq a, IsString a) => a
BOTAN_MAC_HMAC      = "HMAC"
-- pattern BOTAN_MAC_KMAC_128  = ...
-- pattern BOTAN_MAC_KMAC_256  = ...
pattern $mBOTAN_MAC_Poly1305 :: forall {r} {a}.
(Eq a, IsString a) =>
a -> ((# #) -> r) -> ((# #) -> r) -> r
$bBOTAN_MAC_Poly1305 :: forall a. (Eq a, IsString a) => a
BOTAN_MAC_Poly1305  = "Poly1305"
pattern $mBOTAN_MAC_SipHash :: forall {r} {a}.
(Eq a, IsString a) =>
a -> ((# #) -> r) -> ((# #) -> r) -> r
$bBOTAN_MAC_SipHash :: forall a. (Eq a, IsString a) => a
BOTAN_MAC_SipHash   = "SipHash"
pattern $mBOTAN_MAC_X9_19_MAC :: forall {r} {a}.
(Eq a, IsString a) =>
a -> ((# #) -> r) -> ((# #) -> r) -> r
$bBOTAN_MAC_X9_19_MAC :: forall a. (Eq a, IsString a) => a
BOTAN_MAC_X9_19_MAC = "X9.19-MAC"

-- | Initialize a message authentication code object
foreign import capi safe "botan/ffi.h botan_mac_init"
    botan_mac_init
        :: Ptr BotanMAC     -- ^ __mac__: mac object
        -> ConstPtr CChar   -- ^ __mac_name__: name of the hash function, e.g., "HMAC(SHA-384)"
        -> Word32           -- ^ __flags__: should be 0 in current API revision, all other uses are reserved
                            --   and return a negative value (error code)
        -> IO CInt          -- ^ 0 on success, a negative value on failure

-- | Writes the output length of the message authentication code to *output_length
foreign import capi safe "botan/ffi.h botan_mac_output_length"
    botan_mac_output_length
        :: BotanMAC     -- ^ __mac__: mac object
        -> Ptr CSize    -- ^ __output_length__: output buffer to hold the MAC output length
        -> IO CInt      -- ^ 0 on success, a negative value on failure

-- | Sets the key on the MAC
foreign import capi safe "botan/ffi.h botan_mac_set_key"
    botan_mac_set_key
        :: BotanMAC         -- ^ __mac__: mac object
        -> ConstPtr Word8   -- ^ __key__: buffer holding the key
        -> CSize            -- ^ __key_len__: size of the key buffer in bytes
        -> IO CInt          -- ^ 0 on success, a negative value on failure

-- | Sets the nonce on the MAC
foreign import capi safe "botan/ffi.h botan_mac_set_nonce"
    botan_mac_set_nonce
        :: BotanMAC         -- ^ __mac__: mac object
        -> ConstPtr Word8   -- ^ __nonce__: buffer holding the nonce
        -> CSize            -- ^ __nonce_len__: size of the nonce buffer in bytes
        -> IO CInt          -- ^ 0 on success, a negative value on failure

-- | Send more input to the message authentication code
foreign import capi safe "botan/ffi.h botan_mac_update"
    botan_mac_update
        :: BotanMAC         -- ^ __mac__: mac object
        -> ConstPtr Word8   -- ^ __buf__: input buffer
        -> CSize            -- ^ __len__: number of bytes to read from the input buffer
        -> IO CInt          -- ^ 0 on success, a negative value on failure

{- |
Finalizes the MAC computation and writes the output to
out[0:botan_mac_output_length()] then reinitializes for computing
another MAC as if botan_mac_clear had been called.
-}
foreign import capi safe "botan/ffi.h botan_mac_final"
    botan_mac_final
        :: BotanMAC     -- ^ __mac__: mac object
        -> Ptr Word8    -- ^ __out[]__: output buffer
        -> IO CInt      -- ^ 0 on success, a negative value on failure

{- |
Reinitializes the state of the MAC computation. A MAC can
be computed (with update/final) immediately.
-}
foreign import capi safe "botan/ffi.h botan_mac_clear"
    botan_mac_clear
        :: BotanMAC -- ^ __mac__: mac object
        -> IO CInt  -- ^ 0 on success, a negative value on failure

-- | Get the name of this MAC
foreign import capi safe "botan/ffi.h botan_mac_name"
    botan_mac_name
        :: BotanMAC     -- ^ __mac__: the object to read
        -> Ptr CChar    -- ^ __name__: output buffer
        -> Ptr CSize    -- ^ __name_len__: on input, the length of buffer, on success the number of bytes written
        -> IO CInt      -- ^ 0 on success, a negative value on failure

-- | Get the key length limits of this auth code
foreign import capi safe "botan/ffi.h botan_mac_get_keyspec"
    botan_mac_get_keyspec
        :: BotanMAC     -- ^ __mac__: the object to read
        -> Ptr CSize    -- ^ __out_minimum_keylength__: if non-NULL, will be set to minimum keylength of MAC
        -> Ptr CSize    -- ^ __out_maximum_keylength__: if non-NULL, will be set to maximum keylength of MAC
        -> Ptr CSize    -- ^ __out_keylength_modulo__: if non-NULL will be set to byte multiple of valid keys
        -> IO CInt      -- ^ 0 on success, a negative value on failure