-
Import the modules for the kind of handshake you’d like to use.
For example, if you want to use Noise_IK_25519_AESGCM_SHA256
, your imports would be:
import Crypto.Noise.Cipher.AESGCM
import Crypto.Noise.Curve.Curve25519
import Crypto.Noise.Hash.SHA256
import Crypto.Noise.Handshake
import Crypto.Noise.HandshakePatterns (noiseIK)
-
Define the functions that will be called during various stages of the handshake.
writeMsg :: ByteString -> IO ()
readMsg :: IO ByteString
payloadIn :: Plaintext -> IO ()
payloadOut :: IO Plaintext
staticIn :: PublicKey d -> IO Bool
writeMsg
and readMsg
will typically be functions that write to and read from a socket.
The payloadIn
and payloadOut
functions are called when payloads are received and needed.
The staticIn
function is called when a static key is received from the remote peer.
If this function returns False
, the handshake is immediately aborted. Otherwise, it
continues normally. See the documentation of HandshakeCallbacks
for details.
If you don’t need to use payloads and want to accept all remote static keys, do the following:
let hc = HandshakeCallbacks (writeMsg socket)
(readMsg socket)
(\_ -> return ())
(return "")
(\_ -> return True)
-
Create the handshake state.
Select a handshake pattern to use. Patterns are defined in the Crypto.Noise.HandshakePatterns
module.
Ensure that you provide the keys which are required by the handshake pattern you choose. For example,
the Noise_IK
pattern requires that the initiator provides a local static key and a remote static key.
Remote keys are communicated out-of-band.
let initiatorState = handshakeState $ HandshakeOpts
noiseIK
"prologue"
(Just "pre-shared-key")
(Just local_static_key)
Nothing -- local ephemeral key
(Just remote_static_key) -- communicated out-of-band
Nothing -- remote ephemeral key
True -- we are the initiator
let responderState = handshakeState $ HandshakeOpts
noiseIK
"prologue"
(Just "pre-shared-key")
(Just local_static_key)
Nothing -- local ephemeral key
Nothing -- we don't know their static key yet
Nothing -- remote ephemeral key
False -- we are the responder
-
Run the handshake:
(encryptionCipherState, decryptionCipherState) <- runHandshake initiatorState hc
(encryptionCipherState, decryptionCipherState) <- runHandshake responderState hc
-
Send and receive transport messages:
let (cipherText, encryptionCipherState') = encryptPayload "hello world" encryptionCipherState
let (Plaintext pt, decryptionCipherState') = decryptPayload msg decryptionCipherState
Ensure that you never re-use a cipher state.