As a way to roll back the genericity, implement an extension trait of group for password-to-curve hashing,

This supersedes #18.

Co-authored-by: KevinLewi <[email protected]>
This commit is contained in:
François Garillot
2020-07-03 21:05:18 -04:00
co-authored by KevinLewi
parent 41cd80ccb5
commit 9d40aa7659
9 changed files with 46 additions and 70 deletions
Generated
-1
View File
@@ -202,7 +202,6 @@ dependencies = [
"aead 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"base64 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
"curve25519-dalek 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"digest 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"generic-array 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)",
"hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"hkdf 0.9.0-alpha.0 (registry+https://github.com/rust-lang/crates.io-index)",
-1
View File
@@ -15,7 +15,6 @@ slow-hash = ["scrypt"]
[dependencies]
aead = "0.3.1"
curve25519-dalek = "2.1.0"
digest = "0.9"
generic-array = "0.14.2"
hkdf = "0.9.0-alpha.0"
hmac = "0.8.0"
+7 -9
View File
@@ -7,24 +7,22 @@
use crate::{
errors::InternalPakeError,
group::Group,
keypair::{Key, KeyPair},
oprf::HkdfDigest,
map_to_curve::GroupWithMapToCurve,
slow_hash::SlowHash,
};
use digest::FixedOutput;
use generic_array::typenum::{U32};
use rand_core::{CryptoRng, RngCore};
/// Configures the underlying primitives used in OPAQUE
/// * `Digest`: a digest suitable for use in an Hkdf, with an output length equal
/// to the input of the hash-to-curve function of the `Group` parameter.
/// * `Group`: a finite cyclic group along with a point representation
/// * `Group`: a finite cyclic group along with a point representation, along
/// with an extension trait PasswordToCurve that allows some customization on
/// how to hash a password to a curve point. See `group::Group` and
/// `map_to_curve::GroupWithMapToCurve`.
/// * `KeyFormat`: a keypair type composed of public and private components
/// * `SlowHash`: a slow hashing function, typically used for password hashing
pub trait CipherSuite {
type Digest: HkdfDigest;
type Group: Group<ScalarLen = U32, UniformBytesLen = <Self::Digest as FixedOutput>::OutputSize>;
type Group: GroupWithMapToCurve;
type KeyFormat: KeyPair<Repr = Key> + PartialEq;
type SlowHash: SlowHash;
+4 -10
View File
@@ -21,7 +21,6 @@
//! use opaque_ke::ciphersuite::CipherSuite;
//! struct Default;
//! impl CipherSuite for Default {
//! type Digest = sha2::Sha512;
//! type Group = curve25519_dalek::ristretto::RistrettoPoint;
//! type KeyFormat = opaque_ke::keypair::X25519KeyPair;
//! type SlowHash = opaque_ke::slow_hash::NoOpHash;
@@ -42,7 +41,6 @@
//! # use opaque_ke::ciphersuite::CipherSuite;
//! # struct Default;
//! # impl CipherSuite for Default {
//! # type Digest = sha2::Sha512;
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
@@ -74,7 +72,6 @@
//! # use opaque_ke::ciphersuite::CipherSuite;
//! # struct Default;
//! # impl CipherSuite for Default {
//! # type Digest = sha2::Sha512;
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
@@ -103,7 +100,6 @@
//! # use opaque_ke::ciphersuite::CipherSuite;
//! # struct Default;
//! # impl CipherSuite for Default {
//! # type Digest = sha2::Sha512;
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
@@ -135,7 +131,6 @@
//! # use opaque_ke::ciphersuite::CipherSuite;
//! # struct Default;
//! # impl CipherSuite for Default {
//! # type Digest = sha2::Sha512;
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
@@ -169,7 +164,6 @@
//! # use opaque_ke::ciphersuite::CipherSuite;
//! # struct Default;
//! # impl CipherSuite for Default {
//! # type Digest = sha2::Sha512;
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
@@ -211,7 +205,6 @@
//! # use opaque_ke::ciphersuite::CipherSuite;
//! # struct Default;
//! # impl CipherSuite for Default {
//! # type Digest = sha2::Sha512;
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
@@ -240,7 +233,6 @@
//! # use opaque_ke::ciphersuite::CipherSuite;
//! # struct Default;
//! # impl CipherSuite for Default {
//! # type Digest = sha2::Sha512;
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
@@ -284,7 +276,6 @@
//! # use opaque_ke::ciphersuite::CipherSuite;
//! # struct Default;
//! # impl CipherSuite for Default {
//! # type Digest = sha2::Sha512;
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
@@ -340,7 +331,6 @@
//! # use opaque_ke::ciphersuite::CipherSuite;
//! # struct Default;
//! # impl CipherSuite for Default {
//! # type Digest = sha2::Sha512;
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
@@ -390,9 +380,13 @@ pub mod opaque;
pub mod ciphersuite;
mod envelope;
mod group;
mod map_to_curve;
mod key_exchange;
pub mod keypair;
mod oprf;
pub mod slow_hash;
+23
View File
@@ -0,0 +1,23 @@
use crate::group::Group;
use curve25519_dalek::{edwards::EdwardsPoint, ristretto::RistrettoPoint};
use generic_array::GenericArray;
use hkdf::Hkdf;
pub trait GroupWithMapToCurve: Group {
fn map_to_curve(password: &[u8], pepper: Option<&[u8]>) -> Self;
}
impl GroupWithMapToCurve for RistrettoPoint {
fn map_to_curve(password: &[u8], pepper: Option<&[u8]>) -> Self {
let (hashed_input, _) = Hkdf::<sha2::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);
<Self as Group>::hash_to_curve(GenericArray::from_slice(&hashed_input))
}
}
+2 -14
View File
@@ -290,7 +290,6 @@ impl<CS: CipherSuite> ClientRegistration<CS> {
/// use opaque_ke::ciphersuite::CipherSuite;
/// struct Default;
/// impl CipherSuite for Default {
/// type Digest = sha2::Sha512;
/// type Group = curve25519_dalek::ristretto::RistrettoPoint;
/// type KeyFormat = opaque_ke::keypair::X25519KeyPair;
/// type SlowHash = opaque_ke::slow_hash::NoOpHash;
@@ -307,11 +306,7 @@ impl<CS: CipherSuite> ClientRegistration<CS> {
let OprfClientBytes {
alpha,
blinding_factor,
} = oprf::generate_oprf1::<R, CS::Digest, CS::Group>(
&password,
pepper,
blinding_factor_rng,
)?;
} = oprf::generate_oprf1::<R, CS::Group>(&password, pepper, blinding_factor_rng)?;
Ok((
RegisterFirstMessage::<CS::Group> { alpha },
@@ -345,7 +340,6 @@ impl<CS: CipherSuite> ClientRegistration<CS> {
/// use opaque_ke::ciphersuite::CipherSuite;
/// struct Default;
/// impl CipherSuite for Default {
/// type Digest = sha2::Sha512;
/// type Group = curve25519_dalek::ristretto::RistrettoPoint;
/// type KeyFormat = opaque_ke::keypair::X25519KeyPair;
/// type SlowHash = opaque_ke::slow_hash::NoOpHash;
@@ -509,7 +503,6 @@ where
/// use opaque_ke::ciphersuite::CipherSuite;
/// struct Default;
/// impl CipherSuite for Default {
/// type Digest = sha2::Sha512;
/// type Group = curve25519_dalek::ristretto::RistrettoPoint;
/// type KeyFormat = opaque_ke::keypair::X25519KeyPair;
/// type SlowHash = opaque_ke::slow_hash::NoOpHash;
@@ -556,7 +549,6 @@ where
/// use opaque_ke::ciphersuite::CipherSuite;
/// struct Default;
/// impl CipherSuite for Default {
/// type Digest = sha2::Sha512;
/// type Group = curve25519_dalek::ristretto::RistrettoPoint;
/// type KeyFormat = opaque_ke::keypair::X25519KeyPair;
/// type SlowHash = opaque_ke::slow_hash::NoOpHash;
@@ -645,7 +637,6 @@ impl<CS: CipherSuite> ClientLogin<CS> {
/// use opaque_ke::ciphersuite::CipherSuite;
/// struct Default;
/// impl CipherSuite for Default {
/// type Digest = sha2::Sha512;
/// type Group = curve25519_dalek::ristretto::RistrettoPoint;
/// type KeyFormat = opaque_ke::keypair::X25519KeyPair;
/// type SlowHash = opaque_ke::slow_hash::NoOpHash;
@@ -662,7 +653,7 @@ impl<CS: CipherSuite> ClientLogin<CS> {
let OprfClientBytes {
alpha,
blinding_factor,
} = oprf::generate_oprf1::<R, CS::Digest, CS::Group>(&password, pepper, rng)?;
} = oprf::generate_oprf1::<R, CS::Group>(&password, pepper, rng)?;
let (ke1_state, ke1_message) =
generate_ke1::<_, CS::KeyFormat>(alpha.to_arr().to_vec(), rng)?;
@@ -697,7 +688,6 @@ impl<CS: CipherSuite> ClientLogin<CS> {
/// use opaque_ke::ciphersuite::CipherSuite;
/// struct Default;
/// impl CipherSuite for Default {
/// type Digest = sha2::Sha512;
/// type Group = curve25519_dalek::ristretto::RistrettoPoint;
/// type KeyFormat = opaque_ke::keypair::X25519KeyPair;
/// type SlowHash = opaque_ke::slow_hash::NoOpHash;
@@ -793,7 +783,6 @@ impl ServerLogin {
/// use opaque_ke::ciphersuite::CipherSuite;
/// struct Default;
/// impl CipherSuite for Default {
/// type Digest = sha2::Sha512;
/// type Group = curve25519_dalek::ristretto::RistrettoPoint;
/// type KeyFormat = opaque_ke::keypair::X25519KeyPair;
/// type SlowHash = opaque_ke::slow_hash::NoOpHash;
@@ -863,7 +852,6 @@ impl ServerLogin {
/// use opaque_ke::ciphersuite::CipherSuite;
/// struct Default;
/// impl CipherSuite for Default {
/// type Digest = sha2::Sha512;
/// type Group = curve25519_dalek::ristretto::RistrettoPoint;
/// type KeyFormat = opaque_ke::keypair::X25519KeyPair;
/// type SlowHash = opaque_ke::slow_hash::NoOpHash;
+7 -31
View File
@@ -3,9 +3,8 @@
// 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};
use digest::{BlockInput, FixedOutput, Reset, Update};
use generic_array::{typenum::U32, ArrayLength, GenericArray};
use crate::{errors::InternalPakeError, group::Group, map_to_curve::GroupWithMapToCurve};
use generic_array::{typenum::U32, GenericArray};
use hkdf::Hkdf;
use rand_core::{CryptoRng, RngCore};
@@ -14,41 +13,18 @@ pub(crate) struct OprfClientBytes<Grp: Group> {
pub(crate) blinding_factor: Grp::Scalar,
}
/// The `HkDFDigest` trait specifies the interface required for a parameter of `hkdf::Hkdf`.
///
/// It's a convenience wrapper around [`Blockinput`], [`Update`], [`FixedOutput`], [`Reset`],
/// [`Clone`], and [`Default`] traits.
pub trait HkdfDigest: Update + BlockInput + FixedOutput + Reset + Default + Clone
where
Self::BlockSize: ArrayLength<u8>,
Self::OutputSize: ArrayLength<u8>,
{
}
impl<T> HkdfDigest for T
where
T: Update + BlockInput + FixedOutput + Reset + Default + Clone,
T::BlockSize: ArrayLength<u8>,
T::OutputSize: ArrayLength<u8>,
{
}
/// Computes the first step for the multiplicative blinding version of DH-OPRF. This
/// message is sent from the client (who holds the input) to the server (who holds the OPRF key).
/// The client can also pass in an optional "pepper" string to be mixed in with the input through
/// an HKDF computation.
pub(crate) fn generate_oprf1<
R: RngCore + CryptoRng,
D: HkdfDigest,
G: Group<UniformBytesLen = D::OutputSize>,
>(
pub(crate) fn generate_oprf1<R: RngCore + CryptoRng, G: GroupWithMapToCurve>(
input: &[u8],
pepper: Option<&[u8]>,
blinding_factor_rng: &mut R,
) -> Result<OprfClientBytes<G>, InternalPakeError> {
let (hashed_input, _) = Hkdf::<D>::extract(pepper, &input);
let mapped_point = G::map_to_curve(input, pepper);
let blinding_factor = G::random_scalar(blinding_factor_rng);
let alpha = G::hash_to_curve(GenericArray::from_slice(&hashed_input)) * &blinding_factor;
let alpha = mapped_point * &blinding_factor;
Ok(OprfClientBytes {
alpha,
blinding_factor,
@@ -112,7 +88,7 @@ mod tests {
let OprfClientBytes {
alpha,
blinding_factor,
} = generate_oprf1::<_, Sha512, RistrettoPoint>(&input[..], None, &mut rng)?;
} = generate_oprf1::<_, RistrettoPoint>(&input[..], None, &mut rng)?;
let salt_bytes = arr![
u8; 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31, 32,
@@ -133,7 +109,7 @@ mod tests {
let OprfClientBytes {
alpha,
blinding_factor,
} = generate_oprf1::<_, Sha512, RistrettoPoint>(&input, None, &mut rng).unwrap();
} = generate_oprf1::<_, RistrettoPoint>(&input, None, &mut rng).unwrap();
let res = generate_oprf3::<RistrettoPoint>(&input, alpha, &blinding_factor).unwrap();
let (hashed_input, _) = Hkdf::<Sha512>::extract(None, &input);
+3 -3
View File
@@ -23,7 +23,6 @@ use std::convert::TryFrom;
struct X255193dhNoSlowHash;
impl CipherSuite for X255193dhNoSlowHash {
type Digest = sha2::Sha256;
type Group = EdwardsPoint;
type KeyFormat = X25519KeyPair;
type SlowHash = NoOpHash;
@@ -248,13 +247,14 @@ fn generate_parameters<CS: CipherSuite>() -> TestVectorParameters {
)
.unwrap();
let r1_bytes = r1.to_bytes().to_vec();
let blinding_factor_bytes = *CS::Group::scalar_as_bytes(&client_registration.blinding_factor);
let blinding_factor_bytes =
CS::Group::scalar_as_bytes(&client_registration.blinding_factor).clone();
let client_registration_state = client_registration.to_bytes().to_vec();
let mut oprf_key_rng = CycleRng::new(oprf_key_raw.to_vec());
let (r2, server_registration) = ServerRegistration::<CS>::start(r1, &mut oprf_key_rng).unwrap();
let r2_bytes = r2.to_bytes().to_vec();
let oprf_key_bytes = *CS::Group::scalar_as_bytes(&server_registration.oprf_key);
let oprf_key_bytes = CS::Group::scalar_as_bytes(&server_registration.oprf_key).clone();
let server_registration_state = server_registration.to_bytes().to_vec();
let mut client_s_sk_and_nonce: Vec<u8> = Vec::new();
-1
View File
@@ -21,7 +21,6 @@ use std::convert::TryFrom;
struct Default;
impl CipherSuite for Default {
type Digest = sha2::Sha512;
type Group = RistrettoPoint;
type KeyFormat = crate::keypair::X25519KeyPair;
type SlowHash = crate::slow_hash::NoOpHash;