{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
module Sel.PublicKey.Seal
(
PublicKey (..)
, SecretKey (..)
, newKeyPair
, seal
, open
, KeyPairGenerationException
, EncryptionError
) where
import Control.Exception (throw)
import Control.Monad (when)
import Data.ByteString (StrictByteString)
import qualified Data.ByteString.Unsafe as BS
import qualified Foreign
import Foreign.C (CChar, CSize, CUChar, CULLong)
import LibSodium.Bindings.SealedBoxes
( cryptoBoxSeal
, cryptoBoxSealOpen
, cryptoBoxSealbytes
)
import System.IO.Unsafe (unsafeDupablePerformIO)
import Sel.PublicKey.Cipher
( Ciphertext (Ciphertext)
, EncryptionError (..)
, KeyPairGenerationException
, PublicKey (PublicKey)
, SecretKey (..)
, newKeyPair
)
seal
:: StrictByteString
-> PublicKey
-> IO Ciphertext
seal :: StrictByteString -> PublicKey -> IO Ciphertext
seal StrictByteString
messageByteString (PublicKey ForeignPtr CUChar
publicKeyFptr) = do
StrictByteString -> (CStringLen -> IO Ciphertext) -> IO Ciphertext
forall a. StrictByteString -> (CStringLen -> IO a) -> IO a
BS.unsafeUseAsCStringLen StrictByteString
messageByteString ((CStringLen -> IO Ciphertext) -> IO Ciphertext)
-> (CStringLen -> IO Ciphertext) -> IO Ciphertext
forall a b. (a -> b) -> a -> b
$ \(Ptr CChar
messagePtr, Int
messageLen) -> do
ciphertextForeignPtr <-
Int -> IO (ForeignPtr CUChar)
forall a. Int -> IO (ForeignPtr a)
Foreign.mallocForeignPtrBytes
(Int
messageLen Int -> Int -> Int
forall a. Num a => a -> a -> a
+ CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CSize
cryptoBoxSealbytes)
Foreign.withForeignPtr publicKeyFptr $ \Ptr CUChar
publicKeyPtr ->
ForeignPtr CUChar -> (Ptr CUChar -> IO Ciphertext) -> IO Ciphertext
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr CUChar
ciphertextForeignPtr ((Ptr CUChar -> IO Ciphertext) -> IO Ciphertext)
-> (Ptr CUChar -> IO Ciphertext) -> IO Ciphertext
forall a b. (a -> b) -> a -> b
$ \Ptr CUChar
ciphertextPtr -> do
result <-
Ptr CUChar -> Ptr CUChar -> CULLong -> Ptr CUChar -> IO CInt
cryptoBoxSeal
Ptr CUChar
ciphertextPtr
(forall a b. Ptr a -> Ptr b
Foreign.castPtr @CChar @CUChar Ptr CChar
messagePtr)
(forall a b. (Integral a, Num b) => a -> b
fromIntegral @Int @CULLong Int
messageLen)
Ptr CUChar
publicKeyPtr
when (result /= 0) $ throw EncryptionError
pure $
Ciphertext
(fromIntegral @Int @CULLong messageLen)
ciphertextForeignPtr
open
:: Ciphertext
-> PublicKey
-> SecretKey
-> Maybe StrictByteString
open :: Ciphertext -> PublicKey -> SecretKey -> Maybe StrictByteString
open
(Ciphertext CULLong
messageLen ForeignPtr CUChar
cipherForeignPtr)
(PublicKey ForeignPtr CUChar
publicKeyFPtr)
(SecretKey ForeignPtr CUChar
secretKeyFPtr) = IO (Maybe StrictByteString) -> Maybe StrictByteString
forall a. IO a -> a
unsafeDupablePerformIO (IO (Maybe StrictByteString) -> Maybe StrictByteString)
-> IO (Maybe StrictByteString) -> Maybe StrictByteString
forall a b. (a -> b) -> a -> b
$ do
messagePtr <- Int -> IO (Ptr CUChar)
forall a. Int -> IO (Ptr a)
Foreign.mallocBytes (forall a b. (Integral a, Num b) => a -> b
fromIntegral @CULLong @Int CULLong
messageLen)
Foreign.withForeignPtr cipherForeignPtr $ \Ptr CUChar
ciphertextPtr ->
ForeignPtr CUChar
-> (Ptr CUChar -> IO (Maybe StrictByteString))
-> IO (Maybe StrictByteString)
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr CUChar
publicKeyFPtr ((Ptr CUChar -> IO (Maybe StrictByteString))
-> IO (Maybe StrictByteString))
-> (Ptr CUChar -> IO (Maybe StrictByteString))
-> IO (Maybe StrictByteString)
forall a b. (a -> b) -> a -> b
$ \Ptr CUChar
publicKeyPtr ->
ForeignPtr CUChar
-> (Ptr CUChar -> IO (Maybe StrictByteString))
-> IO (Maybe StrictByteString)
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr CUChar
secretKeyFPtr ((Ptr CUChar -> IO (Maybe StrictByteString))
-> IO (Maybe StrictByteString))
-> (Ptr CUChar -> IO (Maybe StrictByteString))
-> IO (Maybe StrictByteString)
forall a b. (a -> b) -> a -> b
$ \Ptr CUChar
secretKeyPtr -> do
result <-
Ptr CUChar
-> Ptr CUChar -> CULLong -> Ptr CUChar -> Ptr CUChar -> IO CInt
cryptoBoxSealOpen
Ptr CUChar
messagePtr
Ptr CUChar
ciphertextPtr
(CULLong
messageLen CULLong -> CULLong -> CULLong
forall a. Num a => a -> a -> a
+ forall a b. (Integral a, Num b) => a -> b
fromIntegral @CSize @CULLong CSize
cryptoBoxSealbytes)
Ptr CUChar
publicKeyPtr
Ptr CUChar
secretKeyPtr
case result of
(-1) -> Maybe StrictByteString -> IO (Maybe StrictByteString)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe StrictByteString
forall a. Maybe a
Nothing
CInt
_ -> do
bsPtr <- Int -> IO (Ptr CUChar)
forall a. Int -> IO (Ptr a)
Foreign.mallocBytes (CULLong -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CULLong
messageLen)
Foreign.copyBytes bsPtr messagePtr (fromIntegral messageLen)
Just
<$> BS.unsafePackMallocCStringLen
(Foreign.castPtr @CUChar @CChar bsPtr, fromIntegral messageLen)