-------------------------------------------------
-- |
-- Module      : Crypto.Noise
-- Maintainer  : John Galt <jgalt@centromere.net>
-- Stability   : experimental
-- Portability : POSIX
--
-- Please see the README for usage information.
module Crypto.Noise
  ( -- * Types
    NoiseState
  , NoiseResult(..)
  , HandshakePattern
  , HandshakeRole(..)
  , HandshakeOpts
    -- * Functions
  , defaultHandshakeOpts
  , noiseState
  , writeMessage
  , readMessage
  , processPSKs
  , remoteStaticKey
  , handshakeComplete
  , handshakeHash
  , rekeySending
  , rekeyReceiving
  , handshakePattern
    -- * HandshakeOpts Setters
  , setLocalEphemeral
  , setLocalStatic
  , setRemoteEphemeral
  , setRemoteStatic
    -- * Classes
  , Cipher
  , DH
  , Hash
    -- * Re-exports
  , ScrubbedBytes
  , convert
  ) where

import Control.Arrow   (arr, second, (***))
import Control.Exception.Safe
import Control.Lens
import Data.ByteArray  (ScrubbedBytes, convert)
import Data.Maybe      (isJust)

import Crypto.Noise.Cipher
import Crypto.Noise.DH
import Crypto.Noise.Hash
import Crypto.Noise.Internal.CipherState
import Crypto.Noise.Internal.Handshake.Pattern hiding (psk)
import Crypto.Noise.Internal.Handshake.State
import Crypto.Noise.Internal.NoiseState
import Crypto.Noise.Internal.SymmetricState

-- | This type is used to indicate to the user the result of either writing or
--   reading a message. In the simplest case, when processing a handshake or
--   transport message, the (en|de)crypted message and mutated state will be
--   available in 'NoiseResultMessage'.
--
--   If during the course of the handshake a pre-shared key is needed, a
--   'NoiseResultNeedPSK' value will be returned along with the mutated state.
--   To continue, the user must re-issue the 'writeMessage' or 'readMessage'
--   call, passing in the PSK as the payload. If no further PSKs are required,
--   the result will be 'NoiseResultMessage'.
--
--   If an exception is encountered at any point while processing a handshake or
--   transport message, 'NoiseResultException' will be returned.
data NoiseResult c d h
  = NoiseResultMessage   ScrubbedBytes (NoiseState c d h)
  | NoiseResultNeedPSK   (NoiseState c d h)
  | NoiseResultException SomeException

-- | Creates a handshake or transport message with the provided payload. Note
--   that the payload may not be authenticated or encrypted at all points during
--   the handshake. Please see section 7.4 of the protocol document for details.
--
--   If a previous call to this function indicated that a pre-shared key is
--   needed, it shall be provided as the payload. See the documentation of
--   'NoiseResult' for details.
--
--   To prevent catastrophic key re-use, this function may only be used to
--   secure 2^64 - 1 post-handshake messages.
writeMessage :: (Cipher c, DH d, Hash h)
             => ScrubbedBytes
             -> NoiseState c d h
             -> NoiseResult c d h
writeMessage :: forall c d h.
(Cipher c, DH d, Hash h) =>
ScrubbedBytes -> NoiseState c d h -> NoiseResult c d h
writeMessage ScrubbedBytes
msg NoiseState c d h
ns = NoiseResult c d h
-> (CipherState c -> NoiseResult c d h)
-> Maybe (CipherState c)
-> NoiseResult c d h
forall b a. b -> (a -> b) -> Maybe a -> b
maybe
  (Either SomeException (HandshakeResult, NoiseState c d h)
-> NoiseResult c d h
forall c d h.
(Cipher c, DH d, Hash h) =>
Either SomeException (HandshakeResult, NoiseState c d h)
-> NoiseResult c d h
convertHandshakeResult (Either SomeException (HandshakeResult, NoiseState c d h)
 -> NoiseResult c d h)
-> Either SomeException (HandshakeResult, NoiseState c d h)
-> NoiseResult c d h
forall a b. (a -> b) -> a -> b
$ ScrubbedBytes
-> NoiseState c d h
-> Either SomeException (HandshakeResult, NoiseState c d h)
forall (m :: * -> *) c d h.
(MonadThrow m, Cipher c, DH d, Hash h) =>
ScrubbedBytes
-> NoiseState c d h -> m (HandshakeResult, NoiseState c d h)
resumeHandshake ScrubbedBytes
msg NoiseState c d h
ns)
  (Either SomeException (ScrubbedBytes, NoiseState c d h)
-> NoiseResult c d h
forall c d h.
(Cipher c, DH d, Hash h) =>
Either SomeException (ScrubbedBytes, NoiseState c d h)
-> NoiseResult c d h
convertTransportResult (Either SomeException (ScrubbedBytes, NoiseState c d h)
 -> NoiseResult c d h)
-> (CipherState c
    -> Either SomeException (ScrubbedBytes, NoiseState c d h))
-> CipherState c
-> NoiseResult c d h
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CipherState c
-> Either SomeException (ScrubbedBytes, NoiseState c d h)
forall {f :: * -> *}.
MonadThrow f =>
CipherState c -> f (ScrubbedBytes, NoiseState c d h)
encryptMsg)
  (NoiseState c d h
ns NoiseState c d h
-> Getting
     (Maybe (CipherState c)) (NoiseState c d h) (Maybe (CipherState c))
-> Maybe (CipherState c)
forall s a. s -> Getting a s a -> a
^. Getting
  (Maybe (CipherState c)) (NoiseState c d h) (Maybe (CipherState c))
forall c d h (f :: * -> *).
Functor f =>
(Maybe (CipherState c) -> f (Maybe (CipherState c)))
-> NoiseState c d h -> f (NoiseState c d h)
nsSendingCipherState)
  where
    ctToMsg :: Ciphertext c -> ScrubbedBytes
ctToMsg       = (Ciphertext c -> ScrubbedBytes) -> Ciphertext c -> ScrubbedBytes
forall b c. (b -> c) -> b -> c
forall (a :: * -> * -> *) b c. Arrow a => (b -> c) -> a b c
arr Ciphertext c -> ScrubbedBytes
forall c. Cipher c => Ciphertext c -> ScrubbedBytes
cipherTextToBytes
    updateState :: CipherState c -> NoiseState c d h
updateState   = (CipherState c -> NoiseState c d h)
-> CipherState c -> NoiseState c d h
forall b c. (b -> c) -> b -> c
forall (a :: * -> * -> *) b c. Arrow a => (b -> c) -> a b c
arr ((CipherState c -> NoiseState c d h)
 -> CipherState c -> NoiseState c d h)
-> (CipherState c -> NoiseState c d h)
-> CipherState c
-> NoiseState c d h
forall a b. (a -> b) -> a -> b
$ \CipherState c
cs -> NoiseState c d h
ns NoiseState c d h
-> (NoiseState c d h -> NoiseState c d h) -> NoiseState c d h
forall a b. a -> (a -> b) -> b
& (Maybe (CipherState c) -> Identity (Maybe (CipherState c)))
-> NoiseState c d h -> Identity (NoiseState c d h)
forall c d h (f :: * -> *).
Functor f =>
(Maybe (CipherState c) -> f (Maybe (CipherState c)))
-> NoiseState c d h -> f (NoiseState c d h)
nsSendingCipherState ((Maybe (CipherState c) -> Identity (Maybe (CipherState c)))
 -> NoiseState c d h -> Identity (NoiseState c d h))
-> CipherState c -> NoiseState c d h -> NoiseState c d h
forall s t a b. ASetter s t a (Maybe b) -> b -> s -> t
?~ CipherState c
cs
    encryptMsg :: CipherState c -> f (ScrubbedBytes, NoiseState c d h)
encryptMsg CipherState c
cs = (Ciphertext c -> ScrubbedBytes
ctToMsg (Ciphertext c -> ScrubbedBytes)
-> (CipherState c -> NoiseState c d h)
-> (Ciphertext c, CipherState c)
-> (ScrubbedBytes, NoiseState c d h)
forall b c b' c'. (b -> c) -> (b' -> c') -> (b, b') -> (c, c')
forall (a :: * -> * -> *) b c b' c'.
Arrow a =>
a b c -> a b' c' -> a (b, b') (c, c')
*** CipherState c -> NoiseState c d h
updateState) ((Ciphertext c, CipherState c)
 -> (ScrubbedBytes, NoiseState c d h))
-> f (Ciphertext c, CipherState c)
-> f (ScrubbedBytes, NoiseState c d h)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ScrubbedBytes
-> ScrubbedBytes
-> CipherState c
-> f (Ciphertext c, CipherState c)
forall (m :: * -> *) c.
(MonadThrow m, Cipher c) =>
ScrubbedBytes
-> ScrubbedBytes
-> CipherState c
-> m (Ciphertext c, CipherState c)
encryptWithAd ScrubbedBytes
forall a. Monoid a => a
mempty ScrubbedBytes
msg CipherState c
cs

-- | Reads a handshake or transport message and returns the embedded payload. If
--   the handshake fails, a 'HandshakeError' will be returned. After the
--   handshake is complete, if decryption fails a 'DecryptionError' is returned.
--
--   If a previous call to this function indicated that a pre-shared key is
--   needed, it shall be provided as the payload. See the documentation of
--   'NoiseResult' for details.
--
--   To prevent catastrophic key re-use, this function may only be used to
--   receive 2^64 - 1 post-handshake messages.
readMessage :: (Cipher c, DH d, Hash h)
            => ScrubbedBytes
            -> NoiseState c d h
            -> NoiseResult c d h
readMessage :: forall c d h.
(Cipher c, DH d, Hash h) =>
ScrubbedBytes -> NoiseState c d h -> NoiseResult c d h
readMessage ScrubbedBytes
ct NoiseState c d h
ns = NoiseResult c d h
-> (CipherState c -> NoiseResult c d h)
-> Maybe (CipherState c)
-> NoiseResult c d h
forall b a. b -> (a -> b) -> Maybe a -> b
maybe
  (Either SomeException (HandshakeResult, NoiseState c d h)
-> NoiseResult c d h
forall c d h.
(Cipher c, DH d, Hash h) =>
Either SomeException (HandshakeResult, NoiseState c d h)
-> NoiseResult c d h
convertHandshakeResult (Either SomeException (HandshakeResult, NoiseState c d h)
 -> NoiseResult c d h)
-> Either SomeException (HandshakeResult, NoiseState c d h)
-> NoiseResult c d h
forall a b. (a -> b) -> a -> b
$ ScrubbedBytes
-> NoiseState c d h
-> Either SomeException (HandshakeResult, NoiseState c d h)
forall (m :: * -> *) c d h.
(MonadThrow m, Cipher c, DH d, Hash h) =>
ScrubbedBytes
-> NoiseState c d h -> m (HandshakeResult, NoiseState c d h)
resumeHandshake ScrubbedBytes
ct NoiseState c d h
ns)
  (Either SomeException (ScrubbedBytes, NoiseState c d h)
-> NoiseResult c d h
forall c d h.
(Cipher c, DH d, Hash h) =>
Either SomeException (ScrubbedBytes, NoiseState c d h)
-> NoiseResult c d h
convertTransportResult (Either SomeException (ScrubbedBytes, NoiseState c d h)
 -> NoiseResult c d h)
-> (CipherState c
    -> Either SomeException (ScrubbedBytes, NoiseState c d h))
-> CipherState c
-> NoiseResult c d h
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CipherState c
-> Either SomeException (ScrubbedBytes, NoiseState c d h)
forall {f :: * -> *}.
MonadThrow f =>
CipherState c -> f (ScrubbedBytes, NoiseState c d h)
decryptMsg)
  (NoiseState c d h
ns NoiseState c d h
-> Getting
     (Maybe (CipherState c)) (NoiseState c d h) (Maybe (CipherState c))
-> Maybe (CipherState c)
forall s a. s -> Getting a s a -> a
^. Getting
  (Maybe (CipherState c)) (NoiseState c d h) (Maybe (CipherState c))
forall c d h (f :: * -> *).
Functor f =>
(Maybe (CipherState c) -> f (Maybe (CipherState c)))
-> NoiseState c d h -> f (NoiseState c d h)
nsReceivingCipherState)
  where
    ct' :: Ciphertext c
ct'           = ScrubbedBytes -> Ciphertext c
forall c. Cipher c => ScrubbedBytes -> Ciphertext c
cipherBytesToText ScrubbedBytes
ct
    updateState :: CipherState c -> NoiseState c d h
updateState   = (CipherState c -> NoiseState c d h)
-> CipherState c -> NoiseState c d h
forall b c. (b -> c) -> b -> c
forall (a :: * -> * -> *) b c. Arrow a => (b -> c) -> a b c
arr ((CipherState c -> NoiseState c d h)
 -> CipherState c -> NoiseState c d h)
-> (CipherState c -> NoiseState c d h)
-> CipherState c
-> NoiseState c d h
forall a b. (a -> b) -> a -> b
$ \CipherState c
cs -> NoiseState c d h
ns NoiseState c d h
-> (NoiseState c d h -> NoiseState c d h) -> NoiseState c d h
forall a b. a -> (a -> b) -> b
& (Maybe (CipherState c) -> Identity (Maybe (CipherState c)))
-> NoiseState c d h -> Identity (NoiseState c d h)
forall c d h (f :: * -> *).
Functor f =>
(Maybe (CipherState c) -> f (Maybe (CipherState c)))
-> NoiseState c d h -> f (NoiseState c d h)
nsReceivingCipherState ((Maybe (CipherState c) -> Identity (Maybe (CipherState c)))
 -> NoiseState c d h -> Identity (NoiseState c d h))
-> CipherState c -> NoiseState c d h -> NoiseState c d h
forall s t a b. ASetter s t a (Maybe b) -> b -> s -> t
?~ CipherState c
cs
    decryptMsg :: CipherState c -> f (ScrubbedBytes, NoiseState c d h)
decryptMsg CipherState c
cs = (CipherState c -> NoiseState c d h)
-> (ScrubbedBytes, CipherState c)
-> (ScrubbedBytes, NoiseState c d h)
forall b c d. (b -> c) -> (d, b) -> (d, c)
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (d, b) (d, c)
second CipherState c -> NoiseState c d h
updateState ((ScrubbedBytes, CipherState c)
 -> (ScrubbedBytes, NoiseState c d h))
-> f (ScrubbedBytes, CipherState c)
-> f (ScrubbedBytes, NoiseState c d h)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ScrubbedBytes
-> Ciphertext c
-> CipherState c
-> f (ScrubbedBytes, CipherState c)
forall (m :: * -> *) c.
(MonadThrow m, Cipher c) =>
ScrubbedBytes
-> Ciphertext c
-> CipherState c
-> m (ScrubbedBytes, CipherState c)
decryptWithAd ScrubbedBytes
forall a. Monoid a => a
mempty Ciphertext c
ct' CipherState c
cs

-- | Given an operation ('writeMessage' or 'readMessage'), a list of PSKs, and
--   a 'NoiseResult', this function will repeatedly apply PSKs to the NoiseState
--   until no more are requested or the list of PSKs becomes empty. This is
--   useful for patterns which require two or more PSKs, and you know exactly
--   what they all should be ahead of time.
processPSKs :: (Cipher c, DH d, Hash h)
            => (ScrubbedBytes -> NoiseState c d h -> NoiseResult c d h)
            -> [ScrubbedBytes]
            -> NoiseResult c d h
            -> ([ScrubbedBytes], NoiseResult c d h)
processPSKs :: forall c d h.
(Cipher c, DH d, Hash h) =>
(ScrubbedBytes -> NoiseState c d h -> NoiseResult c d h)
-> [ScrubbedBytes]
-> NoiseResult c d h
-> ([ScrubbedBytes], NoiseResult c d h)
processPSKs ScrubbedBytes -> NoiseState c d h -> NoiseResult c d h
_ []                NoiseResult c d h
result = ([], NoiseResult c d h
result)
processPSKs ScrubbedBytes -> NoiseState c d h -> NoiseResult c d h
f psks :: [ScrubbedBytes]
psks@(ScrubbedBytes
psk : [ScrubbedBytes]
rest) NoiseResult c d h
result = case NoiseResult c d h
result of
  NoiseResultNeedPSK NoiseState c d h
state' -> (ScrubbedBytes -> NoiseState c d h -> NoiseResult c d h)
-> [ScrubbedBytes]
-> NoiseResult c d h
-> ([ScrubbedBytes], NoiseResult c d h)
forall c d h.
(Cipher c, DH d, Hash h) =>
(ScrubbedBytes -> NoiseState c d h -> NoiseResult c d h)
-> [ScrubbedBytes]
-> NoiseResult c d h
-> ([ScrubbedBytes], NoiseResult c d h)
processPSKs ScrubbedBytes -> NoiseState c d h -> NoiseResult c d h
f [ScrubbedBytes]
rest (ScrubbedBytes -> NoiseState c d h -> NoiseResult c d h
f ScrubbedBytes
psk NoiseState c d h
state')
  NoiseResult c d h
r -> ([ScrubbedBytes]
psks, NoiseResult c d h
r)

-- | For handshake patterns where the remote party's static key is
--   transmitted, this function can be used to retrieve it. This allows
--   for the creation of public key-based access-control lists.
remoteStaticKey :: NoiseState c d h
                -> Maybe (PublicKey d)
remoteStaticKey :: forall c d h. NoiseState c d h -> Maybe (PublicKey d)
remoteStaticKey NoiseState c d h
ns = NoiseState c d h
ns NoiseState c d h
-> Getting
     (Maybe (PublicKey d)) (NoiseState c d h) (Maybe (PublicKey d))
-> Maybe (PublicKey d)
forall s a. s -> Getting a s a -> a
^. (HandshakeState c d h
 -> Const (Maybe (PublicKey d)) (HandshakeState c d h))
-> NoiseState c d h
-> Const (Maybe (PublicKey d)) (NoiseState c d h)
forall c d h (f :: * -> *).
Functor f =>
(HandshakeState c d h -> f (HandshakeState c d h))
-> NoiseState c d h -> f (NoiseState c d h)
nsHandshakeState ((HandshakeState c d h
  -> Const (Maybe (PublicKey d)) (HandshakeState c d h))
 -> NoiseState c d h
 -> Const (Maybe (PublicKey d)) (NoiseState c d h))
-> ((Maybe (PublicKey d)
     -> Const (Maybe (PublicKey d)) (Maybe (PublicKey d)))
    -> HandshakeState c d h
    -> Const (Maybe (PublicKey d)) (HandshakeState c d h))
-> Getting
     (Maybe (PublicKey d)) (NoiseState c d h) (Maybe (PublicKey d))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (HandshakeOpts d -> Const (Maybe (PublicKey d)) (HandshakeOpts d))
-> HandshakeState c d h
-> Const (Maybe (PublicKey d)) (HandshakeState c d h)
forall c d1 h d2 (f :: * -> *).
Functor f =>
(HandshakeOpts d1 -> f (HandshakeOpts d2))
-> HandshakeState c d1 h -> f (HandshakeState c d2 h)
hsOpts ((HandshakeOpts d -> Const (Maybe (PublicKey d)) (HandshakeOpts d))
 -> HandshakeState c d h
 -> Const (Maybe (PublicKey d)) (HandshakeState c d h))
-> ((Maybe (PublicKey d)
     -> Const (Maybe (PublicKey d)) (Maybe (PublicKey d)))
    -> HandshakeOpts d
    -> Const (Maybe (PublicKey d)) (HandshakeOpts d))
-> (Maybe (PublicKey d)
    -> Const (Maybe (PublicKey d)) (Maybe (PublicKey d)))
-> HandshakeState c d h
-> Const (Maybe (PublicKey d)) (HandshakeState c d h)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Maybe (PublicKey d)
 -> Const (Maybe (PublicKey d)) (Maybe (PublicKey d)))
-> HandshakeOpts d -> Const (Maybe (PublicKey d)) (HandshakeOpts d)
forall d (f :: * -> *).
Functor f =>
(Maybe (PublicKey d) -> f (Maybe (PublicKey d)))
-> HandshakeOpts d -> f (HandshakeOpts d)
hoRemoteStatic

-- | Returns @True@ if the handshake is complete.
handshakeComplete :: NoiseState c d h
                  -> Bool
handshakeComplete :: forall c d h. NoiseState c d h -> Bool
handshakeComplete NoiseState c d h
ns = Maybe (CipherState c) -> Bool
forall a. Maybe a -> Bool
isJust (NoiseState c d h
ns NoiseState c d h
-> Getting
     (Maybe (CipherState c)) (NoiseState c d h) (Maybe (CipherState c))
-> Maybe (CipherState c)
forall s a. s -> Getting a s a -> a
^. Getting
  (Maybe (CipherState c)) (NoiseState c d h) (Maybe (CipherState c))
forall c d h (f :: * -> *).
Functor f =>
(Maybe (CipherState c) -> f (Maybe (CipherState c)))
-> NoiseState c d h -> f (NoiseState c d h)
nsSendingCipherState) Bool -> Bool -> Bool
&&
                       Maybe (CipherState c) -> Bool
forall a. Maybe a -> Bool
isJust (NoiseState c d h
ns NoiseState c d h
-> Getting
     (Maybe (CipherState c)) (NoiseState c d h) (Maybe (CipherState c))
-> Maybe (CipherState c)
forall s a. s -> Getting a s a -> a
^. Getting
  (Maybe (CipherState c)) (NoiseState c d h) (Maybe (CipherState c))
forall c d h (f :: * -> *).
Functor f =>
(Maybe (CipherState c) -> f (Maybe (CipherState c)))
-> NoiseState c d h -> f (NoiseState c d h)
nsReceivingCipherState)

-- | Retrieves the @h@ value associated with the conversation's
--   @SymmetricState@. This value is intended to be used for channel
--   binding. For example, the initiator might cryptographically sign this
--   value as part of some higher-level authentication scheme.
--
--   The value returned by this function is only meaningful after the
--   handshake is complete.
--
--   See section 11.2 of the protocol for details.
handshakeHash :: Hash h
              => NoiseState c d h
              -> ScrubbedBytes
handshakeHash :: forall h c d. Hash h => NoiseState c d h -> ScrubbedBytes
handshakeHash NoiseState c d h
ns = (ScrubbedBytes -> ScrubbedBytes)
-> (Digest h -> ScrubbedBytes)
-> Either ScrubbedBytes (Digest h)
-> ScrubbedBytes
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either ScrubbedBytes -> ScrubbedBytes
forall a. a -> a
id Digest h -> ScrubbedBytes
forall h. Hash h => Digest h -> ScrubbedBytes
hashToBytes
                   (Either ScrubbedBytes (Digest h) -> ScrubbedBytes)
-> Either ScrubbedBytes (Digest h) -> ScrubbedBytes
forall a b. (a -> b) -> a -> b
$ NoiseState c d h
ns NoiseState c d h
-> Getting
     (Either ScrubbedBytes (Digest h))
     (NoiseState c d h)
     (Either ScrubbedBytes (Digest h))
-> Either ScrubbedBytes (Digest h)
forall s a. s -> Getting a s a -> a
^. (HandshakeState c d h
 -> Const (Either ScrubbedBytes (Digest h)) (HandshakeState c d h))
-> NoiseState c d h
-> Const (Either ScrubbedBytes (Digest h)) (NoiseState c d h)
forall c d h (f :: * -> *).
Functor f =>
(HandshakeState c d h -> f (HandshakeState c d h))
-> NoiseState c d h -> f (NoiseState c d h)
nsHandshakeState ((HandshakeState c d h
  -> Const (Either ScrubbedBytes (Digest h)) (HandshakeState c d h))
 -> NoiseState c d h
 -> Const (Either ScrubbedBytes (Digest h)) (NoiseState c d h))
-> ((Either ScrubbedBytes (Digest h)
     -> Const
          (Either ScrubbedBytes (Digest h))
          (Either ScrubbedBytes (Digest h)))
    -> HandshakeState c d h
    -> Const (Either ScrubbedBytes (Digest h)) (HandshakeState c d h))
-> Getting
     (Either ScrubbedBytes (Digest h))
     (NoiseState c d h)
     (Either ScrubbedBytes (Digest h))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (SymmetricState c h
 -> Const (Either ScrubbedBytes (Digest h)) (SymmetricState c h))
-> HandshakeState c d h
-> Const (Either ScrubbedBytes (Digest h)) (HandshakeState c d h)
forall c1 d h1 c2 h2 (f :: * -> *).
Functor f =>
(SymmetricState c1 h1 -> f (SymmetricState c2 h2))
-> HandshakeState c1 d h1 -> f (HandshakeState c2 d h2)
hsSymmetricState ((SymmetricState c h
  -> Const (Either ScrubbedBytes (Digest h)) (SymmetricState c h))
 -> HandshakeState c d h
 -> Const (Either ScrubbedBytes (Digest h)) (HandshakeState c d h))
-> ((Either ScrubbedBytes (Digest h)
     -> Const
          (Either ScrubbedBytes (Digest h))
          (Either ScrubbedBytes (Digest h)))
    -> SymmetricState c h
    -> Const (Either ScrubbedBytes (Digest h)) (SymmetricState c h))
-> (Either ScrubbedBytes (Digest h)
    -> Const
         (Either ScrubbedBytes (Digest h))
         (Either ScrubbedBytes (Digest h)))
-> HandshakeState c d h
-> Const (Either ScrubbedBytes (Digest h)) (HandshakeState c d h)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Either ScrubbedBytes (Digest h)
 -> Const
      (Either ScrubbedBytes (Digest h))
      (Either ScrubbedBytes (Digest h)))
-> SymmetricState c h
-> Const (Either ScrubbedBytes (Digest h)) (SymmetricState c h)
forall c h (f :: * -> *).
Functor f =>
(Either ScrubbedBytes (Digest h)
 -> f (Either ScrubbedBytes (Digest h)))
-> SymmetricState c h -> f (SymmetricState c h)
ssh

-- | Rekeys the sending @CipherState@ according to section 11.3 of the protocol.
rekeySending :: (Cipher c, DH d, Hash h)
             => NoiseState c d h
             -> NoiseState c d h
rekeySending :: forall c d h.
(Cipher c, DH d, Hash h) =>
NoiseState c d h -> NoiseState c d h
rekeySending NoiseState c d h
ns = NoiseState c d h
ns NoiseState c d h
-> (NoiseState c d h -> NoiseState c d h) -> NoiseState c d h
forall a b. a -> (a -> b) -> b
& (Maybe (CipherState c) -> Identity (Maybe (CipherState c)))
-> NoiseState c d h -> Identity (NoiseState c d h)
forall c d h (f :: * -> *).
Functor f =>
(Maybe (CipherState c) -> f (Maybe (CipherState c)))
-> NoiseState c d h -> f (NoiseState c d h)
nsSendingCipherState ((Maybe (CipherState c) -> Identity (Maybe (CipherState c)))
 -> NoiseState c d h -> Identity (NoiseState c d h))
-> (Maybe (CipherState c) -> Maybe (CipherState c))
-> NoiseState c d h
-> NoiseState c d h
forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
%~ Maybe (CipherState c -> CipherState c)
-> Maybe (CipherState c) -> Maybe (CipherState c)
forall a b. Maybe (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
(<*>) ((CipherState c -> CipherState c)
-> Maybe (CipherState c -> CipherState c)
forall a. a -> Maybe a
forall (f :: * -> *) a. Applicative f => a -> f a
pure CipherState c -> CipherState c
forall c. Cipher c => CipherState c -> CipherState c
rekey)

-- | Rekeys the receiving @CipherState@ according to section 11.3 of the
--   protocol.
rekeyReceiving :: (Cipher c, DH d, Hash h)
               => NoiseState c d h
               -> NoiseState c d h
rekeyReceiving :: forall c d h.
(Cipher c, DH d, Hash h) =>
NoiseState c d h -> NoiseState c d h
rekeyReceiving NoiseState c d h
ns = NoiseState c d h
ns NoiseState c d h
-> (NoiseState c d h -> NoiseState c d h) -> NoiseState c d h
forall a b. a -> (a -> b) -> b
& (Maybe (CipherState c) -> Identity (Maybe (CipherState c)))
-> NoiseState c d h -> Identity (NoiseState c d h)
forall c d h (f :: * -> *).
Functor f =>
(Maybe (CipherState c) -> f (Maybe (CipherState c)))
-> NoiseState c d h -> f (NoiseState c d h)
nsReceivingCipherState ((Maybe (CipherState c) -> Identity (Maybe (CipherState c)))
 -> NoiseState c d h -> Identity (NoiseState c d h))
-> (Maybe (CipherState c) -> Maybe (CipherState c))
-> NoiseState c d h
-> NoiseState c d h
forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
%~ Maybe (CipherState c -> CipherState c)
-> Maybe (CipherState c) -> Maybe (CipherState c)
forall a b. Maybe (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
(<*>) ((CipherState c -> CipherState c)
-> Maybe (CipherState c -> CipherState c)
forall a. a -> Maybe a
forall (f :: * -> *) a. Applicative f => a -> f a
pure CipherState c -> CipherState c
forall c. Cipher c => CipherState c -> CipherState c
rekey)

--------------------------------------------------------------------------------

convertHandshakeResult :: (Cipher c, DH d, Hash h)
                       => Either SomeException (HandshakeResult, NoiseState c d h)
                       -> NoiseResult c d h
convertHandshakeResult :: forall c d h.
(Cipher c, DH d, Hash h) =>
Either SomeException (HandshakeResult, NoiseState c d h)
-> NoiseResult c d h
convertHandshakeResult Either SomeException (HandshakeResult, NoiseState c d h)
hsr = case Either SomeException (HandshakeResult, NoiseState c d h)
hsr of
  Left SomeException
ex -> SomeException -> NoiseResult c d h
forall c d h. SomeException -> NoiseResult c d h
NoiseResultException SomeException
ex
  Right (HandshakeResultMessage ScrubbedBytes
m, NoiseState c d h
ns) -> ScrubbedBytes -> NoiseState c d h -> NoiseResult c d h
forall c d h.
ScrubbedBytes -> NoiseState c d h -> NoiseResult c d h
NoiseResultMessage ScrubbedBytes
m NoiseState c d h
ns
  Right (HandshakeResult
HandshakeResultNeedPSK  , NoiseState c d h
ns) -> NoiseState c d h -> NoiseResult c d h
forall c d h. NoiseState c d h -> NoiseResult c d h
NoiseResultNeedPSK NoiseState c d h
ns

convertTransportResult :: (Cipher c, DH d, Hash h)
                       => Either SomeException (ScrubbedBytes, NoiseState c d h)
                       -> NoiseResult c d h
convertTransportResult :: forall c d h.
(Cipher c, DH d, Hash h) =>
Either SomeException (ScrubbedBytes, NoiseState c d h)
-> NoiseResult c d h
convertTransportResult = (SomeException -> NoiseResult c d h)
-> ((ScrubbedBytes, NoiseState c d h) -> NoiseResult c d h)
-> Either SomeException (ScrubbedBytes, NoiseState c d h)
-> NoiseResult c d h
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either SomeException -> NoiseResult c d h
forall c d h. SomeException -> NoiseResult c d h
NoiseResultException ((ScrubbedBytes -> NoiseState c d h -> NoiseResult c d h)
-> (ScrubbedBytes, NoiseState c d h) -> NoiseResult c d h
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry ScrubbedBytes -> NoiseState c d h -> NoiseResult c d h
forall c d h.
ScrubbedBytes -> NoiseState c d h -> NoiseResult c d h
NoiseResultMessage)