# noise-libp2p - Secure Channel Handshake > A libp2p transport secure channel handshake built with the Noise Protocol > Framework. | Lifecycle Stage | Maturity | Status | Latest Revision | |-----------------|---------------|--------|-----------------| | 1A | Working Draft | Active | r1, 2020-01-20 | Authors: [@yusefnapora] Interest Group: [@raulk], [@tomaka], [@romanb], [@shahankhatch], [@Mikerah], [@djrtwo], [@dryajov], [@mpetrunic], [@AgeManning], [@morrigan], [@araskachoi], [@mhchia] [@yusefnapora]: https://github.com/yusefnapora [@raulk]: https://github.com/raulk [@tomaka]: https://github.com/tomaka [@romanb]: https://github.com/romanb [@shahankhatch]: https://github.com/shahankhatch [@Mikerah]: https://github.com/Mikerah [@djrtwo]: https://github.com/djrtwo [@dryajov]: https://github.com/dryajov [@mpetrunic]: https://github.com/mpetrunic [@AgeManning]: https://github.com/AgeManning [@morrigan]: https://github.com/morrigan [@araskachoi]: https://github.com/araskachoi [@mhchia]: https://github.com/mhchia See the [lifecycle document][lifecycle-spec] for context about maturity level and spec status. [lifecycle-spec]: https://github.com/libp2p/specs/blob/master/00-framework-01-spec-lifecycle.md ## Table of Contents - [noise-libp2p - Secure Channel Handshake](#noise-libp2p---secure-channel-handshake) - [Table of Contents](#table-of-contents) - [Overview](#overview) - [Negotiation](#negotiation) - [The Noise Handshake](#the-noise-handshake) - [Static Key Authentication](#static-key-authentication) - [libp2p Data in Handshake Messages](#libp2p-data-in-handshake-messages) - [The libp2p Handshake Payload](#the-libp2p-handshake-payload) - [Supported Handshake Patterns](#supported-handshake-patterns) - [XX](#xx) - [Optimistic 0-RTT with Noise Pipes](#optimistic-0-rtt-with-noise-pipes) - [IK](#ik) - [XXfallback](#xxfallback) - [Noise Pipes Message Flow](#noise-pipes-message-flow) - [Cryptographic Primitives](#cryptographic-primitives) - [Valid Noise Protocol Names](#valid-noise-protocol-names) - [Wire Format](#wire-format) - [Encrypted Payloads](#encrypted-payloads) - [Encryption and I/O](#encryption-and-io) - [libp2p Interfaces and API](#libp2p-interfaces-and-api) - [Initialization](#initialization) - [Secure Transport Interface](#secure-transport-interface) - [NoiseConnection](#noiseconnection) - [SecureOutbound](#secureoutbound) - [SecureInbound](#secureinbound) - [Design Considerations](#design-considerations) - [No Negotiation of Noise Protocols](#no-negotiation-of-noise-protocols) - [Why ChaChaPoly?](#why-chachapoly) - [Distinct Noise and Identity Keys](#distinct-noise-and-identity-keys) - [Why Not Noise Signatures?](#why-not-noise-signatures) ## Overview The [Noise Protocol Framework][npf] is a framework for building security protocols by composing a small set of cryptographic primitives into patterns with verifiable security properties. This document specifies noise-libp2p, a libp2p channel security handshake built using the Noise Protocol Framework. As a framework for building protocols rather than a protocol itself, Noise presents a large decision space with many tradeoffs. The [Design Considerations section](#design-considerations) goes into detail about the choices made when designing the protocol. Secure channels in libp2p are established with the help of a transport upgrader, a component that layers security and stream multiplexing over "raw" connections like TCP sockets. When peers connect, the upgrader uses a protocol called multistream-select to negotiate which security and multiplexing protocols to use. The upgrade process is described in the [connection establishment spec][conn-spec]. The transport upgrade process is likely to evolve soon, as we are in the process of designing multiselect 2, a successor to multistream-select. Some noise-libp2p features are designed to enable proposed features of multiselect 2, however noise-libp2p is fully compatible with the current upgrade process and multistream-select. See the [Negotiation section](#negotiation) for details about protocol negotiation. Every Noise connection begins with a handshake between an initiating peer and a responding peer, or in libp2p terms, a dialer and a listener. Over the course of the handshake, peers exchange public keys and perform Diffie-Hellman exchanges to arrive at a pair of symmetric keys that can be used to efficiently encrypt traffic. The [Noise Handshake section](#the-noise-handshake) describes the [supported handshake patterns](#supported-handshake-patterns) and [how libp2p-specific data is exchanged during the handshake](#libp2p-data-in-handshake-messages). During the handshake, the static DH key used for Noise is authenticated using the libp2p identity keypair, as described in the [Static Key Authentication section](#static-key-authentication). Following a successful handshake, peers use the resulting encryption keys to send ciphertexts back and forth. The format for transport messages and the wire protocol used to exchange them is described in the [Wire Format section](#wire-format). The cryptographic primitives used to secure the channel are described in the [Cryptographic Primitives section](#cryptographic-primitives). The [libp2p Interfaces and API section](#libp2p-interfaces-and-api) goes into detail about how noise-libp2p integrates with the libp2p framework and offers a suggested API for implementations to adapt to their respective language idioms. ## Negotiation libp2p has an existing protocol negotiation mechanism which is used to reach agreement on the secure channel and multiplexing protocols used for new connections. A description of the current protocol negotiation flow is available in the [libp2p connections spec][conn-spec]. noise-libp2p is identified by the protocol ID string `/noise`. Peers using multistream-select for protocol negotiation may send this protocol ID during connection establishment to attempt to use noise-libp2p. Future versions of this spec may define new protocol IDs using the `/noise` prefix, for example `/noise/2`. ## The Noise Handshake During the Noise handshake, peers perform an authenticated key exchange according to the rules defined by a concrete Noise protocol. A concrete Noise protocol is identified by the choice of handshake pattern and [cryptographic primitives](#cryptographic-primitives) used to construct it. This section covers the method of [authenticating the Noise static key](#static-key-authentication), the [libp2p-specific data](#libp2p-data-in-handshake-messages) that is exchanged in handshake message payloads, and the set of [supported handshake patterns](#supported-handshake-patterns). A brief overview of the payload security and identity hiding properties of each handshake pattern is included in the description of each pattern, however, readers are strongly encouraged to refer to the [Noise spec][npf] for a full understanding. ### Static Key Authentication The [Security Considerations section of the Noise spec][npf-security] says: * Authentication: A Noise protocol with static public keys verifies that the corresponding private keys are possessed by the participant(s), but it's up to the application to determine whether the remote party's static public key is acceptable. Methods for doing so include certificates which sign the public key (and which may be passed in handshake payloads), preconfigured lists of public keys, or "pinning" / "key-continuity" approaches where parties remember public keys they encounter and check whether the same party presents the same public key in the future. All libp2p peers possess a cryptographic keypair which is used to [derive their peer id][peer-id-spec], which we will refer to as their "identity keypair." To avoid potential static key reuse, and to allow libp2p peers with any type of identity keypair to use Noise, noise-libp2p uses a separate static keypair for Noise that is distinct from the peer's identity keypair. A given libp2p peer will have one or more static Noise keypairs throughout its lifetime. Implementations MAY allow persisting static Noise keys across process restarts, or they may generate new static Noise keys when initializing the noise-libp2p module. Systems which enable the [Noise Pipes pattern](#optimistic-0-rtt-with-noise-pipes) are likely to benefit from a longer lifetime for static Noise keys, as the static key is used in the optimistic case. Other systems may prefer to cycle static Noise keys frequently to reduce exposure. To authenticate the static Noise key used in a handshake, noise-libp2p includes a signature of the static Noise public key in a [handshake payload](#the-libp2p-handshake-payload). This signature is produced with the private libp2p identity key, which proves that the sender was in possession of the private identity key at the time the payload was generated. ### libp2p Data in Handshake Messages In addition to authenticating the static Noise key, noise-libp2p implementations MAY send additional "early data" in the handshake message payload. The contents of this early data are opaque to noise-libp2p, however it is assumed that it will be used to advertise supported stream multiplexers, thus avoiding a round-trip negotiation after the handshake completes. The use of early data MUST be restricted to internal libp2p APIs, and the early data payload MUST NOT be used to transmit user or application data. Some handshake messages containing the early data payload may be susceptible to replay attacks, therefore the processing of early data must be idempotent. The noise-libp2p implementation itself MUST NOT process the early data payload in any way during the handshake, except to produce and validate the signature as described below. Early data provided by a remote peer should only be made available to other libp2p components after the handshake is complete and the payload signature has been validated. If the handshake fails for any reason, the early data payload MUST be discarded immediately. Any early data provided to noise-libp2p MUST be included in the [handshake payload](#the-libp2p-handshake-payload) as a byte string without alteration by the noise-libp2p implementation, and a valid signature of the early data MUST be included as described below. #### The libp2p Handshake Payload The Noise Protocol Framework caters for sending early data alongside handshake messages. We leverage this construct to transmit: 1. the libp2p identity key along with a signature, to authenticate each party to the other. 2. arbitrary data private to the libp2p stack. This facility is not exposed to userland. Examples of usage include streamlining muxer selection. These payloads MUST be inserted into the first message of the handshake pattern **that guarantees secrecy**. * In XX-initiated handshakes, the initiator will send its payload in message 3 (closing message), whereas the responder will send theirs in message 2 (their only message). * In IK-initiated handshakes, the initiator will optimistically send its payload in message 1 (as it satisfies the guarantee). Next, this case bifurcates: * If the responder continues the IK handshake, it will send its payload in message 2. The handshake ends. * If the responder fall backs to `XXfallback`, it will have failed to decrypt the payload in message 1. A retransmission from the initiator with the fresh cryptographic material is necessary. This is performed in message 3. When decrypted, the payload has the structure described in [Encrypted Payloads](#encrypted-payloads), consisting of a length-prefixed `body` field followed by optional padding. The `body` of the payload contains a serialized [protobuf][protobuf] `NoiseHandshakePayload` message with the following schema: ``` protobuf message NoiseHandshakePayload { bytes identity_key = 1; bytes identity_sig = 2; bytes data = 3; } ``` The `identity_key` field contains a serialized `PublicKey` message as defined in the [peer id spec][peer-id-spec]. The `identity_sig` field is produced using the libp2p identity private key according to the [signing rules in the peer id spec][peer-id-spec-signing-rules]. The data to be signed is the UTF-8 string `noise-libp2p-static-key:`, followed by the Noise static public key, encoded according to the rules defined in [section 5 of RFC 7748][rfc-7748-sec-5]. The `data` field contains the "early data" provided to the Noise module when initiating the handshake, if any. The structure of this data is opaque to noise-libp2p and is defined in the connection establishment specs. Upon receiving the handshake payload, peers MUST decode the public key from the `identity_key` field into a usable form. The key MUST then be used to validate the `identity_sig` field against the static Noise key received in the handshake. If the signature is invalid, the connection MUST be terminated immediately. ### Supported Handshake Patterns Noise defines twelve [fundamental interactive handshake patterns][npf-fundamental-patterns] for exchanging public keys between parties and performing Diffie-Hellman computations. The patterns are named according to whether static keypairs are used, and if so, by what means each party gains knowledge of the other's static public key. noise-libp2p supports two fundamental handshake patterns, one of which is optional and may be enabled for efficiency. The [XX handshake pattern](#xx) provides mutual authentication and encryption of static keys and handshake payloads and is resistant to replay attacks. It is the most "expensive" handshake, requiring 1.5 round trips in order to be sound, however, the cost of sending the final handshake message may be amortized by sending the initiator's first transport message within the same transmission unit as the final handshake message. Implementations MUST support the XX handshake pattern. The [IK handshake pattern](#ik) is used in the context of [Optimistic 0-RTT with Noise Pipes](#optimistic-0-rtt-with-noise-pipes) and is described in that section along with the [`XXfallback`](#xxfallback) variation on the `XX` pattern. #### XX ``` XX: -> e <- e, ee, s, es -> s, se ``` In the `XX` handshake pattern, both parties send their static Noise public keys to the other party. The first handshake message contains the initiator's ephemeral public key, which allows subsequent key exchanges and message payloads to be encrypted. The second and third handshake messages include a [handshake payload](#the-libp2p-handshake-payload), which contains a signature authenticating the sender's static Noise key as described in the [Static Key Authentication section](#static-key-authentication) and may include other internal libp2p data. The XX handshake MUST be supported by noise-libp2p implementations. A variation on the `XX` handshake, [`XXfallback`](#xxfallback) can be optionally enabled to support [Optimistic 0-RTT with Noise Pipes](#optimistic-0-rtt-with-noise-pipes) and is described in that context below. ### Optimistic 0-RTT with Noise Pipes The Noise spec describes a [compound protocol][npf-compound-protocols] called [Noise Pipes][npf-noise-pipes], which enables 0-RTT encryption in the optimistic case, while allowing peers to fallback to a different Noise protocol if their initial handshake attempt fails. The Noise Pipes protocol consists of the [`XX`](#xx) and [`IK`](#ik) handshake patterns, as well as a variation on `XX` called [`XXfallback`](#xxfallback). The `XX` pattern is used for a **full handshake** when two peers have not communicated using Noise before. Once the handshake completes, Alice can cache Bob's static Noise key. Later, Alice can open a new Noise connection to Bob using the `IK` pattern. This is a **zero-RTT handshake** that uses the cached static key to encrypt the initial handshake message. If Alice attempts an `IK` handshake but Bob has changed his static Noise key, Bob will fail to decrypt the handshake message. However, Bob may use the ephemeral key from Alice's `IK` message to initiate a **switch handshake** with Alice using the `XXfallback` pattern. Bob effectively treats Alice's `IK` message _as if_ it were the first message in an `XX` handshake and proceeds accordingly. The handshake patterns unique to Noise Pipes, `IK` and `XXfallback`, are described below. Noise Pipes is an optional feature of noise-libp2p, and implementations that do support it SHOULD offer a single configuration option to enable Noise Pipes, rather than separate options for enabling `IK` and `XXfallback`. #### IK ``` IK: <- s ... -> e, es, s, ss <- e, ee, se ``` In the `IK` handshake pattern, the initiator has prior knowledge of the responder's static Noise public key, indicated by the `<- s` token prior to the `...` separator. This allows the initial handshake payload to be encrypted using the known static key, and hides the identity of the initiator from passive observers. If the responder is unable to complete the `IK` handshake because their static key has changed, they may initiate an [`XXfallback`](#xxfallback) handshake, using the ephemeral public key from the failed `IK` handshake message as pre-message knowledge. Each handshake message will include a [libp2p handshake payload](#the-libp2p-handshake-payload) that identifies the sender and authenticates the static Noise key. #### XXfallback ``` XXfallback: -> e ... <- e, ee, s, es -> s, se ``` The `XXfallback` handshake pattern is used when a peer fails to decrypt an incoming `IK` handshake message that was prepared using a static Noise public key that is no longer valid. The *responder* for a failed `IK` handshake becomes the *initiator* of the subsequent `XXfallback` handshake. For example, if Alice initiated an `IK` handshake that Bob was unable to decrypt, Bob will initiate the `XXfallback` handshake to Alice. This is reflected in the arrow direction above; fallback handshake patterns are notated in the [so-called][npf-alice-and-bob] "Bob-initiated form," with arrows reversed from the canonical (Alice-initiated) form. The handshake pattern is the same as in `XX`, however, Alice's ephemeral public key is obtained from her initial `IK` message, moving it to the pre-message section of the handshake pattern. Essentially, the failed `IK` message serves the same role as the first handshake message in the standard `XX` pattern. Each handshake message will include a [libp2p handshake payload](#the-libp2p-handshake-payload) that identifies the sender and authenticates the static Noise key. #### Noise Pipes Message Flow Noise Pipes is a compound protocol, and peers supporting Noise pipes need to be able to distinguish between handshake messages from each pattern. We also wish to impose no additional overhead on peers that do not support Noise Pipes. There are four cases to support: - Neither party supports Noise Pipes. - Alice and Bob both support Noise Pipes. - Bob supports Noise Pipes but Alice does not. - Alice supports Noise Pipes but Bob does not. If **neither party supports Noise Pipes**, they both use the `XX` handshake and life is easy. If **Alice and Bob both support Noise Pipes**, Alice's initial handshake message to Bob may be either an `XX` or `IK` message. Bob, supporting Noise Pipes, will attempt to handle _all_ initial handshake messages as `IK` messages. If Alice sends an `IK` message to Bob to initiate a **zero-RTT handshake** and Bob has not changed his static Noise key, Bob will successfully decrypt the initial message and will respond with the next message in the `IK` sequence. If Alice sends an `XX` message to initiate a **full handshake**, or if Bob's static key has changed, Bob will fail to decrypt the initial message as an `IK` message. Bob will then re-initialize his Noise handshake state using the `XXfallback` pattern, using the ephemeral key from the initial message as pre-message knowledge. This is semantically equivalent to re-initializing with the `XX` pattern and re-processing Alice's message as the first in the `XX` sequence. If Alice sends an `XX` message, she will always receive an `XX`-compatible response. However, if Alice sends an `IK` message, Bob may reply with either the second `IK` message, or the first message in the `XXfallback` sequence (aka the second message in `XX`). Alice will always attempt to process Bob's response to an `IK` handshake attempt as an `IK` response. If this succeeds, the handshake is complete. If Alice fails to decrypt Bob's response as an `IK` message, she will re-initialize her Noise handshake state using the `XXfallback` pattern and re-process Bob's reply. She will then respond with the final message in the `XXfallback` pattern, which also corresponds to the final message in `XX`. If **Bob supports Noise Pipes but Alice does not**, Alice's initial handshake message will always be an `XX` message. Bob will first attempt to decrypt the initial message as an `IK` message, which will fail. He will then re-initialize his Noise state and respond with the first message in `XXfallback`, which is equivalent to the second `XX` message that Alice was expecting. Alice will complete the handshake by sending the final message in the `XX` sequence. If **Alice supports Noise Pipes but Bob does not**, Alice may send an initial `IK` message to Bob. Bob, not knowing anything about Noise Pipes, will treat this as the initial message in the `XX` sequence. This will succeed, because the only required information from the initial `XX` message is the ephemeral public key, which is also present in the `IK` message. Bob's response will be the second message in the `XX` sequence. Alice will first try to decrypt this as an `IK` response, which will fail. She then re-initializes her Noise state to use `XXfallback` as in the case where Bob also supports Noise Pipes but cannot complete an `IK` handshake. She then completes the handshake by sending the third message in the `XX` sequence that Bob was expecting. ## Cryptographic Primitives The Noise framework allows protocol designers to choose from a small set of Diffie-Hellman key exchange functions, symmetric ciphers, and hash functions. For simplicity, and to avoid the need to explicitly negotiate Noise protocols, noise-libp2p defines a single "cipher suite". noise-libp2p implementations MUST support the [25519 DH functions][npf-dh-25519], [ChaChaPoly cipher functions][npf-cipher-chachapoly], and [SHA256 hash function][npf-hash-sha256] as defined in the Noise spec. ## Valid Noise Protocol Names This section lists the [Noise protocol names][npf-protocol-names] that are valid according to the definitions in this spec. Because only a single set of cryptographic primitives is supported, the Noise protocol name depends on the handshake pattern in use. The `Noise_XX_25519_ChaChaPoly_SHA256` protocol MUST be supported by all implementations. Implementations that support Noise Pipes will also support the following Noise protocols: - `Noise_IK_25519_ChaChaPoly_SHA256` - `Noise_XXfallback_25519_ChaChaPoly_SHA256` ## Wire Format noise-libp2p defines a simple message framing format for sending data back and forth over the underlying transport connection. All data is segmented into messages with the following structure: | `noise_message_len` | `noise_message` | |---------------------|-----------------| | 2 bytes | variable length | The `noise_message_len` field stores the length in bytes of the `noise_message` field, encoded as a 16-bit big-endian unsigned integer. The `noise_message` field contains a [Noise Message as defined in the Noise spec][npf-message-format], which has a maximum length of 65535 bytes. During the handshake phase, `noise_message` will be a Noise handshake message. Noise handshake messages may contain encrypted payloads. If so, they will have the structure described in the [Encrypted Payloads section](#encrypted-payloads). After the handshake completes, `noise_message` will be a Noise transport message, which is defined as an AEAD ciphertext consisting of an encrypted payload plus 16 bytes of authentication data. The decrypted plaintext of the encrypted payload will have the structure described in the [Encrypted Payloads section](#encrypted-payloads). ### Encrypted Payloads All Noise transport messages have a single encrypted payload. Noise handshake messages may or may not have an encrypted payload. Once decrypted, the plaintext of an encrypted payload will have this structure: | `body_len` | `body` | `padding` | |------------|-----------------|-----------------| | 2 bytes | variable length | variable length | The `body_len` field stores the length in bytes of the `body` field as an unsigned 16-bit big-endian integer. All data following the `body` field consists of padding bytes, which must be ignored by the recipient. Senders SHOULD use a source of random data to populate the padding field and may use any length of padding that does not cause the total length of the Noise message to exceed 65535 bytes. ## Encryption and I/O During the handshake phase, the initiator (Alice) will initialize a Noise [`HandshakeState` object][npf-handshake-state] with their preferred [concrete Noise protocol](#valid-noise-protocol-names). If Alice does not support [Noise Pipes](#optimistic-0-rtt-with-noise-pipes), this will be `Noise_XX_25519_ChaChaPoly_SHA256`. With Noise pipes, the initial protocol may use the `IK` handshake pattern instead of `XX`. Alice and Bob exchange handshake messages, during which they [authenticate each other's static Noise keys](#static-key-authentication). Handshake messages are framed as described in the [Wire Format section](#wire-format), and if a handshake message contains a payload, it will have the structure described in [Encrypted Payloads](#encrypted-payloads). Following a successful handshake, each peer will possess two Noise [`CipherState` objects][npf-cipher-state]. One is used to encrypt outgoing data to the remote party, and the other is used to decrypt incoming data. After the handshake, peers continue to exchange messages in the format described in the [Wire Format section](#wire-format). However, instead of containing a Noise handshake message, the contents of the `noise_message` field will be Noise transport message, which is an AEAD ciphertext consisting of an encrypted payload plus 16 bytes of authentication data, as [defined in the Noise spec][npf-message-format]. When decrypted, the payload of a Noise transport message will have the structure described in [Encrypted Payloads](#encrypted-payloads). Receivers MUST decode the `body_len` field from the decrypted payload, and MUST ignore any additional padding following the `body` field. In the unlikely event that peers exchange more than `2^64 - 1` messages, they MUST terminate the connection to avoid reusing nonces, in accordance with the [Noise spec][npf-security]. ## libp2p Interfaces and API This section describes an abstract API for noise-libp2p. Implementations may alter this API to conform to language idioms or patterns used by the targeted libp2p implementation. Examples are written in pseudo-code that vaguely resembles Swift. ### Initialization The noise-libp2p module accepts the following inputs at initialization. - The private libp2p identity key - [optional] An early data payload to be sent in handshake messages - [optional] The private Noise static key - [optional] If Noise Pipes is supported, a flag to enable at runtime The private libp2p identity key is required for [static key authentication](#static-key-authentication) and signing of early data (if provided). Implementations that support sending [early data in handshake messages](#libp2p-data-in-handshake-messages) should accept this data at initialization time, rather than accepting an early data payload for each new connection. This ensures that no user or connection-specific data can be present in the early data payload. If a noise-libp2p implementation supports persisting the static Noise key, the constructor for the noise-libp2p module must accept a stored key. If a noise-libp2p implementation supports [Noise Pipes](#optimistic-0-rtt-with-noise-pipes), they may expose a configuration flag to selectively enable Noise Pipes at runtime. A minimal constructor could look like: ``` init(libp2pKey: PrivateKey) -> NoiseLibp2p ``` While one supporting all options might look like: ``` init(libp2pKey: PrivateKey, noiseKey: ByteString, earlyData: ByteString, useNoisePipes: bool) -> NoiseLibp2p ``` ### Secure Transport Interface noise-libp2p is designed to work with libp2p's **transport upgrade** pattern. libp2p security modules conform to a secure transport interface, which provides the `SecureOutbound` and `SecureInbound` methods described below. `SecureOutbound` and `SecureInbound` each accept an `InsecureConnection` and return a `NoiseConnection` on success. The details of the `InsecureConnection` type are libp2p-implementation dependent, but it is assumed to expose a bidirectional, reliable streaming interface. #### NoiseConnection A `NoiseConnection` must conform to the libp2p secure transport interface in the noise-libp2p implementation language by defining `SecureOutbound` and `SecureInbound` connections, described below. In addition to the secure transport interface defined by the libp2p framework, a `NoiseConnection` MAY have an additional method to expose early data transmitted by the remote peer during the handshake phase, if any. For example: ``` remoteEarlyData() -> ByteString? ``` Following a successful handshake, a `NoiseConnection` will transmit and receive data over the `InsecureConnection` as described in [Encryption and I/O](#encryption-and-io). #### SecureOutbound ``` SecureOutbound(insecure: InsecureConnection, remotePeer: PeerId) -> Result ``` `SecureOutbound` initiates a noise-libp2p connection to `remotePeer` over the provided `InsecureConnection`. The `remotePeer` PeerId argument MUST be validated against the libp2p public identity sent by the remote peer during the handshake. If a remote peer sends a public key that is not capable of deriving their expected peer id, the connection MUST be aborted. Note that the interface does not allow the user to choose the Noise handshake pattern. Implementations that support Noise Pipes must decide whether to use an `XX` or `IK` handshake based on whether they possess a cached static Noise key for the remote peer. #### SecureInbound ``` SecureInbound(insecure: InsecureConnection) -> Result ``` `SecureInbound` attempts to complete a noise-libp2p handshake initiated by a remote peer over the given `InsecureConnection`. ## Design Considerations ### No Negotiation of Noise Protocols Supporting a single cipher suite allows us to avoid negotiating which concrete Noise protocol to use for a given connection. This removes a huge source of incidental complexity and makes implementations much simpler. Changes to the cipher suite will require a new version of noise-libp2p, but this should happen infrequently enough to be a non-issue. Users who require cipher agility are encouraged to adopt TLS 1.3, which supports negotiation of cipher suites. ### Why ChaChaPoly? We debated supporting AESGCM in addition to or instead of ChaChaPoly. The desire for a simple protocol without explicit negotiation of ciphers and handshake patterns led us to support a single cipher, so the question became which to support. While AES has broad hardware support that can lead to significant performance improvements on some platforms, secure and performant software implementations are hard to come by. To avoid excluding runtime platforms without hardware AES support, we chose the ChaChaPoly cipher, which is possible to implement in software on all platforms. ### Distinct Noise and Identity Keys Using a separate keypair for Noise adds complexity to the protocol by requiring signature validation and transmission of libp2p public keys during the handshake. However, none of the key types supported by libp2p for use as identity keys are fully compatible with Noise. While it is possible to convert an ed25519 key into the X25519 format used with Noise, it is not possible to do the reverse. This makes it difficult to use any libp2p identity key directly as the Noise static key. Also, Noise [recommends][npf-security] only using Noise static keys with other Noise protocols using the same hash function. Since we can't guarantee that users won't also use their libp2p identity keys in other contexts (e.g. SECIO handshakes, signing pubsub messages, etc), requiring separate keys seems prudent. ### Why Not Noise Signatures? Since we're using signatures for authentication, the [Noise Signatures extension][noise-signatures-spec] is a natural candidate for adoption. Unfortunately, the Noise Signatures spec requires both parties to use the same signature algorithm, which would prevent peers with different identity key types to complete a Noise Signatures handshake. Also, only Ed25519 signatures are currently supported by the spec, while libp2p identity keys may be of other unsupported types like RSA. [peer-id-spec]: ../peer-ids/peer-ids.md [peer-id-spec-signing-rules]: ../peer-ids/peer-ids.md#how-keys-are-encoded-and-messages-signed [conn-spec]: ../connections/README.md [multiselect-2-pr]: https://github.com/libp2p/specs/pull/95 [npf]: https://noiseprotocol.org/noise.html [npf-prologue]: https://noiseprotocol.org/noise.html#prologue [npf-handshake-basics]: https://noiseprotocol.org/noise.html#handshake-pattern-basics [npf-fundamental-patterns]: https://noiseprotocol.org/noise.html#interactive-handshake-patterns-fundamental [npf-compound-protocols]: https://noiseprotocol.org/noise.html#compound-protocols [npf-noise-pipes]: https://noiseprotocol.org/noise.html#noise-pipes [npf-protocol-names]: https://noiseprotocol.org/noise.html#protocol-names-and-modifiers [npf-dh-25519]: https://noiseprotocol.org/noise.html#the-25519-dh-functions [npf-cipher-chachapoly]: https://noiseprotocol.org/noise.html#the-chachapoly-cipher-functions [npf-hash-sha256]: https://noiseprotocol.org/noise.html#the-sha256-hash-function [npf-security]: https://noiseprotocol.org/noise.html#security-considerations [npf-message-format]: https://noiseprotocol.org/noise.html#message-format [npf-alice-and-bob]: https://noiseprotocol.org/noise.html#alice-and-bob [npf-handshake-indistinguishability]: https://noiseprotocol.org/noise.html#handshake-indistinguishability [npf-handshake-state]: https://noiseprotocol.org/noise.html#the-handshakestate-object [npf-cipher-state]: https://noiseprotocol.org/noise.html#the-cipherstate-object [npf-channel-binding]: https://noiseprotocol.org/noise.html#channel-binding [rfc-7748-sec-5]: https://tools.ietf.org/html/rfc7748#section-5 [protobuf]: https://developers.google.com/protocol-buffers/ [noise-socket-spec]: https://github.com/noisesocket/spec [noise-signatures-spec]: https://github.com/noiseprotocol/noise_sig_spec/blob/master/output/noise_sig.pdf