-
Notifications
You must be signed in to change notification settings - Fork 548
AEAD Ciphers
AEAD stands for Authenticated Encryption with Associated Data. Currently we do not use any Associated Data, so effectively we are only using Authenticated Encryption.
AEAD_encrypt is a function that takes a secret key, a non-secret nonce, a message, and produces ciphertext and authentication tag
AEAD_encrypt(key, nonce, message) => (ciphertext, tag)
Nonce must be unique for a given key in each invocation.
AEAD_decrypt is a function that takes a secret key, non-secret nonce, ciphertext, authentication tag, and produces original message.
AEAD_decrypt(key, nonce, ciphertext, tag) => message
If any of the input is tampered with, decryption will fail.
The way Shadowsocks using AEAD ciphers is specified in SIP004 and amended in SIP007. SIP004 was proposed by @Mygod with design inspirations from @breakwa11 and @Noisyfox. SIP007 was proposed by @riobard with input from @madeye, @Mygod, @wongsyrone, and many others.
HKDF_SHA1 is a function that takes a secret key, a non-secret salt, an info string, and produces a subkey that is cryptographically strong even if the input secret key is weak.
HKDF_SHA1(key, salt, info) => subkey
The info string binds the generated subkey to a specific application context. In our case, it must be the string "ss-subkey" without quotes.
We derive a per-session subkey from a pre-shared master key using HKDF_SHA1. Salt must be unique through the entire life of the pre-shared master key.
An AEAD encrypted TCP stream starts with a randomly generated salt to derive the per-session subkey, followed by any number of encrypted chunks. Each chunk has the following structure:
[encrypted payload length][length tag][encrypted payload][payload tag]
Payload length is a 2-byte big-endian unsigned integer capped at 0x3FFF. The higher two bits are reserved and must be set to zero. Payload is therefore limited to 16*1024 - 1 bytes.
The first AEAD encrypt/decrypt operation uses a counting nonce starting from 0. After each encrypt/decrypt operation, the nonce is incremented by one as if it were an unsigned little-endian integer. Note that each TCP chunk involves two AEAD encrypt/decrypt operation: one for the payload length, and one for the payload. Therefore each chunk increases the nonce twice.
An AEAD encrypted UDP packet has the following structure
[salt][encrypted payload][tag]
The salt is used to derive the per-session subkey. Each UDP packet is encrypted/decrypted independently, using the derived subkey and a nonce with all zero bytes.