Noise.HandshakeState (Noise Protocol v0.3.0)

View Source

A HandshakeState (spec §5.3): the symmetric state plus the local and remote key material and the message patterns still to process.

write_message/2 and read_message/2 are the spec's WriteMessage and ReadMessage. Both enforce whose turn it is, the 65535-byte message bound (spec §3) and return {:error, reason} instead of crashing on hostile input. Configuration mistakes (missing keys, wrong PSK count) raise ArgumentError from initialize/4.

Private keys and PSKs are redacted from inspect/1 output.

Summary

Functions

GetHandshakeHash() (spec §5.2); for channel binding (spec §11.2) once complete.

Initialize(handshake_pattern, initiator, prologue, s, e, rs, re) (spec §5.3).

What this party must do next: send a message, receive one, or split/1.

ReadMessage(message) (spec §5.3). Returns the decrypted payload.

The remote static public key, once it is known.

Split() (spec §5.2): {c1, c2} where c1 encrypts initiator→responder and c2 responder→initiator. Raises unless the handshake is complete.

WriteMessage(payload) (spec §5.3). Returns the message to send to the peer.

Types

error()

@type error() ::
  :decrypt_failed
  | :nonce_exhausted
  | :malformed_message
  | :message_too_long
  | :invalid_public_key
  | :wrong_turn
  | :handshake_complete

option()

@type option() ::
  {:s, Noise.Crypto.DH.keypair()}
  | {:rs, Noise.Crypto.DH.pubkey()}
  | {:e, Noise.Crypto.DH.keypair()}
  | {:re, Noise.Crypto.DH.pubkey()}
  | {:psks, [<<_::256>>]}

t()

@opaque t()

Functions

complete?(handshake_state)

@spec complete?(t()) :: boolean()

handshake_hash(handshake_state)

@spec handshake_hash(t()) :: binary()

GetHandshakeHash() (spec §5.2); for channel binding (spec §11.2) once complete.

initialize(protocol, initiator, prologue \\ <<>>, opts \\ [])

@spec initialize(Noise.Protocol.t() | String.t(), boolean(), binary(), [option()]) ::
  t()

Initialize(handshake_pattern, initiator, prologue, s, e, rs, re) (spec §5.3).

Options:

  • :s - local static keypair {private, public}; required when the pattern transmits or pre-shares this party's static key
  • :rs - remote static public key; required when the pattern pre-shares the peer's static key, forbidden when the peer transmits it
  • :psks - list of 32-byte pre-shared keys, one per psk token
  • :e - local ephemeral keypair, for test vectors only; reusing an ephemeral across handshakes is catastrophic (spec §14)
  • :re - remote ephemeral public key; only meaningful for patterns that pre-share it

initiator?(handshake_state)

@spec initiator?(t()) :: boolean()

next_action(handshake_state)

@spec next_action(t()) :: :write | :read | :split

What this party must do next: send a message, receive one, or split/1.

read_message(state, message)

@spec read_message(t(), binary()) :: {:ok, binary(), t()} | {:error, error()}

ReadMessage(message) (spec §5.3). Returns the decrypted payload.

remote_static(handshake_state)

@spec remote_static(t()) :: Noise.Crypto.DH.pubkey() | nil

The remote static public key, once it is known.

split(handshake_state)

@spec split(t()) :: {Noise.CipherState.t(), Noise.CipherState.t()}

Split() (spec §5.2): {c1, c2} where c1 encrypts initiator→responder and c2 responder→initiator. Raises unless the handshake is complete.

write_message(state, payload)

@spec write_message(t(), binary()) :: {:ok, binary(), t()} | {:error, error()}

WriteMessage(payload) (spec §5.3). Returns the message to send to the peer.