Updating to version 0.4.0 and simplifying transcript computation logic in TripleDH (#148)

This commit is contained in:
Kevin Lewi
2021-02-26 15:18:10 -08:00
committed by GitHub
parent a49e089e54
commit ac08801f18
6 changed files with 51 additions and 71 deletions
+9
View File
@@ -1,5 +1,14 @@
# Changelog # 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) ## 0.3.1 (February 11, 2020)
* Re-exporting the rand library (and including it as a dependency instead of * Re-exporting the rand library (and including it as a dependency instead of
Generated
+1 -1
View File
@@ -573,7 +573,7 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]] [[package]]
name = "opaque-ke" name = "opaque-ke"
version = "0.4.0-pre.1" version = "0.4.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"base64", "base64",
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "opaque-ke" name = "opaque-ke"
version = "0.4.0-pre.1" version = "0.4.0"
repository = "https://github.com/novifinancial/opaque-ke" repository = "https://github.com/novifinancial/opaque-ke"
keywords = ["cryptography", "crypto", "opaque", "passwords", "authentication"] keywords = ["cryptography", "crypto", "opaque", "passwords", "authentication"]
description = "An implementation of the OPAQUE password-authenticated key exchange protocol" description = "An implementation of the OPAQUE password-authenticated key exchange protocol"
+2 -2
View File
@@ -22,14 +22,14 @@ Installation
Add the following line to the dependencies of your `Cargo.toml`: Add the following line to the dependencies of your `Cargo.toml`:
``` ```
opaque-ke = "0.3.1" opaque-ke = "0.4.0"
``` ```
Resources Resources
--------- ---------
- [OPAQUE academic publication](https://eprint.iacr.org/2018/163.pdf), including formal definitions and a proof of security - [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 - ["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 Contributors
+37 -66
View File
@@ -34,9 +34,9 @@ static STR_3DH: &[u8] = b"3DH";
static STR_CLIENT_MAC: &[u8] = b"client mac"; static STR_CLIENT_MAC: &[u8] = b"client mac";
static STR_HANDSHAKE_SECRET: &[u8] = b"handshake secret"; static STR_HANDSHAKE_SECRET: &[u8] = b"handshake secret";
static STR_SERVER_MAC: &[u8] = b"server mac"; 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_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 "; static STR_OPAQUE: &[u8] = b"OPAQUE ";
#[allow(clippy::upper_case_acronyms)] #[allow(clippy::upper_case_acronyms)]
@@ -87,21 +87,14 @@ impl<D: Hash, G: Group> KeyExchange<D, G> for TripleDH {
let server_e_kp = KeyPair::<G>::generate_random(rng); let server_e_kp = KeyPair::<G>::generate_random(rng);
let server_nonce = generate_nonce::<R>(rng); let server_nonce = generate_nonce::<R>(rng);
let server_transcript = [ let mut transcript_hasher = D::new()
&l2_bytes[..], .chain(STR_3DH)
&server_nonce[..], .chain(&serialize(&id_u, 2))
&server_e_kp.public().to_arr(), .chain(&serialized_credential_request[..])
] .chain(&serialize(&id_s, 2))
.concat(); .chain(&l2_bytes[..])
.chain(&server_nonce[..])
let derivation_transcript = [ .chain(&server_e_kp.public().to_arr());
STR_3DH,
&serialize(&id_u, 2),
&serialized_credential_request[..],
&serialize(&id_s, 2),
&server_transcript[..],
]
.concat();
let (session_key, km2, ke2, km3) = derive_3dh_keys::<D, G>( let (session_key, km2, ke2, km3) = derive_3dh_keys::<D, G>(
TripleDHComponents { TripleDHComponents {
@@ -112,7 +105,7 @@ impl<D: Hash, G: Group> KeyExchange<D, G> for TripleDH {
pk3: client_s_pk, pk3: client_s_pk,
sk3: server_e_kp.private().clone(), sk3: server_e_kp.private().clone(),
}, },
&derivation_transcript, &transcript_hasher.clone().finalize(),
)?; )?;
// Compute encryption of e_info // Compute encryption of e_info
@@ -126,27 +119,20 @@ impl<D: Hash, G: Group> KeyExchange<D, G> for TripleDH {
.map(|(&x1, &x2)| x1 ^ x2) .map(|(&x1, &x2)| x1 ^ x2)
.collect(); .collect();
let transcript2: Vec<u8> = transcript_hasher.update(&serialize(&ciphertext, 2));
[&derivation_transcript[..], &serialize(&ciphertext, 2)].concat();
let mut hasher = D::new();
hasher.update(&transcript2);
let hashed_transcript_without_mac = hasher.finalize_reset();
let mut mac_hasher = let mut mac_hasher =
Hmac::<D>::new_varkey(&km2).map_err(|_| InternalPakeError::HmacError)?; Hmac::<D>::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(); let mac = mac_hasher.finalize().into_bytes();
hasher.update(&transcript2); transcript_hasher.update(&mac);
hasher.update(&mac);
let hashed_transcript = hasher.finalize();
Ok(( Ok((
ke1_message.info, ke1_message.info,
Ke2State { Ke2State {
km3, km3,
hashed_transcript, hashed_transcript: transcript_hasher.finalize(),
session_key, session_key,
}, },
Ke2Message { Ke2Message {
@@ -169,20 +155,13 @@ impl<D: Hash, G: Group> KeyExchange<D, G> for TripleDH {
id_u: Vec<u8>, id_u: Vec<u8>,
id_s: Vec<u8>, id_s: Vec<u8>,
) -> Result<(Vec<u8>, Vec<u8>, Self::KE3Message), ProtocolError> { ) -> Result<(Vec<u8>, Vec<u8>, Self::KE3Message), ProtocolError> {
let server_transcript = [ let mut transcript_hasher = D::new()
&l2_component[..], .chain(STR_3DH)
&ke2_message.to_bytes_without_info_or_mac(), .chain(&serialize(&id_u, 2))
] .chain(&serialized_credential_request)
.concat(); .chain(&serialize(&id_s, 2))
.chain(&l2_component[..])
let derivation_transcript = [ .chain(&ke2_message.to_bytes_without_info_or_mac());
STR_3DH,
&serialize(&id_u, 2),
&serialized_credential_request,
&serialize(&id_s, 2),
&server_transcript[..],
]
.concat();
let (session_key, km2, ke2, km3) = derive_3dh_keys::<D, G>( let (session_key, km2, ke2, km3) = derive_3dh_keys::<D, G>(
TripleDHComponents { TripleDHComponents {
@@ -193,22 +172,14 @@ impl<D: Hash, G: Group> KeyExchange<D, G> for TripleDH {
pk3: ke2_message.server_e_pk.clone(), pk3: ke2_message.server_e_pk.clone(),
sk3: client_s_sk, sk3: client_s_sk,
}, },
&derivation_transcript, &transcript_hasher.clone().finalize(),
)?; )?;
let transcript: Vec<u8> = [ transcript_hasher.update(&serialize(&ke2_message.e_info[..], 2));
&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();
let mut server_mac = let mut server_mac =
Hmac::<D>::new_varkey(&km2).map_err(|_| InternalPakeError::HmacError)?; Hmac::<D>::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() { if ke2_message.mac != server_mac.finalize().into_bytes() {
return Err(ProtocolError::VerificationError( return Err(ProtocolError::VerificationError(
@@ -216,13 +187,11 @@ impl<D: Hash, G: Group> KeyExchange<D, G> for TripleDH {
)); ));
} }
hasher.update(transcript); transcript_hasher.update(ke2_message.mac.to_vec());
hasher.update(ke2_message.mac.to_vec());
let hashed_transcript = hasher.finalize();
let mut client_mac = let mut client_mac =
Hmac::<D>::new_varkey(&km3).map_err(|_| InternalPakeError::HmacError)?; Hmac::<D>::new_varkey(&km3).map_err(|_| InternalPakeError::HmacError)?;
client_mac.update(&hashed_transcript); client_mac.update(&transcript_hasher.finalize());
// Compute decryption of e_info // Compute decryption of e_info
let h = Hkdf::<D>::from_prk(&ke2).map_err(|_| InternalPakeError::HkdfError)?; let h = Hkdf::<D>::from_prk(&ke2).map_err(|_| InternalPakeError::HkdfError)?;
@@ -467,7 +436,7 @@ impl<HashLen: ArrayLength<u8>> TryFrom<&[u8]> for Ke3Message<HashLen> {
// with some auxiliary metadata, to produce the session key and two MAC keys // with some auxiliary metadata, to produce the session key and two MAC keys
fn derive_3dh_keys<D: Hash, G: Group>( fn derive_3dh_keys<D: Hash, G: Group>(
dh: TripleDHComponents, dh: TripleDHComponents,
derivation_transcript: &[u8], hashed_derivation_transcript: &[u8],
) -> Result<TripleDHDerivationResult<D>, ProtocolError> { ) -> Result<TripleDHDerivationResult<D>, ProtocolError> {
let ikm: Vec<u8> = [ let ikm: Vec<u8> = [
&KeyPair::<G>::diffie_hellman(dh.pk1, dh.sk1)?[..], &KeyPair::<G>::diffie_hellman(dh.pk1, dh.sk1)?[..],
@@ -480,10 +449,13 @@ fn derive_3dh_keys<D: Hash, G: Group>(
let handshake_secret = derive_secrets::<D>( let handshake_secret = derive_secrets::<D>(
&extracted_ikm, &extracted_ikm,
&STR_HANDSHAKE_SECRET, &STR_HANDSHAKE_SECRET,
&derivation_transcript, &hashed_derivation_transcript,
)?;
let session_key = derive_secrets::<D>(
&extracted_ikm,
&STR_SESSION_SECRET,
&hashed_derivation_transcript,
)?; )?;
let session_key =
derive_secrets::<D>(&extracted_ikm, &STR_SESSION_KEY, &derivation_transcript)?;
let km2 = hkdf_expand_label::<D>( let km2 = hkdf_expand_label::<D>(
&handshake_secret, &handshake_secret,
@@ -493,7 +465,7 @@ fn derive_3dh_keys<D: Hash, G: Group>(
)?; )?;
let ke2 = hkdf_expand_label::<D>( let ke2 = hkdf_expand_label::<D>(
&handshake_secret, &handshake_secret,
&STR_SERVER_ENC, &STR_HANDSHAKE_ENC,
b"", b"",
<D as Digest>::OutputSize::to_usize(), <D as Digest>::OutputSize::to_usize(),
)?; )?;
@@ -548,13 +520,12 @@ fn hkdf_expand_label_extracted<D: Hash>(
fn derive_secrets<D: Hash>( fn derive_secrets<D: Hash>(
hkdf: &Hkdf<D>, hkdf: &Hkdf<D>,
label: &[u8], label: &[u8],
transcript: &[u8], hashed_derivation_transcript: &[u8],
) -> Result<Vec<u8>, ProtocolError> { ) -> Result<Vec<u8>, ProtocolError> {
let hashed_transcript = D::digest(transcript);
hkdf_expand_label_extracted::<D>( hkdf_expand_label_extracted::<D>(
hkdf, hkdf,
label, label,
&hashed_transcript, &hashed_derivation_transcript,
<D as Digest>::OutputSize::to_usize(), <D as Digest>::OutputSize::to_usize(),
) )
} }
+1 -1
View File
@@ -5,7 +5,7 @@
//! An implementation of the OPAQUE asymmetric password authentication key exchange protocol //! 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. //! but this specification is subject to change, until the final version published by the IETF.
//! //!
//! # Overview //! # Overview