diff --git a/analysis/rosenpass/03_identity_hiding.mpv b/analysis/rosenpass/03_identity_hiding.mpv index 112ed6c..dc4901c 100644 --- a/analysis/rosenpass/03_identity_hiding.mpv +++ b/analysis/rosenpass/03_identity_hiding.mpv @@ -58,7 +58,7 @@ let secure_init_hello(initiator: kem_sk_tmpl, sidi : SessionId, psk: key_tmpl, r new epkit:kem_pk; // epki new sctrt:bits; // sctr - new pidiCt:bits; // pidiC + new pidi_ct:bits; // pidi_ct new autht:bits; // auth NEW_TRUSTED_SEED(seski_trusted_seed) @@ -70,9 +70,9 @@ let secure_init_hello(initiator: kem_sk_tmpl, sidi : SessionId, psk: key_tmpl, r let secure_resp_hello(initiator: kem_sk_tmpl, responder: kem_sk_tmpl, sidi:SessionId, sidr:SessionId, biscuit_no:Atom, psk:key_tmpl) = - in(D, InitHello(=secure_sidi, epki, sctr, pidiC, auth)); + in(D, InitHello(=secure_sidi, epki, sctr, pidi_ct, auth)); - ih <- InitHello(sidi, epki, sctr, pidiC, auth); + ih <- InitHello(sidi, epki, sctr, pidi_ct, auth); NEW_TRUSTED_SEED(septi_trusted_seed) NEW_TRUSTED_SEED(sspti_trusted_seed) new last_cookie:key; diff --git a/analysis/rosenpass/cookie.mpv b/analysis/rosenpass/cookie.mpv index d28fdef..94cce02 100644 --- a/analysis/rosenpass/cookie.mpv +++ b/analysis/rosenpass/cookie.mpv @@ -19,7 +19,7 @@ fun CookieMsg( COOKIE_EV(event MCAT(eventLbl, _UnderLoadEV) (spkm, spkt, last_cookie);) \ msgB <- Envelope(mac1, RH2b(rh)); \ mac2_key <- create_mac2_key(sskm, spkt) \ - let RespHello(sidi, sidr, ecti, scti, biscuit, auth) = rh in \ + let RespHello(sidi, sidr, ecti, scti, biscuit_ct, auth) = rh in \ if Envelope(mac2_key, msgB) = mac2 then \ COOKIE_EV(event MCAT(eventLbl, _CookieValidated) (spkm, last_cookie);) \ innerFunc \ diff --git a/analysis/rosenpass/oracles.mpv b/analysis/rosenpass/oracles.mpv index d21e6b2..0d8a32d 100644 --- a/analysis/rosenpass/oracles.mpv +++ b/analysis/rosenpass/oracles.mpv @@ -86,8 +86,8 @@ MTX_EV( event RHRjct(RespHello_t, key, kem_sk, kem_pk). ) MTX_EV( event ICSent(RespHello_t, InitConf_t, key, kem_sk, kem_pk). ) SES_EV( event InitiatorSession(RespHello_t, key). ) let Oresp_hello(HS_DECL_ARGS) = - in(C, Cresp_hello(RespHello(sidr, =sidi, ecti, scti, biscuit, auth))); - rh <- RespHello(sidr, sidi, ecti, scti, biscuit, auth); + in(C, Cresp_hello(RespHello(sidr, =sidi, ecti, scti, biscuit_ct, auth))); + rh <- RespHello(sidr, sidi, ecti, scti, biscuit_ct, auth); /* try */ let ic = ( ck_ini <- ck; RESPHELLO_CONSUME() @@ -124,7 +124,7 @@ let Oinit_hello() = call <- Cinit_hello(sidr, biscuit_no, Ssskm, Spsk, Sspkt, Septi, Sspti, ih); #endif // TODO: This is ugly - let InitHello(sidi, epki, sctr, pidiC, auth) = ih in + let InitHello(sidi, epki, sctr, pidi_ct, auth) = ih in SETUP_HANDSHAKE_STATE() eski <- kem_sk0; epti <- rng_key(setup_seed(Septi)); // RHR4 diff --git a/analysis/rosenpass/protocol.mpv b/analysis/rosenpass/protocol.mpv index 658b05f..bb82055 100644 --- a/analysis/rosenpass/protocol.mpv +++ b/analysis/rosenpass/protocol.mpv @@ -7,7 +7,7 @@ fun InitHello( SessionId, // sidi kem_pk, // epki bits, // sctr - bits, // pidiC + bits, // pidi_ct bits // auth ) : InitHello_t [data]. @@ -17,16 +17,16 @@ fun InitHello( /* not handled here */ /* IHI3 */ \ MIX2(sid2b(sidi), kem_pk2b(epki)) /* IHI4 */ \ ENCAPS_AND_MIX(sctr, spkr, sptr) /* IHI5 */ \ - ENCRYPT_AND_MIX(pidiC, pidi) /* IHI6 */ \ + ENCRYPT_AND_MIX(pidi_ct, pidi) /* IHI6 */ \ MIX2(kem_pk2b(spki), k2b(psk)) /* IHI7 */ \ ENCRYPT_AND_MIX(auth, empty) /* IHI8 */ \ - ih <- InitHello(sidi, epki, sctr, pidiC, auth); + ih <- InitHello(sidi, epki, sctr, pidi_ct, auth); #define INITHELLO_CONSUME() \ ck <- lprf1(CK_INIT, kem_pk2b(spkr)); /* IHR1 */ \ MIX2(sid2b(sidi), kem_pk2b(epki)) /* IHR4 */ \ DECAPS_AND_MIX(sskr, spkr, sctr) /* IHR5 */ \ - DECRYPT_AND_MIX(pid, pidiC) /* IHR6 */ \ + DECRYPT_AND_MIX(pid, pidi_ct) /* IHR6 */ \ LOOKUP_SENDER(pid) /* IHR6 */ \ MIX2(kem_pk2b(spki), k2b(psk)) /* IHR7 */ \ DECRYPT_AND_MIX(DUMMY(empty), auth) @@ -46,17 +46,17 @@ fun RespHello( MIX2(sid2b(sidr), sid2b(sidi)) /* RHR3 */ \ ENCAPS_AND_MIX(ecti, epki, epti) /* RHR4 */ \ ENCAPS_AND_MIX(scti, spki, spti) /* RHR5 */ \ - STORE_BISCUIT(biscuit) /* RHR6 */ \ + STORE_BISCUIT(biscuit_ct) /* RHR6 */ \ ENCRYPT_AND_MIX(auth, empty) /* RHR7 */ \ - rh <- RespHello(sidr, sidi, ecti, scti, biscuit, auth); + rh <- RespHello(sidr, sidi, ecti, scti, biscuit_ct, auth); #define RESPHELLO_CONSUME() \ - let RespHello(sidr, sidi, ecti, scti, biscuit, auth) = rh in \ + let RespHello(sidr, sidi, ecti, scti, biscuit_ct, auth) = rh in \ /* not handled here */ /* RHI2 */ \ MIX2(sid2b(sidr), sid2b(sidi)) /* RHI3 */ \ DECAPS_AND_MIX(eski, epki, ecti) /* RHI4 */ \ DECAPS_AND_MIX(sski, spki, scti) /* RHI5 */ \ - MIX(biscuit) /* RHI6 */ \ + MIX(biscuit_ct) /* RHI6 */ \ DECRYPT_AND_MIX(DUMMY(empty), auth) /* RHI7 */ type InitConf_t. @@ -70,11 +70,11 @@ fun InitConf( #define INITCONF_PRODUCE() \ MIX2(sid2b(sidi), sid2b(sidr)) /* ICI3 */ \ ENCRYPT_AND_MIX(auth, empty) /* ICI4 */ \ - ic <- InitConf(sidi, sidr, biscuit, auth); + ic <- InitConf(sidi, sidr, biscuit_ct, auth); #define INITCONF_CONSUME() \ - let InitConf(sidi, sidr, biscuit, auth) = ic in \ - LOAD_BISCUIT(biscuit_no, biscuit) /* ICR1 */ \ + let InitConf(sidi, sidr, biscuit_ct, auth) = ic in \ + LOAD_BISCUIT(biscuit_no, biscuit_ct)/* ICR1 */ \ ENCRYPT_AND_MIX(rh_auth, empty) /* ICIR */ \ ck_rh <- ck; /* ---- */ /* TODO: Move into oracles.mpv */ \ MIX2(sid2b(sidi), sid2b(sidr)) /* ICR3 */ \ diff --git a/papers/whitepaper.md b/papers/whitepaper.md index f67a1ef..c006fb2 100644 --- a/papers/whitepaper.md +++ b/papers/whitepaper.md @@ -479,20 +479,20 @@ fn store_biscuit() { "biscuit additional data", spkr, sidi, sidr); let ct = XAEAD::enc(k, n, pt, ad); - let nct = concat(n, ct); + let biscuit_ct = concat(n, ct); - mix(nct) - nct + mix(biscuit_ct) + biscuit_ct } ``` -Note that the `mix(nct)` call updates the chaining key, but that update does not make it into the biscuit. Therefore, `mix(nct)` is reapplied in `load_biscuit`. The responder handshake code also needs to reapply any other operations modifying `ck` after calling `store_biscuit`. The handshake code on the initiator's side also needs to call `mix(nct)`. +Note that the `mix(biscuit_ct)` call updates the chaining key, but that update does not make it into the biscuit. Therefore, `mix(biscuit_ct)` is reapplied in `load_biscuit`. The responder handshake code also needs to reapply any other operations modifying `ck` after calling `store_biscuit`. The handshake code on the initiator's side also needs to call `mix(biscuit_ct)`. ```pseudorust -fn load_biscuit(nct) { +fn load_biscuit(biscuit_ct) { // Decrypt the biscuit let k = biscuit_key; - let (n, ct) = nct; + let (n, ct) = biscuit_ct; let ad = lhash( "biscuit additional data", spkr, sidi, sidr); @@ -512,7 +512,7 @@ fn load_biscuit(nct) { // Restore the chaining key ck ← pt.ck; - mix(nct); + mix(biscuit_ct); // Expose the biscuit no, // so the handshake code can differentiate @@ -955,6 +955,8 @@ Changes, in particular: ``` 16. Point out explicitly that we use KEMs from NIST-Competition Round 3. Include links to the competition submission packages. Update citations to reflect the exact specification version. 17. Consistent naming convention. Always use the term `secret key`, never `private key`. +18. `pidiC` -> `pidi_ct`; to make it clearer that this is a cipher text +19. Where we refer to the biscuit ciphertext, we now use the term `biscuit_ct`. Previously we had used various variable names such as `nct` (nonce followed by cipher text) or just plain `biscuit`. #### 2025-06-24 – Specifying the `osk` used for WireGuard as a protocol extension diff --git a/rosenpass/.test_vectors/crypto_server_test_vector_1.toml b/rosenpass/.test_vectors/crypto_server_test_vector_1.toml index 89b2e4b..14a1db1 100644 --- a/rosenpass/.test_vectors/crypto_server_test_vector_1.toml +++ b/rosenpass/.test_vectors/crypto_server_test_vector_1.toml @@ -150,7 +150,7 @@ test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:44" [[entries]] entry_type = "Output" -name = "ih.pidic" +name = "ih.pidi_ct" value = "Y3Wstn84+vmUb/a/CtWHFixkdyTFKEaE7joUFM0vBZPehPAeDOXls/u5I1PvViF6" code_location = "rosenpass/src/protocol/protocol.rs:3615" test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:44" diff --git a/rosenpass/src/hash_domains.rs b/rosenpass/src/hash_domains.rs index cc0333b..df64779 100644 --- a/rosenpass/src/hash_domains.rs +++ b/rosenpass/src/hash_domains.rs @@ -166,7 +166,7 @@ hash_domain_ns!( protocol, cookie_key, "cookie-key"); hash_domain_ns!( /// Hash domain based on [protocol] for calculating the peer id as transmitted (encrypted) - /// in [crate::msgs::InitHello::pidic]. + /// in [crate::msgs::InitHello::pidi_ct]. /// /// # Examples /// @@ -179,7 +179,7 @@ hash_domain_ns!( hash_domain_ns!( /// Hash domain based on [protocol] for calculating the additional data /// during [crate::msgs::Biscuit] encryption, storing the biscuit into - /// [crate::msgs::RespHello::biscuit]. + /// [crate::msgs::RespHello::biscuit_ct]. /// /// # Examples /// diff --git a/rosenpass/src/msgs.rs b/rosenpass/src/msgs.rs index f6ea1b6..9fbeba2 100644 --- a/rosenpass/src/msgs.rs +++ b/rosenpass/src/msgs.rs @@ -135,7 +135,7 @@ pub struct InitHello { /// Classic McEliece Ciphertext pub sctr: [u8; StaticKem::CT_LEN], /// Encryped: 16 byte hash of McEliece initiator static key - pub pidic: [u8; Aead::TAG_LEN + 32], + pub pidi_ct: [u8; Aead::TAG_LEN + 32], /// Encrypted TAI64N Time Stamp (against replay attacks) pub auth: [u8; Aead::TAG_LEN], } @@ -188,7 +188,7 @@ pub struct RespHello { /// Empty encrypted message (just an auth tag) pub auth: [u8; Aead::TAG_LEN], /// Responders handshake state in encrypted form - pub biscuit: [u8; BISCUIT_CT_LEN], + pub biscuit_ct: [u8; BISCUIT_CT_LEN], } /// This is the third message sent by the initiator to the responder @@ -233,7 +233,7 @@ pub struct InitConf { /// Copied from RespHello pub sidr: [u8; 4], /// Responders handshake state in encrypted form - pub biscuit: [u8; BISCUIT_CT_LEN], + pub biscuit_ct: [u8; BISCUIT_CT_LEN], /// Empty encrypted message (just an auth tag) pub auth: [u8; Aead::TAG_LEN], } diff --git a/rosenpass/src/protocol/protocol.rs b/rosenpass/src/protocol/protocol.rs index ff1a155..6b6dd61 100644 --- a/rosenpass/src/protocol/protocol.rs +++ b/rosenpass/src/protocol/protocol.rs @@ -3608,7 +3608,7 @@ impl CryptoServer { // IHI6 protocol_section!("IHI6", { hs.core.encrypt_and_mix( - ih.pidic.as_mut_slice(), + ih.pidi_ct.as_mut_slice(), self.pidm(peer.get(self).protocol_version.keyed_hash())? .as_ref(), )?; @@ -3707,7 +3707,7 @@ impl CryptoServer { // IHR6 let peer = protocol_section!("IHR6", { let mut peerid = PeerId::zero(); - core.decrypt_and_mix(&mut *peerid, &ih.pidic)?; + core.decrypt_and_mix(&mut *peerid, &ih.pidi_ct)?; self.find_peer(peerid) .with_context(|| format!("No such peer {peerid:?}."))? }); @@ -3784,7 +3784,7 @@ impl CryptoServer { // RHR6 protocol_section!("RHR6", { - core.store_biscuit_with_test_vector::(self, peer, &mut rh.biscuit)?; + core.store_biscuit_with_test_vector::(self, peer, &mut rh.biscuit_ct)?; TV::check_value( &test_values.chaining_key_rhr_6, &core.ck.clone().danger_into_secret(), @@ -3872,7 +3872,7 @@ impl CryptoServer { // RHI6 protocol_section!("RHI6", { - core.mix(&rh.biscuit)?; + core.mix(&rh.biscuit_ct)?; }); // RHI7 @@ -3889,7 +3889,7 @@ impl CryptoServer { // ICI3 protocol_section!("ICI3", { core.mix(&ic.sidi)?.mix(&ic.sidr)?; - ic.biscuit.copy_from_slice(&rh.biscuit); + ic.biscuit_ct.copy_from_slice(&rh.biscuit_ct); }); // ICI4 @@ -3937,7 +3937,7 @@ impl CryptoServer { let (peer, biscuit_no, mut core) = protocol_section!("ICR1", { HandshakeState::load_biscuit( self, - &ic.biscuit, + &ic.biscuit_ct, SessionId::from_slice(&ic.sidi), SessionId::from_slice(&ic.sidr), keyed_hash,