{-|
Module      : Botan.Low.KeyEncapsulation
Description : Key Encapsulation
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
-}

module Botan.Low.PubKey.KeyEncapsulation (

  -- * PK Key Encapsulation
  -- $introduction
  -- * Usage
  -- $usage

  -- * KEM Encryption
    KEMSharedKey
  , KEMEncapsulatedKey
  , KEMEncrypt(..)
  , withKEMEncrypt
  , kemEncryptDestroy
  , kemEncryptCreate
  , kemEncryptSharedKeyLength
  , kemEncryptEncapsulatedKeyLength
  , kemEncryptCreateSharedKey

  -- * KEM Decryption
  , KEMDecrypt(..)
  , withKEMDecrypt
  , kemDecryptDestroy
  , kemDecryptCreate
  , kemDecryptSharedKeyLength
  , kemDecryptSharedKey

  ) where

import           Botan.Bindings.ConstPtr (ConstPtr (..))
import           Botan.Bindings.PubKey.KeyEncapsulation
import           Botan.Low.Error.Internal
import           Botan.Low.Internal.ByteString
import           Botan.Low.KDF
import           Botan.Low.Make
import           Botan.Low.PubKey
import           Botan.Low.Remake
import           Botan.Low.RNG
import           Control.DeepSeq
import           Data.ByteString (ByteString)
import qualified Data.ByteString as ByteString
import           Foreign.C.Types
import           Foreign.ForeignPtr
import           Foreign.Marshal.Alloc
import           Foreign.Ptr
import           Foreign.Storable

{- $introduction

Key encapsulation (KEM) is a variation on public key encryption which is
commonly used by post-quantum secure schemes. Instead of choosing a random
secret and encrypting it, as in typical public key encryption, a KEM encryption
takes no inputs and produces two values, the shared secret and the encapsulated
key. The decryption operation takes in the encapsulated key and returns the
shared secret.

-}

{- $usage

> NOTE: KEM only requires the public knowledge of one person's key pair, unlike
> Key Agreement.

First, Alice generates her private and public key pair:

> import Botan.Low.PubKey
> import Botan.Low.PubKey.KeyEncapsulation
> import Botan.Low.Hash
> import Botan.Low.KDF
> import Botan.Low.RNG
> rng <- rngInit UserRNG
> -- Alice generates her private and public keys
> alicePrivKey <- privKeyCreate RSA "2048" rng
> alicePubKey <- privKeyExportPubKey alicePrivKey

Then, Alice shares her public key somewhere where others can see. When Bob
wants to create a shared key with Alice, they choose a KDF algorithm, generate
a salt, and choose a shared key length.

> kdfAlg = hkdf SHA256
> salt <- rngGet rng 4
> sharedKeyLength = 256

Then, Bob generates the shared + encapsulated key, and sends the
encapsulated key to Alice:

> encryptCtx <- kemEncryptCreate alicePubKey kdfAlg
> (bobSharedKey, encapsulatedKey) <- kemEncryptCreateSharedKey encryptCtx rng salt sharedKeyLength
> -- sendToAlice encapsulatedKey

Upon receiving the encapsulated key, Alice can decrypt and extract the shared
key using her private key:

> decryptCtx <- kemDecryptCreate alicePrivKey kdfAlg
> aliceSharedKey <- kemDecryptSharedKey decryptCtx salt encapsulatedKey sharedKeyLength
> bobSharedKey == aliceSharedKey
> -- True

Then, this shared key may be used for any suitable purpose.

-}

-- TODO: KEM supports the following key types:
--      RSA
--      Kyber
--      McEliece
--  https://botan.randombit.net/handbook/api_ref/pubkey.html#key-encapsulation
-- KYBER is post-quantum

type KEMSharedKey = ByteString
type KEMEncapsulatedKey = ByteString

newtype KEMEncrypt = MkKEMEncrypt { KEMEncrypt -> ForeignPtr BotanPKOpKEMEncryptStruct
foreignPtr :: ForeignPtr BotanPKOpKEMEncryptStruct }

withKEMEncrypt     :: KEMEncrypt -> (BotanPKOpKEMEncrypt -> IO a) -> IO a
kemEncryptDestroy  :: KEMEncrypt -> IO ()
createKEMEncrypt   :: (Ptr BotanPKOpKEMEncrypt -> IO CInt) -> IO KEMEncrypt
(KEMEncrypt -> (BotanPKOpKEMEncrypt -> IO a) -> IO a
withKEMEncrypt, KEMEncrypt -> IO ()
kemEncryptDestroy, (Ptr BotanPKOpKEMEncrypt -> IO CInt) -> IO KEMEncrypt
createKEMEncrypt)
    = (Ptr BotanPKOpKEMEncryptStruct -> BotanPKOpKEMEncrypt)
-> (BotanPKOpKEMEncrypt -> Ptr BotanPKOpKEMEncryptStruct)
-> (ForeignPtr BotanPKOpKEMEncryptStruct -> KEMEncrypt)
-> (KEMEncrypt -> ForeignPtr BotanPKOpKEMEncryptStruct)
-> FinalizerPtr BotanPKOpKEMEncryptStruct
-> (KEMEncrypt -> (BotanPKOpKEMEncrypt -> IO a) -> IO a,
    KEMEncrypt -> IO (),
    (Ptr BotanPKOpKEMEncrypt -> IO CInt) -> IO KEMEncrypt)
forall botan struct object a.
Storable botan =>
(Ptr struct -> botan)
-> (botan -> Ptr struct)
-> (ForeignPtr struct -> object)
-> (object -> ForeignPtr struct)
-> FinalizerPtr struct
-> (object -> (botan -> IO a) -> IO a, object -> IO (),
    (Ptr botan -> IO CInt) -> IO object)
mkBindings
        Ptr BotanPKOpKEMEncryptStruct -> BotanPKOpKEMEncrypt
MkBotanPKOpKEMEncrypt (.ptr)
        ForeignPtr BotanPKOpKEMEncryptStruct -> KEMEncrypt
MkKEMEncrypt (.foreignPtr)
        FinalizerPtr BotanPKOpKEMEncryptStruct
botan_pk_op_kem_encrypt_destroy





kemEncryptCreate
    :: PubKey           -- ^ __key__
    -> KDFName          -- ^ __kdf__
    -> IO KEMEncrypt    -- ^ __op__
kemEncryptCreate :: PubKey -> KEMSharedKey -> IO KEMEncrypt
kemEncryptCreate PubKey
pk KEMSharedKey
algo = PubKey -> (BotanPubKey -> IO KEMEncrypt) -> IO KEMEncrypt
forall a. PubKey -> (BotanPubKey -> IO a) -> IO a
withPubKey PubKey
pk ((BotanPubKey -> IO KEMEncrypt) -> IO KEMEncrypt)
-> (BotanPubKey -> IO KEMEncrypt) -> IO KEMEncrypt
forall a b. (a -> b) -> a -> b
$ \ BotanPubKey
pkPtr -> do
    KEMSharedKey -> (Ptr CChar -> IO KEMEncrypt) -> IO KEMEncrypt
forall a. KEMSharedKey -> (Ptr CChar -> IO a) -> IO a
asCString KEMSharedKey
algo ((Ptr CChar -> IO KEMEncrypt) -> IO KEMEncrypt)
-> (Ptr CChar -> IO KEMEncrypt) -> IO KEMEncrypt
forall a b. (a -> b) -> a -> b
$ \ Ptr CChar
algoPtr -> do
        (Ptr BotanPKOpKEMEncrypt -> IO CInt) -> IO KEMEncrypt
createKEMEncrypt ((Ptr BotanPKOpKEMEncrypt -> IO CInt) -> IO KEMEncrypt)
-> (Ptr BotanPKOpKEMEncrypt -> IO CInt) -> IO KEMEncrypt
forall a b. (a -> b) -> a -> b
$ \ Ptr BotanPKOpKEMEncrypt
out -> Ptr BotanPKOpKEMEncrypt -> BotanPubKey -> ConstPtr CChar -> IO CInt
botan_pk_op_kem_encrypt_create
            Ptr BotanPKOpKEMEncrypt
out
            BotanPubKey
pkPtr
            (Ptr CChar -> ConstPtr CChar
forall a. Ptr a -> ConstPtr a
ConstPtr Ptr CChar
algoPtr)

kemEncryptSharedKeyLength
    :: KEMEncrypt   -- ^ __op__
    -> Int          -- ^ __desired_shared_key_length__
    -> IO Int       -- ^ __output_shared_key_length__
kemEncryptSharedKeyLength :: KEMEncrypt -> Int -> IO Int
kemEncryptSharedKeyLength = WithPtr KEMEncrypt BotanPKOpKEMEncrypt
-> GetSize_csize BotanPKOpKEMEncrypt -> KEMEncrypt -> Int -> IO Int
forall typ ptr.
WithPtr typ ptr -> GetSize_csize ptr -> typ -> Int -> IO Int
mkGetSize_csize KEMEncrypt -> (BotanPKOpKEMEncrypt -> IO a) -> IO a
WithPtr KEMEncrypt BotanPKOpKEMEncrypt
withKEMEncrypt GetSize_csize BotanPKOpKEMEncrypt
botan_pk_op_kem_encrypt_shared_key_length


kemEncryptEncapsulatedKeyLength
    :: KEMEncrypt   -- ^ __op__
    -> IO Int       -- ^ __output_encapsulated_key_length__
kemEncryptEncapsulatedKeyLength :: KEMEncrypt -> IO Int
kemEncryptEncapsulatedKeyLength = WithPtr KEMEncrypt BotanPKOpKEMEncrypt
-> GetSize BotanPKOpKEMEncrypt -> KEMEncrypt -> IO Int
forall typ ptr. WithPtr typ ptr -> GetSize ptr -> typ -> IO Int
mkGetSize KEMEncrypt -> (BotanPKOpKEMEncrypt -> IO a) -> IO a
WithPtr KEMEncrypt BotanPKOpKEMEncrypt
withKEMEncrypt GetSize BotanPKOpKEMEncrypt
botan_pk_op_kem_encrypt_encapsulated_key_length

-- NOTE: Awkward because of double-query and returning double bytestrings
--  Cannot use allocBytesQuerying because of double-return
-- NOTE: Returns (SharedKey, EncapsulatedKey)


kemEncryptCreateSharedKey
    :: KEMEncrypt                           -- ^ __op__
    -> RNG                                  -- ^ __rng__
    -> ByteString                           -- ^ __salt[]__
    -> Int                                  -- ^ __desired_shared_key_len__
    -> IO (KEMSharedKey,KEMEncapsulatedKey) -- ^ __(shared_key,encapsulated_key)__
kemEncryptCreateSharedKey :: KEMEncrypt
-> RNG -> KEMSharedKey -> Int -> IO (KEMSharedKey, KEMSharedKey)
kemEncryptCreateSharedKey KEMEncrypt
ke RNG
rng KEMSharedKey
salt Int
desiredLen = KEMEncrypt
-> (BotanPKOpKEMEncrypt -> IO (KEMSharedKey, KEMSharedKey))
-> IO (KEMSharedKey, KEMSharedKey)
WithPtr KEMEncrypt BotanPKOpKEMEncrypt
withKEMEncrypt KEMEncrypt
ke ((BotanPKOpKEMEncrypt -> IO (KEMSharedKey, KEMSharedKey))
 -> IO (KEMSharedKey, KEMSharedKey))
-> (BotanPKOpKEMEncrypt -> IO (KEMSharedKey, KEMSharedKey))
-> IO (KEMSharedKey, KEMSharedKey)
forall a b. (a -> b) -> a -> b
$ \ BotanPKOpKEMEncrypt
kePtr -> do
    RNG
-> (BotanRNG -> IO (KEMSharedKey, KEMSharedKey))
-> IO (KEMSharedKey, KEMSharedKey)
forall a. RNG -> (BotanRNG -> IO a) -> IO a
withRNG RNG
rng ((BotanRNG -> IO (KEMSharedKey, KEMSharedKey))
 -> IO (KEMSharedKey, KEMSharedKey))
-> (BotanRNG -> IO (KEMSharedKey, KEMSharedKey))
-> IO (KEMSharedKey, KEMSharedKey)
forall a b. (a -> b) -> a -> b
$ \ BotanRNG
botanRNG -> do
        KEMSharedKey
-> (Ptr Word8 -> CSize -> IO (KEMSharedKey, KEMSharedKey))
-> IO (KEMSharedKey, KEMSharedKey)
forall byte a. KEMSharedKey -> (Ptr byte -> CSize -> IO a) -> IO a
asBytesLen KEMSharedKey
salt ((Ptr Word8 -> CSize -> IO (KEMSharedKey, KEMSharedKey))
 -> IO (KEMSharedKey, KEMSharedKey))
-> (Ptr Word8 -> CSize -> IO (KEMSharedKey, KEMSharedKey))
-> IO (KEMSharedKey, KEMSharedKey)
forall a b. (a -> b) -> a -> b
$ \ Ptr Word8
saltPtr CSize
saltLen -> do
            (Ptr CSize -> IO (KEMSharedKey, KEMSharedKey))
-> IO (KEMSharedKey, KEMSharedKey)
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr CSize -> IO (KEMSharedKey, KEMSharedKey))
 -> IO (KEMSharedKey, KEMSharedKey))
-> (Ptr CSize -> IO (KEMSharedKey, KEMSharedKey))
-> IO (KEMSharedKey, KEMSharedKey)
forall a b. (a -> b) -> a -> b
$ \ Ptr CSize
sharedSzPtr -> do
                (Ptr CSize -> IO (KEMSharedKey, KEMSharedKey))
-> IO (KEMSharedKey, KEMSharedKey)
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr CSize -> IO (KEMSharedKey, KEMSharedKey))
 -> IO (KEMSharedKey, KEMSharedKey))
-> (Ptr CSize -> IO (KEMSharedKey, KEMSharedKey))
-> IO (KEMSharedKey, KEMSharedKey)
forall a b. (a -> b) -> a -> b
$ \ Ptr CSize
encapSzPtr -> do
                    Int
sharedSz <- KEMEncrypt -> Int -> IO Int
kemEncryptSharedKeyLength KEMEncrypt
ke Int
desiredLen
                    Int
encapSz <-  KEMEncrypt -> IO Int
kemEncryptEncapsulatedKeyLength KEMEncrypt
ke
                    Ptr CSize -> CSize -> IO ()
forall a. Storable a => Ptr a -> a -> IO ()
poke Ptr CSize
sharedSzPtr (Int -> CSize
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
sharedSz)
                    Ptr CSize -> CSize -> IO ()
forall a. Storable a => Ptr a -> a -> IO ()
poke Ptr CSize
encapSzPtr (Int -> CSize
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
encapSz)
                    Int
-> (Ptr Word8 -> IO KEMSharedKey)
-> IO (KEMSharedKey, KEMSharedKey)
forall byte a. Int -> (Ptr byte -> IO a) -> IO (a, KEMSharedKey)
allocBytesWith Int
encapSz ((Ptr Word8 -> IO KEMSharedKey) -> IO (KEMSharedKey, KEMSharedKey))
-> (Ptr Word8 -> IO KEMSharedKey)
-> IO (KEMSharedKey, KEMSharedKey)
forall a b. (a -> b) -> a -> b
$ \ Ptr Word8
encapPtr -> do
                        Int -> (Ptr Word8 -> IO ()) -> IO KEMSharedKey
forall byte. Int -> (Ptr byte -> IO ()) -> IO KEMSharedKey
allocBytes Int
sharedSz ((Ptr Word8 -> IO ()) -> IO KEMSharedKey)
-> (Ptr Word8 -> IO ()) -> IO KEMSharedKey
forall a b. (a -> b) -> a -> b
$ \ Ptr Word8
sharedPtr -> do
                            HasCallStack => IO CInt -> IO ()
IO CInt -> IO ()
throwBotanIfNegative_ (IO CInt -> IO ()) -> IO CInt -> IO ()
forall a b. (a -> b) -> a -> b
$ BotanPKOpKEMEncrypt
-> BotanRNG
-> ConstPtr Word8
-> CSize
-> CSize
-> Ptr Word8
-> Ptr CSize
-> Ptr Word8
-> Ptr CSize
-> IO CInt
botan_pk_op_kem_encrypt_create_shared_key
                                BotanPKOpKEMEncrypt
kePtr
                                BotanRNG
botanRNG
                                (Ptr Word8 -> ConstPtr Word8
forall a. Ptr a -> ConstPtr a
ConstPtr Ptr Word8
saltPtr)
                                CSize
saltLen
                                (Int -> CSize
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
desiredLen)
                                Ptr Word8
sharedPtr
                                Ptr CSize
sharedSzPtr
                                Ptr Word8
encapPtr
                                Ptr CSize
encapSzPtr

newtype KEMDecrypt = MkKEMDecrypt { KEMDecrypt -> ForeignPtr BotanPKOpKEMDecryptStruct
foreignPtr :: ForeignPtr BotanPKOpKEMDecryptStruct }

withKEMDecrypt     :: KEMDecrypt -> (BotanPKOpKEMDecrypt -> IO a) -> IO a
kemDecryptDestroy  :: KEMDecrypt -> IO ()
createKEMDecrypt   :: (Ptr BotanPKOpKEMDecrypt -> IO CInt) -> IO KEMDecrypt
(KEMDecrypt -> (BotanPKOpKEMDecrypt -> IO a) -> IO a
withKEMDecrypt, KEMDecrypt -> IO ()
kemDecryptDestroy, (Ptr BotanPKOpKEMDecrypt -> IO CInt) -> IO KEMDecrypt
createKEMDecrypt)
    = (Ptr BotanPKOpKEMDecryptStruct -> BotanPKOpKEMDecrypt)
-> (BotanPKOpKEMDecrypt -> Ptr BotanPKOpKEMDecryptStruct)
-> (ForeignPtr BotanPKOpKEMDecryptStruct -> KEMDecrypt)
-> (KEMDecrypt -> ForeignPtr BotanPKOpKEMDecryptStruct)
-> FinalizerPtr BotanPKOpKEMDecryptStruct
-> (KEMDecrypt -> (BotanPKOpKEMDecrypt -> IO a) -> IO a,
    KEMDecrypt -> IO (),
    (Ptr BotanPKOpKEMDecrypt -> IO CInt) -> IO KEMDecrypt)
forall botan struct object a.
Storable botan =>
(Ptr struct -> botan)
-> (botan -> Ptr struct)
-> (ForeignPtr struct -> object)
-> (object -> ForeignPtr struct)
-> FinalizerPtr struct
-> (object -> (botan -> IO a) -> IO a, object -> IO (),
    (Ptr botan -> IO CInt) -> IO object)
mkBindings
        Ptr BotanPKOpKEMDecryptStruct -> BotanPKOpKEMDecrypt
MkBotanPKOpKEMDecrypt (.ptr)
        ForeignPtr BotanPKOpKEMDecryptStruct -> KEMDecrypt
MkKEMDecrypt (.foreignPtr)
        FinalizerPtr BotanPKOpKEMDecryptStruct
botan_pk_op_kem_decrypt_destroy

kemDecryptCreate
    :: PrivKey          -- ^ __key__
    -> KDFName          -- ^ __kdf__
    -> IO KEMDecrypt    -- ^ __op__
kemDecryptCreate :: PrivKey -> KEMSharedKey -> IO KEMDecrypt
kemDecryptCreate PrivKey
sk KEMSharedKey
algo = PrivKey -> (BotanPrivKey -> IO KEMDecrypt) -> IO KEMDecrypt
forall a. PrivKey -> (BotanPrivKey -> IO a) -> IO a
withPrivKey PrivKey
sk ((BotanPrivKey -> IO KEMDecrypt) -> IO KEMDecrypt)
-> (BotanPrivKey -> IO KEMDecrypt) -> IO KEMDecrypt
forall a b. (a -> b) -> a -> b
$ \ BotanPrivKey
skPtr -> do
    KEMSharedKey -> (Ptr CChar -> IO KEMDecrypt) -> IO KEMDecrypt
forall a. KEMSharedKey -> (Ptr CChar -> IO a) -> IO a
asCString KEMSharedKey
algo ((Ptr CChar -> IO KEMDecrypt) -> IO KEMDecrypt)
-> (Ptr CChar -> IO KEMDecrypt) -> IO KEMDecrypt
forall a b. (a -> b) -> a -> b
$ \ Ptr CChar
algoPtr -> do
        (Ptr BotanPKOpKEMDecrypt -> IO CInt) -> IO KEMDecrypt
createKEMDecrypt ((Ptr BotanPKOpKEMDecrypt -> IO CInt) -> IO KEMDecrypt)
-> (Ptr BotanPKOpKEMDecrypt -> IO CInt) -> IO KEMDecrypt
forall a b. (a -> b) -> a -> b
$ \ Ptr BotanPKOpKEMDecrypt
out -> Ptr BotanPKOpKEMDecrypt
-> BotanPrivKey -> ConstPtr CChar -> IO CInt
botan_pk_op_kem_decrypt_create
            Ptr BotanPKOpKEMDecrypt
out
            BotanPrivKey
skPtr
            (Ptr CChar -> ConstPtr CChar
forall a. Ptr a -> ConstPtr a
ConstPtr Ptr CChar
algoPtr)

kemDecryptSharedKeyLength
    :: KEMDecrypt   -- ^ __op__
    -> Int          -- ^ __desired_shared_key_length__
    -> IO Int       -- ^ __output_shared_key_length__
kemDecryptSharedKeyLength :: KEMDecrypt -> Int -> IO Int
kemDecryptSharedKeyLength = WithPtr KEMDecrypt BotanPKOpKEMDecrypt
-> GetSize_csize BotanPKOpKEMDecrypt -> KEMDecrypt -> Int -> IO Int
forall typ ptr.
WithPtr typ ptr -> GetSize_csize ptr -> typ -> Int -> IO Int
mkGetSize_csize KEMDecrypt -> (BotanPKOpKEMDecrypt -> IO a) -> IO a
WithPtr KEMDecrypt BotanPKOpKEMDecrypt
withKEMDecrypt GetSize_csize BotanPKOpKEMDecrypt
botan_pk_op_kem_decrypt_shared_key_length

kemDecryptSharedKey
    :: KEMDecrypt           -- ^ __op__
    -> ByteString           -- ^ __salt[]__
    -> KEMEncapsulatedKey   -- ^ __encapsulated_key[]__
    -> Int                  -- ^ __desired_shared_key_len__
    -> IO KEMSharedKey      -- ^ __shared_key[]__
kemDecryptSharedKey :: KEMDecrypt
-> KEMSharedKey -> KEMSharedKey -> Int -> IO KEMSharedKey
kemDecryptSharedKey KEMDecrypt
kd KEMSharedKey
salt KEMSharedKey
encap Int
desiredLen = KEMDecrypt
-> (BotanPKOpKEMDecrypt -> IO KEMSharedKey) -> IO KEMSharedKey
WithPtr KEMDecrypt BotanPKOpKEMDecrypt
withKEMDecrypt KEMDecrypt
kd ((BotanPKOpKEMDecrypt -> IO KEMSharedKey) -> IO KEMSharedKey)
-> (BotanPKOpKEMDecrypt -> IO KEMSharedKey) -> IO KEMSharedKey
forall a b. (a -> b) -> a -> b
$ \ BotanPKOpKEMDecrypt
kdPtr -> do
    KEMSharedKey
-> (Ptr Word8 -> CSize -> IO KEMSharedKey) -> IO KEMSharedKey
forall byte a. KEMSharedKey -> (Ptr byte -> CSize -> IO a) -> IO a
asBytesLen KEMSharedKey
salt ((Ptr Word8 -> CSize -> IO KEMSharedKey) -> IO KEMSharedKey)
-> (Ptr Word8 -> CSize -> IO KEMSharedKey) -> IO KEMSharedKey
forall a b. (a -> b) -> a -> b
$ \ Ptr Word8
saltPtr CSize
saltLen -> do
        KEMSharedKey
-> (Ptr Word8 -> CSize -> IO KEMSharedKey) -> IO KEMSharedKey
forall byte a. KEMSharedKey -> (Ptr byte -> CSize -> IO a) -> IO a
asBytesLen KEMSharedKey
encap ((Ptr Word8 -> CSize -> IO KEMSharedKey) -> IO KEMSharedKey)
-> (Ptr Word8 -> CSize -> IO KEMSharedKey) -> IO KEMSharedKey
forall a b. (a -> b) -> a -> b
$ \ Ptr Word8
encapPtr CSize
encapLen -> do
            -- TODO: Consolidate with allocBytesUpperBound or whatever I end up calling it
            (Ptr CSize -> IO KEMSharedKey) -> IO KEMSharedKey
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr CSize -> IO KEMSharedKey) -> IO KEMSharedKey)
-> (Ptr CSize -> IO KEMSharedKey) -> IO KEMSharedKey
forall a b. (a -> b) -> a -> b
$ \ Ptr CSize
sharedSzPtr -> do
                Int
sharedSz <- KEMDecrypt -> Int -> IO Int
kemDecryptSharedKeyLength KEMDecrypt
kd Int
desiredLen
                Ptr CSize -> CSize -> IO ()
forall a. Storable a => Ptr a -> a -> IO ()
poke Ptr CSize
sharedSzPtr (Int -> CSize
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
sharedSz)
                KEMSharedKey
bytes <- Int -> (Ptr Word8 -> IO ()) -> IO KEMSharedKey
forall byte. Int -> (Ptr byte -> IO ()) -> IO KEMSharedKey
allocBytes Int
sharedSz ((Ptr Word8 -> IO ()) -> IO KEMSharedKey)
-> (Ptr Word8 -> IO ()) -> IO KEMSharedKey
forall a b. (a -> b) -> a -> b
$ \ Ptr Word8
outPtr -> do
                    HasCallStack => IO CInt -> IO ()
IO CInt -> IO ()
throwBotanIfNegative_ (IO CInt -> IO ()) -> IO CInt -> IO ()
forall a b. (a -> b) -> a -> b
$ BotanPKOpKEMDecrypt
-> ConstPtr Word8
-> CSize
-> ConstPtr Word8
-> CSize
-> CSize
-> Ptr Word8
-> Ptr CSize
-> IO CInt
botan_pk_op_kem_decrypt_shared_key
                        BotanPKOpKEMDecrypt
kdPtr
                        (Ptr Word8 -> ConstPtr Word8
forall a. Ptr a -> ConstPtr a
ConstPtr Ptr Word8
saltPtr)
                        CSize
saltLen
                        (Ptr Word8 -> ConstPtr Word8
forall a. Ptr a -> ConstPtr a
ConstPtr Ptr Word8
encapPtr)
                        CSize
encapLen
                        (Int -> CSize
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
desiredLen)
                        Ptr Word8
outPtr
                        Ptr CSize
sharedSzPtr
                CSize
actualSharedSz <- Ptr CSize -> IO CSize
forall a. Storable a => Ptr a -> IO a
peek Ptr CSize
sharedSzPtr
                KEMSharedKey -> IO KEMSharedKey
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (KEMSharedKey -> IO KEMSharedKey)
-> KEMSharedKey -> IO KEMSharedKey
forall a b. NFData a => (a -> b) -> a -> b
$!! Int -> KEMSharedKey -> KEMSharedKey
ByteString.take (CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CSize
actualSharedSz) KEMSharedKey
bytes