Secure channels over TCP/IP
- Go package on Github
- C library on Github
- C library manual
- C library version 1.0.1 release tarball signature)
This library was born out of a need to set up a secure channel over a TCP/IP network without the overhead of TLS. It uses NaCl for security, and follows the guidelines for secure channels outlined in Cryptography Engineering.
A secure channel has the following properties:
- A bi-directional channel has separate keys for each direction.
- The channel has send and receive counters to prevent replayed messages; these message counters will be reset whenever the keys are rotated.
- A regressed message counter is considered a decryption failure.
- The channel transmits discrete messages, and doesn’t operate as a stream.
- New keys are generated for each channel.
- An eavesdropper can still perform traffic analysis to note when and how often the two sides communicate, and will be able to observe the size of the messages.
There are three different types of keys that are used in this system; users of this system need only worry about one of them. These three key types are:
Identity keys: these are signature keys used to identify peers. S/Channel uses Ed25519 key pairs for identity. Users will need to supply a private key to sign the key exchange, and a public key that should be used to verify the key exchange. The initial key exchange is signed to provide authenticity. After this initial exchange, key rotation does not need to be signed as authenticity has already been provided.
Key exchange keys: these are randomly generated at the start of each session and every time keys are rotated. These keys are only used in the key exchange, and are wiped once the key exchange is complete. S/Channel currently uses a pair of Curve25519 keypairs for the key exchange, one pair per shared key.
Shared keys: these are the symmetric encryption keys that are used for securing traffic. Each side has separate send and receive keys; once the initial session is established, all traffic is encrypted. These keys are computed from the key exchange ECDH operation; S/Channel currently uses the NaCl secretbox module to provide symmetric security.
Key exchange high-level overview
For this discussion, the client is the peer that initiates the secure channel, and server is the other peer. They are so-named because the corresponding functions are called “dial” and “listen”. It is assumed both sides have set up a TCP connection, e.g. using
- Both sides generate their key exchange pair. If a peer has an identity key, it will sign its keypair. Otherwise, an empty signature is used; this is the tuple
- The client sends its key exchange tuple to the server.
- The server receives the tuple, and verifies the signature as appropriate.
- The server now sends its tuple.
- The client receives this tuple, and verifies the signature as appropriate.
- Both sides can now compute their shared keys. The client computes its send key as ECDH(kpriv,1,kpeer,1), and its receive key as ECDH(kpriv,2,kpeer,2). The server necessarily reverses the order: its send key is computed as ECDH(kpriv,2,kpeer,2), and its receive key as ECDH(kpriv,1,kpeer,1).
- The secure channel is established and both sides can exchange messages.
- If at some point, one side determines that a key rotation is needed, the same basic steps are followed without the signatures. Key rotations are signaled via a key exchange message.
Once the channel is established, all traffic will be authenticated and encrypted. Messages are wrapped in an envelope before encryption that pairs the message with a format version, sequence number, and message type. The message type is used to provide additional messages for managing the secure channel: the normal message type is used for all messages sent from one side to the other. A key exchange message triggers a key rotation, and a shutdown message signals the other side that the secure channel is being closed.