Adding a hash type to CipherSuite (#24)

This commit is contained in:
Kevin Lewi
2020-07-27 15:25:04 -07:00
committed by GitHub
parent 72a3928cbb
commit c2edb2d95e
15 changed files with 570 additions and 492 deletions
Generated
+345 -346
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -18,6 +18,7 @@ u32_backend = ["curve25519-dalek/u32_backend", "x25519-dalek/u32_backend"]
[dependencies]
curve25519-dalek = { version = "2.1.0", default-features = false, features = ["std"]}
digest = "0.9.0"
displaydoc = "0.1.7"
generic-array = "0.14.3"
hkdf = "0.9.0"
+7 -4
View File
@@ -7,6 +7,7 @@
use crate::{
errors::InternalPakeError,
hash::Hash,
key_exchange::traits::KeyExchange,
keypair::{Key, KeyPair},
map_to_curve::GroupWithMapToCurve,
@@ -22,7 +23,8 @@ use rand_core::{CryptoRng, RngCore};
/// `map_to_curve::GroupWithMapToCurve`.
/// * `KeyFormat`: a keypair type composed of public and private components
/// * `KeyExchange`: The key exchange protocol to use in the login step
/// * `SlowHash`: a slow hashing function, typically used for password hashing
/// * `Hash`: The main hashing function to use
/// * `SlowHash`: A slow hashing function, typically used for password hashing
pub trait CipherSuite {
/// A finite cyclic group along with a point representation along with
/// an extension trait PasswordToCurve that allows some customization on
@@ -32,10 +34,11 @@ pub trait CipherSuite {
/// A keypair type composed of public and private components
type KeyFormat: KeyPair<Repr = Key> + PartialEq;
/// A key exchange protocol
type KeyExchange: KeyExchange;
type KeyExchange: KeyExchange<Self::Hash>;
/// The main hash function use (for HKDF computations and hashing transcripts)
type Hash: Hash;
/// A slow hashing function, typically used for password hashing
type SlowHash: SlowHash;
type SlowHash: SlowHash<Self::Hash>;
/// Generating a random key pair given a cryptographic rng
fn generate_random_keypair<R: RngCore + CryptoRng>(
rng: &mut R,
+32 -22
View File
@@ -4,6 +4,8 @@
// LICENSE file in the root directory of this source tree.
use crate::errors::InternalPakeError;
use crate::hash::Hash;
use digest::Digest;
use generic_array::{
typenum::{Unsigned, U32},
GenericArray,
@@ -11,7 +13,6 @@ use generic_array::{
use hkdf::Hkdf;
use hmac::{Hmac, Mac, NewMac};
use rand_core::{CryptoRng, RngCore};
use sha2::Sha256;
// Constant string used as salt for HKDF computation
const STR_ENVU: &[u8] = b"EnvU";
@@ -32,31 +33,40 @@ const NONCE_LEN: usize = 32;
/// The specification update has simplified this assumption by taking
/// an XOR-based approach without compromising on security, and to avoid
/// the confusion around the implementation of an RKR-secure encryption.
pub(crate) struct Envelope {
pub(crate) struct Envelope<D: Hash> {
nonce: Vec<u8>,
ciphertext: Vec<u8>,
hmac: GenericArray<u8, U32>,
hmac: GenericArray<u8, <D as Digest>::OutputSize>,
}
impl Envelope {
pub(crate) struct OpenedEnvelope {
pub(crate) plaintext: Vec<u8>,
pub(crate) export_key: GenericArray<u8, ExportKeySize>,
}
impl<D: Hash> Envelope<D> {
/// The additional number of bytes added to the plaintext
pub(crate) fn additional_size() -> usize {
NONCE_LEN + U32::to_usize()
NONCE_LEN + <D as Digest>::OutputSize::to_usize()
}
fn hmac_key_size() -> usize {
U32::to_usize()
<D as Digest>::OutputSize::to_usize()
}
fn hmac_size() -> usize {
U32::to_usize()
<D as Digest>::OutputSize::to_usize()
}
fn export_key_size() -> usize {
ExportKeySize::to_usize()
}
pub(crate) fn new(nonce: Vec<u8>, ciphertext: Vec<u8>, hmac: GenericArray<u8, U32>) -> Self {
pub(crate) fn new(
nonce: Vec<u8>,
ciphertext: Vec<u8>,
hmac: GenericArray<u8, <D as Digest>::OutputSize>,
) -> Self {
Self {
nonce,
ciphertext,
@@ -93,7 +103,7 @@ impl Envelope {
let mut nonce = vec![0u8; NONCE_LEN];
rng.fill_bytes(&mut nonce);
let h = Hkdf::<Sha256>::new(Some(&nonce), &key);
let h = Hkdf::<D>::new(Some(&nonce), &key);
let mut okm = vec![0u8; plaintext.len() + Self::hmac_key_size() + Self::export_key_size()];
h.expand(STR_ENVU, &mut okm)
.map_err(|_| InternalPakeError::HkdfError)?;
@@ -108,7 +118,7 @@ impl Envelope {
.collect();
let mut hmac =
Hmac::<Sha256>::new_varkey(&hmac_key).map_err(|_| InternalPakeError::HmacError)?;
Hmac::<D>::new_varkey(&hmac_key).map_err(|_| InternalPakeError::HmacError)?;
hmac.update(&ciphertext);
hmac.update(&aad);
@@ -120,12 +130,8 @@ impl Envelope {
/// Attempts to decrypt the envelope using a key, which is successful only if the key and
/// aad used to construct the envelope are the same.
pub(crate) fn open(
&self,
key: &[u8],
aad: &[u8],
) -> Result<(Vec<u8>, GenericArray<u8, ExportKeySize>), InternalPakeError> {
let h = Hkdf::<Sha256>::new(Some(&self.nonce), &key);
pub(crate) fn open(&self, key: &[u8], aad: &[u8]) -> Result<OpenedEnvelope, InternalPakeError> {
let h = Hkdf::<D>::new(Some(&self.nonce), &key);
let mut okm =
vec![0u8; self.ciphertext.len() + Self::hmac_key_size() + Self::export_key_size()];
h.expand(STR_ENVU, &mut okm)
@@ -135,7 +141,7 @@ impl Envelope {
let export_key = &okm[self.ciphertext.len() + Self::hmac_key_size()..];
let mut hmac =
Hmac::<Sha256>::new_varkey(&hmac_key).map_err(|_| InternalPakeError::HmacError)?;
Hmac::<D>::new_varkey(&hmac_key).map_err(|_| InternalPakeError::HmacError)?;
hmac.update(&self.ciphertext);
hmac.update(aad);
if hmac.verify(&self.hmac).is_err() {
@@ -147,7 +153,10 @@ impl Envelope {
.zip(self.ciphertext.iter())
.map(|(&x1, &x2)| x1 ^ x2)
.collect();
Ok((plaintext, *GenericArray::from_slice(&export_key)))
Ok(OpenedEnvelope {
plaintext,
export_key: *GenericArray::from_slice(&export_key),
})
}
}
@@ -165,9 +174,10 @@ mod tests {
let mut msg = [0u8; 100];
rng.fill_bytes(&mut msg);
let (ciphertext, export_key_1) = Envelope::seal(&key, &msg, b"aad", &mut rng).unwrap();
let (plaintext, export_key_2) = ciphertext.open(&key, b"aad").unwrap();
assert_eq!(&msg.to_vec(), &plaintext);
assert_eq!(&export_key_1.to_vec(), &export_key_2.to_vec());
let (envelope, export_key_1) =
Envelope::<sha2::Sha256>::seal(&key, &msg, b"aad", &mut rng).unwrap();
let opened_envelope = envelope.open(&key, b"aad").unwrap();
assert_eq!(&msg.to_vec(), &opened_envelope.plaintext);
assert_eq!(&export_key_1.to_vec(), &opened_envelope.export_key.to_vec());
}
}
+8 -10
View File
@@ -13,14 +13,13 @@ use curve25519_dalek::{
ristretto::{CompressedRistretto, RistrettoPoint},
scalar::Scalar,
};
use digest::Digest;
use generic_array::{
typenum::{U32, U64},
ArrayLength, GenericArray,
};
use rand_core::{CryptoRng, RngCore};
use sha2::{Digest, Sha256};
use sha2::Sha256;
use std::ops::Mul;
use zeroize::Zeroize;
@@ -56,6 +55,7 @@ pub trait Group: Sized + for<'a> Mul<&'a <Self as Group>::Scalar, Output = Self>
/// may not be necessary as this function is going to be called with the
/// output of a kdf.
type UniformBytesLen: ArrayLength<u8>;
/// Hashes a slice of pseudo-random bytes of the correct length to a curve point
fn hash_to_curve(uniform_bytes: &GenericArray<u8, Self::UniformBytesLen>) -> Self;
}
@@ -98,11 +98,8 @@ impl Group for RistrettoPoint {
type UniformBytesLen = U64;
fn hash_to_curve(uniform_bytes: &GenericArray<u8, Self::UniformBytesLen>) -> Self {
// This is because RistrettoPoint is on an obsolete sha2 version, see https://github.com/dalek-cryptography/curve25519-dalek/pull/327
let mut bits = [0u8; 64];
let mut hasher = sha2::Sha512::new();
hasher.update(uniform_bytes);
bits.copy_from_slice(&hasher.finalize());
bits.copy_from_slice(&uniform_bytes);
RistrettoPoint::from_uniform_bytes(&bits)
}
@@ -146,16 +143,17 @@ impl Group for EdwardsPoint {
type UniformBytesLen = U32;
fn hash_to_curve(uniform_bytes: &GenericArray<u8, Self::UniformBytesLen>) -> Self {
let mut result = [0u8; 32];
const HASH_SIZE: usize = 32;
let mut result = [0u8; HASH_SIZE];
let mut counter = 0;
let mut wrapped_point: Option<EdwardsPoint> = None;
while wrapped_point.is_none() {
result.copy_from_slice(
&Sha256::new()
.chain(&uniform_bytes[..32])
.chain(&uniform_bytes[..HASH_SIZE])
.chain(&[counter])
.finalize()[..32],
.finalize()[..HASH_SIZE],
);
wrapped_point = CompressedEdwardsY::from_slice(&result).decompress();
counter += 1;
+22
View File
@@ -0,0 +1,22 @@
// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.
use digest::{BlockInput, FixedOutput, Reset, Update};
use generic_array::ArrayLength;
/// Trait inheriting the requirements from digest::Digest for compatibility with HKDF and HMAC
// Associated types could be simplified when they are made as defaults:
// https://github.com/rust-lang/rust/issues/29661
pub trait Hash: Update + BlockInput + FixedOutput + Reset + Default + Clone {
/// The block size for the hash function
type BlockSize: ArrayLength<u8>;
/// The output size of the hash function
type OutputSize: ArrayLength<u8>;
}
impl<T: Update + BlockInput + FixedOutput + Reset + Default + Clone> Hash for T {
type BlockSize = T::BlockSize;
type OutputSize = T::OutputSize;
}
+2 -1
View File
@@ -5,13 +5,14 @@
use crate::{
errors::{InternalPakeError, ProtocolError},
hash::Hash,
keypair::{Key, KeyPair},
};
use rand_core::{CryptoRng, RngCore};
use std::convert::TryFrom;
pub trait KeyExchange {
pub trait KeyExchange<D: Hash> {
type KE1State: TryFrom<Vec<u8>, Error = InternalPakeError> + ToBytes;
type KE2State: TryFrom<Vec<u8>, Error = ProtocolError> + ToBytes;
type KE1Message: TryFrom<Vec<u8>, Error = InternalPakeError> + ToBytes;
+24 -23
View File
@@ -6,10 +6,12 @@
//! An implementation of the Triple Diffie-Hellman key exchange protocol
use crate::{
errors::{utils::check_slice_size, InternalPakeError, PakeError, ProtocolError},
hash::Hash,
key_exchange::traits::{KeyExchange, ToBytes},
keypair::{Key, KeyPair, SizedBytes},
sized_bytes_using_constant_and_try_from,
};
use digest::Digest;
use generic_array::{
typenum::{U64, U96},
GenericArray,
@@ -18,7 +20,6 @@ use hkdf::Hkdf;
use hmac::{Hmac, Mac, NewMac};
use rand_core::{CryptoRng, RngCore};
use sha2::{Digest, Sha256};
use std::convert::TryFrom;
const KEY_LEN: usize = 32;
@@ -29,9 +30,9 @@ const KE2_MESSAGE_LEN: usize = NONCE_LEN + 2 * KEY_LEN;
static STR_3DH: &[u8] = b"3DH keys";
/// The Triple Diffie-Hellman key exchange implementation
pub struct TripleDH {}
pub struct TripleDH;
impl KeyExchange for TripleDH {
impl<D: Hash> KeyExchange<D> for TripleDH {
type KE1State = KE1State;
type KE2State = KE2State;
type KE1Message = KE1Message;
@@ -52,7 +53,7 @@ impl KeyExchange for TripleDH {
};
let l1_data: Vec<u8> = [&l1_component[..], &ke1_message.to_bytes()].concat();
let mut hasher = Sha256::new();
let mut hasher = D::new();
hasher.update(&l1_data);
let hashed_l1 = hasher.finalize();
@@ -78,7 +79,7 @@ impl KeyExchange for TripleDH {
let mut server_nonce = [0u8; NONCE_LEN];
rng.fill_bytes(&mut server_nonce);
let (shared_secret, km2, km3) = derive_3dh_keys::<KeyFormat>(
let (shared_secret, km2, km3) = derive_3dh_keys::<KeyFormat, D>(
TripleDHComponents {
pk1: ke1_message.client_e_pk.clone(),
sk1: server_e_kp.private().clone(),
@@ -93,7 +94,7 @@ impl KeyExchange for TripleDH {
KeyFormat::public_from_private(&server_s_sk),
)?;
let mut hasher = Sha256::new();
let mut hasher = D::new();
hasher.update(&l1_bytes);
let hashed_l1 = hasher.finalize();
@@ -105,11 +106,11 @@ impl KeyExchange for TripleDH {
]
.concat();
let mut hasher2 = Sha256::new();
let mut hasher2 = D::new();
hasher2.update(&transcript2);
let hashed_transcript = hasher2.finalize();
let mut mac = Hmac::<Sha256>::new_varkey(&km2).map_err(|_| InternalPakeError::HmacError)?;
let mut mac = Hmac::<D>::new_varkey(&km2).map_err(|_| InternalPakeError::HmacError)?;
mac.update(&hashed_transcript);
Ok((
@@ -133,7 +134,7 @@ impl KeyExchange for TripleDH {
server_s_pk: KeyFormat::Repr,
client_s_sk: KeyFormat::Repr,
) -> Result<(Vec<u8>, Self::KE3Message), ProtocolError> {
let (shared_secret, km2, km3) = derive_3dh_keys::<KeyFormat>(
let (shared_secret, km2, km3) = derive_3dh_keys::<KeyFormat, D>(
TripleDHComponents {
pk1: ke2_message.server_e_pk.clone(),
sk1: ke1_state.client_e_sk.clone(),
@@ -156,12 +157,12 @@ impl KeyExchange for TripleDH {
]
.concat();
let mut hasher = Sha256::new();
let mut hasher = D::new();
hasher.update(&transcript);
let hashed_transcript = hasher.finalize();
let mut server_mac =
Hmac::<Sha256>::new_varkey(&km2).map_err(|_| InternalPakeError::HmacError)?;
Hmac::<D>::new_varkey(&km2).map_err(|_| InternalPakeError::HmacError)?;
server_mac.update(&hashed_transcript);
if ke2_message.mac != server_mac.finalize().into_bytes().to_vec() {
@@ -171,7 +172,7 @@ impl KeyExchange for TripleDH {
}
let mut client_mac =
Hmac::<Sha256>::new_varkey(&km3).map_err(|_| InternalPakeError::HmacError)?;
Hmac::<D>::new_varkey(&km3).map_err(|_| InternalPakeError::HmacError)?;
client_mac.update(&hashed_transcript);
Ok((
@@ -187,7 +188,7 @@ impl KeyExchange for TripleDH {
ke2_state: &Self::KE2State,
) -> Result<Vec<u8>, ProtocolError> {
let mut client_mac =
Hmac::<Sha256>::new_varkey(&ke2_state.km3).map_err(|_| InternalPakeError::HmacError)?;
Hmac::<D>::new_varkey(&ke2_state.km3).map_err(|_| InternalPakeError::HmacError)?;
client_mac.update(&ke2_state.hashed_transcript);
if ke3_message.mac != client_mac.finalize().into_bytes().to_vec() {
@@ -350,21 +351,21 @@ struct TripleDHComponents {
}
// Consists of a shared secret, followed by two mac keys
type TripleDHDerivationResult = (
GenericArray<u8, <Sha256 as Digest>::OutputSize>,
GenericArray<u8, <Sha256 as Digest>::OutputSize>,
GenericArray<u8, <Sha256 as Digest>::OutputSize>,
type TripleDHDerivationResult<D> = (
GenericArray<u8, <D as Hash>::OutputSize>,
GenericArray<u8, <D as Hash>::OutputSize>,
GenericArray<u8, <D as Hash>::OutputSize>,
);
// Internal function which takes the public and private components of the client and server keypairs, along
// with some auxiliary metadata, to produce the shared secret and two MAC keys
fn derive_3dh_keys<KeyFormat: KeyPair<Repr = Key>>(
fn derive_3dh_keys<KeyFormat: KeyPair<Repr = Key>, D: Hash>(
dh: TripleDHComponents,
client_nonce: &[u8],
server_nonce: &[u8],
client_s_pk: KeyFormat::Repr,
server_s_pk: KeyFormat::Repr,
) -> Result<TripleDHDerivationResult, ProtocolError> {
) -> Result<TripleDHDerivationResult<D>, ProtocolError> {
let ikm: Vec<u8> = [
&KeyFormat::diffie_hellman(dh.pk1, dh.sk1)[..],
&KeyFormat::diffie_hellman(dh.pk2, dh.sk2)[..],
@@ -383,13 +384,13 @@ fn derive_3dh_keys<KeyFormat: KeyPair<Repr = Key>>(
const OUTPUT_SIZE: usize = 32;
let mut okm = [0u8; 3 * OUTPUT_SIZE];
let h = Hkdf::<Sha256>::new(None, &ikm);
let h = Hkdf::<D>::new(None, &ikm);
h.expand(&info, &mut okm)
.map_err(|_| InternalPakeError::HkdfError)?;
Ok((
*GenericArray::from_slice(&okm[..OUTPUT_SIZE]),
*GenericArray::from_slice(&okm[OUTPUT_SIZE..2 * OUTPUT_SIZE]),
*GenericArray::from_slice(&okm[2 * OUTPUT_SIZE..]),
GenericArray::clone_from_slice(&okm[..OUTPUT_SIZE]),
GenericArray::clone_from_slice(&okm[OUTPUT_SIZE..2 * OUTPUT_SIZE]),
GenericArray::clone_from_slice(&okm[2 * OUTPUT_SIZE..]),
))
}
+13 -1
View File
@@ -14,7 +14,8 @@
//! to be kept consistent throughout protocol execution. These include:
//! * a finite cyclic group along with a point representation,
//! * a keypair type,
//! * a key exchange protocol, and
//! * a key exchange protocol,
//! * a hashing function, and
//! * a slow hashing function.
//!
//! We will use the following choices in this example:
@@ -25,6 +26,7 @@
//! type Group = curve25519_dalek::ristretto::RistrettoPoint;
//! type KeyFormat = opaque_ke::keypair::X25519KeyPair;
//! type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! type Hash = sha2::Sha256;
//! type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! }
//! ```
@@ -46,6 +48,7 @@
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type Hash = sha2::Sha256;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! # }
//! use rand_core::{OsRng, RngCore};
@@ -78,6 +81,7 @@
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type Hash = sha2::Sha256;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! # }
//! use rand_core::{OsRng, RngCore};
@@ -107,6 +111,7 @@
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type Hash = sha2::Sha256;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! # }
//! # use rand_core::{OsRng, RngCore};
@@ -139,6 +144,7 @@
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type Hash = sha2::Sha256;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! # }
//! # use rand_core::{OsRng, RngCore};
@@ -173,6 +179,7 @@
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type Hash = sha2::Sha256;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! # }
//! # use rand_core::{OsRng, RngCore};
@@ -215,6 +222,7 @@
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type Hash = sha2::Sha256;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! # }
//! # use rand_core::{OsRng, RngCore};
@@ -244,6 +252,7 @@
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type Hash = sha2::Sha256;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! # }
//! # use rand_core::{OsRng, RngCore};
@@ -288,6 +297,7 @@
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type Hash = sha2::Sha256;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! # }
//! # use rand_core::{OsRng, RngCore};
@@ -344,6 +354,7 @@
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type Hash = sha2::Sha256;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! # }
//! # use rand_core::{OsRng, RngCore};
@@ -400,6 +411,7 @@ pub mod opaque;
pub mod ciphersuite;
mod envelope;
mod hash;
pub mod group;
pub mod map_to_curve;
+4 -3
View File
@@ -11,8 +11,9 @@ use curve25519_dalek::{edwards::EdwardsPoint, ristretto::RistrettoPoint};
use generic_array::GenericArray;
use hkdf::Hkdf;
use sha2::{Sha256, Sha512};
/// A subtrait of Group specifying how to has a password into a point
/// A subtrait of Group specifying how to hash a password into a point
pub trait GroupWithMapToCurve: Group {
/// transforms a password and optional pepper into a curve point
fn map_to_curve(password: &[u8], pepper: Option<&[u8]>) -> Self;
@@ -20,14 +21,14 @@ pub trait GroupWithMapToCurve: Group {
impl GroupWithMapToCurve for RistrettoPoint {
fn map_to_curve(password: &[u8], pepper: Option<&[u8]>) -> Self {
let (hashed_input, _) = Hkdf::<sha2::Sha512>::extract(pepper, password);
let (hashed_input, _) = Hkdf::<Sha512>::extract(pepper, password);
<Self as Group>::hash_to_curve(GenericArray::from_slice(&hashed_input))
}
}
impl GroupWithMapToCurve for EdwardsPoint {
fn map_to_curve(password: &[u8], pepper: Option<&[u8]>) -> Self {
let (hashed_input, _) = Hkdf::<sha2::Sha256>::extract(pepper, password);
let (hashed_input, _) = Hkdf::<Sha256>::extract(pepper, password);
<Self as Group>::hash_to_curve(GenericArray::from_slice(&hashed_input))
}
}
+62 -44
View File
@@ -10,6 +10,7 @@ use crate::{
envelope::{Envelope, ExportKeySize},
errors::{utils::check_slice_size, InternalPakeError, PakeError, ProtocolError},
group::Group,
hash::Hash,
key_exchange::traits::{KeyExchange, ToBytes},
keypair::{Key, KeyPair, SizedBytes},
oprf,
@@ -87,17 +88,18 @@ where
/// The final message from the client, containing sealed cryptographic
/// identifiers
pub struct RegisterThirdMessage<KeyFormat: KeyPair> {
pub struct RegisterThirdMessage<KeyFormat: KeyPair, D: Hash> {
/// The "envelope" generated by the user, containing sealed
/// cryptographic identifiers
envelope: Envelope,
envelope: Envelope<D>,
/// The user's public key
client_s_pk: KeyFormat::Repr,
}
impl<KeyFormat> RegisterThirdMessage<KeyFormat>
impl<KeyFormat, D> RegisterThirdMessage<KeyFormat, D>
where
KeyFormat: KeyPair,
D: Hash,
{
/// byte representation for the registration upload message
pub fn to_bytes(&self) -> Vec<u8> {
@@ -105,15 +107,16 @@ where
}
}
impl<KeyFormat> TryFrom<&[u8]> for RegisterThirdMessage<KeyFormat>
impl<KeyFormat, D> TryFrom<&[u8]> for RegisterThirdMessage<KeyFormat, D>
where
KeyFormat: KeyPair,
D: Hash,
{
type Error = ProtocolError;
fn try_from(third_message_bytes: &[u8]) -> Result<Self, Self::Error> {
let key_len = <KeyFormat::Repr as SizedBytes>::Len::to_usize();
let envelope_size = key_len + Envelope::additional_size();
let envelope_size = key_len + Envelope::<D>::additional_size();
let checked_bytes = check_slice_size(
third_message_bytes,
envelope_size + key_len,
@@ -123,7 +126,7 @@ where
let client_s_pk = KeyFormat::check_public_key(unchecked_client_s_pk)?;
Ok(Self {
envelope: Envelope::from_bytes(&checked_bytes[..envelope_size])?,
envelope: Envelope::<D>::from_bytes(&checked_bytes[..envelope_size])?,
client_s_pk,
})
}
@@ -133,7 +136,7 @@ where
pub struct LoginFirstMessage<CS: CipherSuite> {
/// blinded password information
alpha: CS::Group,
ke1_message: <CS::KeyExchange as KeyExchange>::KE1Message,
ke1_message: <CS::KeyExchange as KeyExchange<CS::Hash>>::KE1Message,
}
impl<CS: CipherSuite> TryFrom<&[u8]> for LoginFirstMessage<CS> {
@@ -145,7 +148,7 @@ impl<CS: CipherSuite> TryFrom<&[u8]> for LoginFirstMessage<CS> {
let arr = GenericArray::from_slice(&first_message_bytes[..elem_len]);
let alpha = CS::Group::from_element_slice(arr)?;
let ke1_message = <CS::KeyExchange as KeyExchange>::KE1Message::try_from(
let ke1_message = <CS::KeyExchange as KeyExchange<CS::Hash>>::KE1Message::try_from(
first_message_bytes[elem_len..].to_vec(),
)?;
Ok(Self { alpha, ke1_message })
@@ -161,25 +164,27 @@ impl<CS: CipherSuite> LoginFirstMessage<CS> {
/// The answer sent by the server to the user, upon reception of the
/// login attempt.
pub struct LoginSecondMessage<Grp, KeyFormat, KE>
pub struct LoginSecondMessage<Grp, KeyFormat, KE, D>
where
KeyFormat: KeyPair<Repr = Key>,
KE: KeyExchange,
KE: KeyExchange<D>,
D: Hash,
{
_key_format: PhantomData<KeyFormat>,
_key_exchange: PhantomData<KE>,
/// the server's oprf output
beta: Grp,
/// the user's sealed information,
envelope: Envelope,
envelope: Envelope<D>,
ke2_message: KE::KE2Message,
}
impl<Grp, KeyFormat, KE> LoginSecondMessage<Grp, KeyFormat, KE>
impl<Grp, KeyFormat, KE, D> LoginSecondMessage<Grp, KeyFormat, KE, D>
where
Grp: Group,
KeyFormat: KeyPair<Repr = Key>,
KE: KeyExchange,
KE: KeyExchange<D>,
D: Hash,
{
/// byte representation for the login response
pub fn to_bytes(&self) -> Vec<u8> {
@@ -192,16 +197,17 @@ where
}
}
impl<Grp, KeyFormat, KE> TryFrom<&[u8]> for LoginSecondMessage<Grp, KeyFormat, KE>
impl<Grp, KeyFormat, KE, D> TryFrom<&[u8]> for LoginSecondMessage<Grp, KeyFormat, KE, D>
where
Grp: Group,
KeyFormat: KeyPair<Repr = Key>,
KE: KeyExchange,
KE: KeyExchange<D>,
D: Hash,
{
type Error = ProtocolError;
fn try_from(second_message_bytes: &[u8]) -> Result<Self, Self::Error> {
let key_len = <KeyFormat::Repr as SizedBytes>::Len::to_usize();
let envelope_size = key_len + Envelope::additional_size();
let envelope_size = key_len + Envelope::<D>::additional_size();
let elem_len = Grp::ElemLen::to_usize();
let ke2_message_size = KE::ke2_message_size();
let checked_slice = check_slice_size(
@@ -216,7 +222,8 @@ where
let arr = GenericArray::from_slice(beta_bytes);
let beta = Grp::from_element_slice(arr)?;
let envelope = Envelope::from_bytes(&checked_slice[elem_len..elem_len + envelope_size])?;
let envelope =
Envelope::<D>::from_bytes(&checked_slice[elem_len..elem_len + envelope_size])?;
let ke2_message =
KE::KE2Message::try_from(checked_slice[elem_len + envelope_size..].to_vec())?;
@@ -234,14 +241,15 @@ where
/// The answer sent by the client to the server, upon reception of the
/// sealed envelope
pub struct LoginThirdMessage<CS: CipherSuite> {
ke3_message: <CS::KeyExchange as KeyExchange>::KE3Message,
ke3_message: <CS::KeyExchange as KeyExchange<CS::Hash>>::KE3Message,
}
impl<CS: CipherSuite> TryFrom<&[u8]> for LoginThirdMessage<CS> {
type Error = ProtocolError;
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
let ke3_message = <CS::KeyExchange as KeyExchange>::KE3Message::try_from(bytes.to_vec())?;
let ke3_message =
<CS::KeyExchange as KeyExchange<CS::Hash>>::KE3Message::try_from(bytes.to_vec())?;
Ok(Self { ke3_message })
}
}
@@ -310,6 +318,7 @@ impl<CS: CipherSuite> ClientRegistration<CS> {
/// type Group = curve25519_dalek::ristretto::RistrettoPoint;
/// type KeyFormat = opaque_ke::keypair::X25519KeyPair;
/// type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
/// type Hash = sha2::Sha256;
/// type SlowHash = opaque_ke::slow_hash::NoOpHash;
/// }
/// let mut rng = OsRng;
@@ -336,8 +345,8 @@ impl<CS: CipherSuite> ClientRegistration<CS> {
}
}
type ClientRegistrationFinishResult<KeyFormat> = (
RegisterThirdMessage<KeyFormat>,
type ClientRegistrationFinishResult<KeyFormat, D> = (
RegisterThirdMessage<KeyFormat, D>,
GenericArray<u8, ExportKeySize>,
);
@@ -361,6 +370,7 @@ impl<CS: CipherSuite> ClientRegistration<CS> {
/// type Group = curve25519_dalek::ristretto::RistrettoPoint;
/// type KeyFormat = opaque_ke::keypair::X25519KeyPair;
/// type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
/// type Hash = sha2::Sha256;
/// type SlowHash = opaque_ke::slow_hash::NoOpHash;
/// }
/// let mut client_rng = OsRng;
@@ -378,16 +388,16 @@ impl<CS: CipherSuite> ClientRegistration<CS> {
r2: RegisterSecondMessage<CS::Group>,
server_s_pk: &<CS::KeyFormat as KeyPair>::Repr,
rng: &mut R,
) -> Result<ClientRegistrationFinishResult<CS::KeyFormat>, ProtocolError> {
) -> Result<ClientRegistrationFinishResult<CS::KeyFormat, CS::Hash>, ProtocolError> {
let client_static_keypair = CS::KeyFormat::generate_random(rng)?;
let password_derived_key = get_password_derived_key::<CS::Group, CS::SlowHash>(
let password_derived_key = get_password_derived_key::<CS::Group, CS::SlowHash, CS::Hash>(
self.password.clone(),
r2.beta,
&self.blinding_factor,
)?;
let (envelope, export_key) = Envelope::seal(
let (envelope, export_key) = Envelope::<CS::Hash>::seal(
&password_derived_key,
&client_static_keypair.private().to_arr(),
&server_s_pk.to_arr(),
@@ -434,7 +444,7 @@ impl<CS: CipherSuite> Drop for ClientLogin<CS> {
/// The state elements the server holds to record a registration
pub struct ServerRegistration<CS: CipherSuite> {
envelope: Option<Envelope>,
envelope: Option<Envelope<CS::Hash>>,
client_s_pk: Option<<CS::KeyFormat as KeyPair>::Repr>,
pub(crate) oprf_key: <CS::Group as Group>::Scalar,
}
@@ -452,7 +462,7 @@ where
fn try_from(server_registration_bytes: &[u8]) -> Result<Self, Self::Error> {
let key_len = <<CS::KeyFormat as KeyPair>::Repr as SizedBytes>::Len::to_usize();
let scalar_len = <CS::Group as Group>::ScalarLen::to_usize();
let envelope_size = key_len + Envelope::additional_size();
let envelope_size = key_len + Envelope::<CS::Hash>::additional_size();
if server_registration_bytes.len() == scalar_len {
return Ok(Self {
@@ -476,7 +486,7 @@ where
)?;
let client_s_pk = CS::KeyFormat::check_public_key(unchecked_client_s_pk)?;
Ok(Self {
envelope: Some(Envelope::from_bytes(
envelope: Some(Envelope::<CS::Hash>::from_bytes(
&checked_bytes[checked_bytes.len() - envelope_size..],
)?),
client_s_pk: Some(client_s_pk),
@@ -526,6 +536,7 @@ where
/// type Group = curve25519_dalek::ristretto::RistrettoPoint;
/// type KeyFormat = opaque_ke::keypair::X25519KeyPair;
/// type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
/// type Hash = sha2::Sha256;
/// type SlowHash = opaque_ke::slow_hash::NoOpHash;
/// }
/// let mut client_rng = OsRng;
@@ -573,6 +584,7 @@ where
/// type Group = curve25519_dalek::ristretto::RistrettoPoint;
/// type KeyFormat = opaque_ke::keypair::X25519KeyPair;
/// type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
/// type Hash = sha2::Sha256;
/// type SlowHash = opaque_ke::slow_hash::NoOpHash;
/// }
/// let mut client_rng = OsRng;
@@ -588,7 +600,7 @@ where
/// ```
pub fn finish(
self,
message: RegisterThirdMessage<CS::KeyFormat>,
message: RegisterThirdMessage<CS::KeyFormat, CS::Hash>,
) -> Result<Self, ProtocolError> {
Ok(Self {
envelope: Some(message.envelope),
@@ -610,7 +622,7 @@ pub struct ClientLogin<CS: CipherSuite> {
blinding_factor: <CS::Group as Group>::Scalar,
/// The user's password
password: Vec<u8>,
ke1_state: <CS::KeyExchange as KeyExchange>::KE1State,
ke1_state: <CS::KeyExchange as KeyExchange<CS::Hash>>::KE1State,
}
impl<CS: CipherSuite> TryFrom<&[u8]> for ClientLogin<CS> {
@@ -619,8 +631,8 @@ impl<CS: CipherSuite> TryFrom<&[u8]> for ClientLogin<CS> {
let scalar_len = <CS::Group as Group>::ScalarLen::to_usize();
let blinding_factor_bytes = GenericArray::from_slice(&bytes[..scalar_len]);
let blinding_factor = CS::Group::from_scalar_slice(blinding_factor_bytes)?;
let ke1_state_size = <CS::KeyExchange as KeyExchange>::ke1_state_size();
let ke1_state = <CS::KeyExchange as KeyExchange>::KE1State::try_from(
let ke1_state_size = <CS::KeyExchange as KeyExchange<CS::Hash>>::ke1_state_size();
let ke1_state = <CS::KeyExchange as KeyExchange<CS::Hash>>::KE1State::try_from(
bytes[scalar_len..scalar_len + ke1_state_size].to_vec(),
)?;
let password = bytes[scalar_len + ke1_state_size..].to_vec();
@@ -670,6 +682,7 @@ impl<CS: CipherSuite> ClientLogin<CS> {
/// type Group = curve25519_dalek::ristretto::RistrettoPoint;
/// type KeyFormat = opaque_ke::keypair::X25519KeyPair;
/// type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
/// type Hash = sha2::Sha256;
/// type SlowHash = opaque_ke::slow_hash::NoOpHash;
/// }
/// let mut client_rng = OsRng;
@@ -722,6 +735,7 @@ impl<CS: CipherSuite> ClientLogin<CS> {
/// type Group = curve25519_dalek::ristretto::RistrettoPoint;
/// type KeyFormat = opaque_ke::keypair::X25519KeyPair;
/// type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
/// type Hash = sha2::Sha256;
/// type SlowHash = opaque_ke::slow_hash::NoOpHash;
/// }
/// let mut client_rng = OsRng;
@@ -738,19 +752,19 @@ impl<CS: CipherSuite> ClientLogin<CS> {
/// ```
pub fn finish<R: RngCore + CryptoRng>(
self,
l2: LoginSecondMessage<CS::Group, CS::KeyFormat, CS::KeyExchange>,
l2: LoginSecondMessage<CS::Group, CS::KeyFormat, CS::KeyExchange, CS::Hash>,
server_s_pk: &<<CS as CipherSuite>::KeyFormat as KeyPair>::Repr,
_client_e_sk_rng: &mut R,
) -> Result<ClientLoginFinishResult<CS>, ProtocolError> {
let l2_bytes: Vec<u8> = [&l2.beta.to_arr()[..], &l2.envelope.to_bytes()].concat();
let password_derived_key = get_password_derived_key::<CS::Group, CS::SlowHash>(
let password_derived_key = get_password_derived_key::<CS::Group, CS::SlowHash, CS::Hash>(
self.password.clone(),
l2.beta,
&self.blinding_factor,
)?;
let (client_s_sk, export_key) = &l2
let opened_envelope = &l2
.envelope
.open(&password_derived_key, &server_s_pk.to_arr())
.map_err(|e| match e {
@@ -763,20 +777,20 @@ impl<CS: CipherSuite> ClientLogin<CS> {
l2.ke2_message,
&self.ke1_state,
server_s_pk.clone(),
Key::from_bytes(client_s_sk)?,
Key::from_bytes(&opened_envelope.plaintext)?,
)?;
Ok((
LoginThirdMessage { ke3_message },
shared_secret,
*export_key,
opened_envelope.export_key,
))
}
}
/// The state elements the server holds to record a login
pub struct ServerLogin<CS: CipherSuite> {
ke2_state: <CS::KeyExchange as KeyExchange>::KE2State,
ke2_state: <CS::KeyExchange as KeyExchange<CS::Hash>>::KE2State,
_cs: PhantomData<CS>,
}
@@ -785,7 +799,9 @@ impl<CS: CipherSuite> TryFrom<&[u8]> for ServerLogin<CS> {
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
Ok(Self {
_cs: PhantomData,
ke2_state: <CS::KeyExchange as KeyExchange>::KE2State::try_from(bytes.to_vec())?,
ke2_state: <CS::KeyExchange as KeyExchange<CS::Hash>>::KE2State::try_from(
bytes.to_vec(),
)?,
})
}
}
@@ -795,6 +811,7 @@ type ServerLoginStartResult<CS> = (
<CS as CipherSuite>::Group,
<CS as CipherSuite>::KeyFormat,
<CS as CipherSuite>::KeyExchange,
<CS as CipherSuite>::Hash,
>,
ServerLogin<CS>,
);
@@ -825,6 +842,7 @@ impl<CS: CipherSuite> ServerLogin<CS> {
/// type Group = curve25519_dalek::ristretto::RistrettoPoint;
/// type KeyFormat = opaque_ke::keypair::X25519KeyPair;
/// type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
/// type Hash = sha2::Sha256;
/// type SlowHash = opaque_ke::slow_hash::NoOpHash;
/// }
/// let mut client_rng = OsRng;
@@ -901,6 +919,7 @@ impl<CS: CipherSuite> ServerLogin<CS> {
/// type Group = curve25519_dalek::ristretto::RistrettoPoint;
/// type KeyFormat = opaque_ke::keypair::X25519KeyPair;
/// type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
/// type Hash = sha2::Sha256;
/// type SlowHash = opaque_ke::slow_hash::NoOpHash;
/// }
/// let mut client_rng = OsRng;
@@ -918,24 +937,23 @@ impl<CS: CipherSuite> ServerLogin<CS> {
/// # Ok::<(), ProtocolError>(())
/// ```
pub fn finish(&self, message: LoginThirdMessage<CS>) -> Result<Vec<u8>, ProtocolError> {
<CS::KeyExchange as KeyExchange>::finish_ke(message.ke3_message, &self.ke2_state).map_err(
|e| match e {
<CS::KeyExchange as KeyExchange<CS::Hash>>::finish_ke(message.ke3_message, &self.ke2_state)
.map_err(|e| match e {
ProtocolError::VerificationError(PakeError::KeyExchangeMacValidationError) => {
ProtocolError::VerificationError(PakeError::InvalidLoginError)
}
err => err,
},
)
})
}
}
// Helper functions
fn get_password_derived_key<G: Group, SH: SlowHash>(
fn get_password_derived_key<G: Group, SH: SlowHash<D>, D: Hash>(
password: Vec<u8>,
beta: G,
blinding_factor: &G::Scalar,
) -> Result<Vec<u8>, InternalPakeError> {
let oprf_output = oprf::generate_oprf3::<G>(&password, beta, blinding_factor)?;
let oprf_output = oprf::generate_oprf3::<G, D>(&password, beta, blinding_factor)?;
SH::hash(oprf_output)
}
+13 -13
View File
@@ -3,8 +3,11 @@
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.
use crate::{errors::InternalPakeError, group::Group, map_to_curve::GroupWithMapToCurve};
use generic_array::{typenum::U32, GenericArray};
use crate::{
errors::InternalPakeError, group::Group, hash::Hash, map_to_curve::GroupWithMapToCurve,
};
use digest::Digest;
use generic_array::GenericArray;
use hkdf::Hkdf;
use rand_core::{CryptoRng, RngCore};
@@ -42,14 +45,14 @@ pub(crate) fn generate_oprf2<G: Group>(
/// Computes the third step for the multiplicative blinding version of DH-OPRF, in which
/// the client unblinds the server's message.
pub(crate) fn generate_oprf3<G: Group>(
pub(crate) fn generate_oprf3<G: Group, H: Hash>(
input: &[u8],
point: G,
blinding_factor: &G::Scalar,
) -> Result<GenericArray<u8, U32>, InternalPakeError> {
) -> Result<GenericArray<u8, <H as Digest>::OutputSize>, InternalPakeError> {
let unblinded = point * &G::scalar_invert(&blinding_factor);
let ikm: Vec<u8> = [&unblinded.to_arr()[..], input].concat();
let (prk, _) = Hkdf::<sha2::Sha256>::extract(None, &ikm);
let (prk, _) = Hkdf::<H>::extract(None, &ikm);
Ok(prk)
}
@@ -94,7 +97,7 @@ mod tests {
use generic_array::{arr, GenericArray};
use hkdf::Hkdf;
use rand_core::OsRng;
use sha2::{Digest, Sha256, Sha512};
use sha2::{Sha256, Sha512};
fn prf(
input: &[u8],
@@ -125,7 +128,7 @@ mod tests {
];
let salt = RistrettoPoint::from_scalar_slice(&salt_bytes)?;
let beta = generate_oprf2::<RistrettoPoint>(alpha, &salt)?;
let res = generate_oprf3::<RistrettoPoint>(input, beta, &blinding_factor)?;
let res = generate_oprf3::<RistrettoPoint, sha2::Sha256>(input, beta, &blinding_factor)?;
let res2 = prf(&input[..], &salt.as_bytes());
assert_eq!(res, res2);
Ok(())
@@ -140,15 +143,12 @@ mod tests {
alpha,
blinding_factor,
} = generate_oprf1::<_, RistrettoPoint>(&input, None, &mut rng).unwrap();
let res = generate_oprf3::<RistrettoPoint>(&input, alpha, &blinding_factor).unwrap();
let res = generate_oprf3::<RistrettoPoint, sha2::Sha256>(&input, alpha, &blinding_factor)
.unwrap();
let (hashed_input, _) = Hkdf::<Sha512>::extract(None, &input);
// This is because RistrettoPoint is on an obsolete sha2 version
let mut bits = [0u8; 64];
let mut hasher = sha2::Sha512::new();
Digest::update(&mut hasher, &hashed_input[..]);
bits.copy_from_slice(&hasher.finalize());
bits.copy_from_slice(&hashed_input);
let point = RistrettoPoint::from_uniform_bytes(&bits);
let mut ikm: Vec<u8> = Vec::new();
+16 -9
View File
@@ -6,29 +6,36 @@
//! Trait specifying a slow hashing function
use crate::errors::InternalPakeError;
use generic_array::{typenum::U32, GenericArray};
use crate::hash::Hash;
use digest::Digest;
use generic_array::GenericArray;
/// Used for the slow hashing function in OPAQUE
pub trait SlowHash {
pub trait SlowHash<D: Hash> {
/// Computes the slow hashing function
fn hash(input: GenericArray<u8, U32>) -> Result<Vec<u8>, InternalPakeError>;
fn hash(
input: GenericArray<u8, <D as Digest>::OutputSize>,
) -> Result<Vec<u8>, InternalPakeError>;
}
/// A no-op hash which simply returns its input
pub struct NoOpHash;
impl SlowHash for NoOpHash {
fn hash(input: GenericArray<u8, U32>) -> Result<Vec<u8>, InternalPakeError> {
impl<D: Hash> SlowHash<D> for NoOpHash {
fn hash(
input: GenericArray<u8, <D as Digest>::OutputSize>,
) -> Result<Vec<u8>, InternalPakeError> {
Ok(input.to_vec())
}
}
#[cfg(feature = "slow-hash")]
impl SlowHash for scrypt::ScryptParams {
fn hash(input: GenericArray<u8, U32>) -> Result<Vec<u8>, InternalPakeError> {
impl<D: Hash> SlowHash<D> for scrypt::ScryptParams {
fn hash(
input: GenericArray<u8, <D as Digest>::OutputSize>,
) -> Result<Vec<u8>, InternalPakeError> {
let params = scrypt::ScryptParams::new(15, 8, 1).unwrap();
let mut output = [0u8; 32];
let mut output = [0u8; <D as Digest>::OutputSize::to_usize()];
scrypt::scrypt(&input, &[], &params, &mut output)
.map_err(|_| InternalPakeError::SlowHashError)?;
Ok(output.to_vec())
+14 -12
View File
@@ -26,6 +26,7 @@ impl CipherSuite for X255193dhNoSlowHash {
type Group = EdwardsPoint;
type KeyFormat = X25519KeyPair;
type KeyExchange = TripleDH;
type Hash = sha2::Sha256;
type SlowHash = NoOpHash;
}
@@ -470,18 +471,19 @@ fn test_l3() -> Result<(), PakeError> {
let parameters = populate_test_vectors(&serde_json::from_str(TEST_VECTOR).unwrap());
let mut client_e_sk_rng = CycleRng::new(parameters.client_e_sk.to_vec());
let (l3, shared_secret, opaque_key_login) =
ClientLogin::<X255193dhNoSlowHash>::try_from(&parameters.client_login_state[..])
.unwrap()
.finish(
LoginSecondMessage::<EdwardsPoint, X25519KeyPair, TripleDH>::try_from(
&parameters.l2[..],
)
.unwrap(),
&Key::try_from(&parameters.server_s_pk[..])?,
&mut client_e_sk_rng,
)
.unwrap();
let (l3, shared_secret, opaque_key_login) = ClientLogin::<X255193dhNoSlowHash>::try_from(
&parameters.client_login_state[..],
)
.unwrap()
.finish(
LoginSecondMessage::<EdwardsPoint, X25519KeyPair, TripleDH, sha2::Sha256>::try_from(
&parameters.l2[..],
)
.unwrap(),
&Key::try_from(&parameters.server_s_pk[..])?,
&mut client_e_sk_rng,
)
.unwrap();
assert_eq!(
hex::encode(&parameters.shared_secret),
+7 -4
View File
@@ -27,6 +27,7 @@ impl CipherSuite for Default {
type Group = RistrettoPoint;
type KeyFormat = crate::keypair::X25519KeyPair;
type KeyExchange = TripleDH;
type Hash = sha2::Sha256;
type SlowHash = crate::slow_hash::NoOpHash;
}
@@ -71,7 +72,7 @@ fn server_registration_roundtrip() {
// the whole kit
let key_len =
<<<Default as CipherSuite>::KeyFormat as KeyPair>::Repr as SizedBytes>::Len::to_usize();
let envelope_size = key_len + Envelope::additional_size();
let envelope_size = key_len + Envelope::<sha2::Sha256>::additional_size();
let mut mock_envelope_bytes = vec![0u8; envelope_size];
rng.fill_bytes(&mut mock_envelope_bytes);
println!("{}", mock_envelope_bytes.len());
@@ -118,10 +119,11 @@ fn register_third_message_roundtrip() {
let mut msg = [0u8; 32];
rng.fill_bytes(&mut msg);
let (ciphertext, _) = Envelope::seal(&key, &msg, &pubkey_bytes, &mut rng).unwrap();
let (ciphertext, _) =
Envelope::<sha2::Sha256>::seal(&key, &msg, &pubkey_bytes, &mut rng).unwrap();
let message: Vec<u8> = [&ciphertext.to_bytes(), &pubkey_bytes[..]].concat();
let r3 = RegisterThirdMessage::<X25519KeyPair>::try_from(&message[..]).unwrap();
let r3 = RegisterThirdMessage::<X25519KeyPair, sha2::Sha256>::try_from(&message[..]).unwrap();
let r3_bytes = r3.to_bytes();
assert_eq!(message, r3_bytes);
}
@@ -164,7 +166,8 @@ fn login_first_message_roundtrip() {
rng.fill_bytes(&mut client_nonce);
let ke1m: Vec<u8> = [&client_nonce[..], &client_e_kp.public()].concat();
let reg = <TripleDH as KeyExchange>::KE1Message::try_from(ke1m[..].to_vec()).unwrap();
let reg =
<TripleDH as KeyExchange<sha2::Sha256>>::KE1Message::try_from(ke1m[..].to_vec()).unwrap();
let reg_bytes = reg.to_bytes();
assert_eq!(reg_bytes, ke1m);
}