Make oprf::generate_oprf1 generic in the Digest, as long as it matches the hash-to-curve intake of the group
We used to have three problems: - overuse of the <Sha256 as Digest>::OutputSize, which is just, well, U32. Sometimes used as a parameter (as in generate_oprf1), sometimes as a constant (as in generate_oprf3). - the `hash_to_curve` operation for `RistrettoPoint` which requires 64 bits of input entropy, is fed 64 bits of which the last 32 are zero, - the `hash_to_curve` operation for `Curve25519Point` which requires 32 bits of input entropy, is fed 64 bits of which the last 32 are discarded, This corrects all three and uses U32 where the size of the digest is not meant to be a constraint. Addresses #15 partially.
This commit is contained in:
Generated
+1
@@ -202,6 +202,7 @@ dependencies = [
|
|||||||
"aead 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"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)",
|
"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)",
|
"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)",
|
"hkdf 0.9.0-alpha.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ slow-hash = ["scrypt"]
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
aead = "0.3.1"
|
aead = "0.3.1"
|
||||||
curve25519-dalek = "2.1.0"
|
curve25519-dalek = "2.1.0"
|
||||||
|
digest = "0.9"
|
||||||
generic-array = "0.14.2"
|
generic-array = "0.14.2"
|
||||||
hkdf = "0.9.0-alpha.0"
|
hkdf = "0.9.0-alpha.0"
|
||||||
hmac = "0.8.0"
|
hmac = "0.8.0"
|
||||||
|
|||||||
+10
-5
@@ -9,17 +9,22 @@ use crate::{
|
|||||||
errors::InternalPakeError,
|
errors::InternalPakeError,
|
||||||
group::Group,
|
group::Group,
|
||||||
keypair::{Key, KeyPair},
|
keypair::{Key, KeyPair},
|
||||||
|
oprf::HkdfDigest,
|
||||||
slow_hash::SlowHash,
|
slow_hash::SlowHash,
|
||||||
};
|
};
|
||||||
use generic_array::typenum::{U32, U64};
|
use digest::FixedOutput;
|
||||||
|
use generic_array::typenum::{U32};
|
||||||
use rand_core::{CryptoRng, RngCore};
|
use rand_core::{CryptoRng, RngCore};
|
||||||
|
|
||||||
/// Configures the underlying primitives used in OPAQUE
|
/// Configures the underlying primitives used in OPAQUE
|
||||||
/// * Group: a finite cyclic group along with a point representation
|
/// * `Digest`: a digest suitable for use in an Hkdf, with an output length equal
|
||||||
/// * KeyFormat: a keypair type composed of public and private components
|
/// to the input of the hash-to-curve function of the `Group` parameter.
|
||||||
/// * SlowHash: a slow hashing function, typically used for password hashing
|
/// * `Group`: a finite cyclic group along with a point representation
|
||||||
|
/// * `KeyFormat`: a keypair type composed of public and private components
|
||||||
|
/// * `SlowHash`: a slow hashing function, typically used for password hashing
|
||||||
pub trait CipherSuite {
|
pub trait CipherSuite {
|
||||||
type Group: Group<ScalarLen = U32, UniformBytesLen = U64>;
|
type Digest: HkdfDigest;
|
||||||
|
type Group: Group<ScalarLen = U32, UniformBytesLen = <Self::Digest as FixedOutput>::OutputSize>;
|
||||||
type KeyFormat: KeyPair<Repr = Key> + PartialEq;
|
type KeyFormat: KeyPair<Repr = Key> + PartialEq;
|
||||||
type SlowHash: SlowHash;
|
type SlowHash: SlowHash;
|
||||||
|
|
||||||
|
|||||||
+14
-22
@@ -11,14 +11,16 @@ use generic_array::{
|
|||||||
use hkdf::Hkdf;
|
use hkdf::Hkdf;
|
||||||
use hmac::{Hmac, Mac, NewMac};
|
use hmac::{Hmac, Mac, NewMac};
|
||||||
use rand_core::{CryptoRng, RngCore};
|
use rand_core::{CryptoRng, RngCore};
|
||||||
use sha2::{Digest, Sha256};
|
use sha2::Sha256;
|
||||||
|
|
||||||
// Constant string used as salt for HKDF computation
|
// Constant string used as salt for HKDF computation
|
||||||
const STR_ENVU: &[u8] = b"EnvU";
|
const STR_ENVU: &[u8] = b"EnvU";
|
||||||
|
|
||||||
/// The length of the "export key" output by the client registration
|
/// The length of the "export key" output by the client registration
|
||||||
/// and login finish steps
|
/// and login finish steps
|
||||||
pub(crate) type ExportKeySize = <Sha256 as Digest>::OutputSize;
|
pub(crate) type ExportKeySize = U32;
|
||||||
|
|
||||||
|
const NONCE_LEN: usize = 32;
|
||||||
|
|
||||||
/// This struct is an instantiation of the envelope as described in
|
/// This struct is an instantiation of the envelope as described in
|
||||||
/// https://tools.ietf.org/html/draft-krawczyk-cfrg-opaque-06#section-4
|
/// https://tools.ietf.org/html/draft-krawczyk-cfrg-opaque-06#section-4
|
||||||
@@ -33,42 +35,32 @@ pub(crate) type ExportKeySize = <Sha256 as Digest>::OutputSize;
|
|||||||
pub(crate) struct Envelope {
|
pub(crate) struct Envelope {
|
||||||
nonce: Vec<u8>,
|
nonce: Vec<u8>,
|
||||||
ciphertext: Vec<u8>,
|
ciphertext: Vec<u8>,
|
||||||
hmac: Vec<u8>,
|
hmac: GenericArray<u8, U32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
type NonceLen = U32;
|
|
||||||
|
|
||||||
impl Envelope {
|
impl Envelope {
|
||||||
/// The additional number of bytes added to the plaintext
|
/// The additional number of bytes added to the plaintext
|
||||||
pub(crate) fn additional_size() -> usize {
|
pub(crate) fn additional_size() -> usize {
|
||||||
Self::nonce_size() + <Sha256 as Digest>::OutputSize::to_usize()
|
NONCE_LEN + U32::to_usize()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hmac_key_size() -> usize {
|
fn hmac_key_size() -> usize {
|
||||||
<Sha256 as Digest>::OutputSize::to_usize()
|
U32::to_usize()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hmac_size() -> usize {
|
fn hmac_size() -> usize {
|
||||||
<Sha256 as Digest>::OutputSize::to_usize()
|
U32::to_usize()
|
||||||
}
|
|
||||||
|
|
||||||
fn nonce_size() -> usize {
|
|
||||||
NonceLen::to_usize()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn export_key_size() -> usize {
|
fn export_key_size() -> usize {
|
||||||
ExportKeySize::to_usize()
|
ExportKeySize::to_usize()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(nonce: Vec<u8>, ciphertext: Vec<u8>, hmac: GenericArray<u8, U32>) -> Self {
|
||||||
nonce: Vec<u8>,
|
|
||||||
ciphertext: Vec<u8>,
|
|
||||||
hmac: &GenericArray<u8, <Sha256 as Digest>::OutputSize>,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
nonce,
|
nonce,
|
||||||
ciphertext,
|
ciphertext,
|
||||||
hmac: hmac.to_vec(),
|
hmac,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,13 +68,13 @@ impl Envelope {
|
|||||||
/// nonce | ciphertext | hmac
|
/// nonce | ciphertext | hmac
|
||||||
/// nonce_size bytes | variable length | hmac_size bytes
|
/// nonce_size bytes | variable length | hmac_size bytes
|
||||||
pub(crate) fn from_bytes(bytes: &[u8]) -> Result<Self, InternalPakeError> {
|
pub(crate) fn from_bytes(bytes: &[u8]) -> Result<Self, InternalPakeError> {
|
||||||
let ciphertext_start = Self::nonce_size();
|
let ciphertext_start = NONCE_LEN;
|
||||||
let ciphertext_end = bytes.len() - Self::hmac_size();
|
let ciphertext_end = bytes.len() - Self::hmac_size();
|
||||||
|
|
||||||
Ok(Self::new(
|
Ok(Self::new(
|
||||||
bytes[..ciphertext_start].to_vec(),
|
bytes[..ciphertext_start].to_vec(),
|
||||||
bytes[ciphertext_start..ciphertext_end].to_vec(),
|
bytes[ciphertext_start..ciphertext_end].to_vec(),
|
||||||
GenericArray::from_slice(&bytes[ciphertext_end..]),
|
GenericArray::clone_from_slice(&bytes[ciphertext_end..]),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,7 +90,7 @@ impl Envelope {
|
|||||||
aad: &[u8],
|
aad: &[u8],
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
) -> Result<(Self, GenericArray<u8, ExportKeySize>), InternalPakeError> {
|
) -> Result<(Self, GenericArray<u8, ExportKeySize>), InternalPakeError> {
|
||||||
let mut nonce = vec![0u8; Self::nonce_size()];
|
let mut nonce = vec![0u8; NONCE_LEN];
|
||||||
rng.fill_bytes(&mut nonce);
|
rng.fill_bytes(&mut nonce);
|
||||||
|
|
||||||
let h = Hkdf::<Sha256>::new(Some(&nonce), &key);
|
let h = Hkdf::<Sha256>::new(Some(&nonce), &key);
|
||||||
@@ -121,7 +113,7 @@ impl Envelope {
|
|||||||
hmac.update(&aad);
|
hmac.update(&aad);
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
Self::new(nonce, ciphertext.to_vec(), &hmac.finalize().into_bytes()),
|
Self::new(nonce, ciphertext.to_vec(), hmac.finalize().into_bytes()),
|
||||||
*GenericArray::from_slice(&export_key),
|
*GenericArray::from_slice(&export_key),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -140,7 +140,7 @@ impl Group for EdwardsPoint {
|
|||||||
*GenericArray::from_slice(c.as_bytes())
|
*GenericArray::from_slice(c.as_bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
type UniformBytesLen = U64;
|
type UniformBytesLen = U32;
|
||||||
fn hash_to_curve(uniform_bytes: &GenericArray<u8, Self::UniformBytesLen>) -> Self {
|
fn hash_to_curve(uniform_bytes: &GenericArray<u8, Self::UniformBytesLen>) -> Self {
|
||||||
let mut result = [0u8; 32];
|
let mut result = [0u8; 32];
|
||||||
let mut counter = 0;
|
let mut counter = 0;
|
||||||
|
|||||||
+4
-4
@@ -9,7 +9,7 @@ use crate::{
|
|||||||
sized_bytes_using_constant_and_try_from,
|
sized_bytes_using_constant_and_try_from,
|
||||||
};
|
};
|
||||||
use generic_array::{
|
use generic_array::{
|
||||||
typenum::{U64, U96},
|
typenum::{U32, U64, U96},
|
||||||
GenericArray,
|
GenericArray,
|
||||||
};
|
};
|
||||||
use hkdf::Hkdf;
|
use hkdf::Hkdf;
|
||||||
@@ -199,9 +199,9 @@ struct TripleDHComponents {
|
|||||||
|
|
||||||
// Consists of a shared secret, followed by two mac keys
|
// Consists of a shared secret, followed by two mac keys
|
||||||
type TripleDHDerivationResult = (
|
type TripleDHDerivationResult = (
|
||||||
GenericArray<u8, <Sha256 as Digest>::OutputSize>,
|
GenericArray<u8, U32>,
|
||||||
GenericArray<u8, <Sha256 as Digest>::OutputSize>,
|
GenericArray<u8, U32>,
|
||||||
GenericArray<u8, <Sha256 as Digest>::OutputSize>,
|
GenericArray<u8, U32>,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Internal function which takes the public and private components of the client and server keypairs, along
|
// Internal function which takes the public and private components of the client and server keypairs, along
|
||||||
|
|||||||
+10
@@ -21,6 +21,7 @@
|
|||||||
//! use opaque_ke::ciphersuite::CipherSuite;
|
//! use opaque_ke::ciphersuite::CipherSuite;
|
||||||
//! struct Default;
|
//! struct Default;
|
||||||
//! impl CipherSuite for Default {
|
//! impl CipherSuite for Default {
|
||||||
|
//! type Digest = sha2::Sha512;
|
||||||
//! type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
//! type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
//! type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
//! type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
||||||
//! type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
//! type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
@@ -41,6 +42,7 @@
|
|||||||
//! # use opaque_ke::ciphersuite::CipherSuite;
|
//! # use opaque_ke::ciphersuite::CipherSuite;
|
||||||
//! # struct Default;
|
//! # struct Default;
|
||||||
//! # impl CipherSuite for Default {
|
//! # impl CipherSuite for Default {
|
||||||
|
//! # type Digest = sha2::Sha512;
|
||||||
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
||||||
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
@@ -72,6 +74,7 @@
|
|||||||
//! # use opaque_ke::ciphersuite::CipherSuite;
|
//! # use opaque_ke::ciphersuite::CipherSuite;
|
||||||
//! # struct Default;
|
//! # struct Default;
|
||||||
//! # impl CipherSuite for Default {
|
//! # impl CipherSuite for Default {
|
||||||
|
//! # type Digest = sha2::Sha512;
|
||||||
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
||||||
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
@@ -100,6 +103,7 @@
|
|||||||
//! # use opaque_ke::ciphersuite::CipherSuite;
|
//! # use opaque_ke::ciphersuite::CipherSuite;
|
||||||
//! # struct Default;
|
//! # struct Default;
|
||||||
//! # impl CipherSuite for Default {
|
//! # impl CipherSuite for Default {
|
||||||
|
//! # type Digest = sha2::Sha512;
|
||||||
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
||||||
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
@@ -131,6 +135,7 @@
|
|||||||
//! # use opaque_ke::ciphersuite::CipherSuite;
|
//! # use opaque_ke::ciphersuite::CipherSuite;
|
||||||
//! # struct Default;
|
//! # struct Default;
|
||||||
//! # impl CipherSuite for Default {
|
//! # impl CipherSuite for Default {
|
||||||
|
//! # type Digest = sha2::Sha512;
|
||||||
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
||||||
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
@@ -164,6 +169,7 @@
|
|||||||
//! # use opaque_ke::ciphersuite::CipherSuite;
|
//! # use opaque_ke::ciphersuite::CipherSuite;
|
||||||
//! # struct Default;
|
//! # struct Default;
|
||||||
//! # impl CipherSuite for Default {
|
//! # impl CipherSuite for Default {
|
||||||
|
//! # type Digest = sha2::Sha512;
|
||||||
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
||||||
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
@@ -205,6 +211,7 @@
|
|||||||
//! # use opaque_ke::ciphersuite::CipherSuite;
|
//! # use opaque_ke::ciphersuite::CipherSuite;
|
||||||
//! # struct Default;
|
//! # struct Default;
|
||||||
//! # impl CipherSuite for Default {
|
//! # impl CipherSuite for Default {
|
||||||
|
//! # type Digest = sha2::Sha512;
|
||||||
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
||||||
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
@@ -233,6 +240,7 @@
|
|||||||
//! # use opaque_ke::ciphersuite::CipherSuite;
|
//! # use opaque_ke::ciphersuite::CipherSuite;
|
||||||
//! # struct Default;
|
//! # struct Default;
|
||||||
//! # impl CipherSuite for Default {
|
//! # impl CipherSuite for Default {
|
||||||
|
//! # type Digest = sha2::Sha512;
|
||||||
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
||||||
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
@@ -276,6 +284,7 @@
|
|||||||
//! # use opaque_ke::ciphersuite::CipherSuite;
|
//! # use opaque_ke::ciphersuite::CipherSuite;
|
||||||
//! # struct Default;
|
//! # struct Default;
|
||||||
//! # impl CipherSuite for Default {
|
//! # impl CipherSuite for Default {
|
||||||
|
//! # type Digest = sha2::Sha512;
|
||||||
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
||||||
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
@@ -331,6 +340,7 @@
|
|||||||
//! # use opaque_ke::ciphersuite::CipherSuite;
|
//! # use opaque_ke::ciphersuite::CipherSuite;
|
||||||
//! # struct Default;
|
//! # struct Default;
|
||||||
//! # impl CipherSuite for Default {
|
//! # impl CipherSuite for Default {
|
||||||
|
//! # type Digest = sha2::Sha512;
|
||||||
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
||||||
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
|
|||||||
+14
-2
@@ -290,6 +290,7 @@ impl<CS: CipherSuite> ClientRegistration<CS> {
|
|||||||
/// use opaque_ke::ciphersuite::CipherSuite;
|
/// use opaque_ke::ciphersuite::CipherSuite;
|
||||||
/// struct Default;
|
/// struct Default;
|
||||||
/// impl CipherSuite for Default {
|
/// impl CipherSuite for Default {
|
||||||
|
/// type Digest = sha2::Sha512;
|
||||||
/// type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
/// type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
/// type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
/// type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
||||||
/// type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
/// type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
@@ -306,7 +307,11 @@ impl<CS: CipherSuite> ClientRegistration<CS> {
|
|||||||
let OprfClientBytes {
|
let OprfClientBytes {
|
||||||
alpha,
|
alpha,
|
||||||
blinding_factor,
|
blinding_factor,
|
||||||
} = oprf::generate_oprf1::<R, CS::Group>(&password, pepper, blinding_factor_rng)?;
|
} = oprf::generate_oprf1::<R, CS::Digest, CS::Group>(
|
||||||
|
&password,
|
||||||
|
pepper,
|
||||||
|
blinding_factor_rng,
|
||||||
|
)?;
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
RegisterFirstMessage::<CS::Group> { alpha },
|
RegisterFirstMessage::<CS::Group> { alpha },
|
||||||
@@ -340,6 +345,7 @@ impl<CS: CipherSuite> ClientRegistration<CS> {
|
|||||||
/// use opaque_ke::ciphersuite::CipherSuite;
|
/// use opaque_ke::ciphersuite::CipherSuite;
|
||||||
/// struct Default;
|
/// struct Default;
|
||||||
/// impl CipherSuite for Default {
|
/// impl CipherSuite for Default {
|
||||||
|
/// type Digest = sha2::Sha512;
|
||||||
/// type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
/// type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
/// type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
/// type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
||||||
/// type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
/// type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
@@ -503,6 +509,7 @@ where
|
|||||||
/// use opaque_ke::ciphersuite::CipherSuite;
|
/// use opaque_ke::ciphersuite::CipherSuite;
|
||||||
/// struct Default;
|
/// struct Default;
|
||||||
/// impl CipherSuite for Default {
|
/// impl CipherSuite for Default {
|
||||||
|
/// type Digest = sha2::Sha512;
|
||||||
/// type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
/// type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
/// type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
/// type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
||||||
/// type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
/// type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
@@ -549,6 +556,7 @@ where
|
|||||||
/// use opaque_ke::ciphersuite::CipherSuite;
|
/// use opaque_ke::ciphersuite::CipherSuite;
|
||||||
/// struct Default;
|
/// struct Default;
|
||||||
/// impl CipherSuite for Default {
|
/// impl CipherSuite for Default {
|
||||||
|
/// type Digest = sha2::Sha512;
|
||||||
/// type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
/// type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
/// type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
/// type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
||||||
/// type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
/// type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
@@ -637,6 +645,7 @@ impl<CS: CipherSuite> ClientLogin<CS> {
|
|||||||
/// use opaque_ke::ciphersuite::CipherSuite;
|
/// use opaque_ke::ciphersuite::CipherSuite;
|
||||||
/// struct Default;
|
/// struct Default;
|
||||||
/// impl CipherSuite for Default {
|
/// impl CipherSuite for Default {
|
||||||
|
/// type Digest = sha2::Sha512;
|
||||||
/// type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
/// type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
/// type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
/// type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
||||||
/// type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
/// type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
@@ -653,7 +662,7 @@ impl<CS: CipherSuite> ClientLogin<CS> {
|
|||||||
let OprfClientBytes {
|
let OprfClientBytes {
|
||||||
alpha,
|
alpha,
|
||||||
blinding_factor,
|
blinding_factor,
|
||||||
} = oprf::generate_oprf1::<R, CS::Group>(&password, pepper, rng)?;
|
} = oprf::generate_oprf1::<R, CS::Digest, CS::Group>(&password, pepper, rng)?;
|
||||||
|
|
||||||
let (ke1_state, ke1_message) =
|
let (ke1_state, ke1_message) =
|
||||||
generate_ke1::<_, CS::KeyFormat>(alpha.to_arr().to_vec(), rng)?;
|
generate_ke1::<_, CS::KeyFormat>(alpha.to_arr().to_vec(), rng)?;
|
||||||
@@ -688,6 +697,7 @@ impl<CS: CipherSuite> ClientLogin<CS> {
|
|||||||
/// use opaque_ke::ciphersuite::CipherSuite;
|
/// use opaque_ke::ciphersuite::CipherSuite;
|
||||||
/// struct Default;
|
/// struct Default;
|
||||||
/// impl CipherSuite for Default {
|
/// impl CipherSuite for Default {
|
||||||
|
/// type Digest = sha2::Sha512;
|
||||||
/// type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
/// type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
/// type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
/// type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
||||||
/// type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
/// type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
@@ -783,6 +793,7 @@ impl ServerLogin {
|
|||||||
/// use opaque_ke::ciphersuite::CipherSuite;
|
/// use opaque_ke::ciphersuite::CipherSuite;
|
||||||
/// struct Default;
|
/// struct Default;
|
||||||
/// impl CipherSuite for Default {
|
/// impl CipherSuite for Default {
|
||||||
|
/// type Digest = sha2::Sha512;
|
||||||
/// type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
/// type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
/// type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
/// type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
||||||
/// type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
/// type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
@@ -852,6 +863,7 @@ impl ServerLogin {
|
|||||||
/// use opaque_ke::ciphersuite::CipherSuite;
|
/// use opaque_ke::ciphersuite::CipherSuite;
|
||||||
/// struct Default;
|
/// struct Default;
|
||||||
/// impl CipherSuite for Default {
|
/// impl CipherSuite for Default {
|
||||||
|
/// type Digest = sha2::Sha512;
|
||||||
/// type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
/// type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
/// type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
/// type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
||||||
/// type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
/// type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
|
|||||||
+38
-18
@@ -4,29 +4,51 @@
|
|||||||
// LICENSE file in the root directory of this source tree.
|
// LICENSE file in the root directory of this source tree.
|
||||||
|
|
||||||
use crate::{errors::InternalPakeError, group::Group};
|
use crate::{errors::InternalPakeError, group::Group};
|
||||||
use generic_array::{typenum::U64, GenericArray};
|
use digest::{BlockInput, FixedOutput, Reset, Update};
|
||||||
|
use generic_array::{typenum::U32, ArrayLength, GenericArray};
|
||||||
use hkdf::Hkdf;
|
use hkdf::Hkdf;
|
||||||
use rand_core::{CryptoRng, RngCore};
|
use rand_core::{CryptoRng, RngCore};
|
||||||
use sha2::{Digest, Sha256};
|
|
||||||
|
|
||||||
pub(crate) struct OprfClientBytes<Grp: Group> {
|
pub(crate) struct OprfClientBytes<Grp: Group> {
|
||||||
pub(crate) alpha: Grp,
|
pub(crate) alpha: Grp,
|
||||||
pub(crate) blinding_factor: Grp::Scalar,
|
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
|
/// 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).
|
/// 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
|
/// The client can also pass in an optional "pepper" string to be mixed in with the input through
|
||||||
/// an HKDF computation.
|
/// an HKDF computation.
|
||||||
pub(crate) fn generate_oprf1<R: RngCore + CryptoRng, G: Group<UniformBytesLen = U64>>(
|
pub(crate) fn generate_oprf1<
|
||||||
|
R: RngCore + CryptoRng,
|
||||||
|
D: HkdfDigest,
|
||||||
|
G: Group<UniformBytesLen = D::OutputSize>,
|
||||||
|
>(
|
||||||
input: &[u8],
|
input: &[u8],
|
||||||
pepper: Option<&[u8]>,
|
pepper: Option<&[u8]>,
|
||||||
blinding_factor_rng: &mut R,
|
blinding_factor_rng: &mut R,
|
||||||
) -> Result<OprfClientBytes<G>, InternalPakeError> {
|
) -> Result<OprfClientBytes<G>, InternalPakeError> {
|
||||||
let (hashed_input, _) = Hkdf::<Sha256>::extract(pepper, &input);
|
let (hashed_input, _) = Hkdf::<D>::extract(pepper, &input);
|
||||||
let curve_input: Vec<u8> = [hashed_input.as_slice(), &[0u8; 32]].concat();
|
|
||||||
let blinding_factor = G::random_scalar(blinding_factor_rng);
|
let blinding_factor = G::random_scalar(blinding_factor_rng);
|
||||||
let alpha = G::hash_to_curve(GenericArray::from_slice(&curve_input)) * &blinding_factor;
|
let alpha = G::hash_to_curve(GenericArray::from_slice(&hashed_input)) * &blinding_factor;
|
||||||
Ok(OprfClientBytes {
|
Ok(OprfClientBytes {
|
||||||
alpha,
|
alpha,
|
||||||
blinding_factor,
|
blinding_factor,
|
||||||
@@ -48,10 +70,10 @@ pub(crate) fn generate_oprf3<G: Group>(
|
|||||||
input: &[u8],
|
input: &[u8],
|
||||||
point: G,
|
point: G,
|
||||||
blinding_factor: &G::Scalar,
|
blinding_factor: &G::Scalar,
|
||||||
) -> Result<GenericArray<u8, <Sha256 as Digest>::OutputSize>, InternalPakeError> {
|
) -> Result<GenericArray<u8, U32>, InternalPakeError> {
|
||||||
let unblinded = point * &G::scalar_invert(&blinding_factor);
|
let unblinded = point * &G::scalar_invert(&blinding_factor);
|
||||||
let ikm: Vec<u8> = [&unblinded.to_arr()[..], input].concat();
|
let ikm: Vec<u8> = [&unblinded.to_arr()[..], input].concat();
|
||||||
let (prk, _) = Hkdf::<Sha256>::extract(None, &ikm);
|
let (prk, _) = Hkdf::<sha2::Sha256>::extract(None, &ikm);
|
||||||
Ok(prk)
|
Ok(prk)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,14 +88,14 @@ mod tests {
|
|||||||
use generic_array::{arr, GenericArray};
|
use generic_array::{arr, GenericArray};
|
||||||
use hkdf::Hkdf;
|
use hkdf::Hkdf;
|
||||||
use rand_core::OsRng;
|
use rand_core::OsRng;
|
||||||
|
use sha2::{Digest, Sha256, Sha512};
|
||||||
|
|
||||||
fn prf(
|
fn prf(
|
||||||
input: &[u8],
|
input: &[u8],
|
||||||
oprf_key: &[u8; 32],
|
oprf_key: &[u8; 32],
|
||||||
) -> GenericArray<u8, <RistrettoPoint as Group>::ElemLen> {
|
) -> GenericArray<u8, <RistrettoPoint as Group>::ElemLen> {
|
||||||
let (hashed_input, _) = Hkdf::<Sha256>::extract(None, &input);
|
let (hashed_input, _) = Hkdf::<Sha512>::extract(None, &input);
|
||||||
let curve_input: Vec<u8> = [hashed_input.as_slice(), &[0u8; 32]].concat();
|
let point = RistrettoPoint::hash_to_curve(GenericArray::from_slice(&hashed_input));
|
||||||
let point = RistrettoPoint::hash_to_curve(GenericArray::from_slice(&curve_input));
|
|
||||||
let scalar =
|
let scalar =
|
||||||
RistrettoPoint::from_scalar_slice(GenericArray::from_slice(&oprf_key[..])).unwrap();
|
RistrettoPoint::from_scalar_slice(GenericArray::from_slice(&oprf_key[..])).unwrap();
|
||||||
let res = point * scalar;
|
let res = point * scalar;
|
||||||
@@ -90,7 +112,7 @@ mod tests {
|
|||||||
let OprfClientBytes {
|
let OprfClientBytes {
|
||||||
alpha,
|
alpha,
|
||||||
blinding_factor,
|
blinding_factor,
|
||||||
} = generate_oprf1::<_, RistrettoPoint>(&input[..], None, &mut rng)?;
|
} = generate_oprf1::<_, Sha512, RistrettoPoint>(&input[..], None, &mut rng)?;
|
||||||
let salt_bytes = arr![
|
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,
|
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,
|
24, 25, 26, 27, 28, 29, 30, 31, 32,
|
||||||
@@ -111,17 +133,15 @@ mod tests {
|
|||||||
let OprfClientBytes {
|
let OprfClientBytes {
|
||||||
alpha,
|
alpha,
|
||||||
blinding_factor,
|
blinding_factor,
|
||||||
} = generate_oprf1::<_, RistrettoPoint>(&input, None, &mut rng).unwrap();
|
} = generate_oprf1::<_, Sha512, RistrettoPoint>(&input, None, &mut rng).unwrap();
|
||||||
let res = generate_oprf3::<RistrettoPoint>(&input, alpha, &blinding_factor).unwrap();
|
let res = generate_oprf3::<RistrettoPoint>(&input, alpha, &blinding_factor).unwrap();
|
||||||
|
|
||||||
let (hashed_input, _) = Hkdf::<Sha256>::extract(None, &input);
|
let (hashed_input, _) = Hkdf::<Sha512>::extract(None, &input);
|
||||||
let mut curve_input: Vec<u8> = Vec::new();
|
|
||||||
curve_input.extend_from_slice(&hashed_input);
|
|
||||||
curve_input.extend_from_slice(&[0u8; 32]);
|
|
||||||
// This is because RistrettoPoint is on an obsolete sha2 version
|
// This is because RistrettoPoint is on an obsolete sha2 version
|
||||||
let mut bits = [0u8; 64];
|
let mut bits = [0u8; 64];
|
||||||
let mut hasher = sha2::Sha512::new();
|
let mut hasher = sha2::Sha512::new();
|
||||||
hasher.update(&curve_input[..]);
|
Digest::update(&mut hasher, &hashed_input[..]);
|
||||||
bits.copy_from_slice(&hasher.finalize());
|
bits.copy_from_slice(&hasher.finalize());
|
||||||
|
|
||||||
let point = RistrettoPoint::from_uniform_bytes(&bits);
|
let point = RistrettoPoint::from_uniform_bytes(&bits);
|
||||||
|
|||||||
+4
-11
@@ -7,33 +7,26 @@
|
|||||||
|
|
||||||
use crate::errors::InternalPakeError;
|
use crate::errors::InternalPakeError;
|
||||||
|
|
||||||
use generic_array::GenericArray;
|
use generic_array::{typenum::U32, GenericArray};
|
||||||
use sha2::{Digest, Sha256};
|
|
||||||
|
|
||||||
/// Used for the slow hashing function in OPAQUE
|
/// Used for the slow hashing function in OPAQUE
|
||||||
pub trait SlowHash {
|
pub trait SlowHash {
|
||||||
/// Computes the slow hashing function
|
/// Computes the slow hashing function
|
||||||
fn hash(
|
fn hash(input: GenericArray<u8, U32>) -> Result<Vec<u8>, InternalPakeError>;
|
||||||
input: GenericArray<u8, <Sha256 as Digest>::OutputSize>,
|
|
||||||
) -> Result<Vec<u8>, InternalPakeError>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A no-op hash which simply returns its input
|
/// A no-op hash which simply returns its input
|
||||||
pub struct NoOpHash;
|
pub struct NoOpHash;
|
||||||
|
|
||||||
impl SlowHash for NoOpHash {
|
impl SlowHash for NoOpHash {
|
||||||
fn hash(
|
fn hash(input: GenericArray<u8, U32>) -> Result<Vec<u8>, InternalPakeError> {
|
||||||
input: GenericArray<u8, <Sha256 as Digest>::OutputSize>,
|
|
||||||
) -> Result<Vec<u8>, InternalPakeError> {
|
|
||||||
Ok(input.to_vec())
|
Ok(input.to_vec())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "slow-hash")]
|
#[cfg(feature = "slow-hash")]
|
||||||
impl SlowHash for scrypt::ScryptParams {
|
impl SlowHash for scrypt::ScryptParams {
|
||||||
fn hash(
|
fn hash(input: GenericArray<u8, U32>) -> Result<Vec<u8>, InternalPakeError> {
|
||||||
input: GenericArray<u8, <Sha256 as Digest>::OutputSize>,
|
|
||||||
) -> Result<Vec<u8>, InternalPakeError> {
|
|
||||||
let params = scrypt::ScryptParams::new(15, 8, 1).unwrap();
|
let params = scrypt::ScryptParams::new(15, 8, 1).unwrap();
|
||||||
let mut output = [0u8; 32];
|
let mut output = [0u8; 32];
|
||||||
scrypt::scrypt(&input, &[], ¶ms, &mut output)
|
scrypt::scrypt(&input, &[], ¶ms, &mut output)
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ use std::convert::TryFrom;
|
|||||||
|
|
||||||
struct X255193dhNoSlowHash;
|
struct X255193dhNoSlowHash;
|
||||||
impl CipherSuite for X255193dhNoSlowHash {
|
impl CipherSuite for X255193dhNoSlowHash {
|
||||||
|
type Digest = sha2::Sha256;
|
||||||
type Group = EdwardsPoint;
|
type Group = EdwardsPoint;
|
||||||
type KeyFormat = X25519KeyPair;
|
type KeyFormat = X25519KeyPair;
|
||||||
type SlowHash = NoOpHash;
|
type SlowHash = NoOpHash;
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ use std::convert::TryFrom;
|
|||||||
|
|
||||||
struct Default;
|
struct Default;
|
||||||
impl CipherSuite for Default {
|
impl CipherSuite for Default {
|
||||||
|
type Digest = sha2::Sha512;
|
||||||
type Group = RistrettoPoint;
|
type Group = RistrettoPoint;
|
||||||
type KeyFormat = crate::keypair::X25519KeyPair;
|
type KeyFormat = crate::keypair::X25519KeyPair;
|
||||||
type SlowHash = crate::slow_hash::NoOpHash;
|
type SlowHash = crate::slow_hash::NoOpHash;
|
||||||
|
|||||||
Reference in New Issue
Block a user