SIGMA-I Key Exchange (#378)
* Move `KeGroup` to `KeyExchange::Group` - Introduce `KeyExchange::Hash`, which separates the OPRF hash from the one used in `KeyExchange`. - Remove `De/Serialize` requirement on key exchange messages and states, which forced a lot of where bounds on downstream users. - Rename `KeGroup` to `Group`. - Replace `D` generic for hash with `H`. * Use `voprf::derive_key()` directly * Implement SIGMA-I key exchange * Improve `KeyExchange` for SIGMA-I and Ed25519 * Implement EdDSA * Un-qualify some method calls * SIGMA-I: only include client identity in client mac * SIGMA-I: include server mac in client signature * Expose key exchange types in `crate` & move modules * Implement Ed25519ph * Document `ed25519` crate feature * Remove `ristretto255-voprf` crate feature * Adjust CI crate feature testing * Fix Rustdoc * Remove unnecessary generic parameters from SIGMA-I * Properly mark to-do's with TODO * Assorted fixes * SIGMA-I: include context in signature * SIGMA-I: include identifiers in signature * Merge `ServerLoginStart/FinishParameters` * Re-export more necessary types * More carefully expose types * Add ECDSA test * SIGMA-I: share context hashing * De-duplicate client static public key storage * Hide `KeyExchange` better * Use the correct hash in the root documentation * Bump `derive-where` * Format documentation examples a bit further * Add remote OPRF seed documentation * Rename `deserialize_key_pair` to `deserialize_take_key_pair` * Add more key tests * Remove `SharedSecret` trait * SIGMA-I refactor message API * Share more implementation between 3DH and SIGMA-I * Remove unnecessary zero scalar check for Curve25519 * Use correct hash in test * Add some more TODOs * Exclude `tests` folder from Cargo publishing * Enable missing dependencies * Use right crate for testing Ed25519 * Remove unnecessary `Sized` constraints * Remove unnecessary `ecdsa` crate features * Move signature de/serialization to trait methods * Nit: move import to appropriate location * Add warning to SIGMA-I
This commit is contained in:
@@ -16,15 +16,16 @@ use generic_array::{ArrayLength, GenericArray};
|
||||
use rand::rngs::OsRng;
|
||||
use rand::RngCore;
|
||||
use serde_json::Value;
|
||||
use voprf::Group;
|
||||
|
||||
use crate::ciphersuite::{CipherSuite, OprfGroup, OprfHash};
|
||||
use crate::ciphersuite::{CipherSuite, KeGroup, OprfGroup, OprfHash};
|
||||
use crate::envelope::EnvelopeLen;
|
||||
use crate::errors::*;
|
||||
use crate::hash::OutputSize;
|
||||
use crate::key_exchange::group::KeGroup;
|
||||
use crate::key_exchange::traits::{Ke1MessageLen, Ke2MessageLen};
|
||||
use crate::key_exchange::tripledh::{NonceLen, TripleDh};
|
||||
use crate::key_exchange::group::Group;
|
||||
use crate::key_exchange::shared::NonceLen;
|
||||
use crate::key_exchange::traits::{
|
||||
Deserialize, Ke1MessageLen, Ke2MessageLen, KeyExchange, Serialize,
|
||||
};
|
||||
use crate::ksf::Identity;
|
||||
use crate::messages::{
|
||||
CredentialRequestLen, CredentialResponseLen, CredentialResponseWithoutKeLen,
|
||||
@@ -99,7 +100,7 @@ fn populate_test_vectors<CS: CipherSuite>(values: &Value) -> OpaqueTestVectorPar
|
||||
dummy_private_key: {
|
||||
match decode(values, "client_private_key") {
|
||||
Some(value) => value,
|
||||
None => CS::KeGroup::serialize_sk(CS::KeGroup::random_sk(&mut OsRng)).to_vec(),
|
||||
None => KeGroup::<CS>::serialize_sk(KeGroup::<CS>::random_sk(&mut OsRng)).to_vec(),
|
||||
}
|
||||
},
|
||||
dummy_masking_key: {
|
||||
@@ -149,12 +150,9 @@ fn populate_test_vectors<CS: CipherSuite>(values: &Value) -> OpaqueTestVectorPar
|
||||
|
||||
fn get_password_file_bytes<CS: CipherSuite>(parameters: &OpaqueTestVectorParameters) -> Vec<u8>
|
||||
where
|
||||
// Envelope: Nonce + Hash
|
||||
NonceLen: Add<OutputSize<OprfHash<CS>>>,
|
||||
EnvelopeLen<CS>: ArrayLength<u8>,
|
||||
// RegistrationUpload: (KePk + Hash) + Envelope
|
||||
<CS::KeGroup as KeGroup>::PkLen: Add<OutputSize<OprfHash<CS>>>,
|
||||
Sum<<CS::KeGroup as KeGroup>::PkLen, OutputSize<OprfHash<CS>>>:
|
||||
<KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>,
|
||||
Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>:
|
||||
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
|
||||
RegistrationUploadLen<CS>: ArrayLength<u8>,
|
||||
// ServerRegistration = RegistrationUpload
|
||||
@@ -194,8 +192,7 @@ fn tests() -> Result<(), ProtocolError> {
|
||||
struct Ristretto255Sha512NoKsf;
|
||||
impl CipherSuite for Ristretto255Sha512NoKsf {
|
||||
type OprfCs = crate::Ristretto255;
|
||||
type KeGroup = crate::Ristretto255;
|
||||
type KeyExchange = TripleDh;
|
||||
type KeyExchange = TripleDh<crate::Ristretto255, sha2::Sha512>;
|
||||
type Ksf = Identity;
|
||||
}
|
||||
|
||||
@@ -233,8 +230,7 @@ fn tests() -> Result<(), ProtocolError> {
|
||||
struct Ristretto255Sha512Curve25519NoKsf;
|
||||
impl CipherSuite for Ristretto255Sha512Curve25519NoKsf {
|
||||
type OprfCs = crate::Ristretto255;
|
||||
type KeGroup = crate::Curve25519;
|
||||
type KeyExchange = TripleDh;
|
||||
type KeyExchange = TripleDh<crate::Curve25519, sha2::Sha512>;
|
||||
type Ksf = Identity;
|
||||
}
|
||||
|
||||
@@ -270,8 +266,7 @@ fn tests() -> Result<(), ProtocolError> {
|
||||
struct P256Sha256NoKsf;
|
||||
impl CipherSuite for P256Sha256NoKsf {
|
||||
type OprfCs = p256::NistP256;
|
||||
type KeGroup = p256::NistP256;
|
||||
type KeyExchange = TripleDh;
|
||||
type KeyExchange = TripleDh<p256::NistP256, sha2::Sha256>;
|
||||
type Ksf = Identity;
|
||||
}
|
||||
|
||||
@@ -325,7 +320,7 @@ fn test_registration_response<CS: CipherSuite>(
|
||||
) -> Result<(), ProtocolError>
|
||||
where
|
||||
// RegistrationResponse: KgPk + KePk
|
||||
<OprfGroup<CS> as Group>::ElemLen: Add<<CS::KeGroup as KeGroup>::PkLen>,
|
||||
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<<KeGroup<CS> as Group>::PkLen>,
|
||||
RegistrationResponseLen<CS>: ArrayLength<u8>,
|
||||
{
|
||||
for parameters in tvs {
|
||||
@@ -362,12 +357,9 @@ fn test_registration_upload<CS: CipherSuite>(
|
||||
tvs: &[OpaqueTestVectorParameters],
|
||||
) -> Result<(), ProtocolError>
|
||||
where
|
||||
// Envelope: Nonce + Hash
|
||||
NonceLen: Add<OutputSize<OprfHash<CS>>>,
|
||||
EnvelopeLen<CS>: ArrayLength<u8>,
|
||||
// RegistrationUpload: (KePk + Hash) + Envelope
|
||||
<CS::KeGroup as KeGroup>::PkLen: Add<OutputSize<OprfHash<CS>>>,
|
||||
Sum<<CS::KeGroup as KeGroup>::PkLen, OutputSize<OprfHash<CS>>>:
|
||||
<KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>,
|
||||
Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>:
|
||||
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
|
||||
RegistrationUploadLen<CS>: ArrayLength<u8>,
|
||||
{
|
||||
@@ -413,7 +405,8 @@ where
|
||||
fn test_ke1<CS: CipherSuite>(tvs: &[OpaqueTestVectorParameters]) -> Result<(), ProtocolError>
|
||||
where
|
||||
// CredentialRequest: KgPk + Ke1Message
|
||||
<OprfGroup<CS> as Group>::ElemLen: Add<Ke1MessageLen<CS>>,
|
||||
<CS::KeyExchange as KeyExchange>::KE1Message: Serialize,
|
||||
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<Ke1MessageLen<CS>>,
|
||||
CredentialRequestLen<CS>: ArrayLength<u8>,
|
||||
{
|
||||
for parameters in tvs {
|
||||
@@ -437,28 +430,20 @@ where
|
||||
|
||||
fn test_ke2<CS: CipherSuite>(tvs: &[OpaqueTestVectorParameters]) -> Result<(), ProtocolError>
|
||||
where
|
||||
// Envelope: Nonce + Hash
|
||||
NonceLen: Add<OutputSize<OprfHash<CS>>>,
|
||||
EnvelopeLen<CS>: ArrayLength<u8>,
|
||||
<CS::KeyExchange as KeyExchange>::KE1Message: Deserialize,
|
||||
// RegistrationUpload: (KePk + Hash) + Envelope
|
||||
<CS::KeGroup as KeGroup>::PkLen: Add<OutputSize<OprfHash<CS>>>,
|
||||
Sum<<CS::KeGroup as KeGroup>::PkLen, OutputSize<OprfHash<CS>>>:
|
||||
<KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>,
|
||||
Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>:
|
||||
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
|
||||
RegistrationUploadLen<CS>: ArrayLength<u8>,
|
||||
// ServerRegistration = RegistrationUpload
|
||||
// MaskedResponse: (Nonce + Hash) + KePk
|
||||
NonceLen: Add<OutputSize<OprfHash<CS>>>,
|
||||
Sum<NonceLen, OutputSize<OprfHash<CS>>>: ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::PkLen>,
|
||||
MaskedResponseLen<CS>: ArrayLength<u8>,
|
||||
// CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse
|
||||
<OprfGroup<CS> as Group>::ElemLen: Add<NonceLen>,
|
||||
Sum<<OprfGroup<CS> as Group>::ElemLen, NonceLen>: ArrayLength<u8> + Add<MaskedResponseLen<CS>>,
|
||||
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<NonceLen>,
|
||||
Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, NonceLen>:
|
||||
ArrayLength<u8> + Add<MaskedResponseLen<CS>>,
|
||||
CredentialResponseWithoutKeLen<CS>: ArrayLength<u8>,
|
||||
// MaskedResponse: (Nonce + Hash) + KePk
|
||||
NonceLen: Add<OutputSize<OprfHash<CS>>>,
|
||||
Sum<NonceLen, OutputSize<OprfHash<CS>>>: ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::PkLen>,
|
||||
MaskedResponseLen<CS>: ArrayLength<u8>,
|
||||
// CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message
|
||||
<CS::KeyExchange as KeyExchange>::KE2Message: Serialize,
|
||||
CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>,
|
||||
CredentialResponseLen<CS>: ArrayLength<u8>,
|
||||
{
|
||||
@@ -490,7 +475,7 @@ where
|
||||
Some(record),
|
||||
CredentialRequest::<CS>::deserialize(¶meters.KE1).unwrap(),
|
||||
¶meters.credential_identifier,
|
||||
ServerLoginStartParameters {
|
||||
ServerLoginParameters {
|
||||
context: Some(¶meters.context),
|
||||
identifiers: Identifiers {
|
||||
client: parameters.client_identity.as_deref(),
|
||||
@@ -520,10 +505,8 @@ where
|
||||
|
||||
fn test_ke3<CS: CipherSuite>(tvs: &[OpaqueTestVectorParameters]) -> Result<(), ProtocolError>
|
||||
where
|
||||
// MaskedResponse: (Nonce + Hash) + KePk
|
||||
NonceLen: Add<OutputSize<OprfHash<CS>>>,
|
||||
Sum<NonceLen, OutputSize<OprfHash<CS>>>: ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::PkLen>,
|
||||
MaskedResponseLen<CS>: ArrayLength<u8>,
|
||||
<CS::KeyExchange as KeyExchange>::KE2Message: Deserialize + Serialize,
|
||||
<CS::KeyExchange as KeyExchange>::KE3Message: Serialize,
|
||||
{
|
||||
for parameters in tvs {
|
||||
let client_login_start = [
|
||||
@@ -537,6 +520,7 @@ where
|
||||
ClientLogin::<CS>::start(&mut client_login_start_rng, ¶meters.password)?;
|
||||
|
||||
let client_login_finish_result = client_login_start_result.state.finish(
|
||||
&mut OsRng,
|
||||
¶meters.password,
|
||||
CredentialResponse::<CS>::deserialize(¶meters.KE2)?,
|
||||
ClientLoginFinishParameters::new(
|
||||
@@ -577,19 +561,14 @@ fn test_server_login_finish<CS: CipherSuite>(
|
||||
tvs: &[OpaqueTestVectorParameters],
|
||||
) -> Result<(), ProtocolError>
|
||||
where
|
||||
// Envelope: Nonce + Hash
|
||||
NonceLen: Add<OutputSize<OprfHash<CS>>>,
|
||||
EnvelopeLen<CS>: ArrayLength<u8>,
|
||||
<CS::KeyExchange as KeyExchange>::KE1Message: Deserialize,
|
||||
<CS::KeyExchange as KeyExchange>::KE3Message: Deserialize,
|
||||
// RegistrationUpload: (KePk + Hash) + Envelope
|
||||
<CS::KeGroup as KeGroup>::PkLen: Add<OutputSize<OprfHash<CS>>>,
|
||||
Sum<<CS::KeGroup as KeGroup>::PkLen, OutputSize<OprfHash<CS>>>:
|
||||
<KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>,
|
||||
Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>:
|
||||
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
|
||||
RegistrationUploadLen<CS>: ArrayLength<u8>,
|
||||
// ServerRegistration = RegistrationUpload
|
||||
// MaskedResponse: (Nonce + Hash) + KePk
|
||||
NonceLen: Add<OutputSize<OprfHash<CS>>>,
|
||||
Sum<NonceLen, OutputSize<OprfHash<CS>>>: ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::PkLen>,
|
||||
MaskedResponseLen<CS>: ArrayLength<u8>,
|
||||
{
|
||||
for parameters in tvs {
|
||||
let server_setup = ServerSetup::<CS>::deserialize(
|
||||
@@ -619,7 +598,7 @@ where
|
||||
Some(record),
|
||||
CredentialRequest::<CS>::deserialize(¶meters.KE1).unwrap(),
|
||||
¶meters.credential_identifier,
|
||||
ServerLoginStartParameters {
|
||||
ServerLoginParameters {
|
||||
context: Some(¶meters.context),
|
||||
identifiers: Identifiers {
|
||||
client: parameters.client_identity.as_deref(),
|
||||
@@ -628,9 +607,16 @@ where
|
||||
},
|
||||
)?;
|
||||
|
||||
let server_login_result = server_login_start_result
|
||||
.state
|
||||
.finish(CredentialFinalization::deserialize(¶meters.KE3)?)?;
|
||||
let server_login_result = server_login_start_result.state.finish(
|
||||
CredentialFinalization::deserialize(¶meters.KE3)?,
|
||||
ServerLoginParameters {
|
||||
context: Some(¶meters.context),
|
||||
identifiers: Identifiers {
|
||||
client: parameters.client_identity.as_deref(),
|
||||
server: parameters.server_identity.as_deref(),
|
||||
},
|
||||
},
|
||||
)?;
|
||||
|
||||
assert_eq!(
|
||||
hex::encode(¶meters.session_key),
|
||||
@@ -644,15 +630,14 @@ fn test_fake_vectors<CS: CipherSuite>(
|
||||
tvs: &[OpaqueTestVectorParameters],
|
||||
) -> Result<(), ProtocolError>
|
||||
where
|
||||
// MaskedResponse: (Nonce + Hash) + KePk
|
||||
NonceLen: Add<OutputSize<OprfHash<CS>>>,
|
||||
Sum<NonceLen, OutputSize<OprfHash<CS>>>: ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::PkLen>,
|
||||
MaskedResponseLen<CS>: ArrayLength<u8>,
|
||||
<CS::KeyExchange as KeyExchange>::KE1Message: Deserialize,
|
||||
// CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse
|
||||
<OprfGroup<CS> as Group>::ElemLen: Add<NonceLen>,
|
||||
Sum<<OprfGroup<CS> as Group>::ElemLen, NonceLen>: ArrayLength<u8> + Add<MaskedResponseLen<CS>>,
|
||||
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<NonceLen>,
|
||||
Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, NonceLen>:
|
||||
ArrayLength<u8> + Add<MaskedResponseLen<CS>>,
|
||||
CredentialResponseWithoutKeLen<CS>: ArrayLength<u8>,
|
||||
// CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message
|
||||
<CS::KeyExchange as KeyExchange>::KE2Message: Serialize,
|
||||
CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>,
|
||||
CredentialResponseLen<CS>: ArrayLength<u8>,
|
||||
{
|
||||
@@ -681,7 +666,7 @@ where
|
||||
None,
|
||||
CredentialRequest::<CS>::deserialize(¶meters.KE1).unwrap(),
|
||||
¶meters.credential_identifier,
|
||||
ServerLoginStartParameters {
|
||||
ServerLoginParameters {
|
||||
context: Some(¶meters.context),
|
||||
identifiers: Identifiers {
|
||||
client: parameters.client_identity.as_deref(),
|
||||
|
||||
Reference in New Issue
Block a user