-
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 have any Associated Data, so effectively we are using Authenticated Encryption only. AEAD ciphers simultaneously provide confidentiality, integrity, and authenticity. They offer excellent performance and power efficiency on modern hardware. Users are recommended to use the following AEAD ciphers whenever possible.
Name | Key Size | Salt Size | Nonce Size | Tag Size |
---|---|---|---|---|
xchacha20-ietf-poly1305 | 32 | 32 | 24 | 16 |
chacha20-ietf-poly1305 | 32 | 32 | 12 | 16 |
aes-256-gcm | 32 | 32 | 12 | 16 |
aes-192-gcm | 24 | 24 | 12 | 16 |
aes-128-gcm | 16 | 16 | 12 | 16 |
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.
AE_encrypt is a function that takes a secret key, a non-secret nonce, a message, and produces ciphertext and authentication tag. Nonce must be unique for a given key in each invocation.
AE_encrypt(key, nonce, message) => (ciphertext, tag)
AE_decrypt is a function that takes a secret key, non-secret nonce, ciphertext, authentication tag, and produces original message. If any of the input is tampered with, decryption will fail.
AE_decrypt(key, nonce, ciphertext, tag) => message
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.