{-# LINE 1 "src/Botan/Bindings/Cipher.hsc" #-}
{-|
Module      : Botan.Bindings.Cipher
Description : Symmetric cipher modes
Copyright   : (c) 2023-2024, Apotheca Labs
              (c) 2024-2025, Haskell Foundation
License     : BSD-3-Clause
Maintainer  : joris@well-typed.com, leo@apotheca.io
Stability   : experimental
Portability : POSIX

A block cipher by itself, is only able to securely encrypt a single
data block. To be able to securely encrypt data of arbitrary length,
a mode of operation applies the block cipher’s single block operation
repeatedly to encrypt an entire message.
-}

{-# LANGUAGE CApiFFI #-}
{-# LANGUAGE OverloadedStrings #-}

module Botan.Bindings.Cipher (
    BotanCipherStruct
  , BotanCipher (..)
  , botan_cipher_destroy
  , pattern BOTAN_CIPHER_MODE_CBC
  , pattern BOTAN_CIPHER_MODE_CFB
  , pattern BOTAN_CIPHER_MODE_XTS

  , pattern BOTAN_CBC_PADDING_PKCS7
  , pattern BOTAN_CBC_PADDING_ONE_AND_ZEROS
  , pattern BOTAN_CBC_PADDING_X9_23
  , pattern BOTAN_CBC_PADDING_ESP
  , pattern BOTAN_CBC_PADDING_CTS
  , pattern BOTAN_CBC_PADDING_NO_PADDING

  , pattern BOTAN_AEAD_CHACHA20POLY1305

  , pattern BOTAN_AEAD_MODE_GCM
  , pattern BOTAN_AEAD_MODE_OCB
  , pattern BOTAN_AEAD_MODE_EAX
  , pattern BOTAN_AEAD_MODE_SIV
  , pattern BOTAN_AEAD_MODE_CCM

  , pattern BOTAN_CIPHER_INIT_FLAG_MASK_DIRECTION
  , pattern BOTAN_CIPHER_INIT_FLAG_ENCRYPT
  , pattern BOTAN_CIPHER_INIT_FLAG_DECRYPT
  , botan_cipher_init
  , botan_cipher_name
  , botan_cipher_output_length
  , botan_cipher_valid_nonce_length
  , botan_cipher_get_tag_length
  , botan_cipher_get_default_nonce_length
  , botan_cipher_get_update_granularity
  , botan_cipher_get_ideal_update_granularity
  , botan_cipher_query_keylen
  , botan_cipher_get_keyspec
  , botan_cipher_set_key
  , botan_cipher_reset
  , botan_cipher_set_associated_data
  , botan_cipher_start
  , pattern BOTAN_CIPHER_UPDATE_FLAG_NONE
  , pattern BOTAN_CIPHER_UPDATE_FLAG_FINAL
  , botan_cipher_update
  , botan_cipher_clear
  ) where

import Botan.Bindings.ConstPtr
import Data.String
import Data.Word
import Foreign.C.Types
import Foreign.ForeignPtr
import Foreign.Ptr
import Foreign.Storable



-- | Opaque Cipher struct
data {-# CTYPE "botan/ffi.h" "struct botan_cipher_struct" #-} BotanCipherStruct

-- | Botan Cipher object
newtype {-# CTYPE "botan/ffi.h" "botan_cipher_t" #-} BotanCipher
    = MkBotanCipher { BotanCipher -> Ptr BotanCipherStruct
ptr :: Ptr BotanCipherStruct }
        deriving newtype (BotanCipher -> BotanCipher -> Bool
(BotanCipher -> BotanCipher -> Bool)
-> (BotanCipher -> BotanCipher -> Bool) -> Eq BotanCipher
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: BotanCipher -> BotanCipher -> Bool
== :: BotanCipher -> BotanCipher -> Bool
$c/= :: BotanCipher -> BotanCipher -> Bool
/= :: BotanCipher -> BotanCipher -> Bool
Eq, Eq BotanCipher
Eq BotanCipher =>
(BotanCipher -> BotanCipher -> Ordering)
-> (BotanCipher -> BotanCipher -> Bool)
-> (BotanCipher -> BotanCipher -> Bool)
-> (BotanCipher -> BotanCipher -> Bool)
-> (BotanCipher -> BotanCipher -> Bool)
-> (BotanCipher -> BotanCipher -> BotanCipher)
-> (BotanCipher -> BotanCipher -> BotanCipher)
-> Ord BotanCipher
BotanCipher -> BotanCipher -> Bool
BotanCipher -> BotanCipher -> Ordering
BotanCipher -> BotanCipher -> BotanCipher
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 :: BotanCipher -> BotanCipher -> Ordering
compare :: BotanCipher -> BotanCipher -> Ordering
$c< :: BotanCipher -> BotanCipher -> Bool
< :: BotanCipher -> BotanCipher -> Bool
$c<= :: BotanCipher -> BotanCipher -> Bool
<= :: BotanCipher -> BotanCipher -> Bool
$c> :: BotanCipher -> BotanCipher -> Bool
> :: BotanCipher -> BotanCipher -> Bool
$c>= :: BotanCipher -> BotanCipher -> Bool
>= :: BotanCipher -> BotanCipher -> Bool
$cmax :: BotanCipher -> BotanCipher -> BotanCipher
max :: BotanCipher -> BotanCipher -> BotanCipher
$cmin :: BotanCipher -> BotanCipher -> BotanCipher
min :: BotanCipher -> BotanCipher -> BotanCipher
Ord, Ptr BotanCipher -> IO BotanCipher
Ptr BotanCipher -> Int -> IO BotanCipher
Ptr BotanCipher -> Int -> BotanCipher -> IO ()
Ptr BotanCipher -> BotanCipher -> IO ()
BotanCipher -> Int
(BotanCipher -> Int)
-> (BotanCipher -> Int)
-> (Ptr BotanCipher -> Int -> IO BotanCipher)
-> (Ptr BotanCipher -> Int -> BotanCipher -> IO ())
-> (forall b. Ptr b -> Int -> IO BotanCipher)
-> (forall b. Ptr b -> Int -> BotanCipher -> IO ())
-> (Ptr BotanCipher -> IO BotanCipher)
-> (Ptr BotanCipher -> BotanCipher -> IO ())
-> Storable BotanCipher
forall b. Ptr b -> Int -> IO BotanCipher
forall b. Ptr b -> Int -> BotanCipher -> 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 :: BotanCipher -> Int
sizeOf :: BotanCipher -> Int
$calignment :: BotanCipher -> Int
alignment :: BotanCipher -> Int
$cpeekElemOff :: Ptr BotanCipher -> Int -> IO BotanCipher
peekElemOff :: Ptr BotanCipher -> Int -> IO BotanCipher
$cpokeElemOff :: Ptr BotanCipher -> Int -> BotanCipher -> IO ()
pokeElemOff :: Ptr BotanCipher -> Int -> BotanCipher -> IO ()
$cpeekByteOff :: forall b. Ptr b -> Int -> IO BotanCipher
peekByteOff :: forall b. Ptr b -> Int -> IO BotanCipher
$cpokeByteOff :: forall b. Ptr b -> Int -> BotanCipher -> IO ()
pokeByteOff :: forall b. Ptr b -> Int -> BotanCipher -> IO ()
$cpeek :: Ptr BotanCipher -> IO BotanCipher
peek :: Ptr BotanCipher -> IO BotanCipher
$cpoke :: Ptr BotanCipher -> BotanCipher -> IO ()
poke :: Ptr BotanCipher -> BotanCipher -> IO ()
Storable)

-- | Destroy the cipher object
foreign import capi safe "botan/ffi.h &botan_cipher_destroy"
    botan_cipher_destroy
        :: FinalizerPtr BotanCipherStruct

pattern BOTAN_CIPHER_MODE_CBC
    ,   BOTAN_CIPHER_MODE_CFB
    ,   BOTAN_CIPHER_MODE_XTS
    ::  (Eq a, IsString a) => a

pattern $bBOTAN_CIPHER_MODE_CBC :: forall a. (Eq a, IsString a) => a
$mBOTAN_CIPHER_MODE_CBC :: forall {r} {a}.
(Eq a, IsString a) =>
a -> ((# #) -> r) -> ((# #) -> r) -> r
BOTAN_CIPHER_MODE_CBC = "CBC"
pattern $bBOTAN_CIPHER_MODE_CFB :: forall a. (Eq a, IsString a) => a
$mBOTAN_CIPHER_MODE_CFB :: forall {r} {a}.
(Eq a, IsString a) =>
a -> ((# #) -> r) -> ((# #) -> r) -> r
BOTAN_CIPHER_MODE_CFB = "CFB"
pattern $bBOTAN_CIPHER_MODE_XTS :: forall a. (Eq a, IsString a) => a
$mBOTAN_CIPHER_MODE_XTS :: forall {r} {a}.
(Eq a, IsString a) =>
a -> ((# #) -> r) -> ((# #) -> r) -> r
BOTAN_CIPHER_MODE_XTS = "XTS"

pattern BOTAN_CBC_PADDING_PKCS7
    ,   BOTAN_CBC_PADDING_ONE_AND_ZEROS
    ,   BOTAN_CBC_PADDING_X9_23
    ,   BOTAN_CBC_PADDING_ESP
    ,   BOTAN_CBC_PADDING_CTS
    ,   BOTAN_CBC_PADDING_NO_PADDING
    ::  (Eq a, IsString a) => a

pattern $bBOTAN_CBC_PADDING_PKCS7 :: forall a. (Eq a, IsString a) => a
$mBOTAN_CBC_PADDING_PKCS7 :: forall {r} {a}.
(Eq a, IsString a) =>
a -> ((# #) -> r) -> ((# #) -> r) -> r
BOTAN_CBC_PADDING_PKCS7             = "PKCS7"
pattern $bBOTAN_CBC_PADDING_ONE_AND_ZEROS :: forall a. (Eq a, IsString a) => a
$mBOTAN_CBC_PADDING_ONE_AND_ZEROS :: forall {r} {a}.
(Eq a, IsString a) =>
a -> ((# #) -> r) -> ((# #) -> r) -> r
BOTAN_CBC_PADDING_ONE_AND_ZEROS    = "OneAndZeros"
pattern $bBOTAN_CBC_PADDING_X9_23 :: forall a. (Eq a, IsString a) => a
$mBOTAN_CBC_PADDING_X9_23 :: forall {r} {a}.
(Eq a, IsString a) =>
a -> ((# #) -> r) -> ((# #) -> r) -> r
BOTAN_CBC_PADDING_X9_23             = "X9.23"
pattern $bBOTAN_CBC_PADDING_ESP :: forall a. (Eq a, IsString a) => a
$mBOTAN_CBC_PADDING_ESP :: forall {r} {a}.
(Eq a, IsString a) =>
a -> ((# #) -> r) -> ((# #) -> r) -> r
BOTAN_CBC_PADDING_ESP               = "ESP"
pattern $bBOTAN_CBC_PADDING_CTS :: forall a. (Eq a, IsString a) => a
$mBOTAN_CBC_PADDING_CTS :: forall {r} {a}.
(Eq a, IsString a) =>
a -> ((# #) -> r) -> ((# #) -> r) -> r
BOTAN_CBC_PADDING_CTS               = "CTS"
pattern $bBOTAN_CBC_PADDING_NO_PADDING :: forall a. (Eq a, IsString a) => a
$mBOTAN_CBC_PADDING_NO_PADDING :: forall {r} {a}.
(Eq a, IsString a) =>
a -> ((# #) -> r) -> ((# #) -> r) -> r
BOTAN_CBC_PADDING_NO_PADDING        = "NoPadding"

pattern BOTAN_AEAD_CHACHA20POLY1305
    ::  (Eq a, IsString a) => a

pattern $bBOTAN_AEAD_CHACHA20POLY1305 :: forall a. (Eq a, IsString a) => a
$mBOTAN_AEAD_CHACHA20POLY1305 :: forall {r} {a}.
(Eq a, IsString a) =>
a -> ((# #) -> r) -> ((# #) -> r) -> r
BOTAN_AEAD_CHACHA20POLY1305 = "ChaCha20Poly1305"

pattern BOTAN_AEAD_MODE_GCM
    ,   BOTAN_AEAD_MODE_OCB
    ,   BOTAN_AEAD_MODE_EAX
    ,   BOTAN_AEAD_MODE_SIV
    ,   BOTAN_AEAD_MODE_CCM
    ::  (Eq a, IsString a) => a

pattern $bBOTAN_AEAD_MODE_GCM :: forall a. (Eq a, IsString a) => a
$mBOTAN_AEAD_MODE_GCM :: forall {r} {a}.
(Eq a, IsString a) =>
a -> ((# #) -> r) -> ((# #) -> r) -> r
BOTAN_AEAD_MODE_GCM         = "GCM"
pattern $bBOTAN_AEAD_MODE_OCB :: forall a. (Eq a, IsString a) => a
$mBOTAN_AEAD_MODE_OCB :: forall {r} {a}.
(Eq a, IsString a) =>
a -> ((# #) -> r) -> ((# #) -> r) -> r
BOTAN_AEAD_MODE_OCB         = "OCB"
pattern $bBOTAN_AEAD_MODE_EAX :: forall a. (Eq a, IsString a) => a
$mBOTAN_AEAD_MODE_EAX :: forall {r} {a}.
(Eq a, IsString a) =>
a -> ((# #) -> r) -> ((# #) -> r) -> r
BOTAN_AEAD_MODE_EAX         = "EAX"
pattern $bBOTAN_AEAD_MODE_SIV :: forall a. (Eq a, IsString a) => a
$mBOTAN_AEAD_MODE_SIV :: forall {r} {a}.
(Eq a, IsString a) =>
a -> ((# #) -> r) -> ((# #) -> r) -> r
BOTAN_AEAD_MODE_SIV         = "SIV"
pattern $bBOTAN_AEAD_MODE_CCM :: forall a. (Eq a, IsString a) => a
$mBOTAN_AEAD_MODE_CCM :: forall {r} {a}.
(Eq a, IsString a) =>
a -> ((# #) -> r) -> ((# #) -> r) -> r
BOTAN_AEAD_MODE_CCM         = "CCM"

pattern BOTAN_CIPHER_INIT_FLAG_MASK_DIRECTION
    ,   BOTAN_CIPHER_INIT_FLAG_ENCRYPT
    ,   BOTAN_CIPHER_INIT_FLAG_DECRYPT
    ::  (Eq a, Num a) => a
pattern $bBOTAN_CIPHER_INIT_FLAG_MASK_DIRECTION :: forall a. (Eq a, Num a) => a
$mBOTAN_CIPHER_INIT_FLAG_MASK_DIRECTION :: forall {r} {a}.
(Eq a, Num a) =>
a -> ((# #) -> r) -> ((# #) -> r) -> r
BOTAN_CIPHER_INIT_FLAG_MASK_DIRECTION = 1
{-# LINE 136 "src/Botan/Bindings/Cipher.hsc" #-}
pattern BOTAN_CIPHER_INIT_FLAG_ENCRYPT        = 0
{-# LINE 137 "src/Botan/Bindings/Cipher.hsc" #-}
pattern BOTAN_CIPHER_INIT_FLAG_DECRYPT        = 1
{-# LINE 138 "src/Botan/Bindings/Cipher.hsc" #-}

-- | Initialize a cipher object
foreign import capi safe "botan/ffi.h botan_cipher_init"
    botan_cipher_init
        :: Ptr BotanCipher  -- ^ __cipher__
        -> ConstPtr CChar   -- ^ __name__
        -> Word32           -- ^ __flags__
        -> IO CInt

-- | Return the name of the cipher object
foreign import capi safe "botan/ffi.h botan_cipher_name"
    botan_cipher_name
        :: BotanCipher  -- ^ __cipher__
        -> Ptr CChar    -- ^ __name__
        -> Ptr CSize    -- ^ __name_len__
        -> IO CInt

-- | Return the output length of this cipher, for a particular input length.
foreign import capi safe "botan/ffi.h botan_cipher_output_length"
    botan_cipher_output_length
        :: BotanCipher  -- ^ __cipher__
        -> CSize        -- ^ __in_len__
        -> Ptr CSize    -- ^ __out_len__
        -> IO CInt

-- | Return if the specified nonce length is valid for this cipher
--   (0 / SUCCESS if valid, 1 / INVALID_IDENTIFIER if not)
foreign import capi safe "botan/ffi.h botan_cipher_valid_nonce_length"
    botan_cipher_valid_nonce_length
        :: BotanCipher  -- ^ __cipher__
        -> CSize        -- ^ __nl__
        -> IO CInt

-- | Get the tag length of the cipher (0 for non-AEAD modes)
foreign import capi safe "botan/ffi.h botan_cipher_get_tag_length"
    botan_cipher_get_tag_length
        :: BotanCipher  -- ^ __cipher__
        -> Ptr CSize    -- ^ __tag_size__
        -> IO CInt

-- | Get the default nonce length of this cipher
foreign import capi safe "botan/ffi.h botan_cipher_get_default_nonce_length"
    botan_cipher_get_default_nonce_length
        :: BotanCipher  -- ^ __cipher__
        -> Ptr CSize    -- ^ __nl__
        -> IO CInt

-- | Return the update granularity of the cipher;
--   botan_cipher_update must be called with blocks of this size, except for the final.
foreign import capi safe "botan/ffi.h botan_cipher_get_update_granularity"
    botan_cipher_get_update_granularity
        :: BotanCipher  -- ^ __cipher__
        -> Ptr CSize    -- ^ __ug__
        -> IO CInt

{-
Return the ideal update granularity of the cipher.
This is some multiple of the update granularity,
reflecting possibilities for optimization.
-}
foreign import capi safe "botan/ffi.h botan_cipher_get_ideal_update_granularity"
    botan_cipher_get_ideal_update_granularity
        :: BotanCipher  -- ^ __cipher__
        -> Ptr CSize    -- ^ __ug__
        -> IO CInt

-- | Get information about the key lengths. Prefer botan_cipher_get_keyspec
foreign import capi safe "botan/ffi.h botan_cipher_query_keylen"
    botan_cipher_query_keylen
        :: BotanCipher  -- ^ __cipher__
        -> Ptr CSize    -- ^ __out_minimum_keylength__
        -> Ptr CSize    -- ^ __out_maximum_keylength__
        -> IO CInt

-- | Get information about the supported key lengths.
foreign import capi safe "botan/ffi.h botan_cipher_get_keyspec"
    botan_cipher_get_keyspec
        :: BotanCipher  -- ^ __cipher__
        -> Ptr CSize    -- ^ __min_keylen__
        -> Ptr CSize    -- ^ __max_keylen__
        -> Ptr CSize    -- ^ __mod_keylen__
        -> IO CInt

-- | Set the key for this cipher object
foreign import capi safe "botan/ffi.h botan_cipher_set_key"
    botan_cipher_set_key
        :: BotanCipher      -- ^ __cipher__
        -> ConstPtr Word8   -- ^ __key__
        -> CSize            -- ^ __key_len__
        -> IO CInt

{-
Reset the message specific state for this cipher.
Without resetting the keys, this resets the nonce, and any state
associated with any message bits that have been processed so far.

It is conceptually equivalent to calling botan_cipher_clear followed
by botan_cipher_set_key with the original key.
-}
foreign import capi safe "botan/ffi.h botan_cipher_reset"
    botan_cipher_reset
        :: BotanCipher -- ^ __cipher__
        -> IO CInt

-- | Set the associated data. Will fail if cipher is not an AEAD
foreign import capi safe "botan/ffi.h botan_cipher_set_associated_data"
    botan_cipher_set_associated_data
        :: BotanCipher      -- ^ __cipher__
        -> ConstPtr Word8   -- ^ __ad__
        -> CSize            -- ^ __ad_len__
        -> IO CInt

-- | Begin processing a new message using the provided nonce
foreign import capi safe "botan/ffi.h botan_cipher_start"
    botan_cipher_start
        :: BotanCipher      -- ^ __cipher__
        -> ConstPtr Word8   -- ^ __nonce__
        -> CSize            -- ^ __nonce_len__
        -> IO CInt

pattern BOTAN_CIPHER_UPDATE_FLAG_NONE
    ,   BOTAN_CIPHER_UPDATE_FLAG_FINAL
    ::  (Eq a, Num a) => a
pattern $bBOTAN_CIPHER_UPDATE_FLAG_NONE :: forall a. (Eq a, Num a) => a
$mBOTAN_CIPHER_UPDATE_FLAG_NONE :: forall {r} {a}.
(Eq a, Num a) =>
a -> ((# #) -> r) -> ((# #) -> r) -> r
BOTAN_CIPHER_UPDATE_FLAG_NONE   = 0
pattern $bBOTAN_CIPHER_UPDATE_FLAG_FINAL :: forall a. (Eq a, Num a) => a
$mBOTAN_CIPHER_UPDATE_FLAG_FINAL :: forall {r} {a}.
(Eq a, Num a) =>
a -> ((# #) -> r) -> ((# #) -> r) -> r
BOTAN_CIPHER_UPDATE_FLAG_FINAL  = 1
{-# LINE 263 "src/Botan/Bindings/Cipher.hsc" #-}

-- | Encrypt some data
foreign import capi safe "botan/ffi.h botan_cipher_update"
    botan_cipher_update
        :: BotanCipher      -- ^ __cipher__
        -> Word32           -- ^ __flags__
        -> Ptr Word8        -- ^ __output[]__
        -> CSize            -- ^ __output_size__
        -> Ptr CSize        -- ^ __output_written__
        -> ConstPtr Word8   -- ^ __input_bytes[]__
        -> CSize            -- ^ __input_size__
        -> Ptr CSize        -- ^ __input_consumed__
        -> IO CInt

-- | Reset the key, nonce, AD and all other state on this cipher object
foreign import capi safe "botan/ffi.h botan_cipher_clear"
    botan_cipher_clear
        :: BotanCipher -- ^ __hash__
        -> IO CInt