Skip to content

Commit

Permalink
Update keypair generation to use derive_auth_keypair
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinlewi committed May 27, 2023
1 parent c73eb96 commit 75e9170
Show file tree
Hide file tree
Showing 11 changed files with 582 additions and 566 deletions.
21 changes: 8 additions & 13 deletions src/envelope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ use crate::serialization::{Input, MacExt};
const STR_AUTH_KEY: [u8; 7] = *b"AuthKey";
const STR_EXPORT_KEY: [u8; 9] = *b"ExportKey";
const STR_PRIVATE_KEY: [u8; 10] = *b"PrivateKey";
const STR_OPAQUE_DERIVE_AUTH_KEY_PAIR: [u8; 24] = *b"OPAQUE-DeriveAuthKeyPair";
type NonceLen = U32;

#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
Expand Down Expand Up @@ -341,12 +340,10 @@ where
randomized_pwd_hasher
.expand(&nonce.concat(STR_PRIVATE_KEY.into()), &mut keypair_seed)
.map_err(|_| InternalError::HkdfError)?;
let client_static_keypair = KeyPair::<CS::KeGroup>::from_private_key_slice(
&CS::KeGroup::serialize_sk(CS::KeGroup::derive_auth_keypair::<CS::OprfCs>(
keypair_seed,
&GenericArray::from(STR_OPAQUE_DERIVE_AUTH_KEY_PAIR),
)?),
)?;
let client_static_keypair =
KeyPair::<CS::KeGroup>::from_private_key_slice(&CS::KeGroup::serialize_sk(
CS::KeGroup::derive_auth_keypair::<CS::OprfCs>(keypair_seed)?,
))?;

Ok(client_static_keypair.public().clone())
}
Expand All @@ -367,12 +364,10 @@ where
randomized_pwd_hasher
.expand(&nonce.concat(STR_PRIVATE_KEY.into()), &mut keypair_seed)
.map_err(|_| InternalError::HkdfError)?;
let client_static_keypair = KeyPair::<CS::KeGroup>::from_private_key_slice(
&CS::KeGroup::serialize_sk(CS::KeGroup::derive_auth_keypair::<CS::OprfCs>(
keypair_seed,
&GenericArray::from(STR_OPAQUE_DERIVE_AUTH_KEY_PAIR),
)?),
)?;
let client_static_keypair =
KeyPair::<CS::KeGroup>::from_private_key_slice(&CS::KeGroup::serialize_sk(
CS::KeGroup::derive_auth_keypair::<CS::OprfCs>(keypair_seed)?,
))?;

Ok(client_static_keypair)
}
Expand Down
1 change: 0 additions & 1 deletion src/key_exchange/group/curve25519.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ impl KeGroup for Curve25519 {

fn derive_auth_keypair<CS: voprf::CipherSuite>(
seed: GenericArray<u8, Self::SkLen>,
_info: &[u8],
) -> Result<Self::Sk, InternalError>
where
<CS::Hash as OutputSizeUser>::OutputSize:
Expand Down
4 changes: 3 additions & 1 deletion src/key_exchange/group/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ use zeroize::Zeroize;

use crate::errors::InternalError;

const STR_OPAQUE_DERIVE_AUTH_KEY_PAIR: [u8; 33] = *b"OPAQUE-DeriveDiffieHellmanKeyPair";

/// A group representation for use in the key exchange
pub trait KeGroup {
/// Public key
Expand Down Expand Up @@ -62,12 +64,12 @@ pub trait KeGroup {
/// opposed to the OprfGroup).
fn derive_auth_keypair<CS: voprf::CipherSuite>(
seed: GenericArray<u8, Self::SkLen>,
info: &[u8],
) -> Result<Self::Sk, InternalError>
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
let info = &STR_OPAQUE_DERIVE_AUTH_KEY_PAIR;
let dst_1 = GenericArray::from(STR_DERIVE_KEYPAIR)
.concat(STR_OPRF.into())
.concat([voprf::Mode::Oprf.to_u8()].into())
Expand Down
26 changes: 20 additions & 6 deletions src/key_exchange/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
// of this source tree. You may select, at your option, one of the above-listed
// licenses.

use digest::core_api::BlockSizeUser;
use digest::core_api::{BlockSizeUser, OutputSizeUser};
use digest::Output;
use generic_array::typenum::{IsLess, Le, NonZero, U256};
use generic_array::typenum::{IsLess, IsLessOrEqual, Le, NonZero, U256};
use generic_array::{ArrayLength, GenericArray};
use rand::{CryptoRng, RngCore};
use zeroize::ZeroizeOnDrop;
Expand All @@ -31,12 +31,23 @@ where
type KE2Message: Deserialize + Serialize + ZeroizeOnDrop + Clone;
type KE3Message: Deserialize + Serialize + ZeroizeOnDrop + Clone;

fn generate_ke1<R: RngCore + CryptoRng>(
fn generate_ke1<OprfCs: voprf::CipherSuite, R: RngCore + CryptoRng>(
rng: &mut R,
) -> Result<(Self::KE1State, Self::KE1Message), ProtocolError>;
) -> Result<(Self::KE1State, Self::KE1Message), ProtocolError>
where
<OprfCs::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfCs::Hash as BlockSizeUser>::BlockSize>;

#[allow(clippy::too_many_arguments)]
fn generate_ke2<'a, 'b, 'c, 'd, R: RngCore + CryptoRng, S: SecretKey<G>>(
fn generate_ke2<
'a,
'b,
'c,
'd,
OprfCs: voprf::CipherSuite,
R: RngCore + CryptoRng,
S: SecretKey<G>,
>(
rng: &mut R,
l1_bytes: impl Iterator<Item = &'a [u8]>,
l2_bytes: impl Iterator<Item = &'b [u8]>,
Expand All @@ -46,7 +57,10 @@ where
id_u: impl Iterator<Item = &'c [u8]>,
id_s: impl Iterator<Item = &'d [u8]>,
context: &[u8],
) -> Result<GenerateKe2Result<Self, D, G>, ProtocolError<S::Error>>;
) -> Result<GenerateKe2Result<Self, D, G>, ProtocolError<S::Error>>
where
<OprfCs::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfCs::Hash as BlockSizeUser>::BlockSize>;

#[allow(clippy::too_many_arguments)]
fn generate_ke3<'a, 'b, 'c, 'd>(
Expand Down
34 changes: 26 additions & 8 deletions src/key_exchange/tripledh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ use core::ops::Add;

use derive_where::derive_where;
use digest::core_api::BlockSizeUser;
use digest::{Digest, Output};
use digest::{Digest, Output, OutputSizeUser};
use generic_array::sequence::Concat;
use generic_array::typenum::{IsLess, Le, NonZero, Sum, Unsigned, U1, U2, U256, U32};
use generic_array::typenum::{
IsLess, IsLessOrEqual, Le, NonZero, Sum, Unsigned, U1, U2, U256, U32,
};
use generic_array::{ArrayLength, GenericArray};
use hkdf::{Hkdf, HkdfExtract};
use hmac::{Hmac, Mac};
Expand Down Expand Up @@ -161,10 +163,14 @@ where
type KE2Message = Ke2Message<D, KG>;
type KE3Message = Ke3Message<D>;

fn generate_ke1<R: RngCore + CryptoRng>(
fn generate_ke1<OprfCs: voprf::CipherSuite, R: RngCore + CryptoRng>(
rng: &mut R,
) -> Result<(Self::KE1State, Self::KE1Message), ProtocolError> {
let client_e_kp = KeyPair::<KG>::generate_random(rng);
) -> Result<(Self::KE1State, Self::KE1Message), ProtocolError>
where
<OprfCs::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfCs::Hash as BlockSizeUser>::BlockSize>,
{
let client_e_kp = KeyPair::<KG>::generate_random::<OprfCs, _>(rng);
let client_nonce = generate_nonce::<R>(rng);

let ke1_message = Ke1Message {
Expand All @@ -182,7 +188,15 @@ where
}

#[allow(clippy::type_complexity)]
fn generate_ke2<'a, 'b, 'c, 'd, R: RngCore + CryptoRng, S: SecretKey<KG>>(
fn generate_ke2<
'a,
'b,
'c,
'd,
OprfCs: voprf::CipherSuite,
R: RngCore + CryptoRng,
S: SecretKey<KG>,
>(
rng: &mut R,
serialized_credential_request: impl Iterator<Item = &'a [u8]>,
l2_bytes: impl Iterator<Item = &'b [u8]>,
Expand All @@ -192,8 +206,12 @@ where
id_u: impl Iterator<Item = &'c [u8]>,
id_s: impl Iterator<Item = &'d [u8]>,
context: &[u8],
) -> Result<GenerateKe2Result<Self, D, KG>, ProtocolError<S::Error>> {
let server_e_kp = KeyPair::<KG>::generate_random(rng);
) -> Result<GenerateKe2Result<Self, D, KG>, ProtocolError<S::Error>>
where
<OprfCs::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfCs::Hash as BlockSizeUser>::BlockSize>,
{
let server_e_kp = KeyPair::<KG>::generate_random::<OprfCs, _>(rng);
let server_nonce = generate_nonce::<R>(rng);

let mut transcript_hasher = D::new()
Expand Down
32 changes: 24 additions & 8 deletions src/keypair.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
#![allow(unsafe_code)]

use derive_where::derive_where;
use digest::core_api::BlockSizeUser;
use digest::OutputSizeUser;
use generic_array::typenum::{IsLess, IsLessOrEqual, U256};
use generic_array::{ArrayLength, GenericArray};
use rand::{CryptoRng, RngCore};

Expand Down Expand Up @@ -58,8 +61,17 @@ impl<KG: KeGroup, S: SecretKey<KG>> KeyPair<KG, S> {

impl<KG: KeGroup> KeyPair<KG> {
/// Generating a random key pair given a cryptographic rng
pub(crate) fn generate_random<R: RngCore + CryptoRng>(rng: &mut R) -> Self {
let sk = KG::random_sk(rng);
pub(crate) fn generate_random<CS: voprf::CipherSuite, R: RngCore + CryptoRng>(
rng: &mut R,
) -> Self
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
let mut scalar_bytes = GenericArray::<_, <KG as KeGroup>::SkLen>::default();
rng.fill_bytes(&mut scalar_bytes);
let sk =
KG::derive_auth_keypair::<CS>(GenericArray::clone_from_slice(&scalar_bytes)).unwrap();
let pk = KG::public_key(sk);
Self {
pk: PublicKey(pk),
Expand All @@ -76,7 +88,11 @@ where
{
/// Test-only strategy returning a proptest Strategy based on
/// generate_random
fn uniform_keypair_strategy() -> proptest::prelude::BoxedStrategy<Self> {
fn uniform_keypair_strategy<CS: voprf::CipherSuite>() -> proptest::prelude::BoxedStrategy<Self>
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
use proptest::prelude::*;
use rand::rngs::StdRng;
use rand::SeedableRng;
Expand All @@ -86,7 +102,7 @@ where
any::<[u8; 32]>()
.prop_filter_map("valid random keypair", |seed| {
let mut rng = StdRng::from_seed(seed);
Some(Self::generate_random(&mut rng))
Some(Self::generate_random::<CS, _>(&mut rng))
})
.no_shrink()
.boxed()
Expand Down Expand Up @@ -243,15 +259,15 @@ mod tests {

proptest! {
#[test]
fn pub_from_priv(kp in KeyPair::<$point>::uniform_keypair_strategy()) {
fn pub_from_priv(kp in KeyPair::<$point>::uniform_keypair_strategy::<$point>()) {
let pk = kp.public();
let sk = kp.private();
prop_assert_eq!(&sk.public_key()?, pk);
}

#[test]
fn dh(kp1 in KeyPair::<$point>::uniform_keypair_strategy(),
kp2 in KeyPair::<$point>::uniform_keypair_strategy()) {
fn dh(kp1 in KeyPair::<$point>::uniform_keypair_strategy::<$point>(),
kp2 in KeyPair::<$point>::uniform_keypair_strategy::<$point>()) {

let dh1 = kp2.private().diffie_hellman(kp1.public().clone())?;
let dh2 = kp1.private().diffie_hellman(kp2.public().clone())?;
Expand All @@ -260,7 +276,7 @@ mod tests {
}

#[test]
fn private_key_slice(kp in KeyPair::<$point>::uniform_keypair_strategy()) {
fn private_key_slice(kp in KeyPair::<$point>::uniform_keypair_strategy::<$point>()) {
let sk_bytes = kp.private().serialize().to_vec();

let kp2 = KeyPair::<$point>::from_private_key_slice(&sk_bytes)?;
Expand Down
8 changes: 4 additions & 4 deletions src/opaque.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ where
{
/// Generate a new instance of server setup
pub fn new<R: CryptoRng + RngCore>(rng: &mut R) -> Self {
let keypair = KeyPair::generate_random(rng);
let keypair = KeyPair::generate_random::<CS::OprfCs, _>(rng);
Self::new_with_key(rng, keypair)
}
}
Expand Down Expand Up @@ -234,7 +234,7 @@ where
Self {
oprf_seed,
keypair,
fake_keypair: KeyPair::<CS::KeGroup>::generate_random(rng),
fake_keypair: KeyPair::<CS::KeGroup>::generate_random::<CS::OprfCs, _>(rng),
}
}

Expand Down Expand Up @@ -542,7 +542,7 @@ where
password: &[u8],
) -> Result<ClientLoginStartResult<CS>, ProtocolError> {
let blind_result = blind::<CS, _>(rng, password)?;
let (ke1_state, ke1_message) = CS::KeyExchange::generate_ke1(rng)?;
let (ke1_state, ke1_message) = CS::KeyExchange::generate_ke1::<CS::OprfCs, _>(rng)?;

let credential_request = CredentialRequest {
blinded_element: blind_result.message,
Expand Down Expand Up @@ -757,7 +757,7 @@ where
let credential_response_component =
CredentialResponse::<CS>::serialize_without_ke(&beta, &masking_nonce, &masked_response);

let result = CS::KeyExchange::generate_ke2(
let result = CS::KeyExchange::generate_ke2::<CS::OprfCs, _, _>(
rng,
credential_request_bytes,
credential_response_component,
Expand Down
16 changes: 8 additions & 8 deletions src/serialization/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ fn server_registration_roundtrip() -> Result<(), ProtocolError> {
// length-MAC_SIZE hmac
mock_envelope_bytes.extend_from_slice(&Output::<OprfHash<CS>>::default());

let mock_client_kp = KeyPair::<CS::KeGroup>::generate_random(&mut rng);
let mock_client_kp = KeyPair::<CS::KeGroup>::generate_random::<CS::OprfCs, _>(&mut rng);
// serialization order: oprf_key, public key, envelope
let mut bytes = Vec::<u8>::new();
bytes.extend_from_slice(&mock_client_kp.public().serialize());
Expand Down Expand Up @@ -233,7 +233,7 @@ fn registration_response_roundtrip() -> Result<(), ProtocolError> {
let pt = random_point::<CS>();
let beta_bytes = CS::KeGroup::serialize_pk(pt);
let mut rng = OsRng;
let skp = KeyPair::<CS::KeGroup>::generate_random(&mut rng);
let skp = KeyPair::<CS::KeGroup>::generate_random::<CS::OprfCs, _>(&mut rng);
let pubkey_bytes = skp.public().serialize();

let mut input = Vec::new();
Expand Down Expand Up @@ -288,7 +288,7 @@ fn registration_upload_roundtrip() -> Result<(), ProtocolError> {
RegistrationUploadLen<CS>: ArrayLength<u8>,
{
let mut rng = OsRng;
let skp = KeyPair::<CS::KeGroup>::generate_random(&mut rng);
let skp = KeyPair::<CS::KeGroup>::generate_random::<CS::OprfCs, _>(&mut rng);
let pubkey_bytes = skp.public().serialize();

let mut key = [0u8; 32];
Expand Down Expand Up @@ -348,7 +348,7 @@ fn credential_request_roundtrip() -> Result<(), ProtocolError> {
let alpha = random_point::<CS>();
let alpha_bytes = CS::KeGroup::serialize_pk(alpha);

let client_e_kp = KeyPair::<CS::KeGroup>::generate_random(&mut rng);
let client_e_kp = KeyPair::<CS::KeGroup>::generate_random::<CS::OprfCs, _>(&mut rng);
let mut client_nonce = [0u8; NonceLen::USIZE];
rng.fill_bytes(&mut client_nonce);

Expand Down Expand Up @@ -424,7 +424,7 @@ fn credential_response_roundtrip() -> Result<(), ProtocolError> {
vec![0u8; <OprfGroup<CS> as Group>::ElemLen::USIZE + Envelope::<CS>::len()];
rng.fill_bytes(&mut masked_response);

let server_e_kp = KeyPair::<CS::KeGroup>::generate_random(&mut rng);
let server_e_kp = KeyPair::<CS::KeGroup>::generate_random::<CS::OprfCs, _>(&mut rng);
let mut mac = Output::<OprfHash<CS>>::default();
rng.fill_bytes(&mut mac);
let mut server_nonce = [0u8; NonceLen::USIZE];
Expand Down Expand Up @@ -531,7 +531,7 @@ fn client_login_roundtrip() -> Result<(), ProtocolError> {
let pw = b"hunter2";
let mut rng = OsRng;

let client_e_kp = KeyPair::<CS::KeGroup>::generate_random(&mut rng);
let client_e_kp = KeyPair::<CS::KeGroup>::generate_random::<CS::OprfCs, _>(&mut rng);
let mut client_nonce = [0; NonceLen::USIZE];
rng.fill_bytes(&mut client_nonce);

Expand Down Expand Up @@ -590,7 +590,7 @@ fn ke1_message_roundtrip() -> Result<(), ProtocolError> {
{
let mut rng = OsRng;

let client_e_kp = KeyPair::<CS::KeGroup>::generate_random(&mut rng);
let client_e_kp = KeyPair::<CS::KeGroup>::generate_random::<CS::OprfCs, _>(&mut rng);
let mut client_nonce = vec![0u8; NonceLen::USIZE];
rng.fill_bytes(&mut client_nonce);

Expand Down Expand Up @@ -630,7 +630,7 @@ fn ke2_message_roundtrip() -> Result<(), ProtocolError> {
{
let mut rng = OsRng;

let server_e_kp = KeyPair::<CS::KeGroup>::generate_random(&mut rng);
let server_e_kp = KeyPair::<CS::KeGroup>::generate_random::<CS::OprfCs, _>(&mut rng);
let mut mac = Output::<OprfHash<CS>>::default();
rng.fill_bytes(&mut mac);
let mut server_nonce = vec![0u8; NonceLen::USIZE];
Expand Down
Loading

0 comments on commit 75e9170

Please sign in to comment.