sel-0.1.0.0: src/Sel/PublicKey/Seal.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
-- |
--
-- Module: Sel.PublicKey.Seal
-- Description: Anonymous ephemeral authenticated encryption with public and secret keys
-- Copyright: (C) Hécate Moonlight 2022
-- License: BSD-3-Clause
-- Maintainer: The Haskell Cryptography Group
-- Portability: GHC only
module Sel.PublicKey.Seal
( -- ** Introduction
-- $introduction
-- ** Usage
-- $usage
-- ** Keys
PublicKey (..)
, SecretKey (..)
, newKeyPair
-- ** Operations
, seal
, open
-- ** Errors
, 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
)
-- $introduction
-- Ephemeral authenticated encryption allows to anonymously send message to
-- a recipient given their public key.
--
-- Only the recipient can decrypt these messages using their own secret key.
-- While the recipient can verify the integrity of the message, they cannot
-- verify the identity of the sender.
--
-- A message is encrypted using an ephemeral key pair, with the secret key being erased
-- right after the encryption process.
--
-- Without knowing the secret key used for a given message, the sender cannot decrypt
-- their own message later. Furthermore, without additional data, a message cannot
-- be correlated with the identity of its sender.
-- $usage
--
-- > import qualified Sel.PublicKey.Seal as Seal
-- > import Sel (secureMain)
-- >
-- > main = secureMain $ do
-- > -- We get the recipient their pair of keys:
-- > (recipientPublicKey, recipientSecretKey) <- newKeyPair
-- > encryptedMessage <- Seal.encrypt "hello hello" recipientPublicKey
-- > let result = Seal.open encryptedMessage recipientPublicKey recipientSecretKey
-- > print result
-- > -- "Just \"hello hello\""
-- | Encrypt a message with the recipient's public key. A key pair for the sender
-- is generated, and the public key of that pair is attached to the cipher text.
-- The secret key of the sender's pair is automatically destroyed.
--
-- @since 0.0.1.0
seal
:: StrictByteString
-- ^ Message to encrypt
-> PublicKey
-- ^ Public key of the recipient
-> IO Ciphertext
seal messageByteString (PublicKey publicKeyFptr) = do
BS.unsafeUseAsCStringLen messageByteString $ \(messagePtr, messageLen) -> do
ciphertextForeignPtr <-
Foreign.mallocForeignPtrBytes
(messageLen + fromIntegral cryptoBoxSealbytes)
Foreign.withForeignPtr publicKeyFptr $ \publicKeyPtr ->
Foreign.withForeignPtr ciphertextForeignPtr $ \ciphertextPtr -> do
result <-
cryptoBoxSeal
ciphertextPtr
(Foreign.castPtr @CChar @CUChar messagePtr)
(fromIntegral @Int @CULLong messageLen)
publicKeyPtr
when (result /= 0) $ throw EncryptionError
pure $
Ciphertext
(fromIntegral @Int @CULLong messageLen)
ciphertextForeignPtr
-- | Open a sealed message from an unknown sender.
-- You need your public and secret keys.
--
-- @since 0.0.1.0
open
:: Ciphertext
-- ^ Cipher to decrypt
-> PublicKey
-- ^ Public key of the recipient
-> SecretKey
-- ^ Secret key of the recipient
-> Maybe StrictByteString
open
(Ciphertext messageLen cipherForeignPtr)
(PublicKey publicKeyFPtr)
(SecretKey secretKeyFPtr) = unsafeDupablePerformIO $ do
messagePtr <- Foreign.mallocBytes (fromIntegral @CULLong @Int messageLen)
Foreign.withForeignPtr cipherForeignPtr $ \ciphertextPtr ->
Foreign.withForeignPtr publicKeyFPtr $ \publicKeyPtr ->
Foreign.withForeignPtr secretKeyFPtr $ \secretKeyPtr -> do
result <-
cryptoBoxSealOpen
messagePtr
ciphertextPtr
(messageLen + fromIntegral @CSize @CULLong cryptoBoxSealbytes)
publicKeyPtr
secretKeyPtr
case result of
(-1) -> pure Nothing
_ -> do
bsPtr <- Foreign.mallocBytes (fromIntegral messageLen)
Foreign.copyBytes bsPtr messagePtr (fromIntegral messageLen)
Just
<$> BS.unsafePackMallocCStringLen
(Foreign.castPtr @CUChar @CChar bsPtr, fromIntegral messageLen)