{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}

-- |
--
-- Module: Sel.PublicKey.Cipher
-- Description: 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.Cipher
  ( -- ** Introduction
    -- $introduction

    -- ** Usage
    -- $usage

    -- ** Key pair generation
    newKeyPair
  , SecretKey (..)
  , unsafeSecretKeyToHexByteString
  , PublicKey (..)
  , publicKeyToHexByteString
  , keyPairFromHexByteStrings

    -- ** Nonce
  , Nonce (..)
  , nonceFromHexByteString
  , nonceToHexByteString

    -- ** Cipher text
  , CipherText (..)
  , cipherTextFromHexByteString
  , cipherTextToHexText
  , cipherTextToHexByteString
  , cipherTextToBinary

    -- ** Encryption and Decryption
  , encrypt
  , decrypt

    -- ** Errors
  , KeyPairGenerationException (..)
  , EncryptionError (..)
  ) where

import Control.Monad (when)
import Data.ByteString (StrictByteString)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Base16 as Base16
import qualified Data.ByteString.Internal as BS
import qualified Data.ByteString.Unsafe as BS
import Data.Text (Text)
import qualified Data.Text as Text
import Data.Text.Display (Display (displayBuilder), OpaqueInstance (..), ShowInstance (..))
import qualified Data.Text.Lazy.Builder as Builder
import Data.Word (Word8)
import Foreign (ForeignPtr, Ptr)
import qualified Foreign
import Foreign.C (CChar, CSize, CUChar, CULLong)
import qualified Foreign.C as Foreign
import GHC.IO.Handle.Text (memcpy)
import System.IO.Unsafe (unsafeDupablePerformIO)

import Control.Exception
import qualified Data.Base16.Types as Base16
import LibSodium.Bindings.CryptoBox
  ( cryptoBoxEasy
  , cryptoBoxKeyPair
  , cryptoBoxMACBytes
  , cryptoBoxNonceBytes
  , cryptoBoxOpenEasy
  , cryptoBoxPublicKeyBytes
  , cryptoBoxSecretKeyBytes
  )
import LibSodium.Bindings.Random (randombytesBuf)
import LibSodium.Bindings.SecureMemory (finalizerSodiumFree, sodiumFree, sodiumMalloc)
import Sel.Internal

-- $introduction
-- Public-key authenticated encryption allows a sender to encrypt a confidential message
-- specifically for the recipient, using the recipient's public key.

-- $usage
--
-- > import qualified Sel.PublicKey.Cipher as Cipher
-- >
-- > main = do
-- >   -- We get the sender their pair of keys:
-- >   (senderSecretKey, senderPublicKey) <- newKeyPair
-- >   -- We get the nonce from the other party with the message, or with 'encrypt' and our own message.
-- >   (nonce, encryptedMessage) <- Cipher.encrypt "hello hello" secretKey
-- >   let result = Cipher.decrypt encryptedMessage secretKey nonce
-- >   print result
-- >   -- "Just \"hello hello\""

-- | A secret key of size 'cryptoBoxSecretKeyBytes'.
--
-- @since 0.0.1.0
newtype SecretKey = SecretKey (ForeignPtr CUChar)
  deriving
    ( Int -> SecretKey -> Builder
[SecretKey] -> Builder
SecretKey -> Builder
(SecretKey -> Builder)
-> ([SecretKey] -> Builder)
-> (Int -> SecretKey -> Builder)
-> Display SecretKey
forall a.
(a -> Builder)
-> ([a] -> Builder) -> (Int -> a -> Builder) -> Display a
$cdisplayBuilder :: SecretKey -> Builder
displayBuilder :: SecretKey -> Builder
$cdisplayList :: [SecretKey] -> Builder
displayList :: [SecretKey] -> Builder
$cdisplayPrec :: Int -> SecretKey -> Builder
displayPrec :: Int -> SecretKey -> Builder
Display
      -- ^ @since 0.0.1.0
      -- > display secretKey == "[REDACTED]"
    )
    via (OpaqueInstance "[REDACTED]" SecretKey)

-- |
--
-- @since 0.0.1.0
instance Eq SecretKey where
  (SecretKey ForeignPtr CUChar
hk1) == :: SecretKey -> SecretKey -> Bool
== (SecretKey ForeignPtr CUChar
hk2) =
    IO Bool -> Bool
forall a. IO a -> a
unsafeDupablePerformIO (IO Bool -> Bool) -> IO Bool -> Bool
forall a b. (a -> b) -> a -> b
$
      ForeignPtr CUChar -> ForeignPtr CUChar -> CSize -> IO Bool
forall a. ForeignPtr a -> ForeignPtr a -> CSize -> IO Bool
foreignPtrEq ForeignPtr CUChar
hk1 ForeignPtr CUChar
hk2 CSize
cryptoBoxSecretKeyBytes

-- |
--
-- @since 0.0.1.0
instance Ord SecretKey where
  compare :: SecretKey -> SecretKey -> Ordering
compare (SecretKey ForeignPtr CUChar
hk1) (SecretKey ForeignPtr CUChar
hk2) =
    IO Ordering -> Ordering
forall a. IO a -> a
unsafeDupablePerformIO (IO Ordering -> Ordering) -> IO Ordering -> Ordering
forall a b. (a -> b) -> a -> b
$
      ForeignPtr CUChar -> ForeignPtr CUChar -> CSize -> IO Ordering
forall a. ForeignPtr a -> ForeignPtr a -> CSize -> IO Ordering
foreignPtrOrd ForeignPtr CUChar
hk1 ForeignPtr CUChar
hk2 CSize
cryptoBoxSecretKeyBytes

-- | > show secretKey == "[REDACTED]"
--
-- @since 0.0.1.0
instance Show SecretKey where
  show :: SecretKey -> String
show SecretKey
_ = String
"[REDACTED]"

-- | A public key of size 'cryptoBoxPublicKeyBytes'.
--
-- @since 0.0.1.0
newtype PublicKey = PublicKey (ForeignPtr CUChar)
  deriving
    ( Int -> PublicKey -> Builder
[PublicKey] -> Builder
PublicKey -> Builder
(PublicKey -> Builder)
-> ([PublicKey] -> Builder)
-> (Int -> PublicKey -> Builder)
-> Display PublicKey
forall a.
(a -> Builder)
-> ([a] -> Builder) -> (Int -> a -> Builder) -> Display a
$cdisplayBuilder :: PublicKey -> Builder
displayBuilder :: PublicKey -> Builder
$cdisplayList :: [PublicKey] -> Builder
displayList :: [PublicKey] -> Builder
$cdisplayPrec :: Int -> PublicKey -> Builder
displayPrec :: Int -> PublicKey -> Builder
Display
      -- ^ @since 0.0.1.0
    )
    via (ShowInstance PublicKey)

-- |
--
-- @since 0.0.1.0
instance Eq PublicKey where
  (PublicKey ForeignPtr CUChar
hk1) == :: PublicKey -> PublicKey -> Bool
== (PublicKey ForeignPtr CUChar
hk2) =
    IO Bool -> Bool
forall a. IO a -> a
unsafeDupablePerformIO (IO Bool -> Bool) -> IO Bool -> Bool
forall a b. (a -> b) -> a -> b
$
      ForeignPtr CUChar -> ForeignPtr CUChar -> CSize -> IO Bool
forall a. ForeignPtr a -> ForeignPtr a -> CSize -> IO Bool
foreignPtrEq ForeignPtr CUChar
hk1 ForeignPtr CUChar
hk2 CSize
cryptoBoxPublicKeyBytes

-- |
--
-- @since 0.0.1.0
instance Ord PublicKey where
  compare :: PublicKey -> PublicKey -> Ordering
compare (PublicKey ForeignPtr CUChar
hk1) (PublicKey ForeignPtr CUChar
hk2) =
    IO Ordering -> Ordering
forall a. IO a -> a
unsafeDupablePerformIO (IO Ordering -> Ordering) -> IO Ordering -> Ordering
forall a b. (a -> b) -> a -> b
$
      ForeignPtr CUChar -> ForeignPtr CUChar -> CSize -> IO Ordering
forall a. ForeignPtr a -> ForeignPtr a -> CSize -> IO Ordering
foreignPtrOrd ForeignPtr CUChar
hk1 ForeignPtr CUChar
hk2 CSize
cryptoBoxPublicKeyBytes

-- |
--
-- @since 0.0.1.0
instance Show PublicKey where
  show :: PublicKey -> String
show = ByteString -> String
BS.unpackChars (ByteString -> String)
-> (PublicKey -> ByteString) -> PublicKey -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PublicKey -> ByteString
publicKeyToHexByteString

-- | Convert a 'PublicKey' to a hexadecimal-encoded 'StrictByteString'.
--
-- @since 0.0.1.0
publicKeyToHexByteString :: PublicKey -> StrictByteString
publicKeyToHexByteString :: PublicKey -> ByteString
publicKeyToHexByteString (PublicKey ForeignPtr CUChar
publicKeyForeignPtr) =
  Base16 ByteString -> ByteString
forall a. Base16 a -> a
Base16.extractBase16 (Base16 ByteString -> ByteString)
-> (ByteString -> Base16 ByteString) -> ByteString -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Base16 ByteString
Base16.encodeBase16' (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$
    ForeignPtr Word8 -> Int -> ByteString
BS.fromForeignPtr0
      (forall a b. ForeignPtr a -> ForeignPtr b
Foreign.castForeignPtr @CUChar @Word8 ForeignPtr CUChar
publicKeyForeignPtr)
      (forall a b. (Integral a, Num b) => a -> b
fromIntegral @CSize @Int CSize
cryptoBoxPublicKeyBytes)

-- | Generate a new random secret key.
--
-- May throw 'KeyPairGenerationException' if the generation fails.
--
-- @since 0.0.1.0
newKeyPair :: IO (PublicKey, SecretKey)
newKeyPair :: IO (PublicKey, SecretKey)
newKeyPair = (Ptr CUChar -> Ptr CUChar -> IO ()) -> IO (PublicKey, SecretKey)
newKeyPairWith ((Ptr CUChar -> Ptr CUChar -> IO ()) -> IO (PublicKey, SecretKey))
-> (Ptr CUChar -> Ptr CUChar -> IO ()) -> IO (PublicKey, SecretKey)
forall a b. (a -> b) -> a -> b
$ \Ptr CUChar
publicKeyPtr Ptr CUChar
secretKeyPtr -> do
  CInt
result <- Ptr CUChar -> Ptr CUChar -> IO CInt
cryptoBoxKeyPair Ptr CUChar
publicKeyPtr Ptr CUChar
secretKeyPtr
  Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (CInt
result CInt -> CInt -> Bool
forall a. Eq a => a -> a -> Bool
/= CInt
0) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ KeyPairGenerationException -> IO ()
forall a e. Exception e => e -> a
throw KeyPairGenerationException
KeyPairGenerationException

-- | Create a pair of 'SecretKey' and 'PublicKey'  from hexadecimal-encoded
-- 'StrictByteString's that you have obtained on your own, usually from the network or disk.
--
-- The public and secret keys, once decoded from base16, must respectively
-- be at least of length 'cryptoBoxPublicKeyBytes' and 'cryptoBoxSecretKeyBytes.
--
-- @since 0.0.1.0
keyPairFromHexByteStrings
  :: StrictByteString
  -- ^ Public key
  -> StrictByteString
  -- ^ Secret key
  -> Either Text (PublicKey, SecretKey)
keyPairFromHexByteStrings :: ByteString -> ByteString -> Either Text (PublicKey, SecretKey)
keyPairFromHexByteStrings ByteString
publicByteStringHex ByteString
secretByteStringHex =
  case (ByteString -> Either Text ByteString
Base16.decodeBase16Untyped ByteString
publicByteStringHex, ByteString -> Either Text ByteString
Base16.decodeBase16Untyped ByteString
secretByteStringHex) of
    (Right ByteString
publicByteString, Right ByteString
secretByteString) ->
      if ByteString -> Int
BS.length ByteString
publicByteString Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CSize
cryptoBoxPublicKeyBytes
        Bool -> Bool -> Bool
|| ByteString -> Int
BS.length ByteString
secretByteString Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CSize
cryptoBoxSecretKeyBytes
        then Text -> Either Text (PublicKey, SecretKey)
forall a b. a -> Either a b
Left (String -> Text
Text.pack String
"Input too short")
        else IO (Either Text (PublicKey, SecretKey))
-> Either Text (PublicKey, SecretKey)
forall a. IO a -> a
unsafeDupablePerformIO (IO (Either Text (PublicKey, SecretKey))
 -> Either Text (PublicKey, SecretKey))
-> IO (Either Text (PublicKey, SecretKey))
-> Either Text (PublicKey, SecretKey)
forall a b. (a -> b) -> a -> b
$
          ByteString
-> (CString -> IO (Either Text (PublicKey, SecretKey)))
-> IO (Either Text (PublicKey, SecretKey))
forall a. ByteString -> (CString -> IO a) -> IO a
BS.unsafeUseAsCString ByteString
publicByteString ((CString -> IO (Either Text (PublicKey, SecretKey)))
 -> IO (Either Text (PublicKey, SecretKey)))
-> (CString -> IO (Either Text (PublicKey, SecretKey)))
-> IO (Either Text (PublicKey, SecretKey))
forall a b. (a -> b) -> a -> b
$ \CString
outsidePublicKeyPtr ->
            ByteString
-> (CString -> IO (Either Text (PublicKey, SecretKey)))
-> IO (Either Text (PublicKey, SecretKey))
forall a. ByteString -> (CString -> IO a) -> IO a
BS.unsafeUseAsCString ByteString
secretByteString ((CString -> IO (Either Text (PublicKey, SecretKey)))
 -> IO (Either Text (PublicKey, SecretKey)))
-> (CString -> IO (Either Text (PublicKey, SecretKey)))
-> IO (Either Text (PublicKey, SecretKey))
forall a b. (a -> b) -> a -> b
$ \CString
outsideSecretKeyPtr ->
              ((PublicKey, SecretKey) -> Either Text (PublicKey, SecretKey))
-> IO (PublicKey, SecretKey)
-> IO (Either Text (PublicKey, SecretKey))
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (PublicKey, SecretKey) -> Either Text (PublicKey, SecretKey)
forall a b. b -> Either a b
Right (IO (PublicKey, SecretKey)
 -> IO (Either Text (PublicKey, SecretKey)))
-> IO (PublicKey, SecretKey)
-> IO (Either Text (PublicKey, SecretKey))
forall a b. (a -> b) -> a -> b
$
                (Ptr CUChar -> Ptr CUChar -> IO ()) -> IO (PublicKey, SecretKey)
newKeyPairWith ((Ptr CUChar -> Ptr CUChar -> IO ()) -> IO (PublicKey, SecretKey))
-> (Ptr CUChar -> Ptr CUChar -> IO ()) -> IO (PublicKey, SecretKey)
forall a b. (a -> b) -> a -> b
$ \Ptr CUChar
publicKeyPtr Ptr CUChar
secretKeyPtr -> do
                  CString -> CString -> Int -> IO ()
forall a. Storable a => Ptr a -> Ptr a -> Int -> IO ()
Foreign.copyArray
                    (forall a b. Ptr a -> Ptr b
Foreign.castPtr @CUChar @CChar Ptr CUChar
publicKeyPtr)
                    CString
outsidePublicKeyPtr
                    (CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CSize
cryptoBoxPublicKeyBytes)

                  CString -> CString -> Int -> IO ()
forall a. Storable a => Ptr a -> Ptr a -> Int -> IO ()
Foreign.copyArray
                    (forall a b. Ptr a -> Ptr b
Foreign.castPtr @CUChar @CChar Ptr CUChar
secretKeyPtr)
                    CString
outsideSecretKeyPtr
                    (CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CSize
cryptoBoxSecretKeyBytes)
    (Either Text ByteString
_, Left Text
msg) -> Text -> Either Text (PublicKey, SecretKey)
forall a b. a -> Either a b
Left Text
msg
    (Left Text
msg, Either Text ByteString
_) -> Text -> Either Text (PublicKey, SecretKey)
forall a b. a -> Either a b
Left Text
msg

-- | Prepare memory for a 'SecretKey' and 'PublicKey' pair,
-- and use the provided action to fill it.
--
-- Memory is allocated with 'LibSodium.Bindings.SecureMemory.sodiumMalloc'
-- (see the note attached there).
-- A finalizer is run when the key is goes out of scope.
newKeyPairWith
  :: ( Ptr CUChar
       -- \^ Public Key pointer
       -> Ptr CUChar
       -- \^ Secret Key pointer
       -> IO ()
     )
  -> IO (PublicKey, SecretKey)
newKeyPairWith :: (Ptr CUChar -> Ptr CUChar -> IO ()) -> IO (PublicKey, SecretKey)
newKeyPairWith Ptr CUChar -> Ptr CUChar -> IO ()
action = do
  Ptr CUChar
publicKeyPtr <- CSize -> IO (Ptr CUChar)
forall a. CSize -> IO (Ptr a)
sodiumMalloc CSize
cryptoBoxPublicKeyBytes
  Ptr CUChar
secretKeyPtr <- CSize -> IO (Ptr CUChar)
forall a. CSize -> IO (Ptr a)
sodiumMalloc CSize
cryptoBoxSecretKeyBytes
  Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Ptr CUChar
secretKeyPtr Ptr CUChar -> Ptr CUChar -> Bool
forall a. Eq a => a -> a -> Bool
== Ptr CUChar
forall a. Ptr a
Foreign.nullPtr Bool -> Bool -> Bool
|| Ptr CUChar
publicKeyPtr Ptr CUChar -> Ptr CUChar -> Bool
forall a. Eq a => a -> a -> Bool
== Ptr CUChar
forall a. Ptr a
Foreign.nullPtr) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
    Ptr CUChar -> IO ()
forall a. Ptr a -> IO ()
sodiumFree Ptr CUChar
secretKeyPtr
    Ptr CUChar -> IO ()
forall a. Ptr a -> IO ()
sodiumFree Ptr CUChar
publicKeyPtr
    String -> IO ()
forall a. String -> IO a
Foreign.throwErrno String
"sodium_malloc failed to allocate memory"

  ForeignPtr CUChar
secretKeyForeignPtr <- Ptr CUChar -> IO (ForeignPtr CUChar)
forall a. Ptr a -> IO (ForeignPtr a)
Foreign.newForeignPtr_ Ptr CUChar
secretKeyPtr
  FinalizerPtr CUChar -> ForeignPtr CUChar -> IO ()
forall a. FinalizerPtr a -> ForeignPtr a -> IO ()
Foreign.addForeignPtrFinalizer FinalizerPtr CUChar
forall a. FinalizerPtr a
finalizerSodiumFree ForeignPtr CUChar
secretKeyForeignPtr
  ForeignPtr CUChar
publicKeyForeignPtr <- Ptr CUChar -> IO (ForeignPtr CUChar)
forall a. Ptr a -> IO (ForeignPtr a)
Foreign.newForeignPtr_ Ptr CUChar
publicKeyPtr
  FinalizerPtr CUChar -> ForeignPtr CUChar -> IO ()
forall a. FinalizerPtr a -> ForeignPtr a -> IO ()
Foreign.addForeignPtrFinalizer FinalizerPtr CUChar
forall a. FinalizerPtr a
finalizerSodiumFree ForeignPtr CUChar
publicKeyForeignPtr

  Ptr CUChar -> Ptr CUChar -> IO ()
action Ptr CUChar
publicKeyPtr Ptr CUChar
secretKeyPtr
  (PublicKey, SecretKey) -> IO (PublicKey, SecretKey)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ForeignPtr CUChar -> PublicKey
PublicKey ForeignPtr CUChar
publicKeyForeignPtr, ForeignPtr CUChar -> SecretKey
SecretKey ForeignPtr CUChar
secretKeyForeignPtr)

-- | Convert a 'SecretKey' to a hexadecimal-encoded 'StrictByteString'.
--
-- ⚠️  Be prudent as to where you store it!
--
-- @since 0.0.1.0
unsafeSecretKeyToHexByteString :: SecretKey -> StrictByteString
unsafeSecretKeyToHexByteString :: SecretKey -> ByteString
unsafeSecretKeyToHexByteString (SecretKey ForeignPtr CUChar
secretKeyForeignPtr) =
  Base16 ByteString -> ByteString
forall a. Base16 a -> a
Base16.extractBase16 (Base16 ByteString -> ByteString)
-> (ByteString -> Base16 ByteString) -> ByteString -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Base16 ByteString
Base16.encodeBase16' (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$
    ForeignPtr Word8 -> Int -> ByteString
BS.fromForeignPtr0
      (forall a b. ForeignPtr a -> ForeignPtr b
Foreign.castForeignPtr @CUChar @Word8 ForeignPtr CUChar
secretKeyForeignPtr)
      (forall a b. (Integral a, Num b) => a -> b
fromIntegral @CSize @Int CSize
cryptoBoxSecretKeyBytes)

--

-- | Convert a 'SecretKey' to a hexadecimal-encoded 'StrictByteString'.
--
-- ⚠️  Be prudent as to where you store it!
--
-- @since 0.0.1.0

-- | A random number that must only be used once per exchanged message.
-- It does not have to be confidential.
-- It is of size 'cryptoBoxNonceBytes'.
--
-- @since 0.0.1.0
newtype Nonce = Nonce (ForeignPtr CUChar)
  deriving
    ( Int -> Nonce -> Builder
[Nonce] -> Builder
Nonce -> Builder
(Nonce -> Builder)
-> ([Nonce] -> Builder)
-> (Int -> Nonce -> Builder)
-> Display Nonce
forall a.
(a -> Builder)
-> ([a] -> Builder) -> (Int -> a -> Builder) -> Display a
$cdisplayBuilder :: Nonce -> Builder
displayBuilder :: Nonce -> Builder
$cdisplayList :: [Nonce] -> Builder
displayList :: [Nonce] -> Builder
$cdisplayPrec :: Int -> Nonce -> Builder
displayPrec :: Int -> Nonce -> Builder
Display
      -- ^ @since 0.0.1.0
    )
    via (ShowInstance Nonce)

-- |
--
-- @since 0.0.1.0
instance Eq Nonce where
  (Nonce ForeignPtr CUChar
hk1) == :: Nonce -> Nonce -> Bool
== (Nonce ForeignPtr CUChar
hk2) =
    IO Bool -> Bool
forall a. IO a -> a
unsafeDupablePerformIO (IO Bool -> Bool) -> IO Bool -> Bool
forall a b. (a -> b) -> a -> b
$
      ForeignPtr CUChar -> ForeignPtr CUChar -> CSize -> IO Bool
forall a. ForeignPtr a -> ForeignPtr a -> CSize -> IO Bool
foreignPtrEq ForeignPtr CUChar
hk1 ForeignPtr CUChar
hk2 CSize
cryptoBoxNonceBytes

-- |
--
-- @since 0.0.1.0
instance Ord Nonce where
  compare :: Nonce -> Nonce -> Ordering
compare (Nonce ForeignPtr CUChar
hk1) (Nonce ForeignPtr CUChar
hk2) =
    IO Ordering -> Ordering
forall a. IO a -> a
unsafeDupablePerformIO (IO Ordering -> Ordering) -> IO Ordering -> Ordering
forall a b. (a -> b) -> a -> b
$
      ForeignPtr CUChar -> ForeignPtr CUChar -> CSize -> IO Ordering
forall a. ForeignPtr a -> ForeignPtr a -> CSize -> IO Ordering
foreignPtrOrd ForeignPtr CUChar
hk1 ForeignPtr CUChar
hk2 CSize
cryptoBoxNonceBytes

-- |
--
-- @since 0.0.1.0
instance Show Nonce where
  show :: Nonce -> String
show = ByteString -> String
forall a. Show a => a -> String
show (ByteString -> String) -> (Nonce -> ByteString) -> Nonce -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Nonce -> ByteString
nonceToHexByteString

-- | Generate a new random nonce.
-- Only use it once per exchanged message.
--
-- Do not use this outside of ciphertext creation!
newNonce :: IO Nonce
newNonce :: IO Nonce
newNonce = do
  (ForeignPtr CUChar
fPtr :: ForeignPtr CUChar) <- Int -> IO (ForeignPtr CUChar)
forall a. Int -> IO (ForeignPtr a)
Foreign.mallocForeignPtrBytes (CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CSize
cryptoBoxNonceBytes)
  ForeignPtr CUChar -> (Ptr CUChar -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr CUChar
fPtr ((Ptr CUChar -> IO ()) -> IO ()) -> (Ptr CUChar -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr CUChar
ptr ->
    Ptr Word8 -> CSize -> IO ()
randombytesBuf (forall a b. Ptr a -> Ptr b
Foreign.castPtr @CUChar @Word8 Ptr CUChar
ptr) CSize
cryptoBoxNonceBytes
  Nonce -> IO Nonce
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Nonce -> IO Nonce) -> Nonce -> IO Nonce
forall a b. (a -> b) -> a -> b
$ ForeignPtr CUChar -> Nonce
Nonce ForeignPtr CUChar
fPtr

-- | Create a 'Nonce' from a hexadecimal-encoded 'StrictByteString' that you have obtained
-- on your own, usually from the network or disk.
--
-- @since 0.0.1.0
nonceFromHexByteString :: StrictByteString -> Either Text Nonce
nonceFromHexByteString :: ByteString -> Either Text Nonce
nonceFromHexByteString ByteString
hexNonce = IO (Either Text Nonce) -> Either Text Nonce
forall a. IO a -> a
unsafeDupablePerformIO (IO (Either Text Nonce) -> Either Text Nonce)
-> IO (Either Text Nonce) -> Either Text Nonce
forall a b. (a -> b) -> a -> b
$
  case ByteString -> Either Text ByteString
Base16.decodeBase16Untyped ByteString
hexNonce of
    Right ByteString
bytestring ->
      ByteString
-> (CStringLen -> IO (Either Text Nonce)) -> IO (Either Text Nonce)
forall a. ByteString -> (CStringLen -> IO a) -> IO a
BS.unsafeUseAsCStringLen ByteString
bytestring ((CStringLen -> IO (Either Text Nonce)) -> IO (Either Text Nonce))
-> (CStringLen -> IO (Either Text Nonce)) -> IO (Either Text Nonce)
forall a b. (a -> b) -> a -> b
$ \(CString
outsideNoncePtr, Int
_) -> do
        ForeignPtr CChar
nonceForeignPtr <-
          forall a. Int -> IO (ForeignPtr a)
BS.mallocByteString
            @CChar
            (CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CSize
cryptoBoxNonceBytes)
        ForeignPtr CChar -> (CString -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr CChar
nonceForeignPtr ((CString -> IO ()) -> IO ()) -> (CString -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \CString
noncePtr ->
          CString -> CString -> Int -> IO ()
forall a. Storable a => Ptr a -> Ptr a -> Int -> IO ()
Foreign.copyArray
            CString
noncePtr
            CString
outsideNoncePtr
            (CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CSize
cryptoBoxNonceBytes)
        Either Text Nonce -> IO (Either Text Nonce)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either Text Nonce -> IO (Either Text Nonce))
-> Either Text Nonce -> IO (Either Text Nonce)
forall a b. (a -> b) -> a -> b
$ Nonce -> Either Text Nonce
forall a b. b -> Either a b
Right (Nonce -> Either Text Nonce) -> Nonce -> Either Text Nonce
forall a b. (a -> b) -> a -> b
$ ForeignPtr CUChar -> Nonce
Nonce (forall a b. ForeignPtr a -> ForeignPtr b
Foreign.castForeignPtr @CChar @CUChar ForeignPtr CChar
nonceForeignPtr)
    Left Text
msg -> Either Text Nonce -> IO (Either Text Nonce)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either Text Nonce -> IO (Either Text Nonce))
-> Either Text Nonce -> IO (Either Text Nonce)
forall a b. (a -> b) -> a -> b
$ Text -> Either Text Nonce
forall a b. a -> Either a b
Left Text
msg

-- | Convert a 'Nonce' to a hexadecimal-encoded 'StrictByteString'.
--
-- @since 0.0.1.0
nonceToHexByteString :: Nonce -> StrictByteString
nonceToHexByteString :: Nonce -> ByteString
nonceToHexByteString (Nonce ForeignPtr CUChar
nonceForeignPtr) =
  Base16 ByteString -> ByteString
forall a. Base16 a -> a
Base16.extractBase16 (Base16 ByteString -> ByteString)
-> (ByteString -> Base16 ByteString) -> ByteString -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Base16 ByteString
Base16.encodeBase16' (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$
    ForeignPtr Word8 -> Int -> ByteString
BS.fromForeignPtr0
      (forall a b. ForeignPtr a -> ForeignPtr b
Foreign.castForeignPtr @CUChar @Word8 ForeignPtr CUChar
nonceForeignPtr)
      (forall a b. (Integral a, Num b) => a -> b
fromIntegral @CSize @Int CSize
cryptoBoxNonceBytes)

-- | A ciphertext consisting of an encrypted message and an authentication tag.
--
-- @since 0.0.1.0
data CipherText = CipherText
  { CipherText -> CULLong
messageLength :: CULLong
  , CipherText -> ForeignPtr CUChar
cipherTextForeignPtr :: ForeignPtr CUChar
  }

-- |
--
-- @since 0.0.1.0
instance Eq CipherText where
  (CipherText CULLong
messageLength1 ForeignPtr CUChar
hk1) == :: CipherText -> CipherText -> Bool
== (CipherText CULLong
messageLength2 ForeignPtr CUChar
hk2) =
    IO Bool -> Bool
forall a. IO a -> a
unsafeDupablePerformIO (IO Bool -> Bool) -> IO Bool -> Bool
forall a b. (a -> b) -> a -> b
$ do
      let result1 :: Bool
result1 = CULLong
messageLength1 CULLong -> CULLong -> Bool
forall a. Eq a => a -> a -> Bool
== CULLong
messageLength2
      Bool
result2 <-
        ForeignPtr CUChar -> ForeignPtr CUChar -> CSize -> IO Bool
forall a. ForeignPtr a -> ForeignPtr a -> CSize -> IO Bool
foreignPtrEq
          ForeignPtr CUChar
hk1
          ForeignPtr CUChar
hk2
          (CULLong -> CSize
forall a b. (Integral a, Num b) => a -> b
fromIntegral CULLong
messageLength1)
      Bool -> IO Bool
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Bool -> IO Bool) -> Bool -> IO Bool
forall a b. (a -> b) -> a -> b
$ Bool
result1 Bool -> Bool -> Bool
&& Bool
result2

-- |
--
-- @since 0.0.1.0
instance Ord CipherText where
  compare :: CipherText -> CipherText -> Ordering
compare (CipherText CULLong
messageLength1 ForeignPtr CUChar
hk1) (CipherText CULLong
messageLength2 ForeignPtr CUChar
hk2) =
    IO Ordering -> Ordering
forall a. IO a -> a
unsafeDupablePerformIO (IO Ordering -> Ordering) -> IO Ordering -> Ordering
forall a b. (a -> b) -> a -> b
$ do
      let result1 :: Ordering
result1 = CULLong -> CULLong -> Ordering
forall a. Ord a => a -> a -> Ordering
compare CULLong
messageLength1 CULLong
messageLength2
      Ordering
result2 <- ForeignPtr CUChar -> ForeignPtr CUChar -> CSize -> IO Ordering
forall a. ForeignPtr a -> ForeignPtr a -> CSize -> IO Ordering
foreignPtrOrd ForeignPtr CUChar
hk1 ForeignPtr CUChar
hk2 (CULLong -> CSize
forall a b. (Integral a, Num b) => a -> b
fromIntegral CULLong
messageLength1 CSize -> CSize -> CSize
forall a. Num a => a -> a -> a
+ CSize
cryptoBoxMACBytes)
      Ordering -> IO Ordering
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Ordering -> IO Ordering) -> Ordering -> IO Ordering
forall a b. (a -> b) -> a -> b
$ Ordering
result1 Ordering -> Ordering -> Ordering
forall a. Semigroup a => a -> a -> a
<> Ordering
result2

-- | ⚠️  Be prudent as to what you do with it!
--
-- @since 0.0.1.0
instance Display CipherText where
  displayBuilder :: CipherText -> Builder
displayBuilder = Text -> Builder
Builder.fromText (Text -> Builder) -> (CipherText -> Text) -> CipherText -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CipherText -> Text
cipherTextToHexText

-- | ⚠️  Be prudent as to what you do with it!
--
-- @since 0.0.1.0
instance Show CipherText where
  show :: CipherText -> String
show = ByteString -> String
BS.unpackChars (ByteString -> String)
-> (CipherText -> ByteString) -> CipherText -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CipherText -> ByteString
cipherTextToHexByteString

-- | Create a 'CipherText' from a binary 'StrictByteString' that you have obtained on your own,
-- usually from the network or disk. It must be a valid cipherText built from the concatenation
-- of the encrypted message and the authentication tag.
--
-- The input cipher text, once decoded from base16, must be at least of length
-- 'cryptoBoxMACBytes'.
--
-- @since 0.0.1.0
cipherTextFromHexByteString :: StrictByteString -> Either Text CipherText
cipherTextFromHexByteString :: ByteString -> Either Text CipherText
cipherTextFromHexByteString ByteString
hexByteString = IO (Either Text CipherText) -> Either Text CipherText
forall a. IO a -> a
unsafeDupablePerformIO (IO (Either Text CipherText) -> Either Text CipherText)
-> IO (Either Text CipherText) -> Either Text CipherText
forall a b. (a -> b) -> a -> b
$
  case ByteString -> Either Text ByteString
Base16.decodeBase16Untyped ByteString
hexByteString of
    Right ByteString
bytestring ->
      if ByteString -> Int
BS.length ByteString
bytestring Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CSize
cryptoBoxMACBytes
        then ByteString
-> (CStringLen -> IO (Either Text CipherText))
-> IO (Either Text CipherText)
forall a. ByteString -> (CStringLen -> IO a) -> IO a
BS.unsafeUseAsCStringLen ByteString
bytestring ((CStringLen -> IO (Either Text CipherText))
 -> IO (Either Text CipherText))
-> (CStringLen -> IO (Either Text CipherText))
-> IO (Either Text CipherText)
forall a b. (a -> b) -> a -> b
$ \(CString
outsideCipherTextPtr, Int
outsideCipherTextLength) -> do
          ForeignPtr CChar
cipherTextForeignPtr <- forall a. Int -> IO (ForeignPtr a)
BS.mallocByteString @CChar Int
outsideCipherTextLength
          ForeignPtr CChar -> (CString -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr CChar
cipherTextForeignPtr ((CString -> IO ()) -> IO ()) -> (CString -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \CString
cipherTextPtr ->
            CString -> CString -> Int -> IO ()
forall a. Storable a => Ptr a -> Ptr a -> Int -> IO ()
Foreign.copyArray CString
cipherTextPtr CString
outsideCipherTextPtr Int
outsideCipherTextLength
          Either Text CipherText -> IO (Either Text CipherText)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either Text CipherText -> IO (Either Text CipherText))
-> Either Text CipherText -> IO (Either Text CipherText)
forall a b. (a -> b) -> a -> b
$
            CipherText -> Either Text CipherText
forall a b. b -> Either a b
Right (CipherText -> Either Text CipherText)
-> CipherText -> Either Text CipherText
forall a b. (a -> b) -> a -> b
$
              CULLong -> ForeignPtr CUChar -> CipherText
CipherText
                (forall a b. (Integral a, Num b) => a -> b
fromIntegral @Int @CULLong Int
outsideCipherTextLength CULLong -> CULLong -> CULLong
forall a. Num a => a -> a -> a
- forall a b. (Integral a, Num b) => a -> b
fromIntegral @CSize @CULLong CSize
cryptoBoxMACBytes)
                (forall a b. ForeignPtr a -> ForeignPtr b
Foreign.castForeignPtr @CChar @CUChar ForeignPtr CChar
cipherTextForeignPtr)
        else Either Text CipherText -> IO (Either Text CipherText)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either Text CipherText -> IO (Either Text CipherText))
-> Either Text CipherText -> IO (Either Text CipherText)
forall a b. (a -> b) -> a -> b
$ Text -> Either Text CipherText
forall a b. a -> Either a b
Left (Text -> Either Text CipherText) -> Text -> Either Text CipherText
forall a b. (a -> b) -> a -> b
$ String -> Text
Text.pack String
"Cipher text is too short"
    Left Text
msg -> String -> IO (Either Text CipherText)
forall a. HasCallStack => String -> a
error (Text -> String
Text.unpack Text
msg)

-- | Convert a 'CipherText' to a hexadecimal-encoded 'Text'.
--
-- ⚠️  Be prudent as to where you store it!
--
-- @since 0.0.1.0
cipherTextToHexText :: CipherText -> Text
cipherTextToHexText :: CipherText -> Text
cipherTextToHexText = Base16 Text -> Text
forall a. Base16 a -> a
Base16.extractBase16 (Base16 Text -> Text)
-> (CipherText -> Base16 Text) -> CipherText -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Base16 Text
Base16.encodeBase16 (ByteString -> Base16 Text)
-> (CipherText -> ByteString) -> CipherText -> Base16 Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CipherText -> ByteString
cipherTextToBinary

-- | Convert a 'CipherText' to a hexadecimal-encoded 'StrictByteString'.
--
-- ⚠️  Be prudent as to where you store it!
--
-- @since 0.0.1.0
cipherTextToHexByteString :: CipherText -> StrictByteString
cipherTextToHexByteString :: CipherText -> ByteString
cipherTextToHexByteString = Base16 ByteString -> ByteString
forall a. Base16 a -> a
Base16.extractBase16 (Base16 ByteString -> ByteString)
-> (CipherText -> Base16 ByteString) -> CipherText -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Base16 ByteString
Base16.encodeBase16' (ByteString -> Base16 ByteString)
-> (CipherText -> ByteString) -> CipherText -> Base16 ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CipherText -> ByteString
cipherTextToBinary

-- | Convert a 'CipherText' to a binary 'StrictByteString'.
--
-- ⚠️  Be prudent as to where you store it!
--
-- @since 0.0.1.0
cipherTextToBinary :: CipherText -> StrictByteString
cipherTextToBinary :: CipherText -> ByteString
cipherTextToBinary (CipherText CULLong
messageLength ForeignPtr CUChar
fPtr) =
  ForeignPtr Word8 -> Int -> ByteString
BS.fromForeignPtr0
    (ForeignPtr CUChar -> ForeignPtr Word8
forall a b. ForeignPtr a -> ForeignPtr b
Foreign.castForeignPtr ForeignPtr CUChar
fPtr)
    (CULLong -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CULLong
messageLength Int -> Int -> Int
forall a. Num a => a -> a -> a
+ CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CSize
cryptoBoxMACBytes)

-- | Create an authenticated 'CipherText' from a message, a 'SecretKey',
-- and a one-time cryptographic 'Nonce' that must never be re-used with the same
-- secret key to encrypt another message.
--
-- @since 0.0.1.0
encrypt
  :: StrictByteString
  -- ^ Message to encrypt.
  -> PublicKey
  -- ^ Public key of the recipient
  -> SecretKey
  -- ^ Secret key of the sender
  -> IO (Nonce, CipherText)
encrypt :: ByteString -> PublicKey -> SecretKey -> IO (Nonce, CipherText)
encrypt ByteString
message (PublicKey ForeignPtr CUChar
publicKeyForeignPtr) (SecretKey ForeignPtr CUChar
secretKeyForeignPtr) =
  ByteString
-> (CStringLen -> IO (Nonce, CipherText)) -> IO (Nonce, CipherText)
forall a. ByteString -> (CStringLen -> IO a) -> IO a
BS.unsafeUseAsCStringLen ByteString
message ((CStringLen -> IO (Nonce, CipherText)) -> IO (Nonce, CipherText))
-> (CStringLen -> IO (Nonce, CipherText)) -> IO (Nonce, CipherText)
forall a b. (a -> b) -> a -> b
$ \(CString
cString, Int
cStringLen) -> do
    (Nonce ForeignPtr CUChar
nonceForeignPtr) <- IO Nonce
newNonce
    ForeignPtr CUChar
cipherTextForeignPtr <- Int -> IO (ForeignPtr CUChar)
forall a. Int -> IO (ForeignPtr a)
Foreign.mallocForeignPtrBytes (Int
cStringLen Int -> Int -> Int
forall a. Num a => a -> a -> a
+ CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CSize
cryptoBoxMACBytes)
    ForeignPtr CUChar
-> (Ptr CUChar -> IO (Nonce, CipherText)) -> IO (Nonce, CipherText)
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr CUChar
cipherTextForeignPtr ((Ptr CUChar -> IO (Nonce, CipherText)) -> IO (Nonce, CipherText))
-> (Ptr CUChar -> IO (Nonce, CipherText)) -> IO (Nonce, CipherText)
forall a b. (a -> b) -> a -> b
$ \Ptr CUChar
cipherTextPtr ->
      ForeignPtr CUChar
-> (Ptr CUChar -> IO (Nonce, CipherText)) -> IO (Nonce, CipherText)
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr CUChar
publicKeyForeignPtr ((Ptr CUChar -> IO (Nonce, CipherText)) -> IO (Nonce, CipherText))
-> (Ptr CUChar -> IO (Nonce, CipherText)) -> IO (Nonce, CipherText)
forall a b. (a -> b) -> a -> b
$ \Ptr CUChar
publicKeyPtr ->
        ForeignPtr CUChar
-> (Ptr CUChar -> IO (Nonce, CipherText)) -> IO (Nonce, CipherText)
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr CUChar
secretKeyForeignPtr ((Ptr CUChar -> IO (Nonce, CipherText)) -> IO (Nonce, CipherText))
-> (Ptr CUChar -> IO (Nonce, CipherText)) -> IO (Nonce, CipherText)
forall a b. (a -> b) -> a -> b
$ \Ptr CUChar
secretKeyPtr ->
          ForeignPtr CUChar
-> (Ptr CUChar -> IO (Nonce, CipherText)) -> IO (Nonce, CipherText)
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr CUChar
nonceForeignPtr ((Ptr CUChar -> IO (Nonce, CipherText)) -> IO (Nonce, CipherText))
-> (Ptr CUChar -> IO (Nonce, CipherText)) -> IO (Nonce, CipherText)
forall a b. (a -> b) -> a -> b
$ \Ptr CUChar
noncePtr -> do
            CInt
result <-
              Ptr CUChar
-> Ptr CUChar
-> CULLong
-> Ptr CUChar
-> Ptr CUChar
-> Ptr CUChar
-> IO CInt
cryptoBoxEasy
                Ptr CUChar
cipherTextPtr
                (forall a b. Ptr a -> Ptr b
Foreign.castPtr @CChar @CUChar CString
cString)
                (forall a b. (Integral a, Num b) => a -> b
fromIntegral @Int @CULLong Int
cStringLen)
                Ptr CUChar
noncePtr
                Ptr CUChar
publicKeyPtr
                Ptr CUChar
secretKeyPtr
            Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (CInt
result CInt -> CInt -> Bool
forall a. Eq a => a -> a -> Bool
/= CInt
0) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ EncryptionError -> IO ()
forall a e. Exception e => e -> a
throw EncryptionError
EncryptionError
            let cipherText :: CipherText
cipherText = CULLong -> ForeignPtr CUChar -> CipherText
CipherText (forall a b. (Integral a, Num b) => a -> b
fromIntegral @Int @CULLong Int
cStringLen) ForeignPtr CUChar
cipherTextForeignPtr
            (Nonce, CipherText) -> IO (Nonce, CipherText)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ForeignPtr CUChar -> Nonce
Nonce ForeignPtr CUChar
nonceForeignPtr, CipherText
cipherText)

-- | Decrypt a 'CipherText' and authenticated message with the shared
-- secret key and the one-time cryptographic nonce.
--
-- @since 0.0.1.0
decrypt
  :: CipherText
  -- ^ Encrypted message you want to decrypt.
  -> PublicKey
  -- ^ Public key of the sender.
  -> SecretKey
  -- ^ Secret key of the recipient.
  -> Nonce
  -- ^ Nonce used for encrypting the original message.
  -> Maybe StrictByteString
decrypt :: CipherText -> PublicKey -> SecretKey -> Nonce -> Maybe ByteString
decrypt
  CipherText{CULLong
messageLength :: CipherText -> CULLong
messageLength :: CULLong
messageLength, ForeignPtr CUChar
cipherTextForeignPtr :: CipherText -> ForeignPtr CUChar
cipherTextForeignPtr :: ForeignPtr CUChar
cipherTextForeignPtr}
  (PublicKey ForeignPtr CUChar
publicKeyForeignPtr)
  (SecretKey ForeignPtr CUChar
secretKeyForeignPtr)
  (Nonce ForeignPtr CUChar
nonceForeignPtr) = IO (Maybe ByteString) -> Maybe ByteString
forall a. IO a -> a
unsafeDupablePerformIO (IO (Maybe ByteString) -> Maybe ByteString)
-> IO (Maybe ByteString) -> Maybe ByteString
forall a b. (a -> b) -> a -> b
$ do
    Ptr CUChar
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
messageLength)
    ForeignPtr CUChar
-> (Ptr CUChar -> IO (Maybe ByteString)) -> IO (Maybe ByteString)
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr CUChar
cipherTextForeignPtr ((Ptr CUChar -> IO (Maybe ByteString)) -> IO (Maybe ByteString))
-> (Ptr CUChar -> IO (Maybe ByteString)) -> IO (Maybe ByteString)
forall a b. (a -> b) -> a -> b
$ \Ptr CUChar
cipherTextPtr ->
      ForeignPtr CUChar
-> (Ptr CUChar -> IO (Maybe ByteString)) -> IO (Maybe ByteString)
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr CUChar
publicKeyForeignPtr ((Ptr CUChar -> IO (Maybe ByteString)) -> IO (Maybe ByteString))
-> (Ptr CUChar -> IO (Maybe ByteString)) -> IO (Maybe ByteString)
forall a b. (a -> b) -> a -> b
$ \Ptr CUChar
publicKeyPtr ->
        ForeignPtr CUChar
-> (Ptr CUChar -> IO (Maybe ByteString)) -> IO (Maybe ByteString)
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr CUChar
secretKeyForeignPtr ((Ptr CUChar -> IO (Maybe ByteString)) -> IO (Maybe ByteString))
-> (Ptr CUChar -> IO (Maybe ByteString)) -> IO (Maybe ByteString)
forall a b. (a -> b) -> a -> b
$ \Ptr CUChar
secretKeyPtr ->
          ForeignPtr CUChar
-> (Ptr CUChar -> IO (Maybe ByteString)) -> IO (Maybe ByteString)
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr CUChar
nonceForeignPtr ((Ptr CUChar -> IO (Maybe ByteString)) -> IO (Maybe ByteString))
-> (Ptr CUChar -> IO (Maybe ByteString)) -> IO (Maybe ByteString)
forall a b. (a -> b) -> a -> b
$ \Ptr CUChar
noncePtr -> do
            CInt
result <-
              Ptr CUChar
-> Ptr CUChar
-> CULLong
-> Ptr CUChar
-> Ptr CUChar
-> Ptr CUChar
-> IO CInt
cryptoBoxOpenEasy
                Ptr CUChar
messagePtr
                Ptr CUChar
cipherTextPtr
                (CULLong
messageLength CULLong -> CULLong -> CULLong
forall a. Num a => a -> a -> a
+ forall a b. (Integral a, Num b) => a -> b
fromIntegral @CSize @CULLong CSize
cryptoBoxMACBytes)
                Ptr CUChar
noncePtr
                Ptr CUChar
publicKeyPtr
                Ptr CUChar
secretKeyPtr
            case CInt
result of
              (-1) -> Maybe ByteString -> IO (Maybe ByteString)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe ByteString
forall a. Maybe a
Nothing
              CInt
_ -> do
                CString
bsPtr <- Int -> IO CString
forall a. Int -> IO (Ptr a)
Foreign.mallocBytes (CULLong -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CULLong
messageLength)
                CString -> CString -> CSize -> IO (Ptr ())
forall a. Ptr a -> Ptr a -> CSize -> IO (Ptr ())
memcpy CString
bsPtr (Ptr CUChar -> CString
forall a b. Ptr a -> Ptr b
Foreign.castPtr Ptr CUChar
messagePtr) (CULLong -> CSize
forall a b. (Integral a, Num b) => a -> b
fromIntegral CULLong
messageLength)
                ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just
                  (ByteString -> Maybe ByteString)
-> IO ByteString -> IO (Maybe ByteString)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> CStringLen -> IO ByteString
BS.unsafePackMallocCStringLen
                    (forall a b. Ptr a -> Ptr b
Foreign.castPtr @CChar CString
bsPtr, CULLong -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CULLong
messageLength)

-- | Exception thrown upon error during the generation of
-- the key pair by 'newKeyPair'.
--
-- @since 0.0.1.0
data KeyPairGenerationException = KeyPairGenerationException
  deriving stock (KeyPairGenerationException -> KeyPairGenerationException -> Bool
(KeyPairGenerationException -> KeyPairGenerationException -> Bool)
-> (KeyPairGenerationException
    -> KeyPairGenerationException -> Bool)
-> Eq KeyPairGenerationException
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: KeyPairGenerationException -> KeyPairGenerationException -> Bool
== :: KeyPairGenerationException -> KeyPairGenerationException -> Bool
$c/= :: KeyPairGenerationException -> KeyPairGenerationException -> Bool
/= :: KeyPairGenerationException -> KeyPairGenerationException -> Bool
Eq, Eq KeyPairGenerationException
Eq KeyPairGenerationException =>
(KeyPairGenerationException
 -> KeyPairGenerationException -> Ordering)
-> (KeyPairGenerationException
    -> KeyPairGenerationException -> Bool)
-> (KeyPairGenerationException
    -> KeyPairGenerationException -> Bool)
-> (KeyPairGenerationException
    -> KeyPairGenerationException -> Bool)
-> (KeyPairGenerationException
    -> KeyPairGenerationException -> Bool)
-> (KeyPairGenerationException
    -> KeyPairGenerationException -> KeyPairGenerationException)
-> (KeyPairGenerationException
    -> KeyPairGenerationException -> KeyPairGenerationException)
-> Ord KeyPairGenerationException
KeyPairGenerationException -> KeyPairGenerationException -> Bool
KeyPairGenerationException
-> KeyPairGenerationException -> Ordering
KeyPairGenerationException
-> KeyPairGenerationException -> KeyPairGenerationException
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: KeyPairGenerationException
-> KeyPairGenerationException -> Ordering
compare :: KeyPairGenerationException
-> KeyPairGenerationException -> Ordering
$c< :: KeyPairGenerationException -> KeyPairGenerationException -> Bool
< :: KeyPairGenerationException -> KeyPairGenerationException -> Bool
$c<= :: KeyPairGenerationException -> KeyPairGenerationException -> Bool
<= :: KeyPairGenerationException -> KeyPairGenerationException -> Bool
$c> :: KeyPairGenerationException -> KeyPairGenerationException -> Bool
> :: KeyPairGenerationException -> KeyPairGenerationException -> Bool
$c>= :: KeyPairGenerationException -> KeyPairGenerationException -> Bool
>= :: KeyPairGenerationException -> KeyPairGenerationException -> Bool
$cmax :: KeyPairGenerationException
-> KeyPairGenerationException -> KeyPairGenerationException
max :: KeyPairGenerationException
-> KeyPairGenerationException -> KeyPairGenerationException
$cmin :: KeyPairGenerationException
-> KeyPairGenerationException -> KeyPairGenerationException
min :: KeyPairGenerationException
-> KeyPairGenerationException -> KeyPairGenerationException
Ord, Int -> KeyPairGenerationException -> ShowS
[KeyPairGenerationException] -> ShowS
KeyPairGenerationException -> String
(Int -> KeyPairGenerationException -> ShowS)
-> (KeyPairGenerationException -> String)
-> ([KeyPairGenerationException] -> ShowS)
-> Show KeyPairGenerationException
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> KeyPairGenerationException -> ShowS
showsPrec :: Int -> KeyPairGenerationException -> ShowS
$cshow :: KeyPairGenerationException -> String
show :: KeyPairGenerationException -> String
$cshowList :: [KeyPairGenerationException] -> ShowS
showList :: [KeyPairGenerationException] -> ShowS
Show)
  deriving anyclass (Show KeyPairGenerationException
Typeable KeyPairGenerationException
(Typeable KeyPairGenerationException,
 Show KeyPairGenerationException) =>
(KeyPairGenerationException -> SomeException)
-> (SomeException -> Maybe KeyPairGenerationException)
-> (KeyPairGenerationException -> String)
-> Exception KeyPairGenerationException
SomeException -> Maybe KeyPairGenerationException
KeyPairGenerationException -> String
KeyPairGenerationException -> SomeException
forall e.
(Typeable e, Show e) =>
(e -> SomeException)
-> (SomeException -> Maybe e) -> (e -> String) -> Exception e
$ctoException :: KeyPairGenerationException -> SomeException
toException :: KeyPairGenerationException -> SomeException
$cfromException :: SomeException -> Maybe KeyPairGenerationException
fromException :: SomeException -> Maybe KeyPairGenerationException
$cdisplayException :: KeyPairGenerationException -> String
displayException :: KeyPairGenerationException -> String
Exception)

-- | Exception thrown upon error during the encryption
-- of the message by 'encrypt'.
--
-- @since 0.0.1.0
data EncryptionError = EncryptionError
  deriving stock (EncryptionError -> EncryptionError -> Bool
(EncryptionError -> EncryptionError -> Bool)
-> (EncryptionError -> EncryptionError -> Bool)
-> Eq EncryptionError
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: EncryptionError -> EncryptionError -> Bool
== :: EncryptionError -> EncryptionError -> Bool
$c/= :: EncryptionError -> EncryptionError -> Bool
/= :: EncryptionError -> EncryptionError -> Bool
Eq, Eq EncryptionError
Eq EncryptionError =>
(EncryptionError -> EncryptionError -> Ordering)
-> (EncryptionError -> EncryptionError -> Bool)
-> (EncryptionError -> EncryptionError -> Bool)
-> (EncryptionError -> EncryptionError -> Bool)
-> (EncryptionError -> EncryptionError -> Bool)
-> (EncryptionError -> EncryptionError -> EncryptionError)
-> (EncryptionError -> EncryptionError -> EncryptionError)
-> Ord EncryptionError
EncryptionError -> EncryptionError -> Bool
EncryptionError -> EncryptionError -> Ordering
EncryptionError -> EncryptionError -> EncryptionError
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: EncryptionError -> EncryptionError -> Ordering
compare :: EncryptionError -> EncryptionError -> Ordering
$c< :: EncryptionError -> EncryptionError -> Bool
< :: EncryptionError -> EncryptionError -> Bool
$c<= :: EncryptionError -> EncryptionError -> Bool
<= :: EncryptionError -> EncryptionError -> Bool
$c> :: EncryptionError -> EncryptionError -> Bool
> :: EncryptionError -> EncryptionError -> Bool
$c>= :: EncryptionError -> EncryptionError -> Bool
>= :: EncryptionError -> EncryptionError -> Bool
$cmax :: EncryptionError -> EncryptionError -> EncryptionError
max :: EncryptionError -> EncryptionError -> EncryptionError
$cmin :: EncryptionError -> EncryptionError -> EncryptionError
min :: EncryptionError -> EncryptionError -> EncryptionError
Ord, Int -> EncryptionError -> ShowS
[EncryptionError] -> ShowS
EncryptionError -> String
(Int -> EncryptionError -> ShowS)
-> (EncryptionError -> String)
-> ([EncryptionError] -> ShowS)
-> Show EncryptionError
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> EncryptionError -> ShowS
showsPrec :: Int -> EncryptionError -> ShowS
$cshow :: EncryptionError -> String
show :: EncryptionError -> String
$cshowList :: [EncryptionError] -> ShowS
showList :: [EncryptionError] -> ShowS
Show)
  deriving anyclass (Show EncryptionError
Typeable EncryptionError
(Typeable EncryptionError, Show EncryptionError) =>
(EncryptionError -> SomeException)
-> (SomeException -> Maybe EncryptionError)
-> (EncryptionError -> String)
-> Exception EncryptionError
SomeException -> Maybe EncryptionError
EncryptionError -> String
EncryptionError -> SomeException
forall e.
(Typeable e, Show e) =>
(e -> SomeException)
-> (SomeException -> Maybe e) -> (e -> String) -> Exception e
$ctoException :: EncryptionError -> SomeException
toException :: EncryptionError -> SomeException
$cfromException :: SomeException -> Maybe EncryptionError
fromException :: SomeException -> Maybe EncryptionError
$cdisplayException :: EncryptionError -> String
displayException :: EncryptionError -> String
Exception)