{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RoleAnnotations #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}

-- |
--
-- Module: Sel.SecretKey.Stream
-- Description: Encrypted Streams with ChaCha20Poly1305
-- Copyright: (C) Hécate Moonlight 2024
-- License: BSD-3-Clause
-- Maintainer: The Haskell Cryptography Group
-- Portability: GHC only
module Sel.SecretKey.Stream
  ( -- ** Introduction
    -- $introduction

    -- ** Usage
    -- $usage

    -- ** Stream operations

    -- *** Linked List operations
    encryptList
  , decryptList

    -- *** Chunk operations
  , Multipart
  , encryptStream
  , encryptChunk
  , decryptStream
  , decryptChunk

    -- ** Secret Key
  , SecretKey
  , newSecretKey
  , secretKeyFromHexByteString
  , unsafeSecretKeyToHexByteString

    -- ** Header
  , Header
  , headerToHexByteString
  , headerFromHexByteString

    -- ** Message Tags
  , MessageTag (..)

    -- ** CipherText
  , CipherText
  , ciphertextFromHexByteString
  , ciphertextToBinary
  , ciphertextToHexByteString
  , ciphertextToHexText

    -- ** Exceptions
  , StreamInitEncryptionException
  , StreamEncryptionException
  , StreamDecryptionException
  ) where

import Control.Exception (Exception, throw)
import Control.Monad (forM, when)
import Control.Monad.IO.Class (MonadIO, liftIO)
import Data.Base16.Types (Base16)
import qualified Data.Base16.Types as Base16
import Data.ByteString (StrictByteString)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Base16 as Base16
import qualified Data.ByteString.Internal as BSI
import qualified Data.ByteString.Unsafe as BSU
import Data.Kind (Type)
import qualified Data.List as List
import Data.Text (Text)
import qualified Data.Text as Text
import Data.Text.Display (Display (..), OpaqueInstance (..))
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 Foreign.C.Error (throwErrno)
import System.IO.Unsafe (unsafeDupablePerformIO)

import LibSodium.Bindings.SecretStream
  ( CryptoSecretStreamXChaCha20Poly1305State
  , cryptoSecretStreamXChaCha20Poly1305ABytes
  , cryptoSecretStreamXChaCha20Poly1305HeaderBytes
  , cryptoSecretStreamXChaCha20Poly1305InitPull
  , cryptoSecretStreamXChaCha20Poly1305InitPush
  , cryptoSecretStreamXChaCha20Poly1305KeyBytes
  , cryptoSecretStreamXChaCha20Poly1305KeyGen
  , cryptoSecretStreamXChaCha20Poly1305Pull
  , cryptoSecretStreamXChaCha20Poly1305Push
  , cryptoSecretStreamXChaCha20Poly1305StateBytes
  , cryptoSecretStreamXChaCha20Poly1305TagFinal
  , cryptoSecretStreamXChaCha20Poly1305TagMessage
  , cryptoSecretStreamXChaCha20Poly1305TagPush
  , cryptoSecretStreamXChaCha20Poly1305TagRekey
  )
import LibSodium.Bindings.SecureMemory (finalizerSodiumFree, sodiumMalloc)
import Sel.Internal (allocateWith, foreignPtrEq, foreignPtrOrd)

-- $introduction
-- This high-level API encrypts a sequence of messages, or a single message split into an arbitrary number of chunks, using a secret key, with the following properties:
--
-- * Messages cannot be truncated, removed, reordered, duplicated or modified without this being detected by the decryption functions.
-- * The same sequence encrypted twice will produce different ciphertexts.
-- * An authentication tag is added to each encrypted message: stream corruption will be detected early, without having to read the stream until the end.
-- * Each message can include additional data (ex: timestamp, protocol version) in the computation of the authentication tag.
-- * Messages can have different sizes.
-- * There are no practical limits to the total length of the stream, or to the total number of individual messages.
--
-- It uses the [XChaCha20-Poly1305 algorithm](https://en.wikipedia.org/wiki/ChaCha20-Poly1305).

-- $usage
--
-- >>> secretKey <- Stream.newSecretKey
-- >>> (header, cipherTexts) <- Stream.encryptStream secretKey $ \multipartState -> do -- we are in MonadIO
-- ...   message1 <- getMessage -- This is your way to fetch a message from outside
-- ...   encryptedChunk1 <- Stream.encryptChunk multipartState Stream.messag message1
-- ...   message2 <- getMessage
-- ...   encryptedChunk2 <- Stream.encryptChunk multipartState Stream.Final message2
-- ...   pure [encryptedChunk1, encryptedChunk2]
-- >>> result <- Stream.decryptStream secretKey header $ \multipartState-> do
-- ...    forM encryptedMessages $ \cipherText -> do
-- ...      decryptChunk multipartState cipherText

-- | 'Multipart' is the cryptographic context for stream encryption.
--
-- @since 0.0.1.0
newtype Multipart s = Multipart (Ptr CryptoSecretStreamXChaCha20Poly1305State)

type role Multipart nominal

-- | Perform streaming hashing with a 'Multipart' cryptographic context.
--
-- Use 'Stream.encryptChunk' within the continuation.
--
-- The context is safely allocated first, then the continuation is run
-- and then it is deallocated after that.
--
-- @since 0.0.1.0
encryptStream
  :: forall (a :: Type) (m :: Type -> Type)
   . MonadIO m
  => SecretKey
  -- ^ Generated with 'newSecretKey'.
  -> (forall s. Multipart s -> m a)
  -- ^ Continuation that gives you access to a 'Multipart' cryptographic context
  -> m (Header, a)
encryptStream :: forall a (m :: * -> *).
MonadIO m =>
SecretKey -> (forall s. Multipart s -> m a) -> m (Header, a)
encryptStream (SecretKey ForeignPtr CUChar
secretKeyForeignPtr) forall s. Multipart s -> m a
actions = CSize
-> (Ptr CryptoSecretStreamXChaCha20Poly1305State -> m (Header, a))
-> m (Header, a)
forall a b (m :: * -> *).
MonadIO m =>
CSize -> (Ptr a -> m b) -> m b
allocateWith CSize
cryptoSecretStreamXChaCha20Poly1305StateBytes ((Ptr CryptoSecretStreamXChaCha20Poly1305State -> m (Header, a))
 -> m (Header, a))
-> (Ptr CryptoSecretStreamXChaCha20Poly1305State -> m (Header, a))
-> m (Header, a)
forall a b. (a -> b) -> a -> b
$ \Ptr CryptoSecretStreamXChaCha20Poly1305State
statePtr -> do
  Ptr CUChar
headerPtr <- IO (Ptr CUChar) -> m (Ptr CUChar)
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (Ptr CUChar) -> m (Ptr CUChar))
-> IO (Ptr CUChar) -> m (Ptr CUChar)
forall a b. (a -> b) -> a -> b
$ CSize -> IO (Ptr CUChar)
forall a. CSize -> IO (Ptr a)
sodiumMalloc CSize
cryptoSecretStreamXChaCha20Poly1305HeaderBytes
  ForeignPtr CUChar
headerForeignPtr <- IO (ForeignPtr CUChar) -> m (ForeignPtr CUChar)
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (ForeignPtr CUChar) -> m (ForeignPtr CUChar))
-> IO (ForeignPtr CUChar) -> m (ForeignPtr CUChar)
forall a b. (a -> b) -> a -> b
$ FinalizerPtr CUChar -> Ptr CUChar -> IO (ForeignPtr CUChar)
forall a. FinalizerPtr a -> Ptr a -> IO (ForeignPtr a)
Foreign.newForeignPtr FinalizerPtr CUChar
forall a. FinalizerPtr a
finalizerSodiumFree Ptr CUChar
headerPtr
  Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Ptr CUChar
headerPtr Ptr CUChar -> Ptr CUChar -> Bool
forall a. Eq a => a -> a -> Bool
== Ptr CUChar
forall a. Ptr a
Foreign.nullPtr) (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$ IO () -> m ()
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (String -> IO ()
forall a. String -> IO a
throwErrno String
"sodium_malloc")
  IO () -> m ()
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> IO () -> m ()
forall a b. (a -> b) -> a -> b
$ ForeignPtr CUChar -> (Ptr CUChar -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr CUChar
secretKeyForeignPtr ((Ptr CUChar -> IO ()) -> IO ()) -> (Ptr CUChar -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr CUChar
secretKeyPtr -> do
    CInt
result <-
      Ptr CryptoSecretStreamXChaCha20Poly1305State
-> Ptr CUChar -> Ptr CUChar -> IO CInt
cryptoSecretStreamXChaCha20Poly1305InitPush
        Ptr CryptoSecretStreamXChaCha20Poly1305State
statePtr
        Ptr CUChar
headerPtr
        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
$ StreamInitEncryptionException -> IO ()
forall a e. Exception e => e -> a
throw StreamInitEncryptionException
StreamInitEncryptionException
  let part :: Multipart s
part = Ptr CryptoSecretStreamXChaCha20Poly1305State -> Multipart s
forall s.
Ptr CryptoSecretStreamXChaCha20Poly1305State -> Multipart s
Multipart Ptr CryptoSecretStreamXChaCha20Poly1305State
statePtr
  let header :: Header
header = ForeignPtr CUChar -> Header
Header ForeignPtr CUChar
headerForeignPtr
  a
result <- Multipart Any -> m a
forall s. Multipart s -> m a
actions Multipart Any
forall {s}. Multipart s
part
  (Header, a) -> m (Header, a)
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Header
header, a
result)

-- | Add a message portion (/chunk/) to be encrypted.
--
-- Use it within 'encryptStream'.
--
-- This function can throw 'StreamEncryptionException' upon an error in the underlying implementation.
--
-- @since 0.0.1.0
encryptChunk
  :: forall m s
   . MonadIO m
  => Multipart s
  -- ^ Cryptographic context
  -> MessageTag
  -- ^ Tag that will be associated with the message. See the documentation of 'MessageTag' to know which to choose when.
  -> StrictByteString
  -- ^ Message to encrypt.
  -> m CipherText
encryptChunk :: forall (m :: * -> *) s.
MonadIO m =>
Multipart s -> MessageTag -> StrictByteString -> m CipherText
encryptChunk (Multipart Ptr CryptoSecretStreamXChaCha20Poly1305State
statePtr) MessageTag
messageTag StrictByteString
message = IO CipherText -> m CipherText
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO CipherText -> m CipherText) -> IO CipherText -> m CipherText
forall a b. (a -> b) -> a -> b
$ StrictByteString -> (CStringLen -> IO CipherText) -> IO CipherText
forall a. StrictByteString -> (CStringLen -> IO a) -> IO a
BSU.unsafeUseAsCStringLen StrictByteString
message ((CStringLen -> IO CipherText) -> IO CipherText)
-> (CStringLen -> IO CipherText) -> IO CipherText
forall a b. (a -> b) -> a -> b
$ \(Ptr CChar
cString, Int
cStringLen) -> do
  let messagePtr :: Ptr CUChar
messagePtr = forall a b. Ptr a -> Ptr b
Foreign.castPtr @CChar @CUChar Ptr CChar
cString
  let messageLen :: CULLong
messageLen = forall a b. (Integral a, Num b) => a -> b
fromIntegral @Int @CULLong Int
cStringLen
  ForeignPtr CUChar
cipherTextFPtr <- 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
cryptoSecretStreamXChaCha20Poly1305ABytes)
  ForeignPtr CUChar -> (Ptr CUChar -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr CUChar
cipherTextFPtr ((Ptr CUChar -> IO ()) -> IO ()) -> (Ptr CUChar -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr CUChar
cipherTextBuffer -> do
    CInt
result <-
      Ptr CryptoSecretStreamXChaCha20Poly1305State
-> Ptr CUChar
-> Ptr CULLong
-> Ptr CUChar
-> CULLong
-> Ptr CUChar
-> CULLong
-> CUChar
-> IO CInt
cryptoSecretStreamXChaCha20Poly1305Push
        Ptr CryptoSecretStreamXChaCha20Poly1305State
statePtr
        Ptr CUChar
cipherTextBuffer
        Ptr CULLong
forall a. Ptr a
Foreign.nullPtr -- default size of messageLen + 'cryptoSecretStreamXChaCha20Poly1305ABytes'
        Ptr CUChar
messagePtr
        CULLong
messageLen
        Ptr CUChar
forall a. Ptr a
Foreign.nullPtr -- No additional data
        CULLong
0 -- No additional data size
        (MessageTag -> CUChar
messageTagToConstant MessageTag
messageTag)
    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
$ StreamEncryptionException -> IO ()
forall a e. Exception e => e -> a
throw StreamEncryptionException
StreamEncryptionException
  CipherText -> IO CipherText
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CipherText -> IO CipherText) -> CipherText -> IO CipherText
forall a b. (a -> b) -> a -> b
$ CULLong -> ForeignPtr CUChar -> CipherText
CipherText (Int -> CULLong
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
cStringLen) ForeignPtr CUChar
cipherTextFPtr

-- | Perform streaming encryption of a finite list.
--
-- This function can throw 'StreamEncryptionException' upon an error in the underlying implementation.
--
-- @since 0.0.1.0
encryptList :: forall m. MonadIO m => SecretKey -> [StrictByteString] -> m (Header, [CipherText])
encryptList :: forall (m :: * -> *).
MonadIO m =>
SecretKey -> [StrictByteString] -> m (Header, [CipherText])
encryptList SecretKey
secretKey [StrictByteString]
messages = SecretKey
-> (forall {s}. Multipart s -> m [CipherText])
-> m (Header, [CipherText])
forall a (m :: * -> *).
MonadIO m =>
SecretKey -> (forall s. Multipart s -> m a) -> m (Header, a)
encryptStream SecretKey
secretKey ((forall {s}. Multipart s -> m [CipherText])
 -> m (Header, [CipherText]))
-> (forall {s}. Multipart s -> m [CipherText])
-> m (Header, [CipherText])
forall a b. (a -> b) -> a -> b
$ \Multipart s
multipart -> Multipart s -> [StrictByteString] -> [CipherText] -> m [CipherText]
forall s.
Multipart s -> [StrictByteString] -> [CipherText] -> m [CipherText]
go Multipart s
multipart [StrictByteString]
messages []
  where
    go :: Multipart s -> [StrictByteString] -> [CipherText] -> m [CipherText]
    go :: forall s.
Multipart s -> [StrictByteString] -> [CipherText] -> m [CipherText]
go Multipart s
multipart [StrictByteString
lastMsg] [CipherText]
acc = do
      CipherText
encryptedChunk <- Multipart s -> MessageTag -> StrictByteString -> m CipherText
forall (m :: * -> *) s.
MonadIO m =>
Multipart s -> MessageTag -> StrictByteString -> m CipherText
encryptChunk Multipart s
multipart MessageTag
Final StrictByteString
lastMsg
      [CipherText] -> m [CipherText]
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([CipherText] -> m [CipherText]) -> [CipherText] -> m [CipherText]
forall a b. (a -> b) -> a -> b
$ [CipherText] -> [CipherText]
forall a. [a] -> [a]
List.reverse ([CipherText] -> [CipherText]) -> [CipherText] -> [CipherText]
forall a b. (a -> b) -> a -> b
$ CipherText
encryptedChunk CipherText -> [CipherText] -> [CipherText]
forall a. a -> [a] -> [a]
: [CipherText]
acc
    go Multipart s
multipart (StrictByteString
msg : [StrictByteString]
rest) [CipherText]
acc = do
      CipherText
encryptedChunk <- Multipart s -> MessageTag -> StrictByteString -> m CipherText
forall (m :: * -> *) s.
MonadIO m =>
Multipart s -> MessageTag -> StrictByteString -> m CipherText
encryptChunk Multipart s
multipart MessageTag
Message StrictByteString
msg
      Multipart s -> [StrictByteString] -> [CipherText] -> m [CipherText]
forall s.
Multipart s -> [StrictByteString] -> [CipherText] -> m [CipherText]
go Multipart s
multipart [StrictByteString]
rest (CipherText
encryptedChunk CipherText -> [CipherText] -> [CipherText]
forall a. a -> [a] -> [a]
: [CipherText]
acc)
    go Multipart s
_ [] [CipherText]
acc = [CipherText] -> m [CipherText]
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure [CipherText]
acc

-- | Perform streaming decryption with a 'Multipart' cryptographic context.
--
-- Use 'Stream.decryptChunk' within the continuation.
--
-- The context is safely allocated first, then the continuation is run
-- and then it is deallocated after that.
--
-- @since 0.0.1.0
decryptStream
  :: forall (a :: Type) (m :: Type -> Type)
   . MonadIO m
  => SecretKey
  -> Header
  -- ^ Header used by the encrypting party. See its documentation
  -> (forall s. Multipart s -> m a)
  -- ^ Continuation that gives you access to a 'Multipart' cryptographic context
  -> m (Maybe a)
decryptStream :: forall a (m :: * -> *).
MonadIO m =>
SecretKey
-> Header -> (forall s. Multipart s -> m a) -> m (Maybe a)
decryptStream (SecretKey ForeignPtr CUChar
secretKeyForeignPtr) (Header ForeignPtr CUChar
headerForeignPtr) forall s. Multipart s -> m a
actions = CSize
-> (Ptr CryptoSecretStreamXChaCha20Poly1305State -> m (Maybe a))
-> m (Maybe a)
forall a b (m :: * -> *).
MonadIO m =>
CSize -> (Ptr a -> m b) -> m b
allocateWith CSize
cryptoSecretStreamXChaCha20Poly1305StateBytes ((Ptr CryptoSecretStreamXChaCha20Poly1305State -> m (Maybe a))
 -> m (Maybe a))
-> (Ptr CryptoSecretStreamXChaCha20Poly1305State -> m (Maybe a))
-> m (Maybe a)
forall a b. (a -> b) -> a -> b
$ \Ptr CryptoSecretStreamXChaCha20Poly1305State
statePtr -> do
  CInt
result <- IO CInt -> m CInt
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO CInt -> m CInt) -> IO CInt -> m CInt
forall a b. (a -> b) -> a -> b
$ ForeignPtr CUChar -> (Ptr CUChar -> IO CInt) -> IO CInt
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr CUChar
secretKeyForeignPtr ((Ptr CUChar -> IO CInt) -> IO CInt)
-> (Ptr CUChar -> IO CInt) -> IO CInt
forall a b. (a -> b) -> a -> b
$ \Ptr CUChar
secretKeyPtr -> do
    ForeignPtr CUChar -> (Ptr CUChar -> IO CInt) -> IO CInt
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr CUChar
headerForeignPtr ((Ptr CUChar -> IO CInt) -> IO CInt)
-> (Ptr CUChar -> IO CInt) -> IO CInt
forall a b. (a -> b) -> a -> b
$ \Ptr CUChar
headerPtr -> do
      Ptr CryptoSecretStreamXChaCha20Poly1305State
-> Ptr CUChar -> Ptr CUChar -> IO CInt
cryptoSecretStreamXChaCha20Poly1305InitPull
        Ptr CryptoSecretStreamXChaCha20Poly1305State
statePtr
        Ptr CUChar
headerPtr
        Ptr CUChar
secretKeyPtr
  if CInt
result CInt -> CInt -> Bool
forall a. Eq a => a -> a -> Bool
/= CInt
0
    then Maybe a -> m (Maybe a)
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe a
forall a. Maybe a
Nothing
    else do
      let part :: Multipart s
part = Ptr CryptoSecretStreamXChaCha20Poly1305State -> Multipart s
forall s.
Ptr CryptoSecretStreamXChaCha20Poly1305State -> Multipart s
Multipart Ptr CryptoSecretStreamXChaCha20Poly1305State
statePtr
      a -> Maybe a
forall a. a -> Maybe a
Just (a -> Maybe a) -> m a -> m (Maybe a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Multipart Any -> m a
forall s. Multipart s -> m a
actions Multipart Any
forall {s}. Multipart s
part

-- | Add a message portion (/chunk/) to be decrypted.
--
-- Use this function within 'decryptStream'.
--
-- This function can throw 'StreamDecryptionException' if the chunk is invalid, incomplete, or corrupted.
--
-- @since 0.0.1.0
decryptChunk
  :: forall m s
   . MonadIO m
  => Multipart s
  -- ^ Cryptographic context
  -> CipherText
  -- ^ Encrypted message portion to decrypt
  -> m StrictByteString
  -- ^ Decrypted message portion
decryptChunk :: forall (m :: * -> *) s.
MonadIO m =>
Multipart s -> CipherText -> m StrictByteString
decryptChunk (Multipart Ptr CryptoSecretStreamXChaCha20Poly1305State
statePtr) CipherText{CULLong
messageLength :: CULLong
messageLength :: CipherText -> CULLong
messageLength, ForeignPtr CUChar
cipherTextForeignPtr :: ForeignPtr CUChar
cipherTextForeignPtr :: CipherText -> ForeignPtr CUChar
cipherTextForeignPtr} = do
  ForeignPtr CUChar
clearTextForeignPtr <- IO (ForeignPtr CUChar) -> m (ForeignPtr CUChar)
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (ForeignPtr CUChar) -> m (ForeignPtr CUChar))
-> IO (ForeignPtr CUChar) -> m (ForeignPtr CUChar)
forall a b. (a -> b) -> a -> b
$ Int -> IO (ForeignPtr CUChar)
forall a. Int -> IO (ForeignPtr a)
Foreign.mallocForeignPtrBytes (CULLong -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CULLong
messageLength)
  let cipherTextLen :: CULLong
cipherTextLen = CULLong
messageLength CULLong -> CULLong -> CULLong
forall a. Num a => a -> a -> a
+ CSize -> CULLong
forall a b. (Integral a, Num b) => a -> b
fromIntegral CSize
cryptoSecretStreamXChaCha20Poly1305ABytes
  IO StrictByteString -> m StrictByteString
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO StrictByteString -> m StrictByteString)
-> IO StrictByteString -> m StrictByteString
forall a b. (a -> b) -> a -> b
$ ForeignPtr CUChar
-> (Ptr CUChar -> IO StrictByteString) -> IO StrictByteString
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr CUChar
cipherTextForeignPtr ((Ptr CUChar -> IO StrictByteString) -> IO StrictByteString)
-> (Ptr CUChar -> IO StrictByteString) -> IO StrictByteString
forall a b. (a -> b) -> a -> b
$ \Ptr CUChar
cipherTextBuffer -> do
    IO StrictByteString -> IO StrictByteString
forall a. IO a -> IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO StrictByteString -> IO StrictByteString)
-> IO StrictByteString -> IO StrictByteString
forall a b. (a -> b) -> a -> b
$ ForeignPtr CUChar
-> (Ptr CUChar -> IO StrictByteString) -> IO StrictByteString
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr CUChar
clearTextForeignPtr ((Ptr CUChar -> IO StrictByteString) -> IO StrictByteString)
-> (Ptr CUChar -> IO StrictByteString) -> IO StrictByteString
forall a b. (a -> b) -> a -> b
$ \Ptr CUChar
clearTextBuffer -> do
      Ptr CUChar
tagBuffer <- CSize -> IO (Ptr CUChar)
forall a. CSize -> IO (Ptr a)
sodiumMalloc CSize
1
      CInt
result <-
        Ptr CryptoSecretStreamXChaCha20Poly1305State
-> Ptr CUChar
-> Ptr CULLong
-> Ptr CUChar
-> Ptr CUChar
-> CULLong
-> Ptr CUChar
-> CULLong
-> IO CInt
cryptoSecretStreamXChaCha20Poly1305Pull
          Ptr CryptoSecretStreamXChaCha20Poly1305State
statePtr
          Ptr CUChar
clearTextBuffer
          Ptr CULLong
forall a. Ptr a
Foreign.nullPtr
          Ptr CUChar
tagBuffer
          Ptr CUChar
cipherTextBuffer
          CULLong
cipherTextLen
          Ptr CUChar
forall a. Ptr a
Foreign.nullPtr
          CULLong
0
      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
$ StreamDecryptionException -> IO ()
forall a e. Exception e => e -> a
throw StreamDecryptionException
StreamDecryptionException
      Ptr CChar
bsPtr <- Int -> IO (Ptr CChar)
forall a. Int -> IO (Ptr a)
Foreign.mallocBytes (CULLong -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CULLong
messageLength)
      Ptr CChar -> Ptr CChar -> Int -> IO ()
forall a. Ptr a -> Ptr a -> Int -> IO ()
Foreign.copyBytes Ptr CChar
bsPtr (Ptr CUChar -> Ptr CChar
forall a b. Ptr a -> Ptr b
Foreign.castPtr Ptr CUChar
clearTextBuffer) (CULLong -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CULLong
messageLength)
      CStringLen -> IO StrictByteString
BSU.unsafePackMallocCStringLen (Ptr CChar
bsPtr, CULLong -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CULLong
messageLength)

-- | Perform streaming decryption of a finite Linked List.
--
-- This function can throw 'StreamDecryptionException' if the chunk is invalid, incomplete, or corrupted.
--
-- @since 0.0.1.0
decryptList :: forall m. MonadIO m => SecretKey -> Header -> [CipherText] -> m (Maybe [StrictByteString])
decryptList :: forall (m :: * -> *).
MonadIO m =>
SecretKey -> Header -> [CipherText] -> m (Maybe [StrictByteString])
decryptList SecretKey
secretKey Header
header [CipherText]
encryptedMessages =
  SecretKey
-> Header
-> (forall {s}. Multipart s -> m [StrictByteString])
-> m (Maybe [StrictByteString])
forall a (m :: * -> *).
MonadIO m =>
SecretKey
-> Header -> (forall s. Multipart s -> m a) -> m (Maybe a)
decryptStream SecretKey
secretKey Header
header ((forall {s}. Multipart s -> m [StrictByteString])
 -> m (Maybe [StrictByteString]))
-> (forall {s}. Multipart s -> m [StrictByteString])
-> m (Maybe [StrictByteString])
forall a b. (a -> b) -> a -> b
$ \Multipart s
multipart -> do
    [CipherText]
-> (CipherText -> m StrictByteString) -> m [StrictByteString]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM [CipherText]
encryptedMessages ((CipherText -> m StrictByteString) -> m [StrictByteString])
-> (CipherText -> m StrictByteString) -> m [StrictByteString]
forall a b. (a -> b) -> a -> b
$ \CipherText
cipherText -> do
      Multipart s -> CipherText -> m StrictByteString
forall (m :: * -> *) s.
MonadIO m =>
Multipart s -> CipherText -> m StrictByteString
decryptChunk Multipart s
multipart CipherText
cipherText

-- | A secret key of size 'cryptoSecretStreamXChaCha20Poly1305KeyBytes'.
--
-- @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
cryptoSecretStreamXChaCha20Poly1305KeyBytes

-- | @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
cryptoSecretStreamXChaCha20Poly1305KeyBytes

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

-- | Generate a new random secret key.
--
-- @since 0.0.1.0
newSecretKey :: IO SecretKey
newSecretKey :: IO SecretKey
newSecretKey = (Ptr CUChar -> IO ()) -> IO SecretKey
newSecretKeyWith Ptr CUChar -> IO ()
cryptoSecretStreamXChaCha20Poly1305KeyGen

-- | Create a 'SecretKey' from a binary 'StrictByteString' that you have obtained on your own,
-- usually from the network or disk.
--
-- The input secret key, once decoded from base16, must be of length
-- 'cryptoSecretStreamXChaCha20Poly1305KeyBytes'.
--
-- @since 0.0.1.0
secretKeyFromHexByteString :: Base16 StrictByteString -> Either Text SecretKey
secretKeyFromHexByteString :: Base16 StrictByteString -> Either Text SecretKey
secretKeyFromHexByteString Base16 StrictByteString
hexSecretKey = IO (Either Text SecretKey) -> Either Text SecretKey
forall a. IO a -> a
unsafeDupablePerformIO (IO (Either Text SecretKey) -> Either Text SecretKey)
-> IO (Either Text SecretKey) -> Either Text SecretKey
forall a b. (a -> b) -> a -> b
$
  case StrictByteString -> Either Text StrictByteString
Base16.decodeBase16Untyped (Base16 StrictByteString -> StrictByteString
forall a. Base16 a -> a
Base16.extractBase16 Base16 StrictByteString
hexSecretKey) of
    Right StrictByteString
bytestring ->
      if StrictByteString -> Int
BS.length StrictByteString
bytestring Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CSize
cryptoSecretStreamXChaCha20Poly1305KeyBytes
        then StrictByteString
-> (CStringLen -> IO (Either Text SecretKey))
-> IO (Either Text SecretKey)
forall a. StrictByteString -> (CStringLen -> IO a) -> IO a
BSU.unsafeUseAsCStringLen StrictByteString
bytestring ((CStringLen -> IO (Either Text SecretKey))
 -> IO (Either Text SecretKey))
-> (CStringLen -> IO (Either Text SecretKey))
-> IO (Either Text SecretKey)
forall a b. (a -> b) -> a -> b
$ \(Ptr CChar
outsideSecretKeyPtr, Int
_) -> do
          SecretKey
secretKey <- (Ptr CUChar -> IO ()) -> IO SecretKey
newSecretKeyWith ((Ptr CUChar -> IO ()) -> IO SecretKey)
-> (Ptr CUChar -> IO ()) -> IO SecretKey
forall a b. (a -> b) -> a -> b
$ \Ptr CUChar
secretKeyPtr ->
            Ptr CChar -> Ptr CChar -> 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)
              Ptr CChar
outsideSecretKeyPtr
              (CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CSize
cryptoSecretStreamXChaCha20Poly1305KeyBytes)
          Either Text SecretKey -> IO (Either Text SecretKey)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either Text SecretKey -> IO (Either Text SecretKey))
-> Either Text SecretKey -> IO (Either Text SecretKey)
forall a b. (a -> b) -> a -> b
$ SecretKey -> Either Text SecretKey
forall a b. b -> Either a b
Right SecretKey
secretKey
        else Either Text SecretKey -> IO (Either Text SecretKey)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either Text SecretKey -> IO (Either Text SecretKey))
-> Either Text SecretKey -> IO (Either Text SecretKey)
forall a b. (a -> b) -> a -> b
$ Text -> Either Text SecretKey
forall a b. a -> Either a b
Left (Text -> Either Text SecretKey) -> Text -> Either Text SecretKey
forall a b. (a -> b) -> a -> b
$ String -> Text
Text.pack (String
"Secret Key is not of size " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> CSize -> String
forall a. Show a => a -> String
show CSize
cryptoSecretStreamXChaCha20Poly1305KeyBytes)
    Left Text
msg -> Either Text SecretKey -> IO (Either Text SecretKey)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either Text SecretKey -> IO (Either Text SecretKey))
-> Either Text SecretKey -> IO (Either Text SecretKey)
forall a b. (a -> b) -> a -> b
$ Text -> Either Text SecretKey
forall a b. a -> Either a b
Left Text
msg

-- | Convert a 'SecretKey' to a hexadecimal-encoded 'StrictByteString'.
--
-- ⚠️  Be prudent as to where you store it!
--
-- @since 0.0.1.0
unsafeSecretKeyToHexByteString :: SecretKey -> Base16 StrictByteString
unsafeSecretKeyToHexByteString :: SecretKey -> Base16 StrictByteString
unsafeSecretKeyToHexByteString (SecretKey ForeignPtr CUChar
secretKeyForeignPtr) =
  StrictByteString -> Base16 StrictByteString
Base16.encodeBase16' (StrictByteString -> Base16 StrictByteString)
-> StrictByteString -> Base16 StrictByteString
forall a b. (a -> b) -> a -> b
$
    ForeignPtr Word8 -> Int -> StrictByteString
BSI.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
cryptoSecretStreamXChaCha20Poly1305KeyBytes)

-- Prepare memory for a 'SecretKey' 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.
--
-- @since 0.0.1.0
newSecretKeyWith :: (Ptr CUChar -> IO ()) -> IO SecretKey
newSecretKeyWith :: (Ptr CUChar -> IO ()) -> IO SecretKey
newSecretKeyWith Ptr CUChar -> IO ()
action = do
  Ptr CUChar
ptr <- CSize -> IO (Ptr CUChar)
forall a. CSize -> IO (Ptr a)
sodiumMalloc CSize
cryptoSecretStreamXChaCha20Poly1305KeyBytes
  Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Ptr CUChar
ptr 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
$ String -> IO ()
forall a. String -> IO a
throwErrno String
"sodium_malloc"
  ForeignPtr CUChar
fPtr <- FinalizerPtr CUChar -> Ptr CUChar -> IO (ForeignPtr CUChar)
forall a. FinalizerPtr a -> Ptr a -> IO (ForeignPtr a)
Foreign.newForeignPtr FinalizerPtr CUChar
forall a. FinalizerPtr a
finalizerSodiumFree Ptr CUChar
ptr
  Ptr CUChar -> IO ()
action Ptr CUChar
ptr
  SecretKey -> IO SecretKey
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (SecretKey -> IO SecretKey) -> SecretKey -> IO SecretKey
forall a b. (a -> b) -> a -> b
$ ForeignPtr CUChar -> SecretKey
SecretKey ForeignPtr CUChar
fPtr

-- | An encrypted stream starts with a 'Header' of size 'cryptoSecretStreamXChaCha20Poly1305HeaderBytes'.
--
-- That header must be sent/stored before the sequence of encrypted messages, as it is required to decrypt the stream.
--
-- The header content doesn’t have to be secret and decryption with a different header will fail.
--
-- @since 0.0.1.0
newtype Header = Header (ForeignPtr CUChar)

-- | @since 0.0.1.0
instance Show Header where
  show :: Header -> String
show = StrictByteString -> String
BSI.unpackChars (StrictByteString -> String)
-> (Header -> StrictByteString) -> Header -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Base16 StrictByteString -> StrictByteString
forall a. Base16 a -> a
Base16.extractBase16 (Base16 StrictByteString -> StrictByteString)
-> (Header -> Base16 StrictByteString)
-> Header
-> StrictByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Header -> Base16 StrictByteString
headerToHexByteString

-- | @since 0.0.1.0
instance Display Header where
  displayBuilder :: Header -> Builder
displayBuilder = Text -> Builder
Builder.fromText (Text -> Builder) -> (Header -> Text) -> Header -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Base16 Text -> Text
forall a. Base16 a -> a
Base16.extractBase16 (Base16 Text -> Text) -> (Header -> Base16 Text) -> Header -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Header -> Base16 Text
headerToHexText

-- | @since 0.0.1.0
instance Eq Header where
  (Header ForeignPtr CUChar
header1) == :: Header -> Header -> Bool
== (Header ForeignPtr CUChar
header2) =
    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
header1 ForeignPtr CUChar
header2 CSize
cryptoSecretStreamXChaCha20Poly1305HeaderBytes

-- | @since 0.0.1.0
instance Ord Header where
  compare :: Header -> Header -> Ordering
compare (Header ForeignPtr CUChar
header1) (Header ForeignPtr CUChar
header2) =
    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
header1 ForeignPtr CUChar
header2 CSize
cryptoSecretStreamXChaCha20Poly1305HeaderBytes

-- | Convert a 'Header' to a hexadecimal-encoded 'StrictByteString'
--
-- @since 0.0.1.0
headerToHexByteString :: Header -> Base16 StrictByteString
headerToHexByteString :: Header -> Base16 StrictByteString
headerToHexByteString (Header ForeignPtr CUChar
headerForeignPtr) =
  StrictByteString -> Base16 StrictByteString
Base16.encodeBase16' (StrictByteString -> Base16 StrictByteString)
-> StrictByteString -> Base16 StrictByteString
forall a b. (a -> b) -> a -> b
$
    ForeignPtr Word8 -> Int -> StrictByteString
BSI.fromForeignPtr0
      (forall a b. ForeignPtr a -> ForeignPtr b
Foreign.castForeignPtr @CUChar @Word8 ForeignPtr CUChar
headerForeignPtr)
      (forall a b. (Integral a, Num b) => a -> b
fromIntegral @CSize @Int CSize
cryptoSecretStreamXChaCha20Poly1305HeaderBytes)

-- | Build a 'Header' from a base16-encoded 'StrictByteString'
--
-- @since 0.0.1.0
headerFromHexByteString :: Base16 StrictByteString -> Either Text Header
headerFromHexByteString :: Base16 StrictByteString -> Either Text Header
headerFromHexByteString Base16 StrictByteString
hexHeader = IO (Either Text Header) -> Either Text Header
forall a. IO a -> a
unsafeDupablePerformIO (IO (Either Text Header) -> Either Text Header)
-> IO (Either Text Header) -> Either Text Header
forall a b. (a -> b) -> a -> b
$
  case StrictByteString -> Either Text StrictByteString
Base16.decodeBase16Untyped (Base16 StrictByteString -> StrictByteString
forall a. Base16 a -> a
Base16.extractBase16 Base16 StrictByteString
hexHeader) of
    Right StrictByteString
bytestring ->
      if StrictByteString -> Int
BS.length StrictByteString
bytestring Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CSize
cryptoSecretStreamXChaCha20Poly1305HeaderBytes
        then StrictByteString
-> (CStringLen -> IO (Either Text Header))
-> IO (Either Text Header)
forall a. StrictByteString -> (CStringLen -> IO a) -> IO a
BSU.unsafeUseAsCStringLen StrictByteString
bytestring ((CStringLen -> IO (Either Text Header))
 -> IO (Either Text Header))
-> (CStringLen -> IO (Either Text Header))
-> IO (Either Text Header)
forall a b. (a -> b) -> a -> b
$ \(Ptr CChar
outsideHeaderPtr, Int
_) -> do
          let headerLength :: Int
headerLength = CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CSize
cryptoSecretStreamXChaCha20Poly1305HeaderBytes
          ForeignPtr CUChar
headerForeignPtr <- 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
cryptoSecretStreamXChaCha20Poly1305HeaderBytes)
          ForeignPtr CUChar
-> (Ptr CUChar -> IO (Either Text Header))
-> IO (Either Text Header)
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr CUChar
headerForeignPtr ((Ptr CUChar -> IO (Either Text Header))
 -> IO (Either Text Header))
-> (Ptr CUChar -> IO (Either Text Header))
-> IO (Either Text Header)
forall a b. (a -> b) -> a -> b
$ \Ptr CUChar
headerPtr -> do
            Ptr CUChar -> Ptr CUChar -> Int -> IO ()
forall a. Ptr a -> Ptr a -> Int -> IO ()
Foreign.copyBytes Ptr CUChar
headerPtr (Ptr CChar -> Ptr CUChar
forall a b. Ptr a -> Ptr b
Foreign.castPtr Ptr CChar
outsideHeaderPtr) Int
headerLength
            Either Text Header -> IO (Either Text Header)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either Text Header -> IO (Either Text Header))
-> Either Text Header -> IO (Either Text Header)
forall a b. (a -> b) -> a -> b
$ Header -> Either Text Header
forall a b. b -> Either a b
Right (Header -> Either Text Header) -> Header -> Either Text Header
forall a b. (a -> b) -> a -> b
$ ForeignPtr CUChar -> Header
Header ForeignPtr CUChar
headerForeignPtr
        else Either Text Header -> IO (Either Text Header)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either Text Header -> IO (Either Text Header))
-> Either Text Header -> IO (Either Text Header)
forall a b. (a -> b) -> a -> b
$ Text -> Either Text Header
forall a b. a -> Either a b
Left (Text -> Either Text Header) -> Text -> Either Text Header
forall a b. (a -> b) -> a -> b
$ String -> Text
Text.pack (String
"Secret Key is not of size " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> CSize -> String
forall a. Show a => a -> String
show CSize
cryptoSecretStreamXChaCha20Poly1305HeaderBytes)
    Left Text
msg -> Either Text Header -> IO (Either Text Header)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either Text Header -> IO (Either Text Header))
-> Either Text Header -> IO (Either Text Header)
forall a b. (a -> b) -> a -> b
$ Text -> Either Text Header
forall a b. a -> Either a b
Left Text
msg

-- | Convert a 'Header' to a hexadecimal-encoded 'Text'.
--
-- @since 0.0.1.0
headerToHexText :: Header -> Base16 Text
headerToHexText :: Header -> Base16 Text
headerToHexText = StrictByteString -> Base16 Text
Base16.encodeBase16 (StrictByteString -> Base16 Text)
-> (Header -> StrictByteString) -> Header -> Base16 Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Base16 StrictByteString -> StrictByteString
forall a. Base16 a -> a
Base16.extractBase16 (Base16 StrictByteString -> StrictByteString)
-> (Header -> Base16 StrictByteString)
-> Header
-> StrictByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Header -> Base16 StrictByteString
headerToHexByteString

-- | Each encrypted message is associated with a tag.
--
-- A typical encrypted stream simply attaches 'Message' as a tag to all messages,
-- except the last one which is tagged as 'Final'.
--
-- @since 0.0.1.0
data MessageTag
  = -- | The most common tag, that doesn’t add any information about the nature of the message.
    Message
  | -- | Indicates that the message marks the end of the stream, and erases the secret key used to encrypt the previous sequence.
    Final
  | -- | Indicates that the message marks the end of a set of messages, but not the end of the stream.
    Push
  | -- | “Forget” the key used to encrypt this message and the previous ones, and derive a new secret key.
    Rekey

-- | Convert a 'MessageTag' to its corresponding constant.
--
-- @since 0.0.1.0
messageTagToConstant :: MessageTag -> CUChar
messageTagToConstant :: MessageTag -> CUChar
messageTagToConstant = \case
  MessageTag
Message -> CSize -> CUChar
forall a b. (Integral a, Num b) => a -> b
fromIntegral CSize
cryptoSecretStreamXChaCha20Poly1305TagMessage
  MessageTag
Final -> CSize -> CUChar
forall a b. (Integral a, Num b) => a -> b
fromIntegral CSize
cryptoSecretStreamXChaCha20Poly1305TagFinal
  MessageTag
Push -> CSize -> CUChar
forall a b. (Integral a, Num b) => a -> b
fromIntegral CSize
cryptoSecretStreamXChaCha20Poly1305TagPush
  MessageTag
Rekey -> CSize -> CUChar
forall a b. (Integral a, Num b) => a -> b
fromIntegral CSize
cryptoSecretStreamXChaCha20Poly1305TagRekey

-- | An encrypted message. It is guaranteed to be of size:
--  @original_message_length + 'cryptoSecretStreamXChaCha20Poly1305ABytes'@
--
-- @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
cipherTextLength1 ForeignPtr CUChar
h1) == :: CipherText -> CipherText -> Bool
== (CipherText CULLong
cipherTextLength2 ForeignPtr CUChar
h2) =
    IO Bool -> Bool
forall a. IO a -> a
unsafeDupablePerformIO (IO Bool -> Bool) -> IO Bool -> Bool
forall a b. (a -> b) -> a -> b
$ do
      Bool
result1 <-
        ForeignPtr CUChar -> ForeignPtr CUChar -> CSize -> IO Bool
forall a. ForeignPtr a -> ForeignPtr a -> CSize -> IO Bool
foreignPtrEq
          ForeignPtr CUChar
h1
          ForeignPtr CUChar
h2
          (CULLong -> CSize
forall a b. (Integral a, Num b) => a -> b
fromIntegral CULLong
cipherTextLength1 CSize -> CSize -> CSize
forall a. Num a => a -> a -> a
+ CSize
cryptoSecretStreamXChaCha20Poly1305ABytes)
      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
$ CULLong
cipherTextLength1 CULLong -> CULLong -> Bool
forall a. Eq a => a -> a -> Bool
== CULLong
cipherTextLength2 Bool -> Bool -> Bool
&& Bool
result1

-- | @since 0.0.1.0
instance Ord CipherText where
  compare :: CipherText -> CipherText -> Ordering
compare (CipherText CULLong
cipherTextLength1 ForeignPtr CUChar
c1) (CipherText CULLong
cipherTextLength2 ForeignPtr CUChar
c2) =
    IO Ordering -> Ordering
forall a. IO a -> a
unsafeDupablePerformIO (IO Ordering -> Ordering) -> IO Ordering -> Ordering
forall a b. (a -> b) -> a -> b
$ do
      Ordering
result1 <- ForeignPtr CUChar -> ForeignPtr CUChar -> CSize -> IO Ordering
forall a. ForeignPtr a -> ForeignPtr a -> CSize -> IO Ordering
foreignPtrOrd ForeignPtr CUChar
c1 ForeignPtr CUChar
c2 (CULLong -> CSize
forall a b. (Integral a, Num b) => a -> b
fromIntegral CULLong
cipherTextLength1 CSize -> CSize -> CSize
forall a. Num a => a -> a -> a
+ CSize
cryptoSecretStreamXChaCha20Poly1305ABytes)
      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
$ CULLong -> CULLong -> Ordering
forall a. Ord a => a -> a -> Ordering
compare CULLong
cipherTextLength1 CULLong
cipherTextLength2 Ordering -> Ordering -> Ordering
forall a. Semigroup a => a -> a -> a
<> Ordering
result1

-- | @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
. 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
. CipherText -> Base16 Text
ciphertextToHexText

-- | @since 0.0.1.0
instance Show CipherText where
  show :: CipherText -> String
show = StrictByteString -> String
BSI.unpackChars (StrictByteString -> String)
-> (CipherText -> StrictByteString) -> CipherText -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Base16 StrictByteString -> StrictByteString
forall a. Base16 a -> a
Base16.extractBase16 (Base16 StrictByteString -> StrictByteString)
-> (CipherText -> Base16 StrictByteString)
-> CipherText
-> StrictByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CipherText -> Base16 StrictByteString
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 hash built from the concatenation
-- of the encrypted message and the authentication tag.
--
-- The input hash must at least of length 'cryptoSecretStreamXChaCha20Poly1305ABytes'
--
-- @since 0.0.1.0
ciphertextFromHexByteString :: Base16 StrictByteString -> Either Text CipherText
ciphertextFromHexByteString :: Base16 StrictByteString -> Either Text CipherText
ciphertextFromHexByteString Base16 StrictByteString
hexCipherText = 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 StrictByteString -> Either Text StrictByteString
Base16.decodeBase16Untyped (Base16 StrictByteString -> StrictByteString
forall a. Base16 a -> a
Base16.extractBase16 Base16 StrictByteString
hexCipherText) of
    Right StrictByteString
bytestring ->
      if StrictByteString -> Int
BS.length StrictByteString
bytestring Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CSize
cryptoSecretStreamXChaCha20Poly1305ABytes
        then StrictByteString
-> (CStringLen -> IO (Either Text CipherText))
-> IO (Either Text CipherText)
forall a. StrictByteString -> (CStringLen -> IO a) -> IO a
BSU.unsafeUseAsCStringLen StrictByteString
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
$ \(Ptr CChar
outsideCipherTextPtr, Int
outsideCipherTextLength) -> do
          ForeignPtr CChar
cipherTextFPtr <- forall a. Int -> IO (ForeignPtr a)
BSI.mallocByteString @CChar Int
outsideCipherTextLength -- The foreign pointer that will receive the hash data.
          ForeignPtr CChar -> (Ptr CChar -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr CChar
cipherTextFPtr ((Ptr CChar -> IO ()) -> IO ()) -> (Ptr CChar -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr CChar
cipherTextPtr ->
            -- We copy bytes from 'outsideCipherTextPtr' to 'cipherTextPtr.
            Ptr CChar -> Ptr CChar -> Int -> IO ()
forall a. Storable a => Ptr a -> Ptr a -> Int -> IO ()
Foreign.copyArray Ptr CChar
cipherTextPtr Ptr CChar
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
cryptoSecretStreamXChaCha20Poly1305ABytes)
                (forall a b. ForeignPtr a -> ForeignPtr b
Foreign.castForeignPtr @CChar @CUChar ForeignPtr CChar
cipherTextFPtr)
        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
"CipherText is too short"
    Left Text
msg -> 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
msg

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

-- | Convert a 'CipherText' to a hexadecimal-encoded 'StrictByteString'.
--
-- ⚠️  Be prudent as to where you store it!
--
-- @since 0.0.1.0
ciphertextToHexByteString :: CipherText -> Base16 StrictByteString
ciphertextToHexByteString :: CipherText -> Base16 StrictByteString
ciphertextToHexByteString = StrictByteString -> Base16 StrictByteString
Base16.encodeBase16' (StrictByteString -> Base16 StrictByteString)
-> (CipherText -> StrictByteString)
-> CipherText
-> Base16 StrictByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CipherText -> StrictByteString
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 -> StrictByteString
ciphertextToBinary (CipherText CULLong
cipherTextLength ForeignPtr CUChar
fPtr) =
  ForeignPtr Word8 -> Int -> StrictByteString
BSI.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
cipherTextLength Int -> Int -> Int
forall a. Num a => a -> a -> a
+ CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CSize
cryptoSecretStreamXChaCha20Poly1305ABytes)

-- | @since 0.0.1.0
data StreamEncryptionException = StreamEncryptionException
  deriving stock (StreamEncryptionException -> StreamEncryptionException -> Bool
(StreamEncryptionException -> StreamEncryptionException -> Bool)
-> (StreamEncryptionException -> StreamEncryptionException -> Bool)
-> Eq StreamEncryptionException
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: StreamEncryptionException -> StreamEncryptionException -> Bool
== :: StreamEncryptionException -> StreamEncryptionException -> Bool
$c/= :: StreamEncryptionException -> StreamEncryptionException -> Bool
/= :: StreamEncryptionException -> StreamEncryptionException -> Bool
Eq, Eq StreamEncryptionException
Eq StreamEncryptionException =>
(StreamEncryptionException
 -> StreamEncryptionException -> Ordering)
-> (StreamEncryptionException -> StreamEncryptionException -> Bool)
-> (StreamEncryptionException -> StreamEncryptionException -> Bool)
-> (StreamEncryptionException -> StreamEncryptionException -> Bool)
-> (StreamEncryptionException -> StreamEncryptionException -> Bool)
-> (StreamEncryptionException
    -> StreamEncryptionException -> StreamEncryptionException)
-> (StreamEncryptionException
    -> StreamEncryptionException -> StreamEncryptionException)
-> Ord StreamEncryptionException
StreamEncryptionException -> StreamEncryptionException -> Bool
StreamEncryptionException -> StreamEncryptionException -> Ordering
StreamEncryptionException
-> StreamEncryptionException -> StreamEncryptionException
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 :: StreamEncryptionException -> StreamEncryptionException -> Ordering
compare :: StreamEncryptionException -> StreamEncryptionException -> Ordering
$c< :: StreamEncryptionException -> StreamEncryptionException -> Bool
< :: StreamEncryptionException -> StreamEncryptionException -> Bool
$c<= :: StreamEncryptionException -> StreamEncryptionException -> Bool
<= :: StreamEncryptionException -> StreamEncryptionException -> Bool
$c> :: StreamEncryptionException -> StreamEncryptionException -> Bool
> :: StreamEncryptionException -> StreamEncryptionException -> Bool
$c>= :: StreamEncryptionException -> StreamEncryptionException -> Bool
>= :: StreamEncryptionException -> StreamEncryptionException -> Bool
$cmax :: StreamEncryptionException
-> StreamEncryptionException -> StreamEncryptionException
max :: StreamEncryptionException
-> StreamEncryptionException -> StreamEncryptionException
$cmin :: StreamEncryptionException
-> StreamEncryptionException -> StreamEncryptionException
min :: StreamEncryptionException
-> StreamEncryptionException -> StreamEncryptionException
Ord, Int -> StreamEncryptionException -> ShowS
[StreamEncryptionException] -> ShowS
StreamEncryptionException -> String
(Int -> StreamEncryptionException -> ShowS)
-> (StreamEncryptionException -> String)
-> ([StreamEncryptionException] -> ShowS)
-> Show StreamEncryptionException
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> StreamEncryptionException -> ShowS
showsPrec :: Int -> StreamEncryptionException -> ShowS
$cshow :: StreamEncryptionException -> String
show :: StreamEncryptionException -> String
$cshowList :: [StreamEncryptionException] -> ShowS
showList :: [StreamEncryptionException] -> ShowS
Show)
  deriving anyclass (Show StreamEncryptionException
Typeable StreamEncryptionException
(Typeable StreamEncryptionException,
 Show StreamEncryptionException) =>
(StreamEncryptionException -> SomeException)
-> (SomeException -> Maybe StreamEncryptionException)
-> (StreamEncryptionException -> String)
-> Exception StreamEncryptionException
SomeException -> Maybe StreamEncryptionException
StreamEncryptionException -> String
StreamEncryptionException -> SomeException
forall e.
(Typeable e, Show e) =>
(e -> SomeException)
-> (SomeException -> Maybe e) -> (e -> String) -> Exception e
$ctoException :: StreamEncryptionException -> SomeException
toException :: StreamEncryptionException -> SomeException
$cfromException :: SomeException -> Maybe StreamEncryptionException
fromException :: SomeException -> Maybe StreamEncryptionException
$cdisplayException :: StreamEncryptionException -> String
displayException :: StreamEncryptionException -> String
Exception)

-- | @since 0.0.1.0
data StreamInitEncryptionException = StreamInitEncryptionException
  deriving stock (StreamInitEncryptionException
-> StreamInitEncryptionException -> Bool
(StreamInitEncryptionException
 -> StreamInitEncryptionException -> Bool)
-> (StreamInitEncryptionException
    -> StreamInitEncryptionException -> Bool)
-> Eq StreamInitEncryptionException
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: StreamInitEncryptionException
-> StreamInitEncryptionException -> Bool
== :: StreamInitEncryptionException
-> StreamInitEncryptionException -> Bool
$c/= :: StreamInitEncryptionException
-> StreamInitEncryptionException -> Bool
/= :: StreamInitEncryptionException
-> StreamInitEncryptionException -> Bool
Eq, Eq StreamInitEncryptionException
Eq StreamInitEncryptionException =>
(StreamInitEncryptionException
 -> StreamInitEncryptionException -> Ordering)
-> (StreamInitEncryptionException
    -> StreamInitEncryptionException -> Bool)
-> (StreamInitEncryptionException
    -> StreamInitEncryptionException -> Bool)
-> (StreamInitEncryptionException
    -> StreamInitEncryptionException -> Bool)
-> (StreamInitEncryptionException
    -> StreamInitEncryptionException -> Bool)
-> (StreamInitEncryptionException
    -> StreamInitEncryptionException -> StreamInitEncryptionException)
-> (StreamInitEncryptionException
    -> StreamInitEncryptionException -> StreamInitEncryptionException)
-> Ord StreamInitEncryptionException
StreamInitEncryptionException
-> StreamInitEncryptionException -> Bool
StreamInitEncryptionException
-> StreamInitEncryptionException -> Ordering
StreamInitEncryptionException
-> StreamInitEncryptionException -> StreamInitEncryptionException
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 :: StreamInitEncryptionException
-> StreamInitEncryptionException -> Ordering
compare :: StreamInitEncryptionException
-> StreamInitEncryptionException -> Ordering
$c< :: StreamInitEncryptionException
-> StreamInitEncryptionException -> Bool
< :: StreamInitEncryptionException
-> StreamInitEncryptionException -> Bool
$c<= :: StreamInitEncryptionException
-> StreamInitEncryptionException -> Bool
<= :: StreamInitEncryptionException
-> StreamInitEncryptionException -> Bool
$c> :: StreamInitEncryptionException
-> StreamInitEncryptionException -> Bool
> :: StreamInitEncryptionException
-> StreamInitEncryptionException -> Bool
$c>= :: StreamInitEncryptionException
-> StreamInitEncryptionException -> Bool
>= :: StreamInitEncryptionException
-> StreamInitEncryptionException -> Bool
$cmax :: StreamInitEncryptionException
-> StreamInitEncryptionException -> StreamInitEncryptionException
max :: StreamInitEncryptionException
-> StreamInitEncryptionException -> StreamInitEncryptionException
$cmin :: StreamInitEncryptionException
-> StreamInitEncryptionException -> StreamInitEncryptionException
min :: StreamInitEncryptionException
-> StreamInitEncryptionException -> StreamInitEncryptionException
Ord, Int -> StreamInitEncryptionException -> ShowS
[StreamInitEncryptionException] -> ShowS
StreamInitEncryptionException -> String
(Int -> StreamInitEncryptionException -> ShowS)
-> (StreamInitEncryptionException -> String)
-> ([StreamInitEncryptionException] -> ShowS)
-> Show StreamInitEncryptionException
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> StreamInitEncryptionException -> ShowS
showsPrec :: Int -> StreamInitEncryptionException -> ShowS
$cshow :: StreamInitEncryptionException -> String
show :: StreamInitEncryptionException -> String
$cshowList :: [StreamInitEncryptionException] -> ShowS
showList :: [StreamInitEncryptionException] -> ShowS
Show)
  deriving anyclass (Show StreamInitEncryptionException
Typeable StreamInitEncryptionException
(Typeable StreamInitEncryptionException,
 Show StreamInitEncryptionException) =>
(StreamInitEncryptionException -> SomeException)
-> (SomeException -> Maybe StreamInitEncryptionException)
-> (StreamInitEncryptionException -> String)
-> Exception StreamInitEncryptionException
SomeException -> Maybe StreamInitEncryptionException
StreamInitEncryptionException -> String
StreamInitEncryptionException -> SomeException
forall e.
(Typeable e, Show e) =>
(e -> SomeException)
-> (SomeException -> Maybe e) -> (e -> String) -> Exception e
$ctoException :: StreamInitEncryptionException -> SomeException
toException :: StreamInitEncryptionException -> SomeException
$cfromException :: SomeException -> Maybe StreamInitEncryptionException
fromException :: SomeException -> Maybe StreamInitEncryptionException
$cdisplayException :: StreamInitEncryptionException -> String
displayException :: StreamInitEncryptionException -> String
Exception)

-- | @since 0.0.1.0
data StreamDecryptionException = StreamDecryptionException
  deriving stock (StreamDecryptionException -> StreamDecryptionException -> Bool
(StreamDecryptionException -> StreamDecryptionException -> Bool)
-> (StreamDecryptionException -> StreamDecryptionException -> Bool)
-> Eq StreamDecryptionException
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: StreamDecryptionException -> StreamDecryptionException -> Bool
== :: StreamDecryptionException -> StreamDecryptionException -> Bool
$c/= :: StreamDecryptionException -> StreamDecryptionException -> Bool
/= :: StreamDecryptionException -> StreamDecryptionException -> Bool
Eq, Eq StreamDecryptionException
Eq StreamDecryptionException =>
(StreamDecryptionException
 -> StreamDecryptionException -> Ordering)
-> (StreamDecryptionException -> StreamDecryptionException -> Bool)
-> (StreamDecryptionException -> StreamDecryptionException -> Bool)
-> (StreamDecryptionException -> StreamDecryptionException -> Bool)
-> (StreamDecryptionException -> StreamDecryptionException -> Bool)
-> (StreamDecryptionException
    -> StreamDecryptionException -> StreamDecryptionException)
-> (StreamDecryptionException
    -> StreamDecryptionException -> StreamDecryptionException)
-> Ord StreamDecryptionException
StreamDecryptionException -> StreamDecryptionException -> Bool
StreamDecryptionException -> StreamDecryptionException -> Ordering
StreamDecryptionException
-> StreamDecryptionException -> StreamDecryptionException
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 :: StreamDecryptionException -> StreamDecryptionException -> Ordering
compare :: StreamDecryptionException -> StreamDecryptionException -> Ordering
$c< :: StreamDecryptionException -> StreamDecryptionException -> Bool
< :: StreamDecryptionException -> StreamDecryptionException -> Bool
$c<= :: StreamDecryptionException -> StreamDecryptionException -> Bool
<= :: StreamDecryptionException -> StreamDecryptionException -> Bool
$c> :: StreamDecryptionException -> StreamDecryptionException -> Bool
> :: StreamDecryptionException -> StreamDecryptionException -> Bool
$c>= :: StreamDecryptionException -> StreamDecryptionException -> Bool
>= :: StreamDecryptionException -> StreamDecryptionException -> Bool
$cmax :: StreamDecryptionException
-> StreamDecryptionException -> StreamDecryptionException
max :: StreamDecryptionException
-> StreamDecryptionException -> StreamDecryptionException
$cmin :: StreamDecryptionException
-> StreamDecryptionException -> StreamDecryptionException
min :: StreamDecryptionException
-> StreamDecryptionException -> StreamDecryptionException
Ord, Int -> StreamDecryptionException -> ShowS
[StreamDecryptionException] -> ShowS
StreamDecryptionException -> String
(Int -> StreamDecryptionException -> ShowS)
-> (StreamDecryptionException -> String)
-> ([StreamDecryptionException] -> ShowS)
-> Show StreamDecryptionException
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> StreamDecryptionException -> ShowS
showsPrec :: Int -> StreamDecryptionException -> ShowS
$cshow :: StreamDecryptionException -> String
show :: StreamDecryptionException -> String
$cshowList :: [StreamDecryptionException] -> ShowS
showList :: [StreamDecryptionException] -> ShowS
Show)
  deriving anyclass (Show StreamDecryptionException
Typeable StreamDecryptionException
(Typeable StreamDecryptionException,
 Show StreamDecryptionException) =>
(StreamDecryptionException -> SomeException)
-> (SomeException -> Maybe StreamDecryptionException)
-> (StreamDecryptionException -> String)
-> Exception StreamDecryptionException
SomeException -> Maybe StreamDecryptionException
StreamDecryptionException -> String
StreamDecryptionException -> SomeException
forall e.
(Typeable e, Show e) =>
(e -> SomeException)
-> (SomeException -> Maybe e) -> (e -> String) -> Exception e
$ctoException :: StreamDecryptionException -> SomeException
toException :: StreamDecryptionException -> SomeException
$cfromException :: SomeException -> Maybe StreamDecryptionException
fromException :: SomeException -> Maybe StreamDecryptionException
$cdisplayException :: StreamDecryptionException -> String
displayException :: StreamDecryptionException -> String
Exception)