mirror of
https://github.com/vacp2p/specs.git
synced 2026-01-09 07:17:56 -05:00
Finish first pass of SECIO spec
This commit is contained in:
105
secio/README.md
105
secio/README.md
@@ -53,3 +53,108 @@ required to implement SECIO.
|
||||
## Protocol
|
||||
|
||||
### Proposal Generation
|
||||
|
||||
SECIO channel negotiation begins with a proposal phase. Both sides generate a
|
||||
proposal as follows:
|
||||
|
||||
*Note: the public key should be serialized per the `Bytes` method from
|
||||
[go-libp2p-crypto](https://godoc.org/github.com/libp2p/go-libp2p-crypto#Key).*
|
||||
|
||||
```
|
||||
Propose{
|
||||
Rand: <16 secure random bytes>,
|
||||
Pubkey: <public key bytes>,
|
||||
Exchanges: <comma separated string of supported key exchanges>,
|
||||
Ciphers: <comma separated string of supported ciphers>,
|
||||
Hashes: <comma separated string of supported hashes>,
|
||||
}
|
||||
```
|
||||
|
||||
Both peers serialize this message and send it over the wire. Upon deserializing
|
||||
their peer's message, they verify that the pubkey matches that described by the
|
||||
peer's peer ID (NOTE: this is sometimes only possible for the peer *initiating*
|
||||
the connection.) If the key doesn't match the peer ID, the peer can close the
|
||||
connection. If the peer doesn't know the remote peer's ID, they can compute and
|
||||
store the remote peer ID for later use.
|
||||
|
||||
### Determining Roles and Algorithms
|
||||
|
||||
Next, the peers use a deterministic formula to compute their roles in the coming
|
||||
exchanges. Each peer computes:
|
||||
|
||||
```
|
||||
oh1 := sha256(concat(remotePeerPubKeyBytes, myNonce))
|
||||
oh2 := sha256(concat(myPubKeyBytes, remotePeerNonce))
|
||||
```
|
||||
|
||||
With these hashes, determine which peer's preferences to favor. This peer will
|
||||
be referred to as the "preferred peer". If `oh1 == oh2`, then the peer is
|
||||
communicating with itself and should return an error. If `oh1 < oh2`, use the
|
||||
remote peer's preferences. If `oh1 > oh2`, prefer the local peer's preferences.
|
||||
|
||||
Given our preference, we now sort through each of the `Exchanges`, `Ciphers`,
|
||||
and `Hashes` provided by both peers, selecting the first item from our preferred
|
||||
peer's set that is also shared by the other peer.
|
||||
|
||||
### Key Exchange
|
||||
|
||||
Now the peers prepare a key exchange. Both peers generate an ephemeral key based
|
||||
on the agreed upon exchange (currently support is only available for elliptic
|
||||
curve algorithms). Ephemeral keys are generated via
|
||||
[go-libp2p-crypto](https://godoc.org/github.com/libp2p/go-libp2p-crypto#GenerateEKeyPair).
|
||||
|
||||
With keys generated, both peers create a `Exchange` message. First, they start by
|
||||
generating a "corpus" that they will sign.
|
||||
|
||||
```
|
||||
corpus := concat(myProposalBytes, remotePeerProposalBytes, ephemeralPubKey)
|
||||
```
|
||||
|
||||
Then, generate the `Exchange`:
|
||||
|
||||
```
|
||||
Exchange{
|
||||
Epubkey: <ephemeral pubkey>,
|
||||
Signature: <sign corpus with local private key>,
|
||||
}
|
||||
```
|
||||
|
||||
The peers serialize these and write them over the wire. Upon receiving the
|
||||
remote peer's `Exchange`, validate the signature by computing the `corpus` you
|
||||
expect them to have generated with their public key. Peers should close the
|
||||
connection if the signature does not validate.
|
||||
|
||||
### Key Stretching
|
||||
|
||||
Peers now generate their shared secret based on the function generated by the
|
||||
ephemeral key generation, passing it the remote peer's ephemeral key. With the
|
||||
shared secret generated, both peers stretch the key using the algorithm
|
||||
described by
|
||||
[go-libp2p-crypto](https://godoc.org/github.com/libp2p/go-libp2p-crypto#KeyStretcher).
|
||||
|
||||
```
|
||||
k1, k2 := KeyStretcher(sharedSecret)
|
||||
```
|
||||
|
||||
With `k1` and `k2` computed, swap the two values if the remote peer is the
|
||||
preferred peer. After swapping if necessary, `k1` becomes the local peer's key
|
||||
and `k2` the remote peer's key.
|
||||
|
||||
Each peer now generates a MAC key and cipher for the remote and local keys
|
||||
generated in the previous step using the `MacKey` and `CipherKey` from the
|
||||
generated
|
||||
[`StretchedKeys`](https://godoc.org/github.com/libp2p/go-libp2p-crypto#StretchedKeys)
|
||||
objects.
|
||||
|
||||
### Initiate Secure Channel
|
||||
|
||||
With the cipher and HMAC signer created, the secure channel is ready to be
|
||||
opened. Each packet is of the form:
|
||||
|
||||
```
|
||||
[uint32 length of packet | encrypted body | hmac signature of encrypted body]
|
||||
```
|
||||
|
||||
The first packet transmitted by each peer must be the remote peer's nonce. Peers
|
||||
validate that the remote peer sent them their nonce, closing if unsuccessful.
|
||||
Otherwise, a secure channel has been successfully opened.
|
||||
|
||||
Reference in New Issue
Block a user