{-|
Module      : Botan.Low.PubKey.Decrypt
Description : Public Key Decryption
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.Decrypt (

  -- * Public key decryption
    Decrypt(..)
  , withDecrypt
  , decryptCreate
  , decryptDestroy
  , decryptOutputLength
  , decrypt

  ) where

import           Botan.Bindings.ConstPtr (ConstPtr (..))
import           Botan.Bindings.PubKey.Decrypt
import           Botan.Low.Error.Internal (throwBotanIfNegative_)
import           Botan.Low.Internal.ByteString
import           Botan.Low.Make
import           Botan.Low.PubKey
import           Botan.Low.Remake
import           Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Internal as BSI
import           Foreign.C.Types
import           Foreign.ForeignPtr
import           Foreign.Marshal.Alloc
import           Foreign.Ptr
import           Foreign.Storable

-- /*
-- * Public Key Decryption
-- */

newtype Decrypt = MkDecrypt { Decrypt -> ForeignPtr BotanPKOpDecryptStruct
foreignPtr :: ForeignPtr BotanPKOpDecryptStruct }

withDecrypt     :: Decrypt -> (BotanPKOpDecrypt -> IO a) -> IO a
decryptDestroy  :: Decrypt -> IO ()
createDecrypt   :: (Ptr BotanPKOpDecrypt -> IO CInt) -> IO Decrypt
(Decrypt -> (BotanPKOpDecrypt -> IO a) -> IO a
withDecrypt, Decrypt -> IO ()
decryptDestroy, (Ptr BotanPKOpDecrypt -> IO CInt) -> IO Decrypt
createDecrypt)
    = (Ptr BotanPKOpDecryptStruct -> BotanPKOpDecrypt)
-> (BotanPKOpDecrypt -> Ptr BotanPKOpDecryptStruct)
-> (ForeignPtr BotanPKOpDecryptStruct -> Decrypt)
-> (Decrypt -> ForeignPtr BotanPKOpDecryptStruct)
-> FinalizerPtr BotanPKOpDecryptStruct
-> (Decrypt -> (BotanPKOpDecrypt -> IO a) -> IO a,
    Decrypt -> IO (), (Ptr BotanPKOpDecrypt -> IO CInt) -> IO Decrypt)
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 BotanPKOpDecryptStruct -> BotanPKOpDecrypt
MkBotanPKOpDecrypt (.ptr)
        ForeignPtr BotanPKOpDecryptStruct -> Decrypt
MkDecrypt (.foreignPtr)
        FinalizerPtr BotanPKOpDecryptStruct
botan_pk_op_decrypt_destroy

decryptCreate
    :: PrivKey  -- ^ __key__
    -> EMEName  -- ^ __padding__
    -> IO Decrypt
decryptCreate :: PrivKey -> EMEName -> IO Decrypt
decryptCreate PrivKey
sk EMEName
padding =  PrivKey -> (BotanPrivKey -> IO Decrypt) -> IO Decrypt
forall a. PrivKey -> (BotanPrivKey -> IO a) -> IO a
withPrivKey PrivKey
sk ((BotanPrivKey -> IO Decrypt) -> IO Decrypt)
-> (BotanPrivKey -> IO Decrypt) -> IO Decrypt
forall a b. (a -> b) -> a -> b
$ \ BotanPrivKey
skPtr -> do
    EMEName -> (Ptr CChar -> IO Decrypt) -> IO Decrypt
forall a. EMEName -> (Ptr CChar -> IO a) -> IO a
asCString EMEName
padding ((Ptr CChar -> IO Decrypt) -> IO Decrypt)
-> (Ptr CChar -> IO Decrypt) -> IO Decrypt
forall a b. (a -> b) -> a -> b
$ \ Ptr CChar
paddingPtr -> do
        (Ptr BotanPKOpDecrypt -> IO CInt) -> IO Decrypt
createDecrypt ((Ptr BotanPKOpDecrypt -> IO CInt) -> IO Decrypt)
-> (Ptr BotanPKOpDecrypt -> IO CInt) -> IO Decrypt
forall a b. (a -> b) -> a -> b
$ \ Ptr BotanPKOpDecrypt
out -> Ptr BotanPKOpDecrypt
-> BotanPrivKey -> Ptr CChar -> Word32 -> IO CInt
botan_pk_op_decrypt_create
            Ptr BotanPKOpDecrypt
out
            BotanPrivKey
skPtr
            Ptr CChar
paddingPtr
            Word32
forall a. (Eq a, Num a) => a
BOTAN_PUBKEY_DECRYPT_FLAGS_NONE

decryptOutputLength
    :: Decrypt  -- ^ __op__
    -> Int      -- ^ __ctext_len__
    -> IO Int   -- ^ __ptext_len__
decryptOutputLength :: Decrypt -> Int -> IO Int
decryptOutputLength = WithPtr Decrypt BotanPKOpDecrypt
-> GetSize_csize BotanPKOpDecrypt -> Decrypt -> Int -> IO Int
forall typ ptr.
WithPtr typ ptr -> GetSize_csize ptr -> typ -> Int -> IO Int
mkGetSize_csize Decrypt -> (BotanPKOpDecrypt -> IO a) -> IO a
WithPtr Decrypt BotanPKOpDecrypt
withDecrypt GetSize_csize BotanPKOpDecrypt
botan_pk_op_decrypt_output_length

decrypt ::
     Decrypt          -- ^ __op__
  -> ByteString       -- ^ __ciphertext__
  -> IO ByteString    -- ^ __plaintext__
decrypt :: Decrypt -> EMEName -> IO EMEName
decrypt Decrypt
dec EMEName
ctext =
    Decrypt -> (BotanPKOpDecrypt -> IO EMEName) -> IO EMEName
WithPtr Decrypt BotanPKOpDecrypt
withDecrypt Decrypt
dec ((BotanPKOpDecrypt -> IO EMEName) -> IO EMEName)
-> (BotanPKOpDecrypt -> IO EMEName) -> IO EMEName
forall a b. (a -> b) -> a -> b
$ \ BotanPKOpDecrypt
decPtr ->
    EMEName -> (Ptr Word8 -> CSize -> IO EMEName) -> IO EMEName
forall byte a. EMEName -> (Ptr byte -> CSize -> IO a) -> IO a
asBytesLen EMEName
ctext ((Ptr Word8 -> CSize -> IO EMEName) -> IO EMEName)
-> (Ptr Word8 -> CSize -> IO EMEName) -> IO EMEName
forall a b. (a -> b) -> a -> b
$ \ Ptr Word8
ctextPtr CSize
ctextLen ->
    (Ptr CSize -> IO EMEName) -> IO EMEName
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr CSize -> IO EMEName) -> IO EMEName)
-> (Ptr CSize -> IO EMEName) -> IO EMEName
forall a b. (a -> b) -> a -> b
$ \Ptr CSize
szPtr -> do
      Int
sz <- Decrypt -> Int -> IO Int
decryptOutputLength Decrypt
dec (EMEName -> Int
BS.length EMEName
ctext)
      Ptr CSize -> CSize -> IO ()
forall a. Storable a => Ptr a -> a -> IO ()
poke Ptr CSize
szPtr (Int -> CSize
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
sz)
      Int -> (Ptr Word8 -> IO Int) -> IO EMEName
BSI.createAndTrim Int
sz ((Ptr Word8 -> IO Int) -> IO EMEName)
-> (Ptr Word8 -> IO Int) -> IO EMEName
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
$
          BotanPKOpDecrypt
-> Ptr Word8 -> Ptr CSize -> ConstPtr Word8 -> CSize -> IO CInt
botan_pk_op_decrypt
            BotanPKOpDecrypt
decPtr
            Ptr Word8
outPtr
            Ptr CSize
szPtr
            (Ptr Word8 -> ConstPtr Word8
forall a. Ptr a -> ConstPtr a
ConstPtr Ptr Word8
ctextPtr)
            CSize
ctextLen
        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
szPtr