{-# LANGUAGE TemplateHaskell, ScopedTypeVariables #-}
-----------------------------------------------------
-- |
-- Module      : Crypto.Noise.Internal.SymmetricState
-- Maintainer  : John Galt <jgalt@centromere.net>
-- Stability   : experimental
-- Portability : POSIX
module Crypto.Noise.Internal.SymmetricState where

import Control.Exception.Safe
import Control.Lens
import Data.ByteArray  (ScrubbedBytes, length, replicate)
import Data.Proxy
import Prelude hiding  (length, replicate)

import Crypto.Noise.Cipher
import Crypto.Noise.Hash
import Crypto.Noise.Internal.CipherState

data SymmetricState c h =
  SymmetricState { forall c h. SymmetricState c h -> CipherState c
_ssCipher :: CipherState c
                 , forall c h. SymmetricState c h -> ChainingKey h
_ssck     :: ChainingKey h
                 , forall c h. SymmetricState c h -> Either ScrubbedBytes (Digest h)
_ssh      :: Either ScrubbedBytes (Digest h)
                 }

$(makeLenses ''SymmetricState)

-- | Creates a new SymmetricState from the given protocol name.
symmetricState :: forall c h. (Cipher c, Hash h)
               => ScrubbedBytes
               -> SymmetricState c h
symmetricState :: forall c h.
(Cipher c, Hash h) =>
ScrubbedBytes -> SymmetricState c h
symmetricState ScrubbedBytes
protoName = CipherState c
-> ChainingKey h
-> Either ScrubbedBytes (Digest h)
-> SymmetricState c h
forall c h.
CipherState c
-> ChainingKey h
-> Either ScrubbedBytes (Digest h)
-> SymmetricState c h
SymmetricState CipherState c
cs ChainingKey h
ck Either ScrubbedBytes (Digest h)
h
  where
    hashLen :: Int
hashLen    = Proxy h -> Int
forall h (proxy :: * -> *). Hash h => proxy h -> Int
forall (proxy :: * -> *). proxy h -> Int
hashLength (Proxy h
forall {k} (t :: k). Proxy t
Proxy :: Proxy h)
    shouldHash :: Bool
shouldHash = ScrubbedBytes -> Int
forall ba. ByteArrayAccess ba => ba -> Int
length ScrubbedBytes
protoName Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
hashLen
    h :: Either ScrubbedBytes (Digest h)
h         = if Bool
shouldHash
                   then Digest h -> Either ScrubbedBytes (Digest h)
forall a b. b -> Either a b
Right (Digest h -> Either ScrubbedBytes (Digest h))
-> Digest h -> Either ScrubbedBytes (Digest h)
forall a b. (a -> b) -> a -> b
$ ScrubbedBytes -> Digest h
forall h. Hash h => ScrubbedBytes -> Digest h
hash ScrubbedBytes
protoName
                   else ScrubbedBytes -> Either ScrubbedBytes (Digest h)
forall a b. a -> Either a b
Left (ScrubbedBytes -> Either ScrubbedBytes (Digest h))
-> ScrubbedBytes -> Either ScrubbedBytes (Digest h)
forall a b. (a -> b) -> a -> b
$ ScrubbedBytes
protoName ScrubbedBytes -> ScrubbedBytes -> ScrubbedBytes
forall a. Monoid a => a -> a -> a
`mappend` Int -> Word8 -> ScrubbedBytes
forall ba. ByteArray ba => Int -> Word8 -> ba
replicate (Int
hashLen Int -> Int -> Int
forall a. Num a => a -> a -> a
- ScrubbedBytes -> Int
forall ba. ByteArrayAccess ba => ba -> Int
length ScrubbedBytes
protoName) Word8
0
    ck :: ChainingKey h
ck         = ScrubbedBytes -> ChainingKey h
forall h. Hash h => ScrubbedBytes -> ChainingKey h
hashBytesToCK (ScrubbedBytes -> ChainingKey h)
-> (Either ScrubbedBytes (Digest h) -> ScrubbedBytes)
-> Either ScrubbedBytes (Digest h)
-> ChainingKey h
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Either ScrubbedBytes (Digest h) -> ScrubbedBytes
forall h.
Hash h =>
Either ScrubbedBytes (Digest h) -> ScrubbedBytes
sshBytes (Either ScrubbedBytes (Digest h) -> ChainingKey h)
-> Either ScrubbedBytes (Digest h) -> ChainingKey h
forall a b. (a -> b) -> a -> b
$ Either ScrubbedBytes (Digest h)
h
    cs :: CipherState c
cs         = Maybe (SymmetricKey c) -> CipherState c
forall c. Cipher c => Maybe (SymmetricKey c) -> CipherState c
cipherState Maybe (SymmetricKey c)
forall a. Maybe a
Nothing

-- | Mixes keying material in to the SymmetricState.
mixKey :: (Cipher c, Hash h)
       => ScrubbedBytes
       -> SymmetricState c h
       -> SymmetricState c h
mixKey :: forall c h.
(Cipher c, Hash h) =>
ScrubbedBytes -> SymmetricState c h -> SymmetricState c h
mixKey ScrubbedBytes
keyMat SymmetricState c h
ss = SymmetricState c h
ss SymmetricState c h
-> (SymmetricState c h -> SymmetricState c h) -> SymmetricState c h
forall a b. a -> (a -> b) -> b
& (CipherState c -> Identity (CipherState c))
-> SymmetricState c h -> Identity (SymmetricState c h)
forall c h c (f :: * -> *).
Functor f =>
(CipherState c -> f (CipherState c))
-> SymmetricState c h -> f (SymmetricState c h)
ssCipher ((CipherState c -> Identity (CipherState c))
 -> SymmetricState c h -> Identity (SymmetricState c h))
-> CipherState c -> SymmetricState c h -> SymmetricState c h
forall s t a b. ASetter s t a b -> b -> s -> t
.~ CipherState c
cs
                      SymmetricState c h
-> (SymmetricState c h -> SymmetricState c h) -> SymmetricState c h
forall a b. a -> (a -> b) -> b
& (ChainingKey h -> Identity (ChainingKey h))
-> SymmetricState c h -> Identity (SymmetricState c h)
forall c h (f :: * -> *).
Functor f =>
(ChainingKey h -> f (ChainingKey h))
-> SymmetricState c h -> f (SymmetricState c h)
ssck     ((ChainingKey h -> Identity (ChainingKey h))
 -> SymmetricState c h -> Identity (SymmetricState c h))
-> ChainingKey h -> SymmetricState c h -> SymmetricState c h
forall s t a b. ASetter s t a b -> b -> s -> t
.~ ScrubbedBytes -> ChainingKey h
forall h. Hash h => ScrubbedBytes -> ChainingKey h
hashBytesToCK ScrubbedBytes
ck
  where
    [ScrubbedBytes
ck, ScrubbedBytes
k] = ChainingKey h -> ScrubbedBytes -> Word8 -> [ScrubbedBytes]
forall h.
Hash h =>
ChainingKey h -> ScrubbedBytes -> Word8 -> [ScrubbedBytes]
hashHKDF (SymmetricState c h
ss SymmetricState c h
-> Getting (ChainingKey h) (SymmetricState c h) (ChainingKey h)
-> ChainingKey h
forall s a. s -> Getting a s a -> a
^. Getting (ChainingKey h) (SymmetricState c h) (ChainingKey h)
forall c h (f :: * -> *).
Functor f =>
(ChainingKey h -> f (ChainingKey h))
-> SymmetricState c h -> f (SymmetricState c h)
ssck) ScrubbedBytes
keyMat Word8
2
    -- k is truncated automatically by cipherBytesToSym
    cs :: CipherState c
cs      = Maybe (SymmetricKey c) -> CipherState c
forall c. Cipher c => Maybe (SymmetricKey c) -> CipherState c
cipherState (Maybe (SymmetricKey c) -> CipherState c)
-> (ScrubbedBytes -> Maybe (SymmetricKey c))
-> ScrubbedBytes
-> CipherState c
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SymmetricKey c -> Maybe (SymmetricKey c)
forall a. a -> Maybe a
Just (SymmetricKey c -> Maybe (SymmetricKey c))
-> (ScrubbedBytes -> SymmetricKey c)
-> ScrubbedBytes
-> Maybe (SymmetricKey c)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ScrubbedBytes -> SymmetricKey c
forall c. Cipher c => ScrubbedBytes -> SymmetricKey c
cipherBytesToSym (ScrubbedBytes -> CipherState c) -> ScrubbedBytes -> CipherState c
forall a b. (a -> b) -> a -> b
$ ScrubbedBytes
k

-- | Mixes arbitrary data in to the SymmetricState.
mixHash :: Hash h
        => ScrubbedBytes
        -> SymmetricState c h
        -> SymmetricState c h
mixHash :: forall h c.
Hash h =>
ScrubbedBytes -> SymmetricState c h -> SymmetricState c h
mixHash ScrubbedBytes
d SymmetricState c h
ss = SymmetricState c h
ss SymmetricState c h
-> (SymmetricState c h -> SymmetricState c h) -> SymmetricState c h
forall a b. a -> (a -> b) -> b
& (Either ScrubbedBytes (Digest h)
 -> Identity (Either ScrubbedBytes (Digest h)))
-> SymmetricState c h -> Identity (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 ((Either ScrubbedBytes (Digest h)
  -> Identity (Either ScrubbedBytes (Digest h)))
 -> SymmetricState c h -> Identity (SymmetricState c h))
-> (Either ScrubbedBytes (Digest h)
    -> Either ScrubbedBytes (Digest h))
-> SymmetricState c h
-> SymmetricState c h
forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
%~ Digest h -> Either ScrubbedBytes (Digest h)
forall a b. b -> Either a b
Right (Digest h -> Either ScrubbedBytes (Digest h))
-> (Either ScrubbedBytes (Digest h) -> Digest h)
-> Either ScrubbedBytes (Digest h)
-> Either ScrubbedBytes (Digest h)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ScrubbedBytes -> Digest h
forall h. Hash h => ScrubbedBytes -> Digest h
hash (ScrubbedBytes -> Digest h)
-> (Either ScrubbedBytes (Digest h) -> ScrubbedBytes)
-> Either ScrubbedBytes (Digest h)
-> Digest h
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ScrubbedBytes -> ScrubbedBytes -> ScrubbedBytes
forall a. Monoid a => a -> a -> a
`mappend` ScrubbedBytes
d) (ScrubbedBytes -> ScrubbedBytes)
-> (Either ScrubbedBytes (Digest h) -> ScrubbedBytes)
-> Either ScrubbedBytes (Digest h)
-> ScrubbedBytes
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Either ScrubbedBytes (Digest h) -> ScrubbedBytes
forall h.
Hash h =>
Either ScrubbedBytes (Digest h) -> ScrubbedBytes
sshBytes

-- | Mixes key material and arbitrary data in to the SymmetricState.
--   Note that this is not isomorphic to @mixHash . mixKey@.
mixKeyAndHash :: (Cipher c, Hash h)
              => ScrubbedBytes
              -> SymmetricState c h
              -> SymmetricState c h
mixKeyAndHash :: forall c h.
(Cipher c, Hash h) =>
ScrubbedBytes -> SymmetricState c h -> SymmetricState c h
mixKeyAndHash ScrubbedBytes
keyMat SymmetricState c h
ss = SymmetricState c h
ss' SymmetricState c h
-> (SymmetricState c h -> SymmetricState c h) -> SymmetricState c h
forall a b. a -> (a -> b) -> b
& (CipherState c -> Identity (CipherState c))
-> SymmetricState c h -> Identity (SymmetricState c h)
forall c h c (f :: * -> *).
Functor f =>
(CipherState c -> f (CipherState c))
-> SymmetricState c h -> f (SymmetricState c h)
ssCipher ((CipherState c -> Identity (CipherState c))
 -> SymmetricState c h -> Identity (SymmetricState c h))
-> CipherState c -> SymmetricState c h -> SymmetricState c h
forall s t a b. ASetter s t a b -> b -> s -> t
.~ CipherState c
cs
                              SymmetricState c h
-> (SymmetricState c h -> SymmetricState c h) -> SymmetricState c h
forall a b. a -> (a -> b) -> b
& (ChainingKey h -> Identity (ChainingKey h))
-> SymmetricState c h -> Identity (SymmetricState c h)
forall c h (f :: * -> *).
Functor f =>
(ChainingKey h -> f (ChainingKey h))
-> SymmetricState c h -> f (SymmetricState c h)
ssck     ((ChainingKey h -> Identity (ChainingKey h))
 -> SymmetricState c h -> Identity (SymmetricState c h))
-> ChainingKey h -> SymmetricState c h -> SymmetricState c h
forall s t a b. ASetter s t a b -> b -> s -> t
.~ ScrubbedBytes -> ChainingKey h
forall h. Hash h => ScrubbedBytes -> ChainingKey h
hashBytesToCK ScrubbedBytes
ck
  where
    [ScrubbedBytes
ck, ScrubbedBytes
h, ScrubbedBytes
k] = ChainingKey h -> ScrubbedBytes -> Word8 -> [ScrubbedBytes]
forall h.
Hash h =>
ChainingKey h -> ScrubbedBytes -> Word8 -> [ScrubbedBytes]
hashHKDF (SymmetricState c h
ss SymmetricState c h
-> Getting (ChainingKey h) (SymmetricState c h) (ChainingKey h)
-> ChainingKey h
forall s a. s -> Getting a s a -> a
^. Getting (ChainingKey h) (SymmetricState c h) (ChainingKey h)
forall c h (f :: * -> *).
Functor f =>
(ChainingKey h -> f (ChainingKey h))
-> SymmetricState c h -> f (SymmetricState c h)
ssck) ScrubbedBytes
keyMat Word8
3
    ss' :: SymmetricState c h
ss'        = ScrubbedBytes -> SymmetricState c h -> SymmetricState c h
forall h c.
Hash h =>
ScrubbedBytes -> SymmetricState c h -> SymmetricState c h
mixHash ScrubbedBytes
h SymmetricState c h
ss
    cs :: CipherState c
cs         = Maybe (SymmetricKey c) -> CipherState c
forall c. Cipher c => Maybe (SymmetricKey c) -> CipherState c
cipherState (Maybe (SymmetricKey c) -> CipherState c)
-> (ScrubbedBytes -> Maybe (SymmetricKey c))
-> ScrubbedBytes
-> CipherState c
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SymmetricKey c -> Maybe (SymmetricKey c)
forall a. a -> Maybe a
Just (SymmetricKey c -> Maybe (SymmetricKey c))
-> (ScrubbedBytes -> SymmetricKey c)
-> ScrubbedBytes
-> Maybe (SymmetricKey c)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ScrubbedBytes -> SymmetricKey c
forall c. Cipher c => ScrubbedBytes -> SymmetricKey c
cipherBytesToSym (ScrubbedBytes -> CipherState c) -> ScrubbedBytes -> CipherState c
forall a b. (a -> b) -> a -> b
$ ScrubbedBytes
k

-- | Encrypts the given Plaintext. Note that this may not actually perform
--   encryption if a key has not been established yet, in which case the
--   original plaintext is returned.
encryptAndHash :: (MonadThrow m, Cipher c, Hash h)
               => Plaintext
               -> SymmetricState c h
               -> m (Ciphertext c, SymmetricState c h)
encryptAndHash :: forall (m :: * -> *) c h.
(MonadThrow m, Cipher c, Hash h) =>
ScrubbedBytes
-> SymmetricState c h -> m (Ciphertext c, SymmetricState c h)
encryptAndHash ScrubbedBytes
pt SymmetricState c h
ss = do
  (Ciphertext c
ct, CipherState c
cs) <- ScrubbedBytes
-> ScrubbedBytes
-> CipherState c
-> m (Ciphertext c, CipherState c)
forall (m :: * -> *) c.
(MonadThrow m, Cipher c) =>
ScrubbedBytes
-> ScrubbedBytes
-> CipherState c
-> m (Ciphertext c, CipherState c)
encryptWithAd (Either ScrubbedBytes (Digest h) -> ScrubbedBytes
forall h.
Hash h =>
Either ScrubbedBytes (Digest h) -> ScrubbedBytes
sshBytes (SymmetricState c h
ss SymmetricState c h
-> Getting
     (Either ScrubbedBytes (Digest h))
     (SymmetricState c h)
     (Either ScrubbedBytes (Digest h))
-> Either ScrubbedBytes (Digest h)
forall s a. s -> Getting a s a -> a
^. Getting
  (Either ScrubbedBytes (Digest h))
  (SymmetricState c h)
  (Either ScrubbedBytes (Digest h))
forall c h (f :: * -> *).
Functor f =>
(Either ScrubbedBytes (Digest h)
 -> f (Either ScrubbedBytes (Digest h)))
-> SymmetricState c h -> f (SymmetricState c h)
ssh)) ScrubbedBytes
pt (SymmetricState c h
ss SymmetricState c h
-> Getting (CipherState c) (SymmetricState c h) (CipherState c)
-> CipherState c
forall s a. s -> Getting a s a -> a
^. Getting (CipherState c) (SymmetricState c h) (CipherState c)
forall c h c (f :: * -> *).
Functor f =>
(CipherState c -> f (CipherState c))
-> SymmetricState c h -> f (SymmetricState c h)
ssCipher)
  let ss' :: SymmetricState c h
ss' = ScrubbedBytes -> SymmetricState c h -> SymmetricState c h
forall h c.
Hash h =>
ScrubbedBytes -> SymmetricState c h -> SymmetricState c h
mixHash (Ciphertext c -> ScrubbedBytes
forall c. Cipher c => Ciphertext c -> ScrubbedBytes
cipherTextToBytes Ciphertext c
ct) SymmetricState c h
ss
  (Ciphertext c, SymmetricState c h)
-> m (Ciphertext c, SymmetricState c h)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Ciphertext c
ct, SymmetricState c h
ss' SymmetricState c h
-> (SymmetricState c h -> SymmetricState c h) -> SymmetricState c h
forall a b. a -> (a -> b) -> b
& (CipherState c -> Identity (CipherState c))
-> SymmetricState c h -> Identity (SymmetricState c h)
forall c h c (f :: * -> *).
Functor f =>
(CipherState c -> f (CipherState c))
-> SymmetricState c h -> f (SymmetricState c h)
ssCipher ((CipherState c -> Identity (CipherState c))
 -> SymmetricState c h -> Identity (SymmetricState c h))
-> CipherState c -> SymmetricState c h -> SymmetricState c h
forall s t a b. ASetter s t a b -> b -> s -> t
.~ CipherState c
cs)

-- | Decrypts the given Ciphertext. Note that this may not actually perform
--   decryption if a key as not been established yet, in which case the
--   original ciphertext is returned.
decryptAndHash :: (MonadThrow m, Cipher c, Hash h)
               => Ciphertext c
               -> SymmetricState c h
               -> m (Plaintext, SymmetricState c h)
decryptAndHash :: forall (m :: * -> *) c h.
(MonadThrow m, Cipher c, Hash h) =>
Ciphertext c
-> SymmetricState c h -> m (ScrubbedBytes, SymmetricState c h)
decryptAndHash Ciphertext c
ct SymmetricState c h
ss = do
  (ScrubbedBytes
pt, CipherState c
cs) <- ScrubbedBytes
-> Ciphertext c
-> CipherState c
-> m (ScrubbedBytes, CipherState c)
forall (m :: * -> *) c.
(MonadThrow m, Cipher c) =>
ScrubbedBytes
-> Ciphertext c
-> CipherState c
-> m (ScrubbedBytes, CipherState c)
decryptWithAd (Either ScrubbedBytes (Digest h) -> ScrubbedBytes
forall h.
Hash h =>
Either ScrubbedBytes (Digest h) -> ScrubbedBytes
sshBytes (SymmetricState c h
ss SymmetricState c h
-> Getting
     (Either ScrubbedBytes (Digest h))
     (SymmetricState c h)
     (Either ScrubbedBytes (Digest h))
-> Either ScrubbedBytes (Digest h)
forall s a. s -> Getting a s a -> a
^. Getting
  (Either ScrubbedBytes (Digest h))
  (SymmetricState c h)
  (Either ScrubbedBytes (Digest h))
forall c h (f :: * -> *).
Functor f =>
(Either ScrubbedBytes (Digest h)
 -> f (Either ScrubbedBytes (Digest h)))
-> SymmetricState c h -> f (SymmetricState c h)
ssh)) Ciphertext c
ct (SymmetricState c h
ss SymmetricState c h
-> Getting (CipherState c) (SymmetricState c h) (CipherState c)
-> CipherState c
forall s a. s -> Getting a s a -> a
^. Getting (CipherState c) (SymmetricState c h) (CipherState c)
forall c h c (f :: * -> *).
Functor f =>
(CipherState c -> f (CipherState c))
-> SymmetricState c h -> f (SymmetricState c h)
ssCipher)
  let ss' :: SymmetricState c h
ss' = ScrubbedBytes -> SymmetricState c h -> SymmetricState c h
forall h c.
Hash h =>
ScrubbedBytes -> SymmetricState c h -> SymmetricState c h
mixHash (Ciphertext c -> ScrubbedBytes
forall c. Cipher c => Ciphertext c -> ScrubbedBytes
cipherTextToBytes Ciphertext c
ct) SymmetricState c h
ss
  (ScrubbedBytes, SymmetricState c h)
-> m (ScrubbedBytes, SymmetricState c h)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (ScrubbedBytes
pt, SymmetricState c h
ss' SymmetricState c h
-> (SymmetricState c h -> SymmetricState c h) -> SymmetricState c h
forall a b. a -> (a -> b) -> b
& (CipherState c -> Identity (CipherState c))
-> SymmetricState c h -> Identity (SymmetricState c h)
forall c h c (f :: * -> *).
Functor f =>
(CipherState c -> f (CipherState c))
-> SymmetricState c h -> f (SymmetricState c h)
ssCipher ((CipherState c -> Identity (CipherState c))
 -> SymmetricState c h -> Identity (SymmetricState c h))
-> CipherState c -> SymmetricState c h -> SymmetricState c h
forall s t a b. ASetter s t a b -> b -> s -> t
.~ CipherState c
cs)

-- | Returns a pair of CipherStates for encrypting transport messages. The
--   first CipherState is for encrypting messages from the Initiator to the
--   Responder, and the second is for encrypting messages from the Responder
--   to the Initiator.
split :: (Cipher c, Hash h)
      => SymmetricState c h
      -> (CipherState c, CipherState c)
split :: forall c h.
(Cipher c, Hash h) =>
SymmetricState c h -> (CipherState c, CipherState c)
split SymmetricState c h
ss = (CipherState c
c1, CipherState c
c2)
  where
    [ScrubbedBytes
k1, ScrubbedBytes
k2] = ChainingKey h -> ScrubbedBytes -> Word8 -> [ScrubbedBytes]
forall h.
Hash h =>
ChainingKey h -> ScrubbedBytes -> Word8 -> [ScrubbedBytes]
hashHKDF (SymmetricState c h
ss SymmetricState c h
-> Getting (ChainingKey h) (SymmetricState c h) (ChainingKey h)
-> ChainingKey h
forall s a. s -> Getting a s a -> a
^. Getting (ChainingKey h) (SymmetricState c h) (ChainingKey h)
forall c h (f :: * -> *).
Functor f =>
(ChainingKey h -> f (ChainingKey h))
-> SymmetricState c h -> f (SymmetricState c h)
ssck) ScrubbedBytes
forall a. Monoid a => a
mempty Word8
2
    c1 :: CipherState c
c1       = Maybe (SymmetricKey c) -> CipherState c
forall c. Cipher c => Maybe (SymmetricKey c) -> CipherState c
cipherState (Maybe (SymmetricKey c) -> CipherState c)
-> (ScrubbedBytes -> Maybe (SymmetricKey c))
-> ScrubbedBytes
-> CipherState c
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SymmetricKey c -> Maybe (SymmetricKey c)
forall a. a -> Maybe a
Just (SymmetricKey c -> Maybe (SymmetricKey c))
-> (ScrubbedBytes -> SymmetricKey c)
-> ScrubbedBytes
-> Maybe (SymmetricKey c)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ScrubbedBytes -> SymmetricKey c
forall c. Cipher c => ScrubbedBytes -> SymmetricKey c
cipherBytesToSym (ScrubbedBytes -> CipherState c) -> ScrubbedBytes -> CipherState c
forall a b. (a -> b) -> a -> b
$ ScrubbedBytes
k1
    c2 :: CipherState c
c2       = Maybe (SymmetricKey c) -> CipherState c
forall c. Cipher c => Maybe (SymmetricKey c) -> CipherState c
cipherState (Maybe (SymmetricKey c) -> CipherState c)
-> (ScrubbedBytes -> Maybe (SymmetricKey c))
-> ScrubbedBytes
-> CipherState c
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SymmetricKey c -> Maybe (SymmetricKey c)
forall a. a -> Maybe a
Just (SymmetricKey c -> Maybe (SymmetricKey c))
-> (ScrubbedBytes -> SymmetricKey c)
-> ScrubbedBytes
-> Maybe (SymmetricKey c)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ScrubbedBytes -> SymmetricKey c
forall c. Cipher c => ScrubbedBytes -> SymmetricKey c
cipherBytesToSym (ScrubbedBytes -> CipherState c) -> ScrubbedBytes -> CipherState c
forall a b. (a -> b) -> a -> b
$ ScrubbedBytes
k2

-- | Utility function to convert the hash state to ScrubbedBytes.
sshBytes :: Hash h
         => Either ScrubbedBytes (Digest h)
         -> ScrubbedBytes
sshBytes :: forall h.
Hash h =>
Either ScrubbedBytes (Digest h) -> ScrubbedBytes
sshBytes (Left  ScrubbedBytes
h) = ScrubbedBytes
h
sshBytes (Right Digest h
h) = Digest h -> ScrubbedBytes
forall h. Hash h => Digest h -> ScrubbedBytes
hashToBytes Digest h
h