module Crypto.Noise
(
HandshakeRole(..)
, HandshakeOpts
, NoiseException(..)
, NoiseState
, defaultHandshakeOpts
, noiseState
, writeMessage
, readMessage
, remoteStaticKey
, handshakeComplete
, handshakeHash
, setSecondaryKey
, hoPattern
, hoRole
, hoPrologue
, hoPreSharedKey
, hoLocalStatic
, hoLocalSemiEphemeral
, hoLocalEphemeral
, hoRemoteStatic
, hoRemoteSemiEphemeral
, hoRemoteEphemeral
) where
import Control.Arrow
import Control.Lens
import Data.ByteString (ByteString)
import Data.Maybe (isJust)
import Prelude hiding (length)
import Crypto.Noise.Cipher
import Crypto.Noise.DH
import Crypto.Noise.Hash
import Crypto.Noise.Internal.CipherState
import Crypto.Noise.Internal.Handshake
import Crypto.Noise.Internal.NoiseState
import Crypto.Noise.Internal.SymmetricState
import Crypto.Noise.Internal.Types
import Data.ByteArray.Extend
writeMessage :: (Cipher c, Hash h)
=> NoiseState c d h
-> ScrubbedBytes
-> Either NoiseException (ByteString, NoiseState c d h)
writeMessage ns msg = right toByteString $
maybe (runHandshake msg ns)
(right (ctToBytes *** updateState) . encryptAndIncrement "" msg)
(ns ^. nsSendingCipherState)
where
ctToBytes = arr cipherTextToBytes
updateState = arr $ \cs -> ns & nsSendingCipherState .~ Just cs
toByteString = first (arr convert)
readMessage :: (Cipher c, Hash h)
=> NoiseState c d h
-> ByteString
-> Either NoiseException (ScrubbedBytes, NoiseState c d h)
readMessage ns ct =
maybe (runHandshake (convert ct) ns)
((right . second) updateState . (decryptAndIncrement "" . cipherBytesToText . convert) ct)
(ns ^. nsReceivingCipherState)
where
updateState = arr $ \cs -> ns & nsReceivingCipherState .~ Just cs
remoteStaticKey :: NoiseState c d h
-> Maybe (PublicKey d)
remoteStaticKey ns = ns ^. nsHandshakeState . hsOpts . hoRemoteStatic
handshakeComplete :: NoiseState c d h
-> Bool
handshakeComplete ns = isJust (ns ^. nsSendingCipherState) &&
isJust (ns ^. nsReceivingCipherState)
handshakeHash :: Hash h
=> NoiseState c d h
-> ScrubbedBytes
handshakeHash ns = either id hashToBytes
$ ns ^. nsHandshakeState . hsSymmetricState . ssh
setSecondaryKey :: (Cipher c, DH d, Hash h)
=> NoiseState c d h
-> ScrubbedBytes
-> NoiseState c d h
setSecondaryKey ns k | length k == 32 = ns & nsHandshakeState . hsSymmetricState . ssk .~ k
| otherwise = error "secondary key must be 32 bytes in length"