From ac08801f184831a85112ea6b41b28ef8833cdb13 Mon Sep 17 00:00:00 2001 From: Kevin Lewi Date: Fri, 26 Feb 2021 15:18:10 -0800 Subject: [PATCH] Updating to version 0.4.0 and simplifying transcript computation logic in TripleDH (#148) --- CHANGELOG.md | 9 +++ Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 +- src/key_exchange/tripledh.rs | 103 +++++++++++++---------------------- src/lib.rs | 2 +- 6 files changed, 51 insertions(+), 71 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 49014dd..eb59e6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 0.4.0 (February 26, 2020) + +* Adherence to protocol format described in + https://tools.ietf.org/html/draft-irtf-cfrg-opaque-03 +* Renamed to_bytes() and try_from() to serialize() and deserialize() for + top-level structs +* Conformed all message type parameters to be parameterized in the + Ciphersuite object + ## 0.3.1 (February 11, 2020) * Re-exporting the rand library (and including it as a dependency instead of diff --git a/Cargo.lock b/Cargo.lock index 7d3e52e..1af35cf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -573,7 +573,7 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "opaque-ke" -version = "0.4.0-pre.1" +version = "0.4.0" dependencies = [ "anyhow", "base64", diff --git a/Cargo.toml b/Cargo.toml index 3688efe..6f3776d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "opaque-ke" -version = "0.4.0-pre.1" +version = "0.4.0" repository = "https://github.com/novifinancial/opaque-ke" keywords = ["cryptography", "crypto", "opaque", "passwords", "authentication"] description = "An implementation of the OPAQUE password-authenticated key exchange protocol" diff --git a/README.md b/README.md index 23e16d7..f00e4d8 100644 --- a/README.md +++ b/README.md @@ -22,14 +22,14 @@ Installation Add the following line to the dependencies of your `Cargo.toml`: ``` -opaque-ke = "0.3.1" +opaque-ke = "0.4.0" ``` Resources --------- - [OPAQUE academic publication](https://eprint.iacr.org/2018/163.pdf), including formal definitions and a proof of security -- [draft-irtf-cfrg-opaque-02](https://www.ietf.org/archive/id/draft-irtf-cfrg-opaque-02.html), containing a detailed (byte-level) specification for OPAQUE +- [draft-irtf-cfrg-opaque-03](https://www.ietf.org/archive/id/draft-irtf-cfrg-opaque-03.html), containing a detailed (byte-level) specification for OPAQUE - ["Let's talk about PAKE"](https://blog.cryptographyengineering.com/2018/10/19/lets-talk-about-pake/), an introductory blog post written by Matthew Green that covers OPAQUE Contributors diff --git a/src/key_exchange/tripledh.rs b/src/key_exchange/tripledh.rs index 6f8fc33..708158a 100644 --- a/src/key_exchange/tripledh.rs +++ b/src/key_exchange/tripledh.rs @@ -34,9 +34,9 @@ static STR_3DH: &[u8] = b"3DH"; static STR_CLIENT_MAC: &[u8] = b"client mac"; static STR_HANDSHAKE_SECRET: &[u8] = b"handshake secret"; static STR_SERVER_MAC: &[u8] = b"server mac"; -static STR_SERVER_ENC: &[u8] = b"handshake enc"; +static STR_HANDSHAKE_ENC: &[u8] = b"handshake enc"; static STR_ENCRYPTION_PAD: &[u8] = b"encryption pad"; -static STR_SESSION_KEY: &[u8] = b"session secret"; +static STR_SESSION_SECRET: &[u8] = b"session secret"; static STR_OPAQUE: &[u8] = b"OPAQUE "; #[allow(clippy::upper_case_acronyms)] @@ -87,21 +87,14 @@ impl KeyExchange for TripleDH { let server_e_kp = KeyPair::::generate_random(rng); let server_nonce = generate_nonce::(rng); - let server_transcript = [ - &l2_bytes[..], - &server_nonce[..], - &server_e_kp.public().to_arr(), - ] - .concat(); - - let derivation_transcript = [ - STR_3DH, - &serialize(&id_u, 2), - &serialized_credential_request[..], - &serialize(&id_s, 2), - &server_transcript[..], - ] - .concat(); + let mut transcript_hasher = D::new() + .chain(STR_3DH) + .chain(&serialize(&id_u, 2)) + .chain(&serialized_credential_request[..]) + .chain(&serialize(&id_s, 2)) + .chain(&l2_bytes[..]) + .chain(&server_nonce[..]) + .chain(&server_e_kp.public().to_arr()); let (session_key, km2, ke2, km3) = derive_3dh_keys::( TripleDHComponents { @@ -112,7 +105,7 @@ impl KeyExchange for TripleDH { pk3: client_s_pk, sk3: server_e_kp.private().clone(), }, - &derivation_transcript, + &transcript_hasher.clone().finalize(), )?; // Compute encryption of e_info @@ -126,27 +119,20 @@ impl KeyExchange for TripleDH { .map(|(&x1, &x2)| x1 ^ x2) .collect(); - let transcript2: Vec = - [&derivation_transcript[..], &serialize(&ciphertext, 2)].concat(); - - let mut hasher = D::new(); - hasher.update(&transcript2); - let hashed_transcript_without_mac = hasher.finalize_reset(); + transcript_hasher.update(&serialize(&ciphertext, 2)); let mut mac_hasher = Hmac::::new_varkey(&km2).map_err(|_| InternalPakeError::HmacError)?; - mac_hasher.update(&hashed_transcript_without_mac); + mac_hasher.update(&transcript_hasher.clone().finalize()); let mac = mac_hasher.finalize().into_bytes(); - hasher.update(&transcript2); - hasher.update(&mac); - let hashed_transcript = hasher.finalize(); + transcript_hasher.update(&mac); Ok(( ke1_message.info, Ke2State { km3, - hashed_transcript, + hashed_transcript: transcript_hasher.finalize(), session_key, }, Ke2Message { @@ -169,20 +155,13 @@ impl KeyExchange for TripleDH { id_u: Vec, id_s: Vec, ) -> Result<(Vec, Vec, Self::KE3Message), ProtocolError> { - let server_transcript = [ - &l2_component[..], - &ke2_message.to_bytes_without_info_or_mac(), - ] - .concat(); - - let derivation_transcript = [ - STR_3DH, - &serialize(&id_u, 2), - &serialized_credential_request, - &serialize(&id_s, 2), - &server_transcript[..], - ] - .concat(); + let mut transcript_hasher = D::new() + .chain(STR_3DH) + .chain(&serialize(&id_u, 2)) + .chain(&serialized_credential_request) + .chain(&serialize(&id_s, 2)) + .chain(&l2_component[..]) + .chain(&ke2_message.to_bytes_without_info_or_mac()); let (session_key, km2, ke2, km3) = derive_3dh_keys::( TripleDHComponents { @@ -193,22 +172,14 @@ impl KeyExchange for TripleDH { pk3: ke2_message.server_e_pk.clone(), sk3: client_s_sk, }, - &derivation_transcript, + &transcript_hasher.clone().finalize(), )?; - let transcript: Vec = [ - &derivation_transcript[..], - &serialize(&ke2_message.e_info[..], 2), - ] - .concat(); - - let mut hasher = D::new(); - hasher.update(&transcript); - let hashed_transcript_without_mac = hasher.finalize_reset(); + transcript_hasher.update(&serialize(&ke2_message.e_info[..], 2)); let mut server_mac = Hmac::::new_varkey(&km2).map_err(|_| InternalPakeError::HmacError)?; - server_mac.update(&hashed_transcript_without_mac); + server_mac.update(&transcript_hasher.clone().finalize()); if ke2_message.mac != server_mac.finalize().into_bytes() { return Err(ProtocolError::VerificationError( @@ -216,13 +187,11 @@ impl KeyExchange for TripleDH { )); } - hasher.update(transcript); - hasher.update(ke2_message.mac.to_vec()); - let hashed_transcript = hasher.finalize(); + transcript_hasher.update(ke2_message.mac.to_vec()); let mut client_mac = Hmac::::new_varkey(&km3).map_err(|_| InternalPakeError::HmacError)?; - client_mac.update(&hashed_transcript); + client_mac.update(&transcript_hasher.finalize()); // Compute decryption of e_info let h = Hkdf::::from_prk(&ke2).map_err(|_| InternalPakeError::HkdfError)?; @@ -467,7 +436,7 @@ impl> TryFrom<&[u8]> for Ke3Message { // with some auxiliary metadata, to produce the session key and two MAC keys fn derive_3dh_keys( dh: TripleDHComponents, - derivation_transcript: &[u8], + hashed_derivation_transcript: &[u8], ) -> Result, ProtocolError> { let ikm: Vec = [ &KeyPair::::diffie_hellman(dh.pk1, dh.sk1)?[..], @@ -480,10 +449,13 @@ fn derive_3dh_keys( let handshake_secret = derive_secrets::( &extracted_ikm, &STR_HANDSHAKE_SECRET, - &derivation_transcript, + &hashed_derivation_transcript, + )?; + let session_key = derive_secrets::( + &extracted_ikm, + &STR_SESSION_SECRET, + &hashed_derivation_transcript, )?; - let session_key = - derive_secrets::(&extracted_ikm, &STR_SESSION_KEY, &derivation_transcript)?; let km2 = hkdf_expand_label::( &handshake_secret, @@ -493,7 +465,7 @@ fn derive_3dh_keys( )?; let ke2 = hkdf_expand_label::( &handshake_secret, - &STR_SERVER_ENC, + &STR_HANDSHAKE_ENC, b"", ::OutputSize::to_usize(), )?; @@ -548,13 +520,12 @@ fn hkdf_expand_label_extracted( fn derive_secrets( hkdf: &Hkdf, label: &[u8], - transcript: &[u8], + hashed_derivation_transcript: &[u8], ) -> Result, ProtocolError> { - let hashed_transcript = D::digest(transcript); hkdf_expand_label_extracted::( hkdf, label, - &hashed_transcript, + &hashed_derivation_transcript, ::OutputSize::to_usize(), ) } diff --git a/src/lib.rs b/src/lib.rs index 81e3ca7..ad39f38 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,7 +5,7 @@ //! An implementation of the OPAQUE asymmetric password authentication key exchange protocol //! -//! Note: This implementation is in sync with [draft-irtf-cfrg-opaque-02](https://www.ietf.org/archive/id/draft-irtf-cfrg-opaque-02.html), +//! Note: This implementation is in sync with [draft-irtf-cfrg-opaque-03](https://www.ietf.org/archive/id/draft-irtf-cfrg-opaque-03.html), //! but this specification is subject to change, until the final version published by the IETF. //! //! # Overview