diff --git a/docs/01-Protocol-Versions/Version3.md b/docs/01-Protocol-Versions/Version3.md index 8f31013a..1a2e40d4 100644 --- a/docs/01-Protocol-Versions/Version3.md +++ b/docs/01-Protocol-Versions/Version3.md @@ -14,7 +14,7 @@ implicit assertion `i` (which defaults to empty string): 2. Generate 32 random bytes from the OS's CSPRNG to get the nonce, `n`. 3. Split the key into an Encryption key (`Ek`) and Authentication key (`Ak`), - using HKDF-HMAC-SHA384, with `n` as the HKDF salt. + using HKDF-HMAC-SHA384, with `n` appended to the info rather than the salt. * The output length **MUST** be 48 for the first key derivation and 32 for `Ak`. * The derived key will be the leftmost 32 bytes of the first HKDF derivation. @@ -23,16 +23,16 @@ implicit assertion `i` (which defaults to empty string): tmp = hkdf_sha384( len = 48 ikm = k, - info = "paseto-encryption-key", - salt = n + info = "paseto-encryption-key" || n, + salt = NULL ); Ek = tmp[0:32] n2 = tmp[32:] Ak = hkdf_sha384( len = 32 ikm = k, - info = "paseto-auth-key-for-aead", - salt = n + info = "paseto-auth-key-for-aead" || n, + salt = NULL ); ``` 5. Encrypt the message using `AES-256-CTR`, using `Ek` as the key and @@ -61,7 +61,6 @@ Given a message `m`, key `k`, and optional footer `f` (which defaults to empty string), and an optional implicit assertion `i` (which defaults to empty string): - 1. If `f` is not empty, implementations **MAY** verify that the value appended to the token matches some expected string `f`, provided they do so using a constant-time string compare function. @@ -73,7 +72,7 @@ implicit assertion `i` (which defaults to empty string): * `t` to the rightmost 48 bytes * `c` to the middle remainder of the payload, excluding `n` and `t` 4. Split the key (`k`) into an Encryption key (`Ek`) and an Authentication key - (`Ak`), `n` as the HKDF salt. + (`Ak`), `n` appended to the HKDF info. * For encryption keys, the **info** parameter for HKDF **MUST** be set to **paseto-encryption-key**. * For authentication keys, the **info** parameter for HKDF **MUST** be set to @@ -86,16 +85,16 @@ implicit assertion `i` (which defaults to empty string): tmp = hkdf_sha384( len = 48 ikm = k, - info = "paseto-encryption-key", - salt = n + info = "paseto-encryption-key" || n, + salt = NULL ); Ek = tmp[0:32] n2 = tmp[32:] Ak = hkdf_sha384( len = 32 ikm = k, - info = "paseto-auth-key-for-aead", - salt = n + info = "paseto-auth-key-for-aead" || n, + salt = NULL ); ``` 5. Pack `h`, `n`, `c`, `f`, and `i` together (in that order) using diff --git a/docs/Rationale-V3-V4.md b/docs/Rationale-V3-V4.md index ffe476f4..5b7bdc2c 100644 --- a/docs/Rationale-V3-V4.md +++ b/docs/Rationale-V3-V4.md @@ -158,17 +158,25 @@ half was used as an AES-CTR nonce. This is tricky to analyze and didn't extend well for the v4.local proposal. For the sake of consistency and easy-to-analyze security designs, in both v3.local -and v4.local, we now use the entire 32-byte salt in the HKDF step. The nonce -used by AES-256-CTR and XChaCha20 will be derived from the HKDF output (which -is now 48 bytes for v3.local and 56 bytes for v4.local). The first 32 bytes of -each HKDF output will be used as the key. The remaining bytes will be used as -the nonce for the underlying cipher. +and v4.local, we now use the entire 32-byte random value in the HKDF step. + +Instead of being used as a salt, however, it will be appended to the info tag. +This subtle change allows us to use the +[standard security definition for HKDF](https://eprint.iacr.org/2010/264) +in arguments for PASETO's security, rather than treating it as just a +pseudo-random function (PRF). This security definition requires only one salt +to be used, but for many contexts (info tags). + +The nonce used by AES-256-CTR and XChaCha20 will be derived from the HKDF output +(which is now 48 bytes for v3.local and 56 bytes for v4.local). The first 32 +bytes of each HKDF output will be used as the key. The remaining bytes will be +used as the nonce for the underlying cipher. Local PASETOs in v3 and v4 will always have a predictable storage size, and the security of these constructions is more obvious: -* The probability space for either mode is 256-bits of salt + 256-bits of key, - for a total of 512 bits. +* The probability space for either mode is 256-bits of randomness + 256-bits of + key, for a total of 512 bits. * The HKDF output in v3.local is 384 bits. * The HKDF output in v4.local is 448 bits. * Neither of these output sizes reduces the security against collisions.