{-|
Module      : Botan.Low.Encrypt
Description : Public Key Encryption
Copyright   : (c) Leo D, 2023
License     : BSD-3-Clause
Maintainer  : leo@apotheca.io
Stability   : experimental
Portability : POSIX
-}

module Botan.Low.PubKey.Encrypt
(

-- * Public key encryption
  Encrypt(..)
, withEncrypt
, encryptCreate
, encryptDestroy
, encryptOutputLength
, encrypt

) where

import qualified Data.ByteString as ByteString

import Botan.Bindings.PubKey.Encrypt

import Botan.Low.Error
import Botan.Low.Make
import Botan.Low.Prelude
import Botan.Low.RNG
import Botan.Low.PubKey
import Botan.Low.Remake

-- /*
-- * Public Key Encryption
-- */

newtype Encrypt = MkEncrypt { Encrypt -> ForeignPtr BotanPKOpEncryptStruct
getEncryptForeignPtr :: ForeignPtr BotanPKOpEncryptStruct }

newEncrypt      :: BotanPKOpEncrypt -> IO Encrypt
withEncrypt     :: Encrypt -> (BotanPKOpEncrypt -> IO a) -> IO a
encryptDestroy  :: Encrypt -> IO ()
createEncrypt   :: (Ptr BotanPKOpEncrypt -> IO CInt) -> IO Encrypt
(BotanPKOpEncrypt -> IO Encrypt
newEncrypt, Encrypt -> (BotanPKOpEncrypt -> IO a) -> IO a
withEncrypt, Encrypt -> IO ()
encryptDestroy, (Ptr BotanPKOpEncrypt -> IO CInt) -> IO Encrypt
createEncrypt, (Ptr BotanPKOpEncrypt -> Ptr CSize -> IO CInt) -> IO [Encrypt]
_)
    = (Ptr BotanPKOpEncryptStruct -> BotanPKOpEncrypt)
-> (BotanPKOpEncrypt -> Ptr BotanPKOpEncryptStruct)
-> (ForeignPtr BotanPKOpEncryptStruct -> Encrypt)
-> (Encrypt -> ForeignPtr BotanPKOpEncryptStruct)
-> FinalizerPtr BotanPKOpEncryptStruct
-> (BotanPKOpEncrypt -> IO Encrypt,
    Encrypt -> (BotanPKOpEncrypt -> IO a) -> IO a, Encrypt -> IO (),
    (Ptr BotanPKOpEncrypt -> IO CInt) -> IO Encrypt,
    (Ptr BotanPKOpEncrypt -> Ptr CSize -> IO CInt) -> IO [Encrypt])
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 BotanPKOpEncryptStruct -> BotanPKOpEncrypt
MkBotanPKOpEncrypt BotanPKOpEncrypt -> Ptr BotanPKOpEncryptStruct
runBotanPKOpEncrypt
        ForeignPtr BotanPKOpEncryptStruct -> Encrypt
MkEncrypt Encrypt -> ForeignPtr BotanPKOpEncryptStruct
getEncryptForeignPtr
        FinalizerPtr BotanPKOpEncryptStruct
botan_pk_op_encrypt_destroy

encryptCreate
    :: PubKey       -- ^ __key__
    -> EMEName      -- ^ __padding__
    -> IO Encrypt   -- ^ __op__
encryptCreate :: PubKey -> EMEName -> IO Encrypt
encryptCreate PubKey
pk EMEName
padding = PubKey -> (BotanPubKey -> IO Encrypt) -> IO Encrypt
forall a. PubKey -> (BotanPubKey -> IO a) -> IO a
withPubKey PubKey
pk ((BotanPubKey -> IO Encrypt) -> IO Encrypt)
-> (BotanPubKey -> IO Encrypt) -> IO Encrypt
forall a b. (a -> b) -> a -> b
$ \ BotanPubKey
pkPtr -> do
    EMEName -> (Ptr CChar -> IO Encrypt) -> IO Encrypt
forall a. EMEName -> (Ptr CChar -> IO a) -> IO a
asCString EMEName
padding ((Ptr CChar -> IO Encrypt) -> IO Encrypt)
-> (Ptr CChar -> IO Encrypt) -> IO Encrypt
forall a b. (a -> b) -> a -> b
$ \ Ptr CChar
paddingPtr -> do
        (Ptr BotanPKOpEncrypt -> IO CInt) -> IO Encrypt
createEncrypt ((Ptr BotanPKOpEncrypt -> IO CInt) -> IO Encrypt)
-> (Ptr BotanPKOpEncrypt -> IO CInt) -> IO Encrypt
forall a b. (a -> b) -> a -> b
$ \ Ptr BotanPKOpEncrypt
out -> Ptr BotanPKOpEncrypt
-> BotanPubKey -> ConstPtr CChar -> Word32 -> IO CInt
botan_pk_op_encrypt_create
            Ptr BotanPKOpEncrypt
out
            BotanPubKey
pkPtr
            (Ptr CChar -> ConstPtr CChar
forall a. Ptr a -> ConstPtr a
ConstPtr Ptr CChar
paddingPtr)
            Word32
0
            
-- WARNING: withFooInit-style limited lifetime functions moved to high-level botan
withEncryptCreate :: PubKey -> EMEName -> (Encrypt -> IO a) -> IO a
withEncryptCreate :: forall a. PubKey -> EMEName -> (Encrypt -> IO a) -> IO a
withEncryptCreate = (PubKey -> EMEName -> IO Encrypt)
-> (Encrypt -> IO ())
-> PubKey
-> EMEName
-> (Encrypt -> IO a)
-> IO a
forall x y t a.
(x -> y -> IO t) -> (t -> IO ()) -> x -> y -> (t -> IO a) -> IO a
mkWithTemp2 PubKey -> EMEName -> IO Encrypt
encryptCreate Encrypt -> IO ()
encryptDestroy

encryptOutputLength
    :: Encrypt  -- ^ __op__
    -> Int      -- ^ __ptext_len__
    -> IO Int   -- ^ __ctext_len__
encryptOutputLength :: Encrypt -> Int -> IO Int
encryptOutputLength = WithPtr Encrypt BotanPKOpEncrypt
-> GetSize_csize BotanPKOpEncrypt -> Encrypt -> Int -> IO Int
forall typ ptr.
WithPtr typ ptr -> GetSize_csize ptr -> typ -> Int -> IO Int
mkGetSize_csize Encrypt -> (BotanPKOpEncrypt -> IO a) -> IO a
WithPtr Encrypt BotanPKOpEncrypt
withEncrypt GetSize_csize BotanPKOpEncrypt
botan_pk_op_encrypt_output_length

-- NOTE: This properly takes advantage of szPtr, queries the buffer size - do this elsewhere
-- NOTE: SM2 take a hash instead of a padding, and encrypt fails with InsufficientBufferSpace
--  if sm2p256v1 is not used as the curve when creating the key (but creating the key and
--  the encryption context do not fail)
--  This implies that encryptOutputLength may be wrong or hardcoded for SM2 or that we
--  are not supposed to use curves other than sm2p256v1 - this needs investigating
encrypt
    :: Encrypt          -- ^ __op__
    -> RNG              -- ^ __rng__
    -> ByteString       -- ^ __plaintext[]__
    -> IO ByteString    -- ^ __ciphertext[]__
encrypt :: Encrypt -> RNG -> EMEName -> IO EMEName
encrypt Encrypt
enc RNG
rng EMEName
ptext = Encrypt -> (BotanPKOpEncrypt -> IO EMEName) -> IO EMEName
WithPtr Encrypt BotanPKOpEncrypt
withEncrypt Encrypt
enc ((BotanPKOpEncrypt -> IO EMEName) -> IO EMEName)
-> (BotanPKOpEncrypt -> IO EMEName) -> IO EMEName
forall a b. (a -> b) -> a -> b
$ \ BotanPKOpEncrypt
encPtr -> do
    RNG -> (BotanRNG -> IO EMEName) -> IO EMEName
forall a. RNG -> (BotanRNG -> IO a) -> IO a
withRNG RNG
rng ((BotanRNG -> IO EMEName) -> IO EMEName)
-> (BotanRNG -> IO EMEName) -> IO EMEName
forall a b. (a -> b) -> a -> b
$ \ BotanRNG
botanRNG -> do
        EMEName -> (Ptr Word8 -> CSize -> IO EMEName) -> IO EMEName
forall byte a. EMEName -> (Ptr byte -> CSize -> IO a) -> IO a
asBytesLen EMEName
ptext ((Ptr Word8 -> CSize -> IO EMEName) -> IO EMEName)
-> (Ptr Word8 -> CSize -> IO EMEName) -> IO EMEName
forall a b. (a -> b) -> a -> b
$ \ Ptr Word8
ptextPtr CSize
ptextLen -> do
            (Ptr Word8 -> Ptr CSize -> IO CInt) -> IO EMEName
forall byte. (Ptr byte -> Ptr CSize -> IO CInt) -> IO EMEName
allocBytesQuerying ((Ptr Word8 -> Ptr CSize -> IO CInt) -> IO EMEName)
-> (Ptr Word8 -> Ptr CSize -> IO CInt) -> IO EMEName
forall a b. (a -> b) -> a -> b
$ \ Ptr Word8
outPtr Ptr CSize
szPtr -> BotanPKOpEncrypt
-> BotanRNG
-> Ptr Word8
-> Ptr CSize
-> Ptr Word8
-> CSize
-> IO CInt
botan_pk_op_encrypt
                BotanPKOpEncrypt
encPtr
                BotanRNG
botanRNG
                Ptr Word8
outPtr
                Ptr CSize
szPtr
                Ptr Word8
ptextPtr
                CSize
ptextLen