Updating to version 0.4.0 and simplifying transcript computation logic in TripleDH (#148)
This commit is contained in:
@@ -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
|
||||
|
||||
Generated
+1
-1
@@ -573,7 +573,7 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
||||
|
||||
[[package]]
|
||||
name = "opaque-ke"
|
||||
version = "0.4.0-pre.1"
|
||||
version = "0.4.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64",
|
||||
|
||||
+1
-1
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<D: Hash, G: Group> KeyExchange<D, G> for TripleDH {
|
||||
let server_e_kp = KeyPair::<G>::generate_random(rng);
|
||||
let server_nonce = generate_nonce::<R>(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::<D, G>(
|
||||
TripleDHComponents {
|
||||
@@ -112,7 +105,7 @@ impl<D: Hash, G: Group> KeyExchange<D, G> 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<D: Hash, G: Group> KeyExchange<D, G> for TripleDH {
|
||||
.map(|(&x1, &x2)| x1 ^ x2)
|
||||
.collect();
|
||||
|
||||
let transcript2: Vec<u8> =
|
||||
[&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::<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();
|
||||
|
||||
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<D: Hash, G: Group> KeyExchange<D, G> for TripleDH {
|
||||
id_u: Vec<u8>,
|
||||
id_s: Vec<u8>,
|
||||
) -> Result<(Vec<u8>, Vec<u8>, 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::<D, G>(
|
||||
TripleDHComponents {
|
||||
@@ -193,22 +172,14 @@ impl<D: Hash, G: Group> KeyExchange<D, G> for TripleDH {
|
||||
pk3: ke2_message.server_e_pk.clone(),
|
||||
sk3: client_s_sk,
|
||||
},
|
||||
&derivation_transcript,
|
||||
&transcript_hasher.clone().finalize(),
|
||||
)?;
|
||||
|
||||
let transcript: Vec<u8> = [
|
||||
&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::<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() {
|
||||
return Err(ProtocolError::VerificationError(
|
||||
@@ -216,13 +187,11 @@ impl<D: Hash, G: Group> KeyExchange<D, G> 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::<D>::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::<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
|
||||
fn derive_3dh_keys<D: Hash, G: Group>(
|
||||
dh: TripleDHComponents,
|
||||
derivation_transcript: &[u8],
|
||||
hashed_derivation_transcript: &[u8],
|
||||
) -> Result<TripleDHDerivationResult<D>, ProtocolError> {
|
||||
let ikm: Vec<u8> = [
|
||||
&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>(
|
||||
&extracted_ikm,
|
||||
&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>(
|
||||
&handshake_secret,
|
||||
@@ -493,7 +465,7 @@ fn derive_3dh_keys<D: Hash, G: Group>(
|
||||
)?;
|
||||
let ke2 = hkdf_expand_label::<D>(
|
||||
&handshake_secret,
|
||||
&STR_SERVER_ENC,
|
||||
&STR_HANDSHAKE_ENC,
|
||||
b"",
|
||||
<D as Digest>::OutputSize::to_usize(),
|
||||
)?;
|
||||
@@ -548,13 +520,12 @@ fn hkdf_expand_label_extracted<D: Hash>(
|
||||
fn derive_secrets<D: Hash>(
|
||||
hkdf: &Hkdf<D>,
|
||||
label: &[u8],
|
||||
transcript: &[u8],
|
||||
hashed_derivation_transcript: &[u8],
|
||||
) -> Result<Vec<u8>, ProtocolError> {
|
||||
let hashed_transcript = D::digest(transcript);
|
||||
hkdf_expand_label_extracted::<D>(
|
||||
hkdf,
|
||||
label,
|
||||
&hashed_transcript,
|
||||
&hashed_derivation_transcript,
|
||||
<D as Digest>::OutputSize::to_usize(),
|
||||
)
|
||||
}
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user