{-|
Module      : Botan.Low.Cipher
Description : Symmetric cipher modes
Copyright   : (c) Leo D, 2023
License     : BSD-3-Clause
Maintainer  : 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.
-}

module Botan.Low.Cipher
(
 
-- * Cipher
-- $introduction

-- * Usage
-- $usage

  Cipher(..)
, CipherName(..)
, CipherKey(..)
, CipherNonce(..)
, CipherInitFlags(..)
, pattern MaskDirection
, pattern Encrypt
, pattern Decrypt
, CipherUpdateFlags(..)
, pattern CipherUpdate
, pattern CipherFinal
, withCipher
, cipherInit
, cipherDestroy
, cipherName
, cipherOutputLength
, cipherValidNonceLength
, cipherGetTagLength
, cipherGetDefaultNonceLength
, cipherGetUpdateGranularity
, cipherGetIdealUpdateGranularity
, cipherQueryKeylen
, cipherGetKeyspec
, cipherSetKey
, cipherReset
, cipherSetAssociatedData
, cipherStart
, cipherUpdate
, cipherEncrypt
, cipherDecrypt
, cipherClear

-- * Cipher modes
, CipherMode(..)
, cbcMode
, cfbMode
, cfbModeWith
, xtsMode

-- ** CBC padding
, CBCPaddingName(..)
, pattern PKCS7
, pattern OneAndZeros
, pattern X9_23
, pattern ESP
, pattern CTS
, pattern NoPadding

-- * AEAD
, AEADName(..)
, pattern ChaCha20Poly1305
, chaCha20Poly1305

-- * AEAD modes
, AEADMode(..)
, gcmMode
, gcmModeWith
, ocbMode
, ocbModeWith
, eaxMode
, eaxModeWith
, sivMode
, ccmMode
, ccmModeWith

-- * Convenience
, cipherEncryptOnline
, cipherDecryptOnline
, cipherModes
, cbcPaddings
, aeads
, allCiphers

) where

import qualified Data.ByteString as ByteString

import Botan.Bindings.Cipher

import Botan.Low.BlockCipher
import Botan.Low.Error
import Botan.Low.Make
import Botan.Low.Prelude
import Botan.Low.Remake

import Botan.Low.RNG

{- $introduction

A `cipher` mode is a cryptographic algorithm suitable for encrypting and
decrypting large quantities of arbitrarily-sized data. An `aead` is a cipher
mode that also used to provide authentication of the ciphertext, potentially
with plaintext `associated data`.

-}

{- $usage

Unless you need a specific `cipher` or `aead`, it is strongly recommended that you use the `cbcMode AES256 PKCS7` and `gcmMode AES256` (or `ChaCha20Poly1305`) algorithms respectively.

> import Botan.Low.Cipher
> encrypter <- cipherInit ChaCha20Poly1305 Encrypt

To use a cipher, we first need to generate (if we haven't already) a secret key.

> import Botan.Low.RNG
> rng <- rngInit "user"
> -- We will use the maximum key size; ChaCha20Poly1305 keys are always 32 bytes
> (_,keySize,_) <- cipherGetKeyspec encrypter
> -- Block cipher keys are randomly generated
> key <- rngGet rng keySize

After the key is generated, we must set it as the cipher key:

> cipherSetKey encrypter key

If the cipher is an `aead`, we may also set the `associated data`:

> cipherSetAssociatedData encrypter "Fee fi fo fum!"

To ensure that the key is not leaked, we should generate a new nonce for every encryption. The range of allowed nonce sizes depends on the specific algorithm.

> import Botan.Low.RNG
> -- The default ChaCha20Poly1305 nonce is always 12 bytes.
> nonceSize <- cipherGetDefaultNonceLength encrypter
> nonce <- rngGet rng nonceSize

To encrypt a message, it must be a multiple of the block size. If the cipher was an aead, the authentication tag will automatically be included in the ciphertext

> -- Rarely, some cipher modes require that the message size be aligned to the block size
> -- Consult algorithm-specific documentation if this occurs. 
> message = "I smell the blood of an Englishman!"
> cipherStart encrypter nonce
> ciphertext <- cipherEncrypt encrypter message

To decrypt a message, we run the same process with a decrypter, using the same `key` and `nonce` to decode the `ciphertext`:

> decrypter <- cipherInit ChaCha20Poly1305 Decrypt
> cipherSetKey decrypter key
> cipherSetAssociatedData decrypter "Fee fi fo fum!"
> cipherStart decrypter nonce
> plaintext <- cipherDecrypt decrypter ciphertext
> message == plaintext -- True

You can completely clear a cipher's state, leaving it ready for reuse:

> cipherClear encrypter
> -- You'll have to set the key, nonce, (and ad, if aead) again.
> cipherSetKey encrypter anotherKey
> cipherStart encrypter anotherNonce
> cipherSetAssociatedData encrypter anotherAD
> -- Process another message
> anotherCiphertext <- cipherEncrypt encrypter anotherMessage

If you are encrypting or decrypting multiple messages with the same key, you can reset the cipher instead of clearing it, leaving the key set:

> cipherClear encrypter
> -- This is equivalent to calling cipherClear followed by cipherSetKey with the original key.
> -- You'll have to set the nonce  (and ad, if aead) again, but not the key.
> cipherStart encrypter anotherNonce
> cipherSetAssociatedData encrypter anotherAD
> -- Process another message with the same key
> anotherCiphertext <- cipherEncrypt encrypter anotherMessage

-}

-- NOTE: This is *symmetric* ciphers  For the 'raw' interface to ECB mode block ciphers, see BlockCipher.hs

newtype Cipher = MkCipher { Cipher -> ForeignPtr BotanCipherStruct
getCipherForeignPtr :: ForeignPtr BotanCipherStruct }

newCipher      :: BotanCipher -> IO Cipher
withCipher     :: Cipher -> (BotanCipher -> IO a) -> IO a
-- | Destroy the cipher object immediately
cipherDestroy  :: Cipher -> IO ()
createCipher   :: (Ptr BotanCipher -> IO CInt) -> IO Cipher
(BotanCipher -> IO Cipher
newCipher, Cipher -> (BotanCipher -> IO a) -> IO a
withCipher, Cipher -> IO ()
cipherDestroy, (Ptr BotanCipher -> IO CInt) -> IO Cipher
createCipher, (Ptr BotanCipher -> Ptr CSize -> IO CInt) -> IO [Cipher]
_)
    = (Ptr BotanCipherStruct -> BotanCipher)
-> (BotanCipher -> Ptr BotanCipherStruct)
-> (ForeignPtr BotanCipherStruct -> Cipher)
-> (Cipher -> ForeignPtr BotanCipherStruct)
-> FinalizerPtr BotanCipherStruct
-> (BotanCipher -> IO Cipher,
    Cipher -> (BotanCipher -> IO a) -> IO a, Cipher -> IO (),
    (Ptr BotanCipher -> IO CInt) -> IO Cipher,
    (Ptr BotanCipher -> Ptr CSize -> IO CInt) -> IO [Cipher])
forall botan struct object a.
Storable botan =>
(Ptr struct -> botan)
-> (botan -> Ptr struct)
-> (ForeignPtr struct -> object)
-> (object -> ForeignPtr struct)
-> FinalizerPtr struct
-> (botan -> IO object, object -> (botan -> IO a) -> IO a,
    object -> IO (), (Ptr botan -> IO CInt) -> IO object,
    (Ptr botan -> Ptr CSize -> IO CInt) -> IO [object])
mkBindings
        Ptr BotanCipherStruct -> BotanCipher
MkBotanCipher BotanCipher -> Ptr BotanCipherStruct
runBotanCipher
        ForeignPtr BotanCipherStruct -> Cipher
MkCipher Cipher -> ForeignPtr BotanCipherStruct
getCipherForeignPtr
        FinalizerPtr BotanCipherStruct
botan_cipher_destroy

type CipherInitFlags = Word32
type CipherUpdateFlags = Int
type CipherNonce = ByteString
type CipherKey = ByteString

type CipherName = ByteString

type CipherMode = ByteString

type CBCPaddingName = ByteString

pattern PKCS7
    ,   OneAndZeros
    ,   X9_23
    ,   ESP
    ,   CTS
    ,   NoPadding
    ::  CBCPaddingName

pattern $mPKCS7 :: forall {r}. AEADName -> ((# #) -> r) -> ((# #) -> r) -> r
$bPKCS7 :: AEADName
PKCS7       = BOTAN_CBC_PADDING_PKCS7
pattern $mOneAndZeros :: forall {r}. AEADName -> ((# #) -> r) -> ((# #) -> r) -> r
$bOneAndZeros :: AEADName
OneAndZeros = BOTAN_CBC_PADDING_ONE_AND_ZEROS
pattern $mX9_23 :: forall {r}. AEADName -> ((# #) -> r) -> ((# #) -> r) -> r
$bX9_23 :: AEADName
X9_23       = BOTAN_CBC_PADDING_X9_23
pattern $mESP :: forall {r}. AEADName -> ((# #) -> r) -> ((# #) -> r) -> r
$bESP :: AEADName
ESP         = BOTAN_CBC_PADDING_ESP
pattern $mCTS :: forall {r}. AEADName -> ((# #) -> r) -> ((# #) -> r) -> r
$bCTS :: AEADName
CTS         = BOTAN_CBC_PADDING_CTS
pattern $mNoPadding :: forall {r}. AEADName -> ((# #) -> r) -> ((# #) -> r) -> r
$bNoPadding :: AEADName
NoPadding   = BOTAN_CBC_PADDING_NO_PADDING

cbcMode :: BlockCipherName -> CBCPaddingName -> CipherName 
cbcMode :: AEADName -> AEADName -> AEADName
cbcMode AEADName
bc AEADName
padding = AEADName
bc AEADName -> AEADName -> AEADName
forall a. (IsString a, Semigroup a) => a -> a -> a
// AEADName
forall a. (Eq a, IsString a) => a
BOTAN_CIPHER_MODE_CBC AEADName -> AEADName -> AEADName
forall a. (IsString a, Semigroup a) => a -> a -> a
// AEADName
padding

cfbMode :: BlockCipherName -> CipherName 
cfbMode :: AEADName -> AEADName
cfbMode AEADName
bc = AEADName
bc AEADName -> AEADName -> AEADName
forall a. (IsString a, Semigroup a) => a -> a -> a
// AEADName
forall a. (Eq a, IsString a) => a
BOTAN_CIPHER_MODE_CFB

cfbModeWith :: BlockCipherName -> Int -> CipherName 
cfbModeWith :: AEADName -> Int -> AEADName
cfbModeWith AEADName
bc Int
feedbackSz = AEADName -> AEADName
cfbMode AEADName
bc AEADName -> AEADName -> AEADName
forall a. (IsString a, Semigroup a) => a -> a -> a
/$ Int -> AEADName
forall a. Show a => a -> AEADName
showBytes Int
feedbackSz

xtsMode :: BlockCipherName -> CipherName
xtsMode :: AEADName -> AEADName
xtsMode AEADName
bc = AEADName
bc AEADName -> AEADName -> AEADName
forall a. (IsString a, Semigroup a) => a -> a -> a
// AEADName
forall a. (Eq a, IsString a) => a
BOTAN_CIPHER_MODE_XTS

type AEADName = CipherName

pattern ChaCha20Poly1305 :: CipherName
pattern $mChaCha20Poly1305 :: forall {r}. AEADName -> ((# #) -> r) -> ((# #) -> r) -> r
$bChaCha20Poly1305 :: AEADName
ChaCha20Poly1305 = BOTAN_AEAD_CHACHA20POLY1305

chaCha20Poly1305 :: AEADName
chaCha20Poly1305 :: AEADName
chaCha20Poly1305 = AEADName
forall a. (Eq a, IsString a) => a
BOTAN_AEAD_CHACHA20POLY1305

type AEADMode = ByteString

gcmMode :: BlockCipher128Name -> AEADName
gcmMode :: AEADName -> AEADName
gcmMode AEADName
bc = AEADName
bc AEADName -> AEADName -> AEADName
forall a. (IsString a, Semigroup a) => a -> a -> a
// AEADName
forall a. (Eq a, IsString a) => a
BOTAN_AEAD_MODE_GCM

gcmModeWith :: BlockCipher128Name -> Int -> AEADName
gcmModeWith :: AEADName -> Int -> AEADName
gcmModeWith AEADName
bc Int
tagSz = AEADName -> AEADName
gcmMode AEADName
bc AEADName -> AEADName -> AEADName
forall a. (IsString a, Semigroup a) => a -> a -> a
/$ Int -> AEADName
forall a. Show a => a -> AEADName
showBytes Int
tagSz

ocbMode :: BlockCipher128Name -> AEADName
ocbMode :: AEADName -> AEADName
ocbMode AEADName
bc = AEADName
bc AEADName -> AEADName -> AEADName
forall a. (IsString a, Semigroup a) => a -> a -> a
// AEADName
forall a. (Eq a, IsString a) => a
BOTAN_AEAD_MODE_OCB

ocbModeWith :: BlockCipher128Name -> Int -> AEADName
ocbModeWith :: AEADName -> Int -> AEADName
ocbModeWith AEADName
bc Int
tagSz = AEADName -> AEADName
ocbMode AEADName
bc AEADName -> AEADName -> AEADName
forall a. (IsString a, Semigroup a) => a -> a -> a
/$ Int -> AEADName
forall a. Show a => a -> AEADName
showBytes Int
tagSz

eaxMode :: BlockCipherName -> AEADName
eaxMode :: AEADName -> AEADName
eaxMode AEADName
bc = AEADName
bc AEADName -> AEADName -> AEADName
forall a. (IsString a, Semigroup a) => a -> a -> a
// AEADName
forall a. (Eq a, IsString a) => a
BOTAN_AEAD_MODE_EAX

eaxModeWith :: BlockCipherName -> Int -> AEADName
eaxModeWith :: AEADName -> Int -> AEADName
eaxModeWith AEADName
bc Int
tagSz = AEADName -> AEADName
eaxMode AEADName
bc AEADName -> AEADName -> AEADName
forall a. (IsString a, Semigroup a) => a -> a -> a
/$ Int -> AEADName
forall a. Show a => a -> AEADName
showBytes Int
tagSz

sivMode :: BlockCipher128Name -> AEADName
sivMode :: AEADName -> AEADName
sivMode AEADName
bc = AEADName
bc AEADName -> AEADName -> AEADName
forall a. (IsString a, Semigroup a) => a -> a -> a
// AEADName
forall a. (Eq a, IsString a) => a
BOTAN_AEAD_MODE_SIV

ccmMode :: BlockCipher128Name -> AEADName
ccmMode :: AEADName -> AEADName
ccmMode AEADName
bc = AEADName
bc AEADName -> AEADName -> AEADName
forall a. (IsString a, Semigroup a) => a -> a -> a
// AEADName
forall a. (Eq a, IsString a) => a
BOTAN_AEAD_MODE_CCM

ccmModeWith :: BlockCipher128Name -> Int -> Int -> AEADName
ccmModeWith :: AEADName -> Int -> Int -> AEADName
ccmModeWith AEADName
bc Int
tagSz Int
l = AEADName -> AEADName
ccmMode AEADName
bc AEADName -> AEADName -> AEADName
forall a. (IsString a, Semigroup a) => a -> a -> a
/$ Int -> AEADName
forall a. Show a => a -> AEADName
showBytes Int
tagSz AEADName -> AEADName -> AEADName
forall a. Semigroup a => a -> a -> a
<> AEADName
"," AEADName -> AEADName -> AEADName
forall a. Semigroup a => a -> a -> a
<> Int -> AEADName
forall a. Show a => a -> AEADName
showBytes Int
l

cbcPaddings :: [AEADName]
cbcPaddings =
    [ AEADName
PKCS7
    , AEADName
OneAndZeros
    , AEADName
X9_23
    , AEADName
ESP
    , AEADName
CTS
    , AEADName
NoPadding
    ]

cipherModes :: [AEADName]
cipherModes = [[AEADName]] -> [AEADName]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
    [ [ AEADName -> AEADName -> AEADName
cbcMode AEADName
bc AEADName
pd | AEADName
bc <- [AEADName]
allBlockCiphers, AEADName
pd <- [AEADName]
cbcPaddings ]
    , [ AEADName -> AEADName
cfbMode AEADName
bc    | AEADName
bc <- [AEADName]
allBlockCiphers ]
    , [ AEADName -> AEADName
xtsMode AEADName
bc    | AEADName
bc <- [AEADName]
allBlockCiphers ]
    ]

aeads :: [AEADName]
aeads = [[AEADName]] -> [AEADName]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
    [ [ AEADName
chaCha20Poly1305 ]
    , [ AEADName -> AEADName
gcmMode AEADName
bc | AEADName
bc <- [AEADName]
blockCipher128s ]
    , [ AEADName -> AEADName
ocbMode AEADName
bc | AEADName
bc <- [AEADName]
blockCipher128s ]
    , [ AEADName -> AEADName
eaxMode AEADName
bc | AEADName
bc <- [AEADName]
blockCiphers ] -- WARNING: Why just blockCiphers, why not allBlockCiphers?
    , [ AEADName -> AEADName
sivMode AEADName
bc | AEADName
bc <- [AEADName]
blockCipher128s ]
    , [ AEADName -> AEADName
ccmMode AEADName
bc | AEADName
bc <- [AEADName]
blockCipher128s ]
    ]

allCiphers :: [AEADName]
allCiphers = [AEADName]
cipherModes [AEADName] -> [AEADName] -> [AEADName]
forall a. [a] -> [a] -> [a]
++ [AEADName]
aeads

-- TODO: Rename CipherMaskDirection, CipherEncrypt, CipherDecrypt;
--  Leave slim terminology for botan
pattern MaskDirection
    ,   Encrypt         -- ^ May be renamed Encipher to avoid confusion with PKEncrypt
    ,   Decrypt         -- ^ May be renamed Decipher to avoid confusion with PKDecrypt
    ::  CipherInitFlags

pattern $mMaskDirection :: forall {r}. CipherInitFlags -> ((# #) -> r) -> ((# #) -> r) -> r
$bMaskDirection :: CipherInitFlags
MaskDirection = BOTAN_CIPHER_INIT_FLAG_MASK_DIRECTION
pattern $mEncrypt :: forall {r}. CipherInitFlags -> ((# #) -> r) -> ((# #) -> r) -> r
$bEncrypt :: CipherInitFlags
Encrypt = BOTAN_CIPHER_INIT_FLAG_ENCRYPT
pattern $mDecrypt :: forall {r}. CipherInitFlags -> ((# #) -> r) -> ((# #) -> r) -> r
$bDecrypt :: CipherInitFlags
Decrypt = BOTAN_CIPHER_INIT_FLAG_DECRYPT

pattern CipherUpdate
    ,   CipherFinal
    ::  CipherUpdateFlags

pattern $mCipherUpdate :: forall {r}. Int -> ((# #) -> r) -> ((# #) -> r) -> r
$bCipherUpdate :: Int
CipherUpdate    = BOTAN_CIPHER_UPDATE_FLAG_NONE
pattern $mCipherFinal :: forall {r}. Int -> ((# #) -> r) -> ((# #) -> r) -> r
$bCipherFinal :: Int
CipherFinal     = BOTAN_CIPHER_UPDATE_FLAG_FINAL

-- |Initialize a cipher object
cipherInit
    :: CipherName       -- ^ __name__
    -> CipherInitFlags  -- ^ __flags__
    -> IO Cipher        -- ^ __cipher__
cipherInit :: AEADName -> CipherInitFlags -> IO Cipher
cipherInit = ((Ptr BotanCipher -> IO CInt) -> IO Cipher)
-> (Ptr BotanCipher
    -> ConstPtr CChar -> CipherInitFlags -> IO CInt)
-> AEADName
-> CipherInitFlags
-> IO Cipher
forall botan object a.
((Ptr botan -> IO CInt) -> IO object)
-> (Ptr botan -> ConstPtr CChar -> a -> IO CInt)
-> AEADName
-> a
-> IO object
mkCreateObjectCString1 (Ptr BotanCipher -> IO CInt) -> IO Cipher
createCipher Ptr BotanCipher -> ConstPtr CChar -> CipherInitFlags -> IO CInt
botan_cipher_init

-- WARNING: withFooInit-style limited lifetime functions moved to high-level botan
withCipherInit :: CipherName -> CipherInitFlags -> (Cipher -> IO a) -> IO a
withCipherInit :: forall a. AEADName -> CipherInitFlags -> (Cipher -> IO a) -> IO a
withCipherInit = (AEADName -> CipherInitFlags -> IO Cipher)
-> (Cipher -> IO ())
-> AEADName
-> CipherInitFlags
-> (Cipher -> IO a)
-> IO a
forall x y t a.
(x -> y -> IO t) -> (t -> IO ()) -> x -> y -> (t -> IO a) -> IO a
mkWithTemp2 AEADName -> CipherInitFlags -> IO Cipher
cipherInit Cipher -> IO ()
cipherDestroy

-- |Return the name of the cipher object
cipherName
    :: Cipher           -- ^ __cipher__
    -> IO CipherName    -- ^ __name__
cipherName :: Cipher -> IO AEADName
cipherName = WithPtr Cipher BotanCipher
-> GetCString BotanCipher CChar -> Cipher -> IO AEADName
forall typ ptr byte.
WithPtr typ ptr -> GetCString ptr byte -> typ -> IO AEADName
mkGetCString Cipher -> (BotanCipher -> IO a) -> IO a
WithPtr Cipher BotanCipher
withCipher GetCString BotanCipher CChar
botan_cipher_name

-- |Return the output length of this cipher, for a particular input length.
--
--  WARNING: This function is of limited use. From the C++ docs:
--   /**
--   * Returns the size of the output if this transform is used to process a
--   * message with input_length bytes. In most cases the answer is precise.
--   * If it is not possible to precise (namely for CBC decryption) instead an
--   * upper bound is returned.
--   */
--  We need to explicitly calculate padding + tag length
cipherOutputLength
    :: Cipher   -- ^ __cipher__
    -> Int      -- ^ __in_len__
    -> IO Int   -- ^ __out_len__
cipherOutputLength :: Cipher -> Int -> IO Int
cipherOutputLength = WithPtr Cipher BotanCipher
-> GetSize_csize BotanCipher -> Cipher -> Int -> IO Int
forall typ ptr.
WithPtr typ ptr -> GetSize_csize ptr -> typ -> Int -> IO Int
mkGetSize_csize Cipher -> (BotanCipher -> IO a) -> IO a
WithPtr Cipher BotanCipher
withCipher GetSize_csize BotanCipher
botan_cipher_output_length

-- NOTE: Unique function form?
-- |Return if the specified nonce length is valid for this cipher
-- NOTE: This just always seems to return 'True', even for -1 and maxBound
cipherValidNonceLength
    :: Cipher   -- ^ __cipher__
    -> Int      -- ^ __nl__
    -> IO Bool
cipherValidNonceLength :: Cipher -> Int -> IO Bool
cipherValidNonceLength = WithPtr Cipher BotanCipher
-> GetBoolCode_csize BotanCipher -> Cipher -> Int -> IO Bool
forall typ ptr.
WithPtr typ ptr -> GetBoolCode_csize ptr -> typ -> Int -> IO Bool
mkGetBoolCode_csize Cipher -> (BotanCipher -> IO a) -> IO a
WithPtr Cipher BotanCipher
withCipher GetBoolCode_csize BotanCipher
botan_cipher_valid_nonce_length

-- |Get the tag length of the cipher (0 for non-AEAD modes)
cipherGetTagLength
    :: Cipher   -- ^ __cipher__
    -> IO Int   -- ^ __tag_size__
cipherGetTagLength :: Cipher -> IO Int
cipherGetTagLength = WithPtr Cipher BotanCipher
-> GetSize BotanCipher -> Cipher -> IO Int
forall typ ptr. WithPtr typ ptr -> GetSize ptr -> typ -> IO Int
mkGetSize Cipher -> (BotanCipher -> IO a) -> IO a
WithPtr Cipher BotanCipher
withCipher GetSize BotanCipher
botan_cipher_get_tag_length

-- |Get the default nonce length of this cipher
cipherGetDefaultNonceLength
    :: Cipher   -- ^ __cipher__
    -> IO Int   -- ^ __nl__
cipherGetDefaultNonceLength :: Cipher -> IO Int
cipherGetDefaultNonceLength = WithPtr Cipher BotanCipher
-> GetSize BotanCipher -> Cipher -> IO Int
forall typ ptr. WithPtr typ ptr -> GetSize ptr -> typ -> IO Int
mkGetSize Cipher -> (BotanCipher -> IO a) -> IO a
WithPtr Cipher BotanCipher
withCipher GetSize BotanCipher
botan_cipher_get_default_nonce_length

-- |Return the update granularity of the cipher; botan_cipher_update must be
--  called with blocks of this size, except for the final.
cipherGetUpdateGranularity
    :: Cipher   -- ^ __cipher__
    -> IO Int   -- ^ __ug__
cipherGetUpdateGranularity :: Cipher -> IO Int
cipherGetUpdateGranularity = WithPtr Cipher BotanCipher
-> GetSize BotanCipher -> Cipher -> IO Int
forall typ ptr. WithPtr typ ptr -> GetSize ptr -> typ -> IO Int
mkGetSize Cipher -> (BotanCipher -> IO a) -> IO a
WithPtr Cipher BotanCipher
withCipher GetSize BotanCipher
botan_cipher_get_update_granularity

-- |Return the ideal update granularity of the cipher. This is some multiple of the
--  update granularity, reflecting possibilities for optimization.
--
-- Some ciphers (ChaChaPoly, EAX) may consume less input than the reported ideal granularity
cipherGetIdealUpdateGranularity
    :: Cipher   -- ^ __cipher__
    -> IO Int   -- ^ __ug__
cipherGetIdealUpdateGranularity :: Cipher -> IO Int
cipherGetIdealUpdateGranularity = WithPtr Cipher BotanCipher
-> GetSize BotanCipher -> Cipher -> IO Int
forall typ ptr. WithPtr typ ptr -> GetSize ptr -> typ -> IO Int
mkGetSize Cipher -> (BotanCipher -> IO a) -> IO a
WithPtr Cipher BotanCipher
withCipher GetSize BotanCipher
botan_cipher_get_ideal_update_granularity

-- |Get information about the key lengths.
cipherQueryKeylen
    :: Cipher       -- ^ __cipher__
    -> IO (Int,Int) -- ^ __(min,max)__
cipherQueryKeylen :: Cipher -> IO (Int, Int)
cipherQueryKeylen = WithPtr Cipher BotanCipher
-> GetSizes2 BotanCipher -> Cipher -> IO (Int, Int)
forall typ ptr.
WithPtr typ ptr -> GetSizes2 ptr -> typ -> IO (Int, Int)
mkGetSizes2 Cipher -> (BotanCipher -> IO a) -> IO a
WithPtr Cipher BotanCipher
withCipher GetSizes2 BotanCipher
botan_cipher_query_keylen
{-# DEPRECATED cipherQueryKeylen "Prefer cipherGetKeyspec." #-}

-- |Get information about the supported key lengths.
cipherGetKeyspec
    :: Cipher           -- ^ __cipher__
    -> IO (Int,Int,Int) -- ^ __(min,max,mod)__
cipherGetKeyspec :: Cipher -> IO (Int, Int, Int)
cipherGetKeyspec = WithPtr Cipher BotanCipher
-> GetSizes3 BotanCipher -> Cipher -> IO (Int, Int, Int)
forall typ ptr.
WithPtr typ ptr -> GetSizes3 ptr -> typ -> IO (Int, Int, Int)
mkGetSizes3 Cipher -> (BotanCipher -> IO a) -> IO a
WithPtr Cipher BotanCipher
withCipher GetSizes3 BotanCipher
botan_cipher_get_keyspec

-- |Set the key for this cipher object
cipherSetKey
    :: Cipher       -- ^ __cipher__
    -> ByteString   -- ^ __key__
    -> IO ()
cipherSetKey :: Cipher -> AEADName -> IO ()
cipherSetKey = WithPtr Cipher BotanCipher
-> (BotanCipher -> ConstPtr Word8 -> CSize -> IO CInt)
-> Cipher
-> AEADName
-> IO ()
forall object botan.
(forall a. object -> (botan -> IO a) -> IO a)
-> (botan -> ConstPtr Word8 -> CSize -> IO CInt)
-> object
-> AEADName
-> IO ()
mkWithObjectSetterCBytesLen Cipher -> (BotanCipher -> IO a) -> IO a
WithPtr Cipher BotanCipher
withCipher BotanCipher -> ConstPtr Word8 -> CSize -> IO CInt
botan_cipher_set_key

-- |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.
cipherReset
    :: Cipher   -- ^ __cipher__
    -> IO ()
cipherReset :: Cipher -> IO ()
cipherReset = WithPtr Cipher BotanCipher -> Action BotanCipher -> Cipher -> IO ()
forall typ ptr. WithPtr typ ptr -> Action ptr -> typ -> IO ()
mkAction Cipher -> (BotanCipher -> IO a) -> IO a
WithPtr Cipher BotanCipher
withCipher Action BotanCipher
botan_cipher_reset

-- |Set the associated data. Will fail if cipher is not an AEAD
cipherSetAssociatedData
    :: Cipher       -- ^ __cipher__
    -> ByteString   -- ^ __ad__
    -> IO ()
cipherSetAssociatedData :: Cipher -> AEADName -> IO ()
cipherSetAssociatedData = WithPtr Cipher BotanCipher
-> (BotanCipher -> ConstPtr Word8 -> CSize -> IO CInt)
-> Cipher
-> AEADName
-> IO ()
forall object botan.
(forall a. object -> (botan -> IO a) -> IO a)
-> (botan -> ConstPtr Word8 -> CSize -> IO CInt)
-> object
-> AEADName
-> IO ()
mkWithObjectSetterCBytesLen Cipher -> (BotanCipher -> IO a) -> IO a
WithPtr Cipher BotanCipher
withCipher BotanCipher -> ConstPtr Word8 -> CSize -> IO CInt
botan_cipher_set_associated_data

-- |Begin processing a new message using the provided nonce
cipherStart
    :: Cipher       -- ^ __cipher__
    -> ByteString   -- ^ __nonce__
    -> IO ()
cipherStart :: Cipher -> AEADName -> IO ()
cipherStart = WithPtr Cipher BotanCipher
-> (BotanCipher -> ConstPtr Word8 -> CSize -> IO CInt)
-> Cipher
-> AEADName
-> IO ()
forall object botan.
(forall a. object -> (botan -> IO a) -> IO a)
-> (botan -> ConstPtr Word8 -> CSize -> IO CInt)
-> object
-> AEADName
-> IO ()
mkWithObjectSetterCBytesLen Cipher -> (BotanCipher -> IO a) -> IO a
WithPtr Cipher BotanCipher
withCipher BotanCipher -> ConstPtr Word8 -> CSize -> IO CInt
botan_cipher_start

-- |"Encrypt some data"
--
--  This function is ill-documented.
--
--  See the source for authoritative details:
--  https://github.com/randombit/botan/blob/72dc18bbf598f2c3bef81a4fb2915e9c3c524ac4/src/lib/ffi/ffi_cipher.cpp#L133
--
-- Some ciphers (ChaChaPoly, EAX) may consume less input than the reported ideal granularity
cipherUpdate
    :: Cipher               -- ^ __cipher__
    -> CipherUpdateFlags    -- ^ __flags__
    -> Int                  -- ^ __output_size__
    -> ByteString           -- ^ __input_bytes[]__
    -> IO (Int,ByteString)  -- ^ __(input_consumed,output[])__
cipherUpdate :: Cipher -> Int -> Int -> AEADName -> IO (Int, AEADName)
cipherUpdate Cipher
ctx Int
flags Int
outputSz AEADName
input = Cipher -> (BotanCipher -> IO (Int, AEADName)) -> IO (Int, AEADName)
WithPtr Cipher BotanCipher
withCipher Cipher
ctx ((BotanCipher -> IO (Int, AEADName)) -> IO (Int, AEADName))
-> (BotanCipher -> IO (Int, AEADName)) -> IO (Int, AEADName)
forall a b. (a -> b) -> a -> b
$ \ BotanCipher
ctxPtr -> do
    AEADName
-> (Ptr Word8 -> CSize -> IO (Int, AEADName)) -> IO (Int, AEADName)
forall byte a. AEADName -> (Ptr byte -> CSize -> IO a) -> IO a
unsafeAsBytesLen AEADName
input ((Ptr Word8 -> CSize -> IO (Int, AEADName)) -> IO (Int, AEADName))
-> (Ptr Word8 -> CSize -> IO (Int, AEADName)) -> IO (Int, AEADName)
forall a b. (a -> b) -> a -> b
$ \ Ptr Word8
inputPtr CSize
inputSz -> do
        (Ptr CSize -> IO (Int, AEADName)) -> IO (Int, AEADName)
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr CSize -> IO (Int, AEADName)) -> IO (Int, AEADName))
-> (Ptr CSize -> IO (Int, AEADName)) -> IO (Int, AEADName)
forall a b. (a -> b) -> a -> b
$ \ Ptr CSize
consumedPtr -> do
            (Ptr CSize -> IO (Int, AEADName)) -> IO (Int, AEADName)
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr CSize -> IO (Int, AEADName)) -> IO (Int, AEADName))
-> (Ptr CSize -> IO (Int, AEADName)) -> IO (Int, AEADName)
forall a b. (a -> b) -> a -> b
$ \ Ptr CSize
writtenPtr -> do
                AEADName
output <- Int -> (Ptr Word8 -> IO ()) -> IO AEADName
forall byte. Int -> (Ptr byte -> IO ()) -> IO AEADName
allocBytes Int
outputSz ((Ptr Word8 -> IO ()) -> IO AEADName)
-> (Ptr Word8 -> IO ()) -> IO AEADName
forall a b. (a -> b) -> a -> b
$ \ Ptr Word8
outputPtr -> do
                    HasCallStack => IO CInt -> IO ()
IO CInt -> IO ()
throwBotanIfNegative_ (IO CInt -> IO ()) -> IO CInt -> IO ()
forall a b. (a -> b) -> a -> b
$ BotanCipher
-> CipherInitFlags
-> Ptr Word8
-> CSize
-> Ptr CSize
-> ConstPtr Word8
-> CSize
-> Ptr CSize
-> IO CInt
botan_cipher_update
                        BotanCipher
ctxPtr
                        (Int -> CipherInitFlags
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
flags)
                        Ptr Word8
outputPtr
                        (Int -> CSize
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
outputSz)
                        Ptr CSize
writtenPtr
                        (Ptr Word8 -> ConstPtr Word8
forall a. Ptr a -> ConstPtr a
ConstPtr Ptr Word8
inputPtr)
                        CSize
inputSz
                        Ptr CSize
consumedPtr
                Int
consumed <- CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CSize -> Int) -> IO CSize -> IO Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Ptr CSize -> IO CSize
forall a. Storable a => Ptr a -> IO a
peek Ptr CSize
consumedPtr
                Int
written <- CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CSize -> Int) -> IO CSize -> IO Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Ptr CSize -> IO CSize
forall a. Storable a => Ptr a -> IO a
peek Ptr CSize
writtenPtr
                -- NOTE: The safety of this function is suspect - may require deepseq
                let processed :: AEADName
processed = Int -> AEADName -> AEADName
ByteString.take Int
written AEADName
output
                    in AEADName
processed AEADName -> IO (Int, AEADName) -> IO (Int, AEADName)
forall a b. a -> b -> b
`seq` (Int, AEADName) -> IO (Int, AEADName)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Int
consumed,AEADName
processed)

{- |
Encrypt and finalize a complete piece of data.

This is not a canonical Botan C/C++ function.
-}
cipherEncrypt :: Cipher -> ByteString -> IO ByteString
cipherEncrypt :: Cipher -> AEADName -> IO AEADName
cipherEncrypt = Cipher -> AEADName -> IO AEADName
cipherEncryptOffline

{- |
Encrypt and finalize a complete piece of data.

This is not a canonical Botan C/C++ function.
-}
cipherDecrypt :: Cipher -> ByteString -> IO ByteString
cipherDecrypt :: Cipher -> AEADName -> IO AEADName
cipherDecrypt = Cipher -> AEADName -> IO AEADName
cipherDecryptOffline

-- |Reset the key, nonce, AD and all other state on this cipher object
cipherClear :: Cipher -> IO ()
cipherClear :: Cipher -> IO ()
cipherClear = WithPtr Cipher BotanCipher -> Action BotanCipher -> Cipher -> IO ()
forall typ ptr. WithPtr typ ptr -> Action ptr -> typ -> IO ()
mkAction Cipher -> (BotanCipher -> IO a) -> IO a
WithPtr Cipher BotanCipher
withCipher Action BotanCipher
botan_cipher_clear

{-
Non-standard functions
-}

-- NOTE: out + ug + tag is safe overestimate for encryption
-- NOTE: out + ug - tag may not be a safe overestimate for decryption
{-# DEPRECATED cipherEstimateOutputLength "This will be moved from botan-low to botan" #-}
cipherEstimateOutputLength :: Cipher -> CipherInitFlags -> Int -> IO Int
cipherEstimateOutputLength :: Cipher -> CipherInitFlags -> Int -> IO Int
cipherEstimateOutputLength Cipher
ctx CipherInitFlags
flags Int
input = do
    Int
o <- Cipher -> Int -> IO Int
cipherOutputLength Cipher
ctx Int
input  -- NOTE: Flawed but usable
    Int
u <- Cipher -> IO Int
cipherGetUpdateGranularity Cipher
ctx -- TODO: When u == 1, it should be just input + t, right?
    Int
t <- Cipher -> IO Int
cipherGetTagLength Cipher
ctx
    if CipherInitFlags
flags CipherInitFlags -> CipherInitFlags -> Bool
forall a. Eq a => a -> a -> Bool
== CipherInitFlags
forall a. (Eq a, Num a) => a
BOTAN_CIPHER_INIT_FLAG_ENCRYPT
        then Int -> IO Int
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Int
o Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
u Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
t)
        else Int -> IO Int
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Int
o Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
u Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
t) -- TODO: Maybe just 'o'... 

-- NOTE: Offset must be a valid length of the input so far processed
-- NOTE: If (estimated) outputLength input + offset == outputLength (input + offset) then
--  we can just use cipherEstimateOutputLength instead of this
--  However, this may not be completely true due to block alignment requirements
--  For the moment this function exists for clarity.
{-# DEPRECATED cipherEstimateFinalOutputLength "Moving from botan-low to botan" #-}
cipherEstimateFinalOutputLength :: Cipher -> CipherInitFlags -> Int -> Int -> IO Int
cipherEstimateFinalOutputLength :: Cipher -> CipherInitFlags -> Int -> Int -> IO Int
cipherEstimateFinalOutputLength Cipher
ctx CipherInitFlags
flags Int
offset Int
input = do
    Int
len <- Cipher -> CipherInitFlags -> Int -> IO Int
cipherEstimateOutputLength Cipher
ctx CipherInitFlags
flags (Int
offset Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
input)
    Int -> IO Int
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Int -> IO Int) -> Int -> IO Int
forall a b. (a -> b) -> a -> b
$ Int
len Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
offset

-- A better version of cipherUpdate
-- NOTE: It returns (processed,remaining) compared to (consumed,processed)
--  so the processed ciphertext has moved from snd to fst
-- TODO: Use Builder to do this
--  https://hackage.haskell.org/package/bytestring-0.12.0.2/docs/Data-ByteString-Builder.html
-- NOTE: There still is (an efficiency) use for a version that reports only consumed length
--  and defers the computation of the 'remaining' bytestring
{-# DEPRECATED cipherProcess "Moving from botan-low to botan" #-}
cipherProcess :: Cipher -> CipherUpdateFlags -> Int -> ByteString -> IO (ByteString,ByteString)
cipherProcess :: Cipher -> Int -> Int -> AEADName -> IO (AEADName, AEADName)
cipherProcess Cipher
ctx Int
flags Int
outputSz AEADName
input = do
    (Int
consumed,AEADName
processed) <- Cipher -> Int -> Int -> AEADName -> IO (Int, AEADName)
cipherUpdate Cipher
ctx Int
flags Int
outputSz AEADName
input
    -- NOTE: The safety of this function is suspect - may require deepseq
    let remaining :: AEADName
remaining = Int -> AEADName -> AEADName
ByteString.drop Int
consumed AEADName
input
        in AEADName
processed AEADName -> IO (AEADName, AEADName) -> IO (AEADName, AEADName)
forall a b. a -> b -> b
`seq` AEADName
remaining AEADName -> IO (AEADName, AEADName) -> IO (AEADName, AEADName)
forall a b. a -> b -> b
`seq` (AEADName, AEADName) -> IO (AEADName, AEADName)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (AEADName
processed,AEADName
remaining)

{-# DEPRECATED cipherProcessOffline "Moving from botan-low to botan" #-}
cipherProcessOffline :: Cipher -> CipherInitFlags -> ByteString -> IO ByteString
cipherProcessOffline :: Cipher -> CipherInitFlags -> AEADName -> IO AEADName
cipherProcessOffline Cipher
ctx CipherInitFlags
flags AEADName
msg = do
    Int
o <- Cipher -> CipherInitFlags -> Int -> IO Int
cipherEstimateOutputLength Cipher
ctx CipherInitFlags
flags (AEADName -> Int
ByteString.length AEADName
msg)
    -- snd <$> cipherUpdate ctx BOTAN_CIPHER_UPDATE_FLAG_FINAL o msg
    (AEADName, AEADName) -> AEADName
forall a b. (a, b) -> a
fst ((AEADName, AEADName) -> AEADName)
-> IO (AEADName, AEADName) -> IO AEADName
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Cipher -> Int -> Int -> AEADName -> IO (AEADName, AEADName)
cipherProcess Cipher
ctx Int
forall a. (Eq a, Num a) => a
BOTAN_CIPHER_UPDATE_FLAG_FINAL Int
o AEADName
msg

{-# WARNING cipherEncryptOffline "May be renamed to cipherEncrypt, may be moved to botan" #-}
cipherEncryptOffline :: Cipher -> ByteString -> IO ByteString
cipherEncryptOffline :: Cipher -> AEADName -> IO AEADName
cipherEncryptOffline Cipher
ctx = Cipher -> CipherInitFlags -> AEADName -> IO AEADName
cipherProcessOffline Cipher
ctx CipherInitFlags
forall a. (Eq a, Num a) => a
BOTAN_CIPHER_INIT_FLAG_ENCRYPT

{-# WARNING cipherDecryptOffline "May be renamed to cipherDecrypt, may be moved to botan" #-}
cipherDecryptOffline :: Cipher -> ByteString -> IO ByteString
cipherDecryptOffline :: Cipher -> AEADName -> IO AEADName
cipherDecryptOffline Cipher
ctx = Cipher -> CipherInitFlags -> AEADName -> IO AEADName
cipherProcessOffline Cipher
ctx CipherInitFlags
forall a. (Eq a, Num a) => a
BOTAN_CIPHER_INIT_FLAG_DECRYPT

{-
Experiments with online processing
-}

-- cipherEncryptOnline :: Cipher -> ByteString -> IO ByteString
-- cipherEncryptOnline ctx msg = do
--     u <- cipherGetUpdateGranularity ctx
--     t <- cipherGetTagLength ctx
--     g <- cipherGetIdealUpdateGranularity ctx
--     ByteString.concat <$> go 0 u t g msg
--     where
--         go i u t g bs = case ByteString.splitAt g bs of
--             (block,"")      -> do
--                 o <- cipherOutputLength ctx (i + ByteString.length block)  -- NOTE: Flawed but usable
--                 (_,encblock) <- cipherUpdate ctx BOTAN_CIPHER_UPDATE_FLAG_FINAL (o + u + t - i) block
--                 return [encblock]
--             (block,rest)    -> do
--                 (_,encblock) <- cipherUpdate ctx BOTAN_CIPHER_UPDATE_FLAG_NONE g block
--                 encrest <- go (i + g) u t g rest
--                 return $! encblock : encrest

--  NOTE: Some ciphers (SIV, CCM) are not online-capable algorithms, but Botan does not throw
--  an error even though it should.
{-# DEPRECATED cipherProcessOnline "Moving from botan-low to botan" #-}
cipherProcessOnline :: Cipher -> CipherInitFlags -> ByteString -> IO ByteString
cipherProcessOnline :: Cipher -> CipherInitFlags -> AEADName -> IO AEADName
cipherProcessOnline Cipher
ctx CipherInitFlags
flags = if CipherInitFlags
flags CipherInitFlags -> CipherInitFlags -> Bool
forall a. Eq a => a -> a -> Bool
== CipherInitFlags
forall a. (Eq a, Num a) => a
BOTAN_CIPHER_INIT_FLAG_ENCRYPT
    then Cipher -> AEADName -> IO AEADName
cipherEncryptOnline Cipher
ctx
    else Cipher -> AEADName -> IO AEADName
cipherDecryptOnline Cipher
ctx

-- TODO: Consolidate online encipher / decipher
-- TODO: Use Builder to do this
--  https://hackage.haskell.org/package/bytestring-0.12.0.2/docs/Data-ByteString-Builder.html
{-# DEPRECATED cipherEncryptOnline "Moving from botan-low to botan" #-}
cipherEncryptOnline :: Cipher -> ByteString -> IO ByteString
cipherEncryptOnline :: Cipher -> AEADName -> IO AEADName
cipherEncryptOnline Cipher
ctx AEADName
msg = do
    Int
g <- Cipher -> IO Int
cipherGetIdealUpdateGranularity Cipher
ctx
    [AEADName] -> AEADName
ByteString.concat ([AEADName] -> AEADName) -> IO [AEADName] -> IO AEADName
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Int -> Int -> AEADName -> IO [AEADName]
go Int
0 Int
g AEADName
msg
    where
        go :: Int -> Int -> AEADName -> IO [AEADName]
go Int
i Int
g AEADName
bs = case Int -> AEADName -> (AEADName, AEADName)
ByteString.splitAt Int
g AEADName
bs of
            (AEADName
block,AEADName
"")      -> do
                Int
o <- Cipher -> CipherInitFlags -> Int -> Int -> IO Int
cipherEstimateFinalOutputLength Cipher
ctx CipherInitFlags
forall a. (Eq a, Num a) => a
BOTAN_CIPHER_INIT_FLAG_ENCRYPT Int
i (AEADName -> Int
ByteString.length AEADName
block)
                (AEADName
processed,AEADName
_) <- Cipher -> Int -> Int -> AEADName -> IO (AEADName, AEADName)
cipherProcess Cipher
ctx Int
forall a. (Eq a, Num a) => a
BOTAN_CIPHER_UPDATE_FLAG_FINAL Int
o AEADName
block
                [AEADName] -> IO [AEADName]
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return [AEADName
processed]
            (AEADName
block,AEADName
rest)    -> do
                (AEADName
processed,AEADName
remaining) <- Cipher -> Int -> Int -> AEADName -> IO (AEADName, AEADName)
cipherProcess Cipher
ctx Int
forall a. (Eq a, Num a) => a
BOTAN_CIPHER_UPDATE_FLAG_NONE Int
g AEADName
block
                (AEADName
processed AEADName -> [AEADName] -> [AEADName]
forall a. a -> [a] -> [a]
:) ([AEADName] -> [AEADName]) -> IO [AEADName] -> IO [AEADName]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Int -> Int -> AEADName -> IO [AEADName]
go (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
g) Int
g (AEADName
remaining AEADName -> AEADName -> AEADName
forall a. Semigroup a => a -> a -> a
<> AEADName
rest)
                -- Though this following version may be more efficient especially with lazy bytestrings
                --  or builder, though note *which* update function it uses - the original
                -- (consumed,processed) <- cipherUpdate ctx BOTAN_CIPHER_UPDATE_FLAG_NONE g block
                -- (processed :) <$> go (i + g) g (ByteString.drop consumed bs)

-- TODO: Consolidate online encipher / decipher
{-# DEPRECATED cipherDecryptOnline "Moving from botan-low to botan" #-}
cipherDecryptOnline :: Cipher -> ByteString -> IO ByteString
cipherDecryptOnline :: Cipher -> AEADName -> IO AEADName
cipherDecryptOnline Cipher
ctx AEADName
msg = do
    Int
g <- Cipher -> IO Int
cipherGetIdealUpdateGranularity Cipher
ctx
    Int
t <- Cipher -> IO Int
cipherGetTagLength Cipher
ctx
    [AEADName] -> AEADName
ByteString.concat ([AEADName] -> AEADName) -> IO [AEADName] -> IO AEADName
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Int -> Int -> Int -> AEADName -> IO [AEADName]
forall {t}. Int -> Int -> t -> AEADName -> IO [AEADName]
go Int
0 Int
g Int
t AEADName
msg
    where
        go :: Int -> Int -> t -> AEADName -> IO [AEADName]
go Int
i Int
g t
t AEADName
bs = case Int -> AEADName -> (AEADName, AEADName)
ByteString.splitAt Int
g AEADName
bs of
            (AEADName
block,AEADName
"")      -> do
                Int
o <- Cipher -> CipherInitFlags -> Int -> Int -> IO Int
cipherEstimateFinalOutputLength Cipher
ctx CipherInitFlags
forall a. (Eq a, Num a) => a
BOTAN_CIPHER_INIT_FLAG_DECRYPT Int
i (AEADName -> Int
ByteString.length AEADName
block)
                (AEADName
processed,AEADName
_) <- Cipher -> Int -> Int -> AEADName -> IO (AEADName, AEADName)
cipherProcess Cipher
ctx Int
forall a. (Eq a, Num a) => a
BOTAN_CIPHER_UPDATE_FLAG_FINAL Int
o AEADName
block
                [AEADName] -> IO [AEADName]
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return [AEADName
processed]
            (AEADName
block,AEADName
rest)    -> do
                (AEADName
processed,AEADName
remaining) <- Cipher -> Int -> Int -> AEADName -> IO (AEADName, AEADName)
cipherProcess Cipher
ctx Int
forall a. (Eq a, Num a) => a
BOTAN_CIPHER_UPDATE_FLAG_NONE Int
g AEADName
block
                (AEADName
processed AEADName -> [AEADName] -> [AEADName]
forall a. a -> [a] -> [a]
:) ([AEADName] -> [AEADName]) -> IO [AEADName] -> IO [AEADName]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Int -> Int -> t -> AEADName -> IO [AEADName]
go (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
g) Int
g t
t (AEADName
remaining AEADName -> AEADName -> AEADName
forall a. Semigroup a => a -> a -> a
<> AEADName
rest)