diff --git a/i2p2www/spec/proposals/169-pq-crypto.rst b/i2p2www/spec/proposals/169-pq-crypto.rst index ea1ebc253ce83eb73c16768d89bd16eb94d72c28..bccc87d193dbc522142abf1885e860aaf0063696 100644 --- a/i2p2www/spec/proposals/169-pq-crypto.rst +++ b/i2p2www/spec/proposals/169-pq-crypto.rst @@ -435,11 +435,71 @@ XK: XKhfs: Noise Handshake KDF --------------------- +This section applies to both IK and XK protocols. + The KEM 32-byte shared secret is combined or mixHash()ed or HKDF()ed into the final Noise shared secret, before split(), for a final 32-byte shared secret. Not concatenated with the DH shared secret for a 64-byte final shared secret, which is what TLS does [TLS-HYBRID]_. +Defined ML-KEM Operations +````````````````````````` + +We define the following functions corresponding to the cryptographic building blocks used +as defined in [FIPS203]_. + +(encap_key, decap_key) = KEYGEN() + Alice creates the encapsulation and decapsulation keys + The encapsulation key is sent in message 1. + encap_key and decap_key sizes vary based on ML-KEM variant. + +(cihpertext, kem_shared_key) = ENCAPS(encap_key) + Bob calculates the ciphertext and shared key, + using the ciphertext received in message 1. + The ciphertext is sent in message 2. + ciphertext size varies based on ML-KEM variant. + The kem_shared_key is always 32 bytes. + +kem_shared_key = DECAPS(ciphertext, decap_key) + Alice calculates the shared key, + using the ciphertext received in message 2. + The kem_shared_key is always 32 bytes. + +Note that both the encap_key and the ciphertext are encrypted inside ChaCha/Poly +blocks in the Noise handshake messages 1 and 2. +They will be decrypted as part of the handshake process. + +The kem_shared_key is combined with the X25519 DH shared key to +create a shared session key. +See below for details. + + +Alice KDF for Message 1 +````````````````````````` + +(encap_key, decap_key) = KEYGEN() + + +Bob KDF for Message 2 +````````````````````````` + +(cihpertext, kem_shared_key) = ENCAPS(encap_key) + + +Alice KDF for Message 2 +````````````````````````` + +kem_shared_key = DECAPS(ciphertext, decap_key) + + +Alice/Bob KDF for split() +````````````````````````` + +see below + + + + Ratchet --------- @@ -474,7 +534,7 @@ Encrypted format: | | +----+----+----+----+----+----+----+----+ | | - + ML-KEM key and Static Key + + + ML-KEM encap_key and X25519 Static Key+ | ChaCha20 encrypted data | + (see table below for length) + | | @@ -511,7 +571,7 @@ Payload Part 1: +----+----+----+----+----+----+----+----+ | | - + ML-KEM key + + + ML-KEM encap_key + | | + (see table below for length) + | | @@ -578,7 +638,7 @@ Encrypted format: +----+----+----+----+----+----+----+----+ | | + + - | ChaCha20 encrypted PQ ciphertext | + | ChaCha20 encrypted ML-KEM ciphertext | + (see table below for length) + ~ ~ + + @@ -732,7 +792,7 @@ Unencrypted data (Poly1305 authentication tag not shown): + + | | +----+----+----+----+----+----+----+----+ - | ML-KEM Public Key | + | ML-KEM encap_key | + (see table below for length) + | | +----+----+----+----+----+----+----+----+ @@ -1001,7 +1061,7 @@ Unencrypted data (Poly1305 authentication tag not shown): + + | | +----+----+----+----+----+----+----+----+ - | ML-KEM Public Key | + | ML-KEM encap_key | + (see table below for length) + | | +----+----+----+----+----+----+----+----+ @@ -1130,7 +1190,7 @@ unchanged KDF for data phase ``````````````````` -The data phase uses the header for associated data. +This section applies to both IK and XK protocols. The KDF generates two cipher keys k_ab and k_ba from the chaining key ck, using HMAC-SHA256(key, data) as defined in [RFC-2104]_. @@ -1139,17 +1199,25 @@ This is the split() function, exactly as defined in the Noise spec. .. raw:: html {% highlight lang='text' %} -// split() +// Alice side + (cihpertext, kem_shared_key) = ENCAPS(encap_key) + // Bob side + kem_shared_key = DECAPS(ciphertext, decap_key) + + // split() // chainKey = from handshake phase - keydata = HKDF(chainKey, ZEROLEN, "", 64) - TODO + // mix the ML-KEM shared key into the chaining key + mixKey(kem_shared_key); + // chainKey was changed by the mixKey() - k_ab = keydata[0:31] - k_ba = keydata[32:63] + keydata = HKDF(chainKey, ZEROLEN, "", 64) + + remainder unchanged - Remainder unchanged + k_ab = ... + k_ba = ... {% endhighlight %}