This protocol provides authentication and initializes stream encryption for later protocols.
- server confirms the client knows the password (don't allow random people to start broadcasting your webcam to the internet)
- client confirms the server knows the password (probably not neccessary for this case, but why not)
- establish a secure client-to-server stream
- establish a secure server-to-client stream
- be replay-resistent, both for servers and clients (don't allow someone who sniffed your wifi to start broadcasting your webcam to the internet)
We build this using libsodium secret boxes and secret streams.
All random nonces and keys must be re-generated for each connection.
This is the first message sent.
The pre-shared key is used to send "secret boxes", containing the data that we actually need to share
- A random
unit8[crypto_pwhash_SALTBYTES]
salt is created - A key is created using
crypto_pwhash()
, using the password, salt, default algorithm, and interactive memory and opslimits. If you are working in Javascript, the default memory limit requires the 'sumo' variant of libsodium.js - The key must be retained to complete the handshake
- A random
uint8[crypto_secretstream_xchacha20poly1305_KEYBYTES]
key is created usingcrypto_secretstream_xchacha20poly1305_keygen()
- The key must be retained to complete the handshake
- A random
uint8[crypto_secretbox_NONCEBYTES]
nonce is created - A secretbox is created using
crypto_secretbox_easy
- the plaintext (box contents) is the Server-To-Client stream key
- the key is the secretbox key created above using
crypto_pwhash
The message is a packed binary struct, containing:
struct {
uint8 pwhash_salt[crypto_pwhash_SALTBYTES];
uint8 secretbox_nonce[crypto_secretbox_NONCEBYTES];
uint8 secretbox[crypto_secretstream_xchacha20poly1305_KEYBYTES + crypto_secretbox_MACBYTES];
}
This is sent by the server in response to a valid client hello
The key is created in the same manner as the client, except that the client-provided pwhash_nonce
is used,
instead of a new random value.
- The key is extracted from the secretbox using the key derived above, and the client-provided nonce
- A state object and header blob are created using
crypto_secretstream_xchacha20poly1305_init_push
and the key - The state object must be retained for use with the RPC protocol
- A random
uint8[crypto_secretstream_xchacha20poly1305_KEYBYTES]
key is created usingcrypto_secretstream_xchacha20poly1305_keygen()
- The key must be retained to complete the handshake
- A random
uint8[crypto_auth_KEYBYTES]
key is created usingcrypto_auth_keygen()
- The key must be retained to complete the handshake
- A random
uint8[crypto_secretbox_NONCEBYTES]
nonce is created - A secretbox is created using
crypto_secretbox_easy
- the plaintext (box contents) is a packed binary struct:
struct { uint8 client_to_server_key[crypto_secretstream_chacha20poly1305_KEYBYTES]; uint8 authentication_key[crypto_auth_KEYBYTES]; }
- the key is the secretbox key created above using
crypto_pwhash
- the plaintext (box contents) is a packed binary struct:
The message is a packed binary struct, containing:
struct {
uint8 secretbox_nonce[crypto_secretbox_NONCEBYTES];
uint8 secretbox[
crypto_secretstream_xchacha20poly1305_KEYBYTES
+ crypto_auth_KEYBYTES
+ crypto_secretbox_MACBYTES
];
uint8 server_to_client_header[crypto_secretstream_xchacha20poly1305_HEADERBYTES];
}
This is sent by the client in response to a valid server hello.
- The key is extracted from the secretbox using the key derived above, and the server-provided nonce
- A state object and header blob are created using
crypto_secretstream_xchacha20poly1305_init_push
and the key - The state object must be retained for use with the RPC protocol
- A state object is created from the header blob using the previously established key
and
crypto_secretstream_xchacha20poly1305_init_pull
- The state object must be retained for use with the RPC protocol
- the authentication key is extracted from the secretbox
- a mac is created using
crypto_auth()
using the provided key, and using the client-to-server header as the message
This is to confirm to the server that the client is actually decrypting the boxes - e.g. that this isn't a replay attack.
The message is a packed binary struct, containing:
struct {
uint8 client_to_server_header[crypto_secretstream_xchacha20poly1305_HEADERBYTES];
uint8 authentication_mac[crypto_auth_BYTES];
}
- It is now only neccessary to retain the stream state objects, not the keys. Keys should not be retained longer.
- Future client/server messages should follow the RPC protocol.
- The authentication mac must be verified
- A state object for the client-to-server stream should be initialized using
crypto_secretstream_xchacha20poly1305_secretstream_init_pull()
and the client-provided header - The state object must be retained for the RPC protocol
- It is now only neccessary to retain the stream state objects, not the keys. Keys should not be retained longer.