core/crypto/noise

noise

Types

7

Handshake_Pattern

Handshake_Pattern :: enum int { Invalid = 0, // One way patterns N = 1, K = 2, X = 3, // Fundamental patterns XX = 4, NK = 5, NN = 6, KN = 7, KK = 8, NX = 9, KX = 10, XN = 11, IN = 12, XK = 13, IK = 14, IX = 15, // Deferred patterns NK1 = 16, NX1 = 17, X1N = 18, X1K = 19, XK1 = 20, X1K1 = 21, X1X = 22, XX1 = 23, X1X1 = 24, K1N = 25, K1K = 26, KK1 = 27, K1K1 = 28, K1X = 29, KX1 = 30, K1X1 = 31, I1N = 32, I1K = 33, IK1 = 34, I1K1 = 35, I1X = 36, IX1 = 37, I1X1 = 38, // Recommended PSK patterns Npsk0 = 39, Kpsk0 = 40, Xpsk1 = 41, NNpsk0 = 42, NNpsk2 = 43, NKpsk0 = 44, NKpsk2 = 45, NXpsk2 = 46, XNpsk3 = 47, XKpsk3 = 48, XXpsk3 = 49, KNpsk0 = 50, KNpsk2 = 51, KKpsk0 = 52, KKpsk2 = 53, KXpsk2 = 54, INpsk1 = 55, INpsk2 = 56, IKpsk1 = 57, IKpsk2 = 58, IXpsk2 = 59, }Source

Handshake_Pattern is the list of currently supported Noise Handshake Patterns.

Status

Status :: enum int { Ok = 0, // States Handshake_Pending = 1, Handshake_Complete = 2, Handshake_Split = 3, Handshake_Failed = 4, // Errors Invalid_Protocol_String = 5, Invalid_Pre_Shared_Key = 6, Invalid_DH_Key = 7, No_Self_Identity = 8, No_Peer_Identity = 9, Unexpected_Peer_Identity = 10, Unexpected_Pre_Shared_Key = 11, DH_Failure = 12, Invalid_Handshake_Message = 13, Decryption_Failure = 14, IV_Exhausted = 15, Invalid_Cipher_State = 16, Invalid_Destination_Buffer = 17, Invalid_Payload_Message = 18, Max_Packet_Size = 19, Out_Of_Memory = 20, }Source

Status is the status of Noise protocol operation.

Constants

8

Procedures

49

_decrypt

_decrypt :: proc(ctx: ^aead.Context, n: u64, ad: []u8, ciphertext: []u8, dst: []u8) -> (Status)Source

Decrypts ciphertext using a cipher key k of 32 bytes, an 8-byte unsigned integer nonce n, and associated data ad. Returns the plaintext, unless authentication fails, in which case an error is signaled to the caller.

_dh

_dh :: proc(our_private_key: ^ecdh.Private_Key, their_public_key: ^ecdh.Public_Key, dst: []u8) -> (Status)Source

Performs a Diffie-Hellman calculation between the private key in key_pair and the public_key and returns an output sequence of bytes of length DHLEN. For security, the Gap-DH problem based on this function must be unsolvable by any practical cryptanalytic adversary [2].

The public_key either encodes some value which is a generator in a large prime-order group (which value may have multiple equivalent encodings), or is an invalid value. Implementations must handle invalid public keys either by returning some output which is purely a function of the public key and does not depend on the private key, or by signaling an error to the caller.

The DH function may define more specific rules for handling invalid values.

_encrypt

_encrypt :: proc(ctx: ^aead.Context, n: u64, ad: []u8, plaintext: []u8, dst: []u8)Source

Encrypts plaintext using the cipher key k of 32 bytes and an 8-byte unsigned integer nonce n which must be unique for the key k. Returns the ciphertext. Encryption must be done with an "AEAD" encryption mode with the associated data(AD) (using the terminology from [1]) and returns a ciphertext that is the same size as the plaintext plus 16 bytes for authentication data. The entire ciphertext must be indistinguishable from random if the key is secret (note that this is an additional requirement that isn't necessarily met by all AEAD schemes).

_hash

_hash :: proc(dst: []u8, protocol: ^Protocol, data)Source

Hashes some arbitrary-length data with a collision-resistant cryptographic hash function and returns an output of HASHLEN bytes.

_hkdf

_hkdf :: proc(dst: []u8, chaining_key: []u8, input_key_material: []u8, protocol: ^Protocol) -> ([]u8, []u8, []u8)Source

Takes a chaining_key byte sequence of length HASHLEN, and an input_key_material byte sequence with length either zero bytes, 32 bytes, or DHLEN bytes. Returns a pair or triple of byte sequences each of length HASHLEN, depending on whether num_outputs is two or three:

  • Sets temp_key = HMAC-HASH(chaining_key, input_key_material).
  • Sets output1 = HMAC-HASH(temp_key, byte(0x01)).
  • Sets output2 = HMAC-HASH(temp_key, output1 || byte(0x02)).
  • If num_outputs == 2 then returns the pair (output1, output2).
  • Sets output3 = HMAC-HASH(temp_key, output2 || byte(0x03)).
  • Returns the triple (output1, output2, output3).

Note that temp_key, output1, output2, and output3 are all HASHLEN bytes in length. Also note that the HKDF() function is simply HKDF from [4] with the chaining_key as HKDF salt, and zero-length HKDF info.

cipherstates_n

cipherstates_n :: proc(self: ^Cipher_States, seal_key: bool, n: u64) -> (Status, u64)Source

cipherstates_n returns the interal counter used to generate the AEAD IV. This can be used to deal with out-of-order transport messages. See 11.4 of the specification.

WARNING: Reusing n across different aad/messages with the same Cipher_States will result in catastrophic loss of security.

cipherstates_rekey

cipherstates_rekey :: proc(self: ^Cipher_States, seal_key: bool) -> (Status)Source

cipherstates_rekey updates the selected AEAD key, using a one way function. See 11.3 of the specification for examples of usage.

Note: If one side updates the seal_key, the other side must update the non-seal_key and vice versa.

cipherstates_set_n

cipherstates_set_n :: proc(self: ^Cipher_States, seal_key: bool, n: u64) -> (Status)Source

cipherstates_set_n sets the interal counter used to generate the AEAD IV to an explicit value. This can be used to deal with out-of-order transport messages. See 11.4 of the specification.

WARNING: Reusing n across different aad/messages with the same Cipher_States will result in catastrophic loss of security.

generate_keypair

generate_keypair :: proc(protocol: ^Protocol, private_key: ^ecdh.Private_Key)Source

Generates a new Diffie-Hellman key pair. A DH key pair consists of public_key and private_key elements. public_key represents an encoding of a DH public key into a byte sequence of length DHLEN. The public_key encoding details are specific to each set of DH functions.

handshake_hash

handshake_hash :: proc(self: ^Handshake_State) -> ([]u8, Status)Source

handshake_hash returns the handshake transcript hash of a completed handshake, for the purposes of channel binding. See 11.2 of the specification for details on usage.

This returns a slice to an internal buffer that will get wiped by handshake_reset. If the hash is needed after a call to handshake_reset, the slice must be copied.

handshake_init

handshake_init :: proc( self: ^Handshake_State, initiator: bool, prologue: []u8, s: ^ecdh.Private_Key, rs: ^ecdh.Public_Key, protocol_name: string, psk: []u8, _e: ^ecdh.Private_Key, ) -> (Status)Source

handshake_init initializes a Handshake_State with the provided parameters. The relevant values are copied into the Handshake_State instance, and can be discarded/sanitized right after handshake_init returns (eg: psk).

Note: While this implementation supports setting e, this is primarily intended for testing, or cases where the runtime cryptographic entropy source is unavailable. Use of this functionality is STRONGLY discouraged.

handshake_initiator_step

handshake_initiator_step :: proc(self: ^Handshake_State, input_message: []u8, payload: []u8, dst: []u8, allocator: mem.Allocator = context.allocator) -> ([]u8, []u8, Status)Source

handshake_initiator_step takes an input_message received from the responder if any and an optional payload to be sent to the responder, and performs one step of the Noise handshake process, returning the message to be sent to the responder if any, the payload received from the responder if any, and the status of the handshake.

The output message MUST be sent to the responder even if the status code returned is .Handshake_Complete.

If the dst parameter is provided, the message and payload will be written to dst, otherwise new buffers will be allocated.

handshake_read_message

handshake_read_message :: proc(self: ^Handshake_State, message: []u8, dst: []u8, allocator: mem.Allocator = context.allocator) -> ([]u8, Status)Source

handshake_read_message calls the Noise HandshakeState's ReadMessage function directly. In most cases you are better off using handshake_initiator_step or handshake_responder_step.

If the dst parameter is provided, the message and payload will be written to dst, otherwise new buffers will be allocated.

handshake_reset

handshake_reset :: proc(self: ^Handshake_State)Source

handshake_reset sanitizes the Handshake_State. It is both safe and recommended to call this as soon as practical (after any calls to handshake_peer_identity, handshake_hash, and handshake_split are complete).

handshake_responder_step

handshake_responder_step :: proc(self: ^Handshake_State, input_message: []u8, payload: []u8, dst: []u8, allocator: mem.Allocator = context.allocator) -> ([]u8, []u8, Status)Source

handshake_responder_step takes a input_message received from the initiator, and and an optional payload to be sent to the initiator, and performs one step of the Noise handshake process, returning the message to be sent to the initiator if any, the payload received from the initiator if any, and the status of the handshake.

The output message MUST be sent to the initiator even if the status code returned is .Handshake_Complete.

If the dst parameter is provided, the message and payload will be written to dst, otherwise new buffers will be allocated.

handshake_write_message

handshake_write_message :: proc(self: ^Handshake_State, payload: []u8, dst: []u8, allocator: mem.Allocator = context.allocator) -> ([]u8, Status)Source

handshake_write_message calls the Noise HandshakeState's WriteMessage function directly. In most cases you are better off using handshake_initiator_step or handshake_responder_step.

If the dst parameter is provided, the message and payload will be written to dst, otherwise new buffers will be allocated.

handshakestate_initialize

handshakestate_initialize :: proc( handshake_state: ^Handshake_State, initiator: bool, prologue: []u8, s: ^ecdh.Private_Key, e: ^ecdh.Private_Key, rs: ^ecdh.Public_Key, re: ^ecdh.Public_Key, protocol_name: string, psk: []u8, ) -> (Status)Source

Takes a valid handshake_pattern (see Section 7) and an initiator boolean specifying this party's role as either initiator or responder. Takes a prologue byte sequence which may be zero-length, or which may contain context information that both parties want to confirm is identical (see Section 6).

Takes a set of DH key pairs (s, e) and public keys (rs, re) for initializing local variables, any of which may be empty. Public keys are only passed in if the handshake_pattern uses pre-messages (see Section 7). The ephemeral values (e, re) are typically left empty, since they are created and exchanged during the handshake; but there are exceptions (see Section 10).

Performs the following steps:

  • Derives a protocol_name byte sequence by combining the names for
the handshake pattern and crypto functions, as specified in Section 8.
 - Calls InitializeSymmetric(protocol_name).
 - Calls MixHash(prologue).
 - Sets the initiator, s, e, rs, and re variables to the corresponding
	arguments.
 - Calls MixHash() once for each public key listed in the pre-messages
	from handshake_pattern, with the specified public key as input
	(see Section 7 for an explanation of pre-messages).
 - If both initiator and responder have pre-messages, the initiator's
	public keys are hashed first.
 - If multiple public keys are listed in either party's pre-message,
	the public keys are hashed in the order that they are listed.
 -  Sets message_pattern to the message patterns from handshake_pattern.

handshakestate_read_message

handshakestate_read_message :: proc(self: ^Handshake_State, message: []u8, dst: []u8, allocator: mem.Allocator = context.allocator) -> ([]u8, Status)Source

Takes a byte sequence containing a Noise handshake message, and a payload_buffer to write the message's plaintext payload into. Performs the following steps, aborting if any DecryptAndHash() call returns an error:

  • Fetches and deletes the next message pattern from message_pattern,

then sequentially processes each token from the message pattern:

  • For "e": Sets re (which must be empty) to the next DHLEN bytes

from the message. Calls MixHash(re.public_key).

  • For "s": Sets temp to the next DHLEN + 16 bytes of the message

if HasKey() == True, or to the next DHLEN bytes otherwise. Sets rs (which must be empty) to DecryptAndHash(temp).

  • For "ee": Calls MixKey(DH(e, re)).
  • For "es": Calls MixKey(DH(e, rs)) if initiator, MixKey(DH(s, re))

if responder.

  • For "se": Calls MixKey(DH(s, re)) if initiator, MixKey(DH(e, rs))

if responder. -For "ss": Calls MixKey(DH(s, rs)).

  • Calls DecryptAndHash() on the remaining bytes of the message and stores

the output into payload_buffer. – (SKIPPED) If there are no more message patterns returns two new CipherState objects by calling Split().

Calling Split() is left to a separate function, although it is technically part of the specification.

handshakestate_write_message

handshakestate_write_message :: proc(self: ^Handshake_State, payload: []u8, dst: []u8, allocator: mem.Allocator = context.allocator) -> ([]u8, Status)Source

Takes a payload byte sequence which may be zero-length, and a message_buffer to write the output into. Performs the following steps, aborting if any EncryptAndHash() call returns an error:

  • Fetches and deletes the next message pattern from message_pattern,
then sequentially processes each token from the message pattern:
	  - For "e": Sets e (which must be empty) to GENERATE_KEYPAIR().
		Appends e.public_key to the buffer. Calls MixHash(e.public_key).
	  - For "s": Appends EncryptAndHash(s.public_key) to the buffer.
	  - For "ee": Calls MixKey(DH(e, re)).
	  - For "es": Calls MixKey(DH(e, rs)) if initiator, MixKey(DH(s, re))
		if responder.
	  - For "se": Calls MixKey(DH(s, re)) if initiator, MixKey(DH(e, rs))
		if responder.
	  - For "ss": Calls MixKey(DH(s, rs)).
 - Appends EncryptAndHash(payload) to the buffer.
  (SKIPPED) If there are no more message patterns returns two new
   CipherState objects by calling Split().

Calling Split() is left to a separate function, although it is technically
part of the specification.

open_message

open_message :: proc(self: ^Cipher_States, aad: []u8, ciphertext: []u8, dst: []u8, allocator: mem.Allocator = context.allocator) -> ([]u8, Status)Source

open_message authenticates the aad and ciphertext, decrypts the ciphertext and returns the resulting plaintext. The plaintext will ALWAYS be len(ciphertext) - TAG_SIZE bytes in length.

If the dst parameter is provided, the plaintext will be written to dst, otherwise a new buffer will be allocated.

seal_message

seal_message :: proc(self: ^Cipher_States, aad: []u8, plaintext: []u8, dst: []u8, allocator: mem.Allocator = context.allocator) -> ([]u8, Status)Source

seal_message encrypts the provided data, authenticates the aad and ciphertext, and returns the resulting ciphertext. The ciphertext will ALWAYS be len(plaintext) + TAG_SIZE bytes in length.

If the dst parameter is provided, the ciphertext will be written to dst, otherwise a new buffer will be allocated.

symmetricstate_initialize

symmetricstate_initialize :: proc(ss: ^Symmetric_State, protocol_name: string) -> (Status)Source

Takes an arbitrary-length protocol_name byte sequence (see Section 8). Executes the following steps:

  • If protocol_name is less than or equal to HASHLEN bytes in length,
sets h equal to protocol_name with zero bytes appended to make
	HASHLEN bytes.
 - Otherwise sets h = HASH(protocol_name).
 - Sets ck = h.
 - Calls InitializeKey(empty).

symmetricstate_split

symmetricstate_split :: proc(self: ^Symmetric_State, cipher_states: ^Cipher_States)Source

Returns a pair of CipherState objects for encrypting transport messages. Executes the following steps, where zerolen is a zero-length byte sequence:

  • Sets temp_k1, temp_k2 = HKDF(ck, zerolen, 2).
  • If HASHLEN is 64, then truncates temp_k1 and temp_k2 to 32 bytes.
  • Creates two new CipherState objects c1 and c2.
  • Calls c1.InitializeKey(temp_k1) and c2.InitializeKey(temp_k2).
  • Returns the pair (c1, c2).

Reference search

Find anything

Documentation preferences

Settings

System theme variants

Used only while Theme is set to System.