General Improvements (#268)

* Move `elliptic-curve` implementation to points to allow `Zeroize`

* Simplify `Ristretto255::random_scalar` implementation

* Fix `Ristretto255` deserialization

* Remove unnecessary check in `Ristretto255::random_scalar`

* Base `X25519` implementation on `curve25519-dalek`

* Constrain public and secret key to `Copy`

* Replace manual `ZeroizeOnDrop` implementation with `derive`

* Update dependencies

* Add `warn(unused_crate_dependencies)`

* Sync crate feature naming with `voprf`

* Remove unnecessary dependency crate features

* Never produce a zero scalar

* Rename `OprfGroup` to `OprfCs`

* Rename `TripleDH` to `TripleDh`

* Remove `slow-hash` crate feature

* Rename `NoOpHash` to `Identity`

* Rename `SlowHash` to `Ksf`

* Move `KeyExchange` type definitions down

* Deserialize secret and public keys from slices

* Remove `PrivateKey::from_bytes`

* Rename `From/ToBytes` to `De/Serialize`

* Re-export `serde_` as `serde`

* Custom `De/Serialize` implementation for keys

* Remove custom `De/Serialize` implementation

* Run Taplo v0.6
This commit is contained in:
daxpedda
2022-04-01 16:10:00 -07:00
committed by GitHub
parent f952a26e29
commit 384207acbb
25 changed files with 849 additions and 1109 deletions
+33 -33
View File
@@ -13,16 +13,16 @@ jobs:
fail-fast: false
matrix:
backend_feature:
- --features ristretto255_u64,ristretto255_voprf
- --features ristretto255_u32,ristretto255_voprf
-
- --features x25519_u64,ristretto255_u64,ristretto255_voprf
- --features x25519_u32,ristretto255_u32,ristretto255_voprf
- --features x25519_u64
- --features x25519_u32
- --features ristretto255-u64,ristretto255-voprf
- --features ristretto255-u32,ristretto255-voprf
-
- --features x25519-u64,ristretto255-u64,ristretto255-voprf
- --features x25519-u32,ristretto255-u32,ristretto255-voprf
- --features x25519-u64
- --features x25519-u32
frontend_feature:
-
- --features slow-hash
-
- --features argon2
- --features serde
toolchain:
- stable
@@ -61,13 +61,13 @@ jobs:
# 32-bit x86
- i686-unknown-linux-gnu
backend_feature:
- --features ristretto255_u64,ristretto255_voprf
- --features ristretto255_u32,ristretto255_voprf
-
- x25519_u64,ristretto255_u64,ristretto255_voprf
- x25519_u32,ristretto255_u64,ristretto255_voprf
- x25519_u64
- x25519_u32
- --features ristretto255-u64,ristretto255-voprf
- --features ristretto255-u32,ristretto255-voprf
-
- x25519-u64,ristretto255-u64,ristretto255-voprf
- x25519-u32,ristretto255-u64,ristretto255-voprf
- x25519-u64
- x25519-u32
steps:
- uses: actions/checkout@v2
- uses: hecrj/setup-rust-action@v1
@@ -135,15 +135,15 @@ jobs:
# for any no_std target
- thumbv6m-none-eabi
backend_feature:
- ristretto255_u64,ristretto255_voprf
- ristretto255_u32,ristretto255_voprf
-
- x25519_u64,ristretto255_u64,ristretto255_voprf
- x25519_u32,ristretto255_u32,ristretto255_voprf
- x25519_u64
- x25519_u32
- ristretto255-u64,ristretto255-voprf
- ristretto255-u32,ristretto255-voprf
-
- x25519-u64,ristretto255-u64,ristretto255-voprf
- x25519-u32,ristretto255-u32,ristretto255-voprf
- x25519-u64
- x25519-u32
frontend_feature:
- slow-hash
- argon2
- serde
steps:
- uses: actions/checkout@v2
@@ -158,13 +158,13 @@ jobs:
fail-fast: false
matrix:
backend_feature:
- --features ristretto255_u64,ristretto255_voprf
- --features ristretto255_u32,ristretto255_voprf
-
- --features x25519_u64,ristretto255_u64,ristretto255_voprf
- --features x25519_u32,ristretto255_u32,ristretto255_voprf
- --features x25519_u32
- --features x25519_u32
- --features ristretto255-u64,ristretto255-voprf
- --features ristretto255-u32,ristretto255-voprf
-
- --features x25519-u64,ristretto255-u64,ristretto255-voprf
- --features x25519-u32,ristretto255-u32,ristretto255-voprf
- --features x25519-u32
- --features x25519-u32
steps:
- name: Checkout sources
uses: actions/checkout@v2
@@ -201,7 +201,7 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: clippy
args: --all-targets --features slow-hash,std,x25519_u64 -- -D warnings
args: --all-targets --features argon2,std,x25519-u64 -- -D warnings
- name: Run cargo doc
uses: actions-rs/cargo@v1
@@ -209,7 +209,7 @@ jobs:
RUSTDOCFLAGS: -D warnings
with:
command: doc
args: --no-deps --document-private-items --features slow-hash,std,x25519_u64
args: --no-deps --document-private-items --features argon2,std,x25519-u64
format:
name: cargo fmt
+18 -35
View File
@@ -12,42 +12,33 @@ rust-version = "1.57"
version = "2.0.0-pre.1"
[features]
default = ["ristretto255_u64", "ristretto255_voprf", "serde"]
default = ["ristretto255-u64", "ristretto255-voprf", "serde"]
ristretto255 = ["curve25519-dalek", "voprf/ristretto255"]
ristretto255_fiat_u32 = ["curve25519-dalek/fiat_u32_backend", "ristretto255"]
ristretto255_fiat_u64 = ["curve25519-dalek/fiat_u64_backend", "ristretto255"]
ristretto255_simd = ["curve25519-dalek/simd_backend", "ristretto255"]
ristretto255_u32 = ["curve25519-dalek/u32_backend", "ristretto255"]
ristretto255_u64 = ["curve25519-dalek/u64_backend", "ristretto255"]
ristretto255_voprf = ["ristretto255", "voprf/ristretto255-ciphersuite"]
ristretto255-fiat-u32 = ["curve25519-dalek/fiat_u32_backend", "ristretto255"]
ristretto255-fiat-u64 = ["curve25519-dalek/fiat_u64_backend", "ristretto255"]
ristretto255-simd = ["curve25519-dalek/simd_backend", "ristretto255"]
ristretto255-u32 = ["curve25519-dalek/u32_backend", "ristretto255"]
ristretto255-u64 = ["curve25519-dalek/u64_backend", "ristretto255"]
ristretto255-voprf = ["ristretto255", "voprf/ristretto255-ciphersuite"]
serde = ["serde_", "generic-array/serde", "voprf/serde"]
slow-hash = ["argon2"]
std = ["getrandom", "rand/std", "rand/std_rng", "voprf/std"]
x25519 = ["curve25519-dalek-3"]
x25519_fiat_u32 = ["x25519", "x25519-dalek/fiat_u32_backend"]
x25519_fiat_u64 = ["x25519", "x25519-dalek/fiat_u64_backend"]
# x25519-dalek isn't properly re-exposing `simd_backend`.
x25519_simd = [
"curve25519-dalek-3/simd_backend",
"x25519",
"x25519-dalek/nightly",
]
x25519_u32 = ["x25519", "x25519-dalek/u32_backend"]
x25519_u64 = ["x25519", "x25519-dalek/u64_backend"]
std = ["getrandom"]
x25519 = ["curve25519-dalek"]
x25519-fiat-u32 = ["curve25519-dalek/fiat_u32_backend", "x25519"]
x25519-fiat-u64 = ["curve25519-dalek/fiat_u64_backend", "x25519"]
x25519-simd = ["curve25519-dalek/simd_backend", "x25519"]
x25519-u32 = ["curve25519-dalek/u32_backend", "x25519"]
x25519-u64 = ["curve25519-dalek/u64_backend", "x25519"]
[dependencies]
argon2 = { version = "0.3", default-features = false, features = [
argon2 = { version = "0.4", default-features = false, features = [
"alloc",
], optional = true }
constant_time_eq = "0.1"
curve25519-dalek = { version = "=4.0.0-pre.1", default-features = false, optional = true }
curve25519-dalek-3 = { version = "3", package = "curve25519-dalek", default-features = false, optional = true }
derive-where = { version = "=1.0.0-rc.3", features = ["zeroize-on-drop"] }
digest = "0.10"
displaydoc = { version = "0.2", default-features = false }
elliptic-curve = { version = "0.12.0-pre.1", features = ["hash2curve", "sec1"] }
generic-array = "0.14"
getrandom = { version = "0.2", optional = true }
hkdf = "0.12"
hmac = "0.12"
rand = { version = "0.8", default-features = false }
@@ -56,20 +47,17 @@ serde_ = { version = "1", package = "serde", default-features = false, features
], optional = true }
subtle = { version = "2.3", default-features = false }
voprf = { version = "0.3", default-features = false, features = ["danger"] }
x25519-dalek = { version = "=2.0.0-pre.1", default-features = false, optional = true }
zeroize = { version = "1", features = ["zeroize_derive"] }
zeroize = { version = "1.5", features = ["zeroize_derive"] }
[target.'cfg(target_arch = "wasm32")'.dependencies]
getrandom = { version = "0.2", features = ["js"], optional = true }
[dev-dependencies]
base64 = "0.13"
bincode = "1"
chacha20poly1305 = "0.9"
chacha20poly1305 = "=0.10.0-pre"
criterion = "0.3"
hex = "0.4"
json = "0.12"
lazy_static = "1"
p256 = { version = "=0.11.0-pre.0", default-features = false, features = [
"hash2curve",
"voprf",
@@ -79,19 +67,14 @@ rand = "0.8"
regex = "1"
rustyline = "9"
serde_json = "1"
sha2 = "0.10"
[[bench]]
harness = false
name = "opaque"
[package.metadata.docs.rs]
features = ["std", "slow-hash", "x25519_u64"]
features = ["argon2", "std", "x25519-u64"]
targets = []
[patch.crates-io]
chacha20 = { git = "https://github.com/RustCrypto/stream-ciphers" }
chacha20poly1305 = { git = "https://github.com/khonsulabs/aeads", branch = "update-dependencies" }
derive-where = { git = "https://github.com/ModProg/derive-where" }
poly1305 = { git = "https://github.com/RustCrypto/universal-hashes" }
voprf = { git = "https://github.com/khonsulabs/voprf", branch = "v08" }
+14 -14
View File
@@ -12,14 +12,14 @@ use criterion::Criterion;
use opaque_ke::*;
use rand::rngs::OsRng;
#[cfg(feature = "ristretto255_u64")]
static SUFFIX: &str = "ristretto255_u64";
#[cfg(feature = "ristretto255_u32")]
static SUFFIX: &str = "ristretto255_u32";
#[cfg(feature = "ristretto255_fiat_u64")]
static SUFFIX: &str = "ristretto255_fiat_u64";
#[cfg(feature = "ristretto255_fiat_u32")]
static SUFFIX: &str = "ristretto255_fiat_u32";
#[cfg(feature = "ristretto255-u64")]
static SUFFIX: &str = "ristretto255-u64";
#[cfg(feature = "ristretto255-u32")]
static SUFFIX: &str = "ristretto255-u32";
#[cfg(feature = "ristretto255-fiat-u64")]
static SUFFIX: &str = "ristretto255-fiat-u64";
#[cfg(feature = "ristretto255-fiat-u32")]
static SUFFIX: &str = "ristretto255-fiat-u32";
#[cfg(all(not(feature = "ristretto255")))]
static SUFFIX: &str = "p256";
@@ -27,18 +27,18 @@ struct Default;
#[cfg(feature = "ristretto255")]
impl CipherSuite for Default {
type OprfGroup = opaque_ke::Ristretto255;
type OprfCs = opaque_ke::Ristretto255;
type KeGroup = opaque_ke::Ristretto255;
type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
type SlowHash = opaque_ke::slow_hash::NoOpHash;
type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
type Ksf = opaque_ke::ksf::Identity;
}
#[cfg(not(feature = "ristretto255"))]
impl CipherSuite for Default {
type OprfGroup = p256::NistP256;
type OprfCs = p256::NistP256;
type KeGroup = p256::NistP256;
type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
type SlowHash = opaque_ke::slow_hash::NoOpHash;
type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
type Ksf = opaque_ke::ksf::Identity;
}
fn server_setup(c: &mut Criterion) {
+6 -6
View File
@@ -49,18 +49,18 @@ struct Default;
#[cfg(feature = "ristretto255")]
impl CipherSuite for Default {
type OprfGroup = opaque_ke::Ristretto255;
type OprfCs = opaque_ke::Ristretto255;
type KeGroup = opaque_ke::Ristretto255;
type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
type SlowHash = opaque_ke::slow_hash::NoOpHash;
type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
type Ksf = opaque_ke::ksf::Identity;
}
#[cfg(not(feature = "ristretto255"))]
impl CipherSuite for Default {
type OprfGroup = p256::NistP256;
type OprfCs = p256::NistP256;
type KeGroup = p256::NistP256;
type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
type SlowHash = opaque_ke::slow_hash::NoOpHash;
type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
type Ksf = opaque_ke::ksf::Identity;
}
struct Locker {
+6 -6
View File
@@ -43,18 +43,18 @@ struct Default;
#[cfg(feature = "ristretto255")]
impl CipherSuite for Default {
type OprfGroup = opaque_ke::Ristretto255;
type OprfCs = opaque_ke::Ristretto255;
type KeGroup = opaque_ke::Ristretto255;
type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
type SlowHash = opaque_ke::slow_hash::NoOpHash;
type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
type Ksf = opaque_ke::ksf::Identity;
}
#[cfg(not(feature = "ristretto255"))]
impl CipherSuite for Default {
type OprfGroup = p256::NistP256;
type OprfCs = p256::NistP256;
type KeGroup = p256::NistP256;
type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
type SlowHash = opaque_ke::slow_hash::NoOpHash;
type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
type Ksf = opaque_ke::ksf::Identity;
}
// Password-based registration between a client and server
+9 -14
View File
@@ -15,17 +15,14 @@ use generic_array::typenum::{IsLess, IsLessOrEqual, Le, NonZero, U256};
use crate::hash::{Hash, ProxyHash};
use crate::key_exchange::group::KeGroup;
use crate::key_exchange::traits::KeyExchange;
use crate::slow_hash::SlowHash;
use crate::ksf::Ksf;
/// Configures the underlying primitives used in OPAQUE
/// * `OprfGroup`: 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`.
/// * `OprfCs`: A VOPRF ciphersuite, see [`voprf::CipherSuite`].
/// * `KeGroup`: A `Group` used for the `KeyExchange`.
/// * `KeyExchange`: The key exchange protocol to use in the login step
/// * `Hash`: The main hashing function to use
/// * `SlowHash`: A slow hashing function, typically used for password hashing
/// * `Ksf`: A key stretching function, typically used for password hashing
pub trait CipherSuite
where
<OprfHash<Self> as OutputSizeUser>::OutputSize:
@@ -35,17 +32,15 @@ where
<<OprfHash<Self> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<Self> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
/// 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`.
type OprfGroup: voprf::CipherSuite;
/// A VOPRF ciphersuite, see [`voprf::CipherSuite`].
type OprfCs: voprf::CipherSuite;
/// A `Group` used for the `KeyExchange`.
type KeGroup: KeGroup;
/// A key exchange protocol
type KeyExchange: KeyExchange<OprfHash<Self>, Self::KeGroup>;
/// A slow hashing function, typically used for password hashing
type SlowHash: SlowHash;
/// A key stretching function, typically used for password hashing
type Ksf: Ksf;
}
pub(crate) type OprfGroup<CS> = <<CS as CipherSuite>::OprfGroup as voprf::CipherSuite>::Group;
pub(crate) type OprfHash<CS> = <<CS as CipherSuite>::OprfGroup as voprf::CipherSuite>::Hash;
pub(crate) type OprfGroup<CS> = <<CS as CipherSuite>::OprfCs as voprf::CipherSuite>::Group;
pub(crate) type OprfHash<CS> = <<CS as CipherSuite>::OprfCs as voprf::CipherSuite>::Hash;
+20 -37
View File
@@ -26,7 +26,7 @@ use crate::hash::{Hash, OutputSize, ProxyHash};
use crate::key_exchange::group::KeGroup;
use crate::keypair::{KeyPair, PublicKey};
use crate::opaque::{bytestrings_from_identifiers, Identifiers};
use crate::serialization::{MacExt, Serialize};
use crate::serialization::{Input, MacExt};
// Constant string used as salt for HKDF computation
const STR_AUTH_KEY: [u8; 7] = *b"AuthKey";
@@ -35,6 +35,11 @@ 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),
serde(crate = "serde")
)]
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, ZeroizeOnDrop)]
pub(crate) enum InnerEnvelopeMode {
Zero = 0,
@@ -65,7 +70,12 @@ impl TryFrom<u8> for InnerEnvelopeMode {
/// 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.
#[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cfg_attr(
feature = "serde",
derive(serde::Deserialize, serde::Serialize),
serde(bound = "", crate = "serde")
)]
#[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, ZeroizeOnDrop)]
pub(crate) struct Envelope<CS: CipherSuite>
where
<OprfHash<CS> as OutputSizeUser>::OutputSize:
@@ -80,33 +90,6 @@ where
hmac: Output<OprfHash<CS>>,
}
impl<CS: CipherSuite> Drop for Envelope<CS>
where
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
fn drop(&mut self) {
self.mode.zeroize();
self.nonce.zeroize();
self.hmac.zeroize();
}
}
impl<CS: CipherSuite> ZeroizeOnDrop for Envelope<CS>
where
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
}
// Note that this struct represents an envelope that has been "opened" with the
// asssociated key. This key is also used to derive the export_key parameter,
// which is technically unrelated to the envelope's encrypted and authenticated
@@ -122,8 +105,8 @@ where
{
pub(crate) client_static_keypair: KeyPair<CS::KeGroup>,
pub(crate) export_key: Output<OprfHash<CS>>,
pub(crate) id_u: Serialize<'a, U2, <CS::KeGroup as KeGroup>::PkLen>,
pub(crate) id_s: Serialize<'a, U2, <CS::KeGroup as KeGroup>::PkLen>,
pub(crate) id_u: Input<'a, U2, <CS::KeGroup as KeGroup>::PkLen>,
pub(crate) id_s: Input<'a, U2, <CS::KeGroup as KeGroup>::PkLen>,
}
pub(crate) struct OpenedInnerEnvelope<D: Hash>
@@ -175,10 +158,10 @@ where
build_inner_envelope_internal::<CS>(randomized_pwd_hasher.clone(), nonce)?,
);
let server_s_pk_bytes = server_s_pk.to_bytes();
let server_s_pk_bytes = server_s_pk.serialize();
let (id_u, id_s) = bytestrings_from_identifiers::<CS::KeGroup>(
ids,
client_s_pk.to_bytes(),
client_s_pk.serialize(),
server_s_pk_bytes.clone(),
)?;
let aad = construct_aad(id_u.iter(), id_s.iter(), &server_s_pk_bytes);
@@ -246,10 +229,10 @@ where
}
};
let server_s_pk_bytes = server_s_pk.to_bytes();
let server_s_pk_bytes = server_s_pk.serialize();
let (id_u, id_s) = bytestrings_from_identifiers::<CS::KeGroup>(
optional_ids,
client_static_keypair.public().to_bytes(),
client_static_keypair.public().serialize(),
server_s_pk_bytes.clone(),
)?;
let aad = construct_aad(id_u.iter(), id_s.iter(), &server_s_pk_bytes);
@@ -362,7 +345,7 @@ where
.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::hash_to_scalar::<OprfHash<CS>>(
&CS::KeGroup::serialize_sk(CS::KeGroup::hash_to_scalar::<OprfHash<CS>>(
&[keypair_seed.as_slice()],
&GenericArray::from(STR_OPAQUE_DERIVE_AUTH_KEY_PAIR),
)?),
@@ -388,7 +371,7 @@ where
.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::hash_to_scalar::<OprfHash<CS>>(
&CS::KeGroup::serialize_sk(CS::KeGroup::hash_to_scalar::<OprfHash<CS>>(
&[keypair_seed.as_slice()],
&GenericArray::from(STR_OPAQUE_DERIVE_AUTH_KEY_PAIR),
)?),
+4 -4
View File
@@ -37,8 +37,8 @@ pub enum InternalError<T = Infallible> {
HkdfError,
/// Computing HMAC failed while supplying a secret key
HmacError,
/// Computing the slow hashing function failed
SlowHashError,
/// Computing the key stretching function failed
KsfError,
/** This error occurs when the envelope seal open hmac check fails
HMAC check in seal open failed. */
SealOpenHmacError,
@@ -70,7 +70,7 @@ impl<T: Debug> Debug for InternalError<T> {
Self::HashToScalar => f.debug_tuple("HashToScalar").finish(),
Self::HkdfError => f.debug_tuple("HkdfError").finish(),
Self::HmacError => f.debug_tuple("HmacError").finish(),
Self::SlowHashError => f.debug_tuple("SlowHashError").finish(),
Self::KsfError => f.debug_tuple("KsfError").finish(),
Self::SealOpenHmacError => f.debug_tuple("SealOpenHmacError").finish(),
Self::IncompatibleEnvelopeModeError => {
f.debug_tuple("IncompatibleEnvelopeModeError").finish()
@@ -105,7 +105,7 @@ impl InternalError {
Self::HashToScalar => InternalError::HashToScalar,
Self::HkdfError => InternalError::HkdfError,
Self::HmacError => InternalError::HmacError,
Self::SlowHashError => InternalError::SlowHashError,
Self::KsfError => InternalError::KsfError,
Self::SealOpenHmacError => InternalError::SealOpenHmacError,
Self::IncompatibleEnvelopeModeError => InternalError::IncompatibleEnvelopeModeError,
Self::OprfError(error) => InternalError::OprfError(error),
-98
View File
@@ -1,98 +0,0 @@
// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is licensed under both the MIT license found in the
// LICENSE-MIT file in the root directory of this source tree and the Apache
// License, Version 2.0 found in the LICENSE-APACHE file in the root directory
// of this source tree.
/// Macro used for deriving `serde`'s `Serialize` and `Deserialize` traits.
macro_rules! impl_serialize_and_deserialize_for {
($item:ident$( where $($path:ty: $bound1:path $(| $bound2:path)*),+$(,)?)?) => {
#[cfg(feature = "serde")]
impl<CS: CipherSuite> serde_::Serialize for $item<CS>
where
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
$($($path: $bound1 $(+ $bound2)*),+)?
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde_::Serializer,
{
serializer.serialize_bytes(&self.serialize())
}
}
#[cfg(feature = "serde")]
impl<'de, CS: CipherSuite> serde_::Deserialize<'de> for $item<CS>
where
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde_::Deserializer<'de>,
{
use serde_::de::Error;
struct ByteVisitor<CS: CipherSuite>(core::marker::PhantomData<CS>)
where
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero;
impl<'de, CS: CipherSuite> serde_::de::Visitor<'de> for ByteVisitor<CS>
where
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
type Value = $item<CS>;
fn expecting(
&self,
formatter: &mut core::fmt::Formatter,
) -> core::fmt::Result {
formatter.write_str(core::concat!(
"the byte representation of a ",
core::stringify!($t)
))
}
fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E>
where
E: Error,
{
$item::<CS>::deserialize(value).map_err(|_| {
Error::invalid_value(
serde_::de::Unexpected::Bytes(value),
&core::concat!(
"invalid byte sequence for ",
core::stringify!($t)
),
)
})
}
}
deserializer
.deserialize_bytes(ByteVisitor::<CS>(core::marker::PhantomData))
.map_err(Error::custom)
}
}
};
}
+29 -27
View File
@@ -11,8 +11,7 @@ use elliptic_curve::group::cofactor::CofactorGroup;
use elliptic_curve::hash2curve::{ExpandMsgXmd, FromOkm, GroupDigest};
use elliptic_curve::sec1::{FromEncodedPoint, ModulusSize, ToEncodedPoint};
use elliptic_curve::{
AffinePoint, Curve, FieldSize, NonZeroScalar, ProjectiveArithmetic, ProjectivePoint, PublicKey,
Scalar, SecretKey,
AffinePoint, Field, FieldSize, Group, ProjectivePoint, PublicKey, Scalar, SecretKey,
};
use generic_array::typenum::{IsLess, IsLessOrEqual, U256};
use generic_array::GenericArray;
@@ -21,31 +20,34 @@ use rand::{CryptoRng, RngCore};
use super::KeGroup;
use crate::errors::InternalError;
impl<G: Curve + GroupDigest + ProjectiveArithmetic> KeGroup for G
impl<G> KeGroup for G
where
G: GroupDigest,
FieldSize<Self>: ModulusSize,
AffinePoint<Self>: FromEncodedPoint<Self> + ToEncodedPoint<Self>,
ProjectivePoint<Self>: CofactorGroup + ToEncodedPoint<Self>,
Scalar<Self>: FromOkm,
{
type Pk = PublicKey<Self>;
type Pk = ProjectivePoint<Self>;
type PkLen = <FieldSize<Self> as ModulusSize>::CompressedPointSize;
type Sk = SecretKey<Self>;
type Sk = Scalar<Self>;
type SkLen = FieldSize<Self>;
fn serialize_pk(pk: &Self::Pk) -> GenericArray<u8, Self::PkLen> {
fn serialize_pk(pk: Self::Pk) -> GenericArray<u8, Self::PkLen> {
GenericArray::clone_from_slice(pk.to_encoded_point(true).as_bytes())
}
fn deserialize_pk(bytes: &GenericArray<u8, Self::PkLen>) -> Result<Self::Pk, InternalError> {
PublicKey::from_sec1_bytes(bytes).map_err(|_| InternalError::PointError)
fn deserialize_pk(bytes: &[u8]) -> Result<Self::Pk, InternalError> {
PublicKey::<Self>::from_sec1_bytes(bytes)
.map(|public_key| public_key.to_projective())
.map_err(|_| InternalError::PointError)
}
fn random_sk<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Sk {
SecretKey::random(rng)
*SecretKey::<Self>::random(rng).to_nonzero_scalar()
}
// Implements the `HashToScalar()` function
@@ -55,31 +57,31 @@ where
H::OutputSize: IsLess<U256> + IsLessOrEqual<H::BlockSize>,
{
Self::hash_to_scalar::<ExpandMsgXmd<H>>(input, dst)
.ok()
.and_then(|scalar| Option::<NonZeroScalar<Self>>::from(NonZeroScalar::new(scalar)))
.map(SecretKey::from)
.ok_or(InternalError::HashToScalar)
.map_err(|_| InternalError::HashToScalar)
.and_then(|scalar| {
if bool::from(scalar.is_zero()) {
Err(InternalError::HashToScalar)
} else {
Ok(scalar)
}
})
}
fn public_key(sk: &Self::Sk) -> Self::Pk {
sk.public_key()
fn public_key(sk: Self::Sk) -> Self::Pk {
ProjectivePoint::<Self>::generator() * sk
}
fn diffie_hellman(pk: &Self::Pk, sk: &Self::Sk) -> GenericArray<u8, Self::PkLen> {
GenericArray::clone_from_slice(
(pk.to_projective() * sk.to_nonzero_scalar().as_ref())
.to_encoded_point(true)
.as_bytes(),
)
fn diffie_hellman(pk: Self::Pk, sk: Self::Sk) -> GenericArray<u8, Self::PkLen> {
Self::serialize_pk(pk * sk)
}
fn zeroize_sk_on_drop(_sk: &mut Self::Sk) {}
fn serialize_sk(sk: &Self::Sk) -> GenericArray<u8, Self::SkLen> {
sk.to_be_bytes()
fn serialize_sk(sk: Self::Sk) -> GenericArray<u8, Self::SkLen> {
sk.into()
}
fn deserialize_sk(bytes: &GenericArray<u8, Self::SkLen>) -> Result<Self::Sk, InternalError> {
SecretKey::from_be_bytes(bytes).map_err(|_| InternalError::PointError)
fn deserialize_sk(bytes: &[u8]) -> Result<Self::Sk, InternalError> {
SecretKey::<Self>::from_be_bytes(bytes)
.map(|secret_key| *secret_key.to_nonzero_scalar())
.map_err(|_| InternalError::PointError)
}
}
+9 -11
View File
@@ -18,25 +18,26 @@ use digest::Digest;
use generic_array::typenum::{IsLess, IsLessOrEqual, U256};
use generic_array::{ArrayLength, GenericArray};
use rand::{CryptoRng, RngCore};
use zeroize::Zeroize;
use crate::errors::InternalError;
/// A group representation for use in the key exchange
pub trait KeGroup {
/// Public key
type Pk: Clone;
type Pk: Copy + Zeroize;
/// Length of the public key
type PkLen: ArrayLength<u8>;
/// Secret key
type Sk: Clone;
type Sk: Copy + Zeroize;
/// Length of the secret key
type SkLen: ArrayLength<u8>;
/// Serializes `self`
fn serialize_pk(pk: &Self::Pk) -> GenericArray<u8, Self::PkLen>;
fn serialize_pk(pk: Self::Pk) -> GenericArray<u8, Self::PkLen>;
/// Return a public key from its fixed-length bytes representation
fn deserialize_pk(bytes: &GenericArray<u8, Self::PkLen>) -> Result<Self::Pk, InternalError>;
fn deserialize_pk(bytes: &[u8]) -> Result<Self::Pk, InternalError>;
/// Generate a random secret key
fn random_sk<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Sk;
@@ -52,17 +53,14 @@ pub trait KeGroup {
H::OutputSize: IsLess<U256> + IsLessOrEqual<H::BlockSize>;
/// Return a public key from its secret key
fn public_key(sk: &Self::Sk) -> Self::Pk;
fn public_key(sk: Self::Sk) -> Self::Pk;
/// Diffie-Hellman key exchange
fn diffie_hellman(pk: &Self::Pk, sk: &Self::Sk) -> GenericArray<u8, Self::PkLen>;
/// Zeroize secret key on drop.
fn zeroize_sk_on_drop(sk: &mut Self::Sk);
fn diffie_hellman(pk: Self::Pk, sk: Self::Sk) -> GenericArray<u8, Self::PkLen>;
/// Serializes `self`
fn serialize_sk(sk: &Self::Sk) -> GenericArray<u8, Self::SkLen>;
fn serialize_sk(sk: Self::Sk) -> GenericArray<u8, Self::SkLen>;
/// Return a public key from its fixed-length bytes representation
fn deserialize_sk(bytes: &GenericArray<u8, Self::SkLen>) -> Result<Self::Sk, InternalError>;
fn deserialize_sk(bytes: &[u8]) -> Result<Self::Sk, InternalError>;
}
+29 -19
View File
@@ -10,6 +10,7 @@
use curve25519_dalek::constants::RISTRETTO_BASEPOINT_POINT;
use curve25519_dalek::ristretto::{CompressedRistretto, RistrettoPoint};
use curve25519_dalek::scalar::Scalar;
use curve25519_dalek::traits::Identity;
use digest::core_api::BlockSizeUser;
use digest::{Digest, OutputSizeUser};
use elliptic_curve::hash2curve::{ExpandMsg, ExpandMsgXmd, Expander};
@@ -17,7 +18,6 @@ use generic_array::typenum::{IsLess, IsLessOrEqual, U256, U32, U64};
use generic_array::GenericArray;
use rand::{CryptoRng, RngCore};
use voprf::Group;
use zeroize::Zeroize;
use super::KeGroup;
use crate::errors::InternalError;
@@ -33,13 +33,18 @@ impl KeGroup for Ristretto255 {
type Sk = Scalar;
type SkLen = U32;
fn serialize_pk(pk: &Self::Pk) -> GenericArray<u8, Self::PkLen> {
fn serialize_pk(pk: Self::Pk) -> GenericArray<u8, Self::PkLen> {
pk.compress().to_bytes().into()
}
fn deserialize_pk(bytes: &GenericArray<u8, Self::PkLen>) -> Result<Self::Pk, InternalError> {
fn deserialize_pk(bytes: &[u8]) -> Result<Self::Pk, InternalError> {
if bytes.len() != 32 {
return Err(InternalError::PointError);
}
CompressedRistretto::from_slice(bytes)
.decompress()
.filter(|point| point != &RistrettoPoint::identity())
.ok_or(InternalError::PointError)
}
@@ -48,9 +53,7 @@ impl KeGroup for Ristretto255 {
let scalar = {
#[cfg(not(test))]
{
let mut scalar_bytes = [0u8; 64];
rng.fill_bytes(&mut scalar_bytes);
Scalar::from_bytes_mod_order_wide(&scalar_bytes)
Scalar::random(rng)
}
// Tests need an exact conversion from bytes to scalar, sampling only 32 bytes
@@ -63,7 +66,7 @@ impl KeGroup for Ristretto255 {
}
};
if scalar != Scalar::zero() && scalar.is_canonical() {
if scalar != Scalar::zero() {
break scalar;
}
}
@@ -81,31 +84,38 @@ impl KeGroup for Ristretto255 {
.map_err(|_| InternalError::HashToScalar)?
.fill_bytes(&mut uniform_bytes);
Ok(Scalar::from_bytes_mod_order_wide(&uniform_bytes.into()))
let scalar = Scalar::from_bytes_mod_order_wide(&uniform_bytes.into());
if scalar == Scalar::zero() {
Err(InternalError::HashToScalar)
} else {
Ok(scalar)
}
}
fn public_key(sk: &Self::Sk) -> Self::Pk {
fn public_key(sk: Self::Sk) -> Self::Pk {
RISTRETTO_BASEPOINT_POINT * sk
}
fn diffie_hellman(pk: &Self::Pk, sk: &Self::Sk) -> GenericArray<u8, Self::PkLen> {
Self::serialize_pk(&(pk * sk))
fn diffie_hellman(pk: Self::Pk, sk: Self::Sk) -> GenericArray<u8, Self::PkLen> {
Self::serialize_pk(pk * sk)
}
fn zeroize_sk_on_drop(sk: &mut Self::Sk) {
sk.zeroize()
}
fn serialize_sk(sk: &Self::Sk) -> GenericArray<u8, Self::SkLen> {
fn serialize_sk(sk: Self::Sk) -> GenericArray<u8, Self::SkLen> {
sk.to_bytes().into()
}
fn deserialize_sk(bytes: &GenericArray<u8, Self::PkLen>) -> Result<Self::Sk, InternalError> {
Scalar::from_canonical_bytes((*bytes).into()).ok_or(InternalError::PointError)
fn deserialize_sk(bytes: &[u8]) -> Result<Self::Sk, InternalError> {
bytes
.try_into()
.ok()
.and_then(Scalar::from_canonical_bytes)
.filter(|scalar| scalar != &Scalar::zero())
.ok_or(InternalError::PointError)
}
}
#[cfg(feature = "ristretto255_voprf")]
#[cfg(feature = "ristretto255-voprf")]
impl voprf::CipherSuite for Ristretto255 {
const ID: u16 = voprf::Ristretto255::ID;
+36 -41
View File
@@ -7,15 +7,16 @@
//! Key Exchange group implementation for X25519
use curve25519_dalek_3::scalar::Scalar;
use curve25519_dalek::constants::ED25519_BASEPOINT_TABLE;
use curve25519_dalek::montgomery::MontgomeryPoint;
use curve25519_dalek::scalar::Scalar;
use curve25519_dalek::traits::Identity;
use digest::core_api::BlockSizeUser;
use digest::Digest;
use elliptic_curve::hash2curve::{ExpandMsg, ExpandMsgXmd, Expander};
use generic_array::typenum::{IsLess, IsLessOrEqual, U256, U32, U64};
use generic_array::GenericArray;
use rand::{CryptoRng, RngCore};
use x25519_dalek::{PublicKey, StaticSecret};
use zeroize::Zeroize;
use super::KeGroup;
use crate::errors::InternalError;
@@ -25,31 +26,30 @@ pub struct X25519;
/// The implementation of such a subgroup for Ristretto
impl KeGroup for X25519 {
type Pk = PublicKey;
type Pk = MontgomeryPoint;
type PkLen = U32;
type Sk = StaticSecret;
type Sk = Scalar;
type SkLen = U32;
fn serialize_pk(pk: &Self::Pk) -> GenericArray<u8, Self::PkLen> {
fn serialize_pk(pk: Self::Pk) -> GenericArray<u8, Self::PkLen> {
pk.to_bytes().into()
}
fn deserialize_pk(bytes: &GenericArray<u8, Self::PkLen>) -> Result<Self::Pk, InternalError> {
if **bytes == [0; 32] {
Err(InternalError::PointError)
} else {
Ok(PublicKey::from(<[_; 32]>::from(*bytes)))
}
fn deserialize_pk(bytes: &[u8]) -> Result<Self::Pk, InternalError> {
bytes
.try_into()
.ok()
.map(MontgomeryPoint)
.filter(|pk| pk != &MontgomeryPoint::identity())
.ok_or(InternalError::PointError)
}
fn random_sk<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Sk {
let mut scalar_bytes = [0u8; 32];
loop {
rng.fill_bytes(&mut scalar_bytes);
let scalar = Scalar::random(rng);
if scalar_bytes != [0u8; 32] {
break StaticSecret::from(scalar_bytes);
if scalar != Scalar::zero() {
break scalar;
}
}
}
@@ -66,38 +66,33 @@ impl KeGroup for X25519 {
.map_err(|_| InternalError::HashToScalar)?
.fill_bytes(&mut uniform_bytes);
Ok(StaticSecret::from(
Scalar::from_bytes_mod_order_wide(&uniform_bytes.into()).to_bytes(),
))
let scalar = Scalar::from_bytes_mod_order_wide(&uniform_bytes.into());
if scalar == Scalar::zero() {
Err(InternalError::HashToScalar)
} else {
Ok(scalar)
}
}
fn public_key(sk: &Self::Sk) -> Self::Pk {
PublicKey::from(sk)
fn public_key(sk: Self::Sk) -> Self::Pk {
(&ED25519_BASEPOINT_TABLE * &sk).to_montgomery()
}
fn diffie_hellman(pk: &Self::Pk, sk: &Self::Sk) -> GenericArray<u8, Self::PkLen> {
sk.diffie_hellman(pk).to_bytes().into()
fn diffie_hellman(pk: Self::Pk, sk: Self::Sk) -> GenericArray<u8, Self::PkLen> {
Self::serialize_pk(sk * pk)
}
fn zeroize_sk_on_drop(sk: &mut Self::Sk) {
sk.zeroize()
}
fn serialize_sk(sk: &Self::Sk) -> GenericArray<u8, Self::SkLen> {
fn serialize_sk(sk: Self::Sk) -> GenericArray<u8, Self::SkLen> {
sk.to_bytes().into()
}
fn deserialize_sk(bytes: &GenericArray<u8, Self::PkLen>) -> Result<Self::Sk, InternalError> {
if **bytes == [0; 32] {
Err(InternalError::PointError)
} else {
let sk = StaticSecret::from(<[u8; 32]>::from(*bytes));
if sk.to_bytes() == **bytes {
Ok(sk)
} else {
Err(InternalError::PointError)
}
}
fn deserialize_sk(bytes: &[u8]) -> Result<Self::Sk, InternalError> {
bytes
.try_into()
.ok()
.and_then(Scalar::from_canonical_bytes)
.filter(|scalar| scalar != &Scalar::zero())
.ok_or(InternalError::PointError)
}
}
+36 -36
View File
@@ -18,39 +18,17 @@ use crate::hash::{Hash, ProxyHash};
use crate::key_exchange::group::KeGroup;
use crate::keypair::{PrivateKey, PublicKey, SecretKey};
#[cfg(not(test))]
pub type GenerateKe2Result<K, D, G> = (
<K as KeyExchange<D, G>>::KE2State,
<K as KeyExchange<D, G>>::KE2Message,
);
#[cfg(test)]
pub type GenerateKe2Result<K, D, G> = (
<K as KeyExchange<D, G>>::KE2State,
<K as KeyExchange<D, G>>::KE2Message,
Output<D>,
Output<D>,
);
#[cfg(not(test))]
pub type GenerateKe3Result<K, D, G> = (Output<D>, <K as KeyExchange<D, G>>::KE3Message);
#[cfg(test)]
pub type GenerateKe3Result<K, D, G> = (
Output<D>,
<K as KeyExchange<D, G>>::KE3Message,
Output<D>,
Output<D>,
);
pub trait KeyExchange<D: Hash, G: KeGroup>
where
D::Core: ProxyHash,
<D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
type KE1State: FromBytes + ToBytes + ZeroizeOnDrop + Clone;
type KE2State: FromBytes + ToBytes + ZeroizeOnDrop + Clone;
type KE1Message: FromBytes + ToBytes + ZeroizeOnDrop + Clone;
type KE2Message: FromBytes + ToBytes + ZeroizeOnDrop + Clone;
type KE3Message: FromBytes + ToBytes + ZeroizeOnDrop + Clone;
type KE1State: Deserialize + Serialize + ZeroizeOnDrop + Clone;
type KE2State: Deserialize + Serialize + ZeroizeOnDrop + Clone;
type KE1Message: Deserialize + Serialize + ZeroizeOnDrop + Clone;
type KE2Message: Deserialize + Serialize + ZeroizeOnDrop + Clone;
type KE3Message: Deserialize + Serialize + ZeroizeOnDrop + Clone;
fn generate_ke1<R: RngCore + CryptoRng>(
rng: &mut R,
@@ -88,23 +66,45 @@ where
) -> Result<Output<D>, ProtocolError>;
}
pub trait FromBytes: Sized {
fn from_bytes(input: &[u8]) -> Result<Self, ProtocolError>;
pub trait Deserialize: Sized {
fn deserialize(input: &[u8]) -> Result<Self, ProtocolError>;
}
pub trait ToBytes {
pub trait Serialize {
type Len: ArrayLength<u8>;
fn to_bytes(&self) -> GenericArray<u8, Self::Len>;
fn serialize(&self) -> GenericArray<u8, Self::Len>;
}
#[cfg(not(test))]
pub type GenerateKe2Result<K, D, G> = (
<K as KeyExchange<D, G>>::KE2State,
<K as KeyExchange<D, G>>::KE2Message,
);
#[cfg(test)]
pub type GenerateKe2Result<K, D, G> = (
<K as KeyExchange<D, G>>::KE2State,
<K as KeyExchange<D, G>>::KE2Message,
Output<D>,
Output<D>,
);
#[cfg(not(test))]
pub type GenerateKe3Result<K, D, G> = (Output<D>, <K as KeyExchange<D, G>>::KE3Message);
#[cfg(test)]
pub type GenerateKe3Result<K, D, G> = (
Output<D>,
<K as KeyExchange<D, G>>::KE3Message,
Output<D>,
Output<D>,
);
pub type Ke1StateLen<CS: CipherSuite> =
<<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE1State as ToBytes>::Len;
<<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE1State as Serialize>::Len;
pub type Ke1MessageLen<CS: CipherSuite> =
<<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE1Message as ToBytes>::Len;
<<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE1Message as Serialize>::Len;
pub type Ke2StateLen<CS: CipherSuite> =
<<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE2State as ToBytes>::Len;
<<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE2State as Serialize>::Len;
pub type Ke2MessageLen<CS: CipherSuite> =
<<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE2Message as ToBytes>::Len;
<<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE2Message as Serialize>::Len;
pub type Ke3MessageLen<CS: CipherSuite> =
<<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE3Message as ToBytes>::Len;
<<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE3Message as Serialize>::Len;
+54 -152
View File
@@ -18,17 +18,16 @@ use generic_array::{ArrayLength, GenericArray};
use hkdf::{Hkdf, HkdfExtract};
use hmac::{Hmac, Mac};
use rand::{CryptoRng, RngCore};
use zeroize::{Zeroize, ZeroizeOnDrop};
use crate::errors::utils::{check_slice_size, check_slice_size_atleast};
use crate::errors::{InternalError, ProtocolError};
use crate::hash::{Hash, OutputSize, ProxyHash};
use crate::key_exchange::group::KeGroup;
use crate::key_exchange::traits::{
FromBytes, GenerateKe2Result, GenerateKe3Result, KeyExchange, ToBytes,
Deserialize, GenerateKe2Result, GenerateKe3Result, KeyExchange, Serialize,
};
use crate::keypair::{KeyPair, PrivateKey, PublicKey, SecretKey};
use crate::serialization::{Serialize, UpdateExt};
use crate::serialization::{Input, UpdateExt};
///////////////
// Constants //
@@ -48,71 +47,42 @@ static STR_OPAQUE: &[u8] = b"OPAQUE-";
// ====================== //
////////////////////////////
#[allow(clippy::upper_case_acronyms)]
/// The Triple Diffie-Hellman key exchange implementation
pub struct TripleDH;
pub struct TripleDh;
/// The client state produced after the first key exchange message
#[cfg_attr(
feature = "serde",
derive(serde_::Deserialize, serde_::Serialize),
serde(
bound(
deserialize = "KG::Sk: serde_::Deserialize<'de>",
serialize = "KG::Sk: serde_::Serialize",
),
crate = "serde_"
)
derive(serde::Deserialize, serde::Serialize),
serde(bound = "", crate = "serde")
)]
#[derive_where(Clone)]
#[derive_where(Clone, ZeroizeOnDrop)]
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; KG::Sk)]
pub struct Ke1State<KG: KeGroup> {
client_e_sk: PrivateKey<KG>,
client_nonce: GenericArray<u8, NonceLen>,
}
impl<KG: KeGroup> Drop for Ke1State<KG> {
fn drop(&mut self) {
self.client_nonce.zeroize();
}
}
impl<KG: KeGroup> ZeroizeOnDrop for Ke1State<KG> {}
/// The first key exchange message
#[cfg_attr(
feature = "serde",
derive(serde_::Deserialize, serde_::Serialize),
serde(
bound(
deserialize = "KG::Pk: serde_::Deserialize<'de>",
serialize = "KG::Pk: serde_::Serialize",
),
crate = "serde_"
)
derive(serde::Deserialize, serde::Serialize),
serde(bound = "", crate = "serde")
)]
#[derive_where(Clone)]
#[derive_where(Clone, ZeroizeOnDrop)]
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; KG::Pk)]
pub struct Ke1Message<KG: KeGroup> {
pub(crate) client_nonce: GenericArray<u8, NonceLen>,
pub(crate) client_e_pk: PublicKey<KG>,
}
impl<KG: KeGroup> Drop for Ke1Message<KG> {
fn drop(&mut self) {
self.client_nonce.zeroize();
}
}
impl<KG: KeGroup> ZeroizeOnDrop for Ke1Message<KG> {}
/// The server state produced after the second key exchange message
#[cfg_attr(
feature = "serde",
derive(serde_::Deserialize, serde_::Serialize),
serde(bound = "", crate = "serde_")
derive(serde::Deserialize, serde::Serialize),
serde(bound = "", crate = "serde")
)]
#[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, ZeroizeOnDrop)]
pub struct Ke2State<D: Hash>
where
D::Core: ProxyHash,
@@ -124,40 +94,13 @@ where
session_key: Output<D>,
}
impl<D: Hash> Drop for Ke2State<D>
where
D::Core: ProxyHash,
<D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
fn drop(&mut self) {
self.km3.zeroize();
self.hashed_transcript.zeroize();
self.session_key.zeroize();
}
}
impl<D: Hash> ZeroizeOnDrop for Ke2State<D>
where
D::Core: ProxyHash,
<D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
}
/// The second key exchange message
#[cfg_attr(
feature = "serde",
derive(serde_::Deserialize, serde_::Serialize),
serde(
bound(
deserialize = "KG::Pk: serde_::Deserialize<'de>",
serialize = "KG::Pk: serde_::Serialize",
),
crate = "serde_"
)
derive(serde::Deserialize, serde::Serialize),
serde(bound = "", crate = "serde")
)]
#[derive_where(Clone)]
#[derive_where(Clone, ZeroizeOnDrop)]
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; KG::Pk)]
pub struct Ke2Message<D: Hash, KG: KeGroup>
where
@@ -170,33 +113,13 @@ where
mac: Output<D>,
}
impl<D: Hash, KG: KeGroup> Drop for Ke2Message<D, KG>
where
D::Core: ProxyHash,
<D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
fn drop(&mut self) {
self.server_nonce.zeroize();
self.mac.zeroize();
}
}
impl<D: Hash, KG: KeGroup> ZeroizeOnDrop for Ke2Message<D, KG>
where
D::Core: ProxyHash,
<D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
}
/// The third key exchange message
#[cfg_attr(
feature = "serde",
derive(serde_::Deserialize, serde_::Serialize),
serde(bound = "", crate = "serde_")
derive(serde::Deserialize, serde::Serialize),
serde(bound = "", crate = "serde")
)]
#[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, ZeroizeOnDrop)]
pub struct Ke3Message<D: Hash>
where
D::Core: ProxyHash,
@@ -206,31 +129,12 @@ where
mac: Output<D>,
}
impl<D: Hash> Drop for Ke3Message<D>
where
D::Core: ProxyHash,
<D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
fn drop(&mut self) {
self.mac.zeroize();
}
}
impl<D: Hash> ZeroizeOnDrop for Ke3Message<D>
where
D::Core: ProxyHash,
<D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
}
////////////////////////////////
// High-level Implementations //
// ========================== //
////////////////////////////////
impl<D: Hash, KG: KeGroup> KeyExchange<D, KG> for TripleDH
impl<D: Hash, KG: KeGroup> KeyExchange<D, KG> for TripleDh
where
D::Core: ProxyHash,
<D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
@@ -294,7 +198,7 @@ where
let mut transcript_hasher = D::new()
.chain(STR_RFC)
.chain_iter(
Serialize::<U2>::from(context)
Input::<U2>::from(context)
.map_err(ProtocolError::into_custom)?
.iter(),
)
@@ -303,10 +207,10 @@ where
.chain_iter(id_s.into_iter())
.chain_iter(l2_bytes)
.chain(server_nonce)
.chain(&server_e_kp.public().to_bytes());
.chain(&server_e_kp.public().serialize());
let result = derive_3dh_keys::<D, KG, S>(
TripleDHComponents {
TripleDhComponents {
pk1: ke1_message.client_e_pk.clone(),
sk1: server_e_kp.private().clone(),
pk2: ke1_message.client_e_pk.clone(),
@@ -356,7 +260,7 @@ where
) -> Result<GenerateKe3Result<Self, D, KG>, ProtocolError> {
let mut transcript_hasher = D::new()
.chain(STR_RFC)
.chain_iter(Serialize::<U2>::from(context)?.iter())
.chain_iter(Input::<U2>::from(context)?.iter())
.chain_iter(id_u)
.chain_iter(serialized_credential_request)
.chain_iter(id_s)
@@ -364,7 +268,7 @@ where
.chain(ke2_message.to_bytes_without_mac());
let result = derive_3dh_keys::<D, KG, PrivateKey<KG>>(
TripleDHComponents {
TripleDhComponents {
pk1: ke2_message.server_e_pk.clone(),
sk1: ke1_state.client_e_sk.clone(),
pk2: server_s_pk,
@@ -422,9 +326,8 @@ where
//==================== //
/////////////////////////
#[allow(clippy::upper_case_acronyms)]
// The triple of public and private components used in the 3DH computation
struct TripleDHComponents<KG: KeGroup, S: SecretKey<KG>> {
struct TripleDhComponents<KG: KeGroup, S: SecretKey<KG>> {
pk1: PublicKey<KG>,
sk1: PrivateKey<KG>,
pk2: PublicKey<KG>,
@@ -435,10 +338,9 @@ struct TripleDHComponents<KG: KeGroup, S: SecretKey<KG>> {
// Consists of a session key, followed by two mac keys: (session_key, km2, km3)
#[cfg(not(test))]
#[allow(clippy::upper_case_acronyms)]
type TripleDHDerivationResult<D> = (Output<D>, Output<D>, Output<D>);
type TripleDhDerivationResult<D> = (Output<D>, Output<D>, Output<D>);
#[cfg(test)]
type TripleDHDerivationResult<D> = (Output<D>, Output<D>, Output<D>, Output<D>);
type TripleDhDerivationResult<D> = (Output<D>, Output<D>, Output<D>, Output<D>);
////////////////////////////////////////////////
// Helper functions and Trait Implementations //
@@ -451,9 +353,9 @@ type TripleDHDerivationResult<D> = (Output<D>, Output<D>, Output<D>, Output<D>);
// and server keypairs, along with some auxiliary metadata, to produce the
// session key and two MAC keys
fn derive_3dh_keys<D: Hash, KG: KeGroup, S: SecretKey<KG>>(
dh: TripleDHComponents<KG, S>,
dh: TripleDhComponents<KG, S>,
hashed_derivation_transcript: &[u8],
) -> Result<TripleDHDerivationResult<D>, ProtocolError<S::Error>>
) -> Result<TripleDhDerivationResult<D>, ProtocolError<S::Error>>
where
D::Core: ProxyHash,
<D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
@@ -529,9 +431,9 @@ where
let length_u16: u16 =
u16::try_from(OutputSize::<D>::USIZE).map_err(|_| ProtocolError::SerializationError)?;
let label = Serialize::<U1>::from_label(STR_OPAQUE, label)?;
let label = Input::<U1>::from_label(STR_OPAQUE, label)?;
let label = label.to_array_3();
let context = Serialize::<U1>::from(context)?;
let context = Input::<U1>::from(context)?;
let context = context.to_array_2();
let hkdf_label = [
@@ -570,8 +472,8 @@ fn generate_nonce<R: RngCore + CryptoRng>(rng: &mut R) -> GenericArray<u8, Nonce
// Serialization and deserialization implementations
impl<KG: KeGroup> FromBytes for Ke1State<KG> {
fn from_bytes(bytes: &[u8]) -> Result<Self, ProtocolError> {
impl<KG: KeGroup> Deserialize for Ke1State<KG> {
fn deserialize(bytes: &[u8]) -> Result<Self, ProtocolError> {
let key_len = KG::SkLen::USIZE;
let nonce_len = NonceLen::USIZE;
@@ -586,7 +488,7 @@ impl<KG: KeGroup> FromBytes for Ke1State<KG> {
}
}
impl<KG: KeGroup> ToBytes for Ke1State<KG>
impl<KG: KeGroup> Serialize for Ke1State<KG>
where
// Ke1State: KeSk + Nonce
KG::SkLen: Add<NonceLen>,
@@ -594,13 +496,13 @@ where
{
type Len = Sum<KG::SkLen, NonceLen>;
fn to_bytes(&self) -> GenericArray<u8, Self::Len> {
fn serialize(&self) -> GenericArray<u8, Self::Len> {
self.client_e_sk.serialize().concat(self.client_nonce)
}
}
impl<KG: KeGroup> FromBytes for Ke1Message<KG> {
fn from_bytes(ke1_message_bytes: &[u8]) -> Result<Self, ProtocolError> {
impl<KG: KeGroup> Deserialize for Ke1Message<KG> {
fn deserialize(ke1_message_bytes: &[u8]) -> Result<Self, ProtocolError> {
let nonce_len = NonceLen::USIZE;
let checked_nonce = check_slice_size(
ke1_message_bytes,
@@ -615,7 +517,7 @@ impl<KG: KeGroup> FromBytes for Ke1Message<KG> {
}
}
impl<KG: KeGroup> ToBytes for Ke1Message<KG>
impl<KG: KeGroup> Serialize for Ke1Message<KG>
where
// Ke1Message: Nonce + KePk
NonceLen: Add<KG::PkLen>,
@@ -623,18 +525,18 @@ where
{
type Len = Sum<NonceLen, KG::PkLen>;
fn to_bytes(&self) -> GenericArray<u8, Self::Len> {
self.client_nonce.concat(self.client_e_pk.to_bytes())
fn serialize(&self) -> GenericArray<u8, Self::Len> {
self.client_nonce.concat(self.client_e_pk.serialize())
}
}
impl<D: Hash> FromBytes for Ke2State<D>
impl<D: Hash> Deserialize for Ke2State<D>
where
D::Core: ProxyHash,
<D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
fn from_bytes(input: &[u8]) -> Result<Self, ProtocolError> {
fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
let hash_len = OutputSize::<D>::USIZE;
let checked_bytes = check_slice_size(input, 3 * hash_len, "ke2_state")?;
@@ -648,7 +550,7 @@ where
}
}
impl<D: Hash> ToBytes for Ke2State<D>
impl<D: Hash> Serialize for Ke2State<D>
where
D::Core: ProxyHash,
<D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
@@ -660,7 +562,7 @@ where
{
type Len = Sum<Sum<OutputSize<D>, OutputSize<D>>, OutputSize<D>>;
fn to_bytes(&self) -> GenericArray<u8, Self::Len> {
fn serialize(&self) -> GenericArray<u8, Self::Len> {
self.km3
.clone()
.concat(self.hashed_transcript.clone())
@@ -668,13 +570,13 @@ where
}
}
impl<KG: KeGroup, D: Hash> FromBytes for Ke2Message<D, KG>
impl<KG: KeGroup, D: Hash> Deserialize for Ke2Message<D, KG>
where
D::Core: ProxyHash,
<D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
fn from_bytes(input: &[u8]) -> Result<Self, ProtocolError> {
fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
let key_len = <KG as KeGroup>::PkLen::USIZE;
let nonce_len = NonceLen::USIZE;
let checked_nonce = check_slice_size_atleast(input, nonce_len, "ke2_message nonce")?;
@@ -701,7 +603,7 @@ where
}
}
impl<D: Hash, KG: KeGroup> ToBytes for Ke2Message<D, KG>
impl<D: Hash, KG: KeGroup> Serialize for Ke2Message<D, KG>
where
D::Core: ProxyHash,
<D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
@@ -713,9 +615,9 @@ where
{
type Len = Sum<Sum<NonceLen, KG::PkLen>, OutputSize<D>>;
fn to_bytes(&self) -> GenericArray<u8, Self::Len> {
fn serialize(&self) -> GenericArray<u8, Self::Len> {
self.server_nonce
.concat(self.server_e_pk.to_bytes())
.concat(self.server_e_pk.serialize())
.concat(self.mac.clone())
}
}
@@ -729,17 +631,17 @@ where
Sum<NonceLen, KG::PkLen>: ArrayLength<u8>,
{
fn to_bytes_without_mac(&self) -> GenericArray<u8, Sum<NonceLen, KG::PkLen>> {
self.server_nonce.concat(self.server_e_pk.to_bytes())
self.server_nonce.concat(self.server_e_pk.serialize())
}
}
impl<D: Hash> FromBytes for Ke3Message<D>
impl<D: Hash> Deserialize for Ke3Message<D>
where
D::Core: ProxyHash,
<D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
fn from_bytes(bytes: &[u8]) -> Result<Self, ProtocolError> {
fn deserialize(bytes: &[u8]) -> Result<Self, ProtocolError> {
let checked_bytes = check_slice_size(bytes, OutputSize::<D>::USIZE, "ke3_message")?;
Ok(Self {
@@ -748,7 +650,7 @@ where
}
}
impl<D: Hash> ToBytes for Ke3Message<D>
impl<D: Hash> Serialize for Ke3Message<D>
where
D::Core: ProxyHash,
<D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
@@ -756,7 +658,7 @@ where
{
type Len = OutputSize<D>;
fn to_bytes(&self) -> GenericArray<u8, Self::Len> {
fn serialize(&self) -> GenericArray<u8, Self::Len> {
self.mac.clone()
}
}
+64 -60
View File
@@ -12,22 +12,20 @@
use derive_where::derive_where;
use generic_array::{ArrayLength, GenericArray};
use rand::{CryptoRng, RngCore};
use zeroize::ZeroizeOnDrop;
use crate::errors::{InternalError, ProtocolError};
use crate::key_exchange::group::KeGroup;
use crate::serialization::GenericArrayExt;
/// A Keypair trait with public-private verification
#[cfg_attr(
feature = "serde",
derive(serde_::Deserialize, serde_::Serialize),
derive(serde::Deserialize, serde::Serialize),
serde(
bound(
deserialize = "KG::Pk: serde_::Deserialize<'de>, S: serde_::Deserialize<'de>",
serialize = "KG::Pk: serde_::Serialize, S: serde_::Serialize"
deserialize = "S: serde::Deserialize<'de>",
serialize = "S: serde::Serialize"
),
crate = "serde_"
crate = "serde"
)
)]
#[derive_where(Clone)]
@@ -64,7 +62,7 @@ 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);
let pk = KG::public_key(&sk);
let pk = KG::public_key(sk);
Self {
pk: PublicKey(pk),
sk: PrivateKey(sk),
@@ -98,36 +96,10 @@ where
}
/// Wrapper around a Key to enforce that it's a private one.
#[cfg_attr(
feature = "serde",
derive(serde_::Deserialize, serde_::Serialize),
serde(
bound(
deserialize = "KG::Sk: serde_::Deserialize<'de>",
serialize = "KG::Sk: serde_::Serialize"
),
crate = "serde_"
)
)]
#[derive_where(Clone)]
#[derive_where(Clone, ZeroizeOnDrop)]
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; KG::Sk)]
pub struct PrivateKey<KG: KeGroup>(KG::Sk);
impl<KG: KeGroup> Drop for PrivateKey<KG> {
fn drop(&mut self) {
KG::zeroize_sk_on_drop(&mut self.0)
}
}
impl<KG: KeGroup> ZeroizeOnDrop for PrivateKey<KG> {}
impl<KG: KeGroup> PrivateKey<KG> {
/// Convert from bytes
pub fn from_bytes(key_bytes: &GenericArray<u8, KG::SkLen>) -> Result<Self, InternalError> {
KG::deserialize_sk(key_bytes).map(Self)
}
}
/// A trait specifying the requirements for a private key container
pub trait SecretKey<KG: KeGroup>: Clone + Sized {
/// Custom error type that can be passed down to `InternalError::Custom`
@@ -159,52 +131,84 @@ impl<KG: KeGroup> SecretKey<KG> for PrivateKey<KG> {
&self,
pk: PublicKey<KG>,
) -> Result<GenericArray<u8, KG::PkLen>, InternalError> {
Ok(KG::diffie_hellman(&pk.0, &self.0))
Ok(KG::diffie_hellman(pk.0, self.0))
}
fn public_key(&self) -> Result<PublicKey<KG>, InternalError> {
Ok(PublicKey(KG::public_key(&self.0)))
Ok(PublicKey(KG::public_key(self.0)))
}
fn serialize(&self) -> GenericArray<u8, Self::Len> {
KG::serialize_sk(&self.0)
KG::serialize_sk(self.0)
}
fn deserialize(input: &[u8]) -> Result<Self, InternalError> {
GenericArray::try_from_slice(input).and_then(Self::from_bytes)
KG::deserialize_sk(input).map(Self)
}
}
#[cfg(feature = "serde")]
impl<'de, KG: KeGroup> serde::Deserialize<'de> for PrivateKey<KG> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
use serde::de::Error;
KG::deserialize_sk(&GenericArray::<_, KG::SkLen>::deserialize(deserializer)?)
.map(Self)
.map_err(D::Error::custom)
}
}
#[cfg(feature = "serde")]
impl<KG: KeGroup> serde::Serialize for PrivateKey<KG> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
KG::serialize_sk(self.0).serialize(serializer)
}
}
/// Wrapper around a Key to enforce that it's a public one.
#[cfg_attr(
feature = "serde",
derive(serde_::Deserialize, serde_::Serialize),
serde(
bound(
deserialize = "KG::Pk: serde_::Deserialize<'de>",
serialize = "KG::Pk: serde_::Serialize"
),
crate = "serde_"
)
)]
#[derive_where(Clone)]
#[derive_where(Clone, ZeroizeOnDrop)]
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; KG::Pk)]
pub struct PublicKey<KG: KeGroup>(KG::Pk);
impl<KG: KeGroup> PublicKey<KG> {
/// Convert from bytes
pub fn from_bytes(key_bytes: &GenericArray<u8, KG::PkLen>) -> Result<Self, InternalError> {
pub fn deserialize(key_bytes: &[u8]) -> Result<Self, InternalError> {
KG::deserialize_pk(key_bytes).map(Self)
}
/// Convert to bytes
pub fn to_bytes(&self) -> GenericArray<u8, KG::PkLen> {
KG::serialize_pk(&self.0)
pub fn serialize(&self) -> GenericArray<u8, KG::PkLen> {
KG::serialize_pk(self.0)
}
}
/// Convert from slice
pub fn deserialize(input: &[u8]) -> Result<Self, InternalError> {
GenericArray::try_from_slice(input).and_then(Self::from_bytes)
#[cfg(feature = "serde")]
impl<'de, KG: KeGroup> serde::Deserialize<'de> for PublicKey<KG> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
use serde::de::Error;
KG::deserialize_pk(&GenericArray::<_, KG::PkLen>::deserialize(deserializer)?)
.map(Self)
.map_err(D::Error::custom)
}
}
#[cfg(feature = "serde")]
impl<KG: KeGroup> serde::Serialize for PublicKey<KG> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
KG::serialize_pk(self.0).serialize(serializer)
}
}
@@ -290,15 +294,15 @@ mod tests {
impl CipherSuite for Default {
#[cfg(feature = "ristretto255")]
type OprfGroup = crate::Ristretto255;
type OprfCs = crate::Ristretto255;
#[cfg(not(feature = "ristretto255"))]
type OprfGroup = ::p256::NistP256;
type OprfCs = ::p256::NistP256;
#[cfg(feature = "ristretto255")]
type KeGroup = crate::Ristretto255;
#[cfg(not(feature = "ristretto255"))]
type KeGroup = ::p256::NistP256;
type KeyExchange = crate::key_exchange::tripledh::TripleDH;
type SlowHash = crate::slow_hash::NoOpHash;
type KeyExchange = crate::key_exchange::tripledh::TripleDh;
type Ksf = crate::ksf::Identity;
}
type KeCurve = <Default as CipherSuite>::KeGroup;
+9 -9
View File
@@ -5,15 +5,15 @@
// License, Version 2.0 found in the LICENSE-APACHE file in the root directory
// of this source tree.
//! Trait specifying a slow hashing function
//! Trait specifying a key stretching function
use generic_array::{ArrayLength, GenericArray};
use crate::errors::InternalError;
/// Used for the slow hashing function in OPAQUE
pub trait SlowHash: Default {
/// Computes the slow hashing function
/// Used for the key stretching function in OPAQUE
pub trait Ksf: Default {
/// Computes the key stretching function
fn hash<L: ArrayLength<u8>>(
&self,
input: GenericArray<u8, L>,
@@ -22,9 +22,9 @@ pub trait SlowHash: Default {
/// A no-op hash which simply returns its input
#[derive(Default)]
pub struct NoOpHash;
pub struct Identity;
impl SlowHash for NoOpHash {
impl Ksf for Identity {
fn hash<L: ArrayLength<u8>>(
&self,
input: GenericArray<u8, L>,
@@ -33,15 +33,15 @@ impl SlowHash for NoOpHash {
}
}
#[cfg(feature = "slow-hash")]
impl SlowHash for argon2::Argon2<'_> {
#[cfg(feature = "argon2")]
impl Ksf for argon2::Argon2<'_> {
fn hash<L: ArrayLength<u8>>(
&self,
input: GenericArray<u8, L>,
) -> Result<GenericArray<u8, L>, InternalError> {
let mut output = GenericArray::default();
self.hash_password_into(&input, &[0; argon2::MIN_SALT_LEN], &mut output)
.map_err(|_| InternalError::SlowHashError)?;
.map_err(|_| InternalError::KsfError)?;
Ok(output)
}
}
+141 -139
View File
@@ -26,26 +26,26 @@
//! * for the key exchange
//! * a key exchange protocol,
//! * a hashing function, and
//! * a slow hashing function.
//! * a key stretching function.
//!
//! We will use the following choices in this example:
//! ```ignore
//! use opaque_ke::CipherSuite;
//! struct Default;
//! impl CipherSuite for Default {
//! type OprfGroup = opaque_ke::Ristretto255;
//! type OprfCs = opaque_ke::Ristretto255;
//! type KeGroup = opaque_ke::Ristretto255;
//! type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
//! type Ksf = opaque_ke::ksf::Identity;
//! }
//! ```
//! See [examples/simple_login.rs](https://github.com/novifinancial/opaque-ke/blob/main/examples/simple_login.rs)
//! for a working example of a simple password-based login using OPAQUE.
//!
//! Note that our choice of slow hashing function in this example, `NoOpHash`,
//! Note that our choice of key stretching function in this example, `Identity`,
//! is selected only to ensure that the tests execute quickly. A real
//! application should use an actual slow hashing function, such as `Argon2`,
//! which can be enabled through the `slow-hash` feature. See more details in
//! application should use an actual key stretching function, such as `Argon2`,
//! which can be enabled through the `argon2` feature. See more details in
//! the [features](#features) section.
//!
//! ## Setup
@@ -58,17 +58,17 @@
//! # struct Default;
//! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default {
//! # type OprfGroup = opaque_ke::Ristretto255;
//! # type OprfCs = opaque_ke::Ristretto255;
//! # type KeGroup = opaque_ke::Ristretto255;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # }
//! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default {
//! # type OprfGroup = p256::NistP256;
//! # type OprfCs = p256::NistP256;
//! # type KeGroup = p256::NistP256;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # }
//! use rand::rngs::OsRng;
//! use rand::RngCore;
@@ -101,23 +101,23 @@
//! # use opaque_ke::{
//! # errors::ProtocolError,
//! # ServerRegistration,
//! # slow_hash::NoOpHash,
//! # ksf::Identity,
//! # };
//! # use opaque_ke::CipherSuite;
//! # struct Default;
//! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default {
//! # type OprfGroup = opaque_ke::Ristretto255;
//! # type OprfCs = opaque_ke::Ristretto255;
//! # type KeGroup = opaque_ke::Ristretto255;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # }
//! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default {
//! # type OprfGroup = p256::NistP256;
//! # type OprfCs = p256::NistP256;
//! # type KeGroup = p256::NistP256;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # }
//! use opaque_ke::ClientRegistration;
//! use rand::rngs::OsRng;
@@ -139,23 +139,23 @@
//! # errors::ProtocolError,
//! # ClientRegistration,
//! # ServerSetup,
//! # slow_hash::NoOpHash,
//! # ksf::Identity,
//! # };
//! # use opaque_ke::CipherSuite;
//! # struct Default;
//! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default {
//! # type OprfGroup = opaque_ke::Ristretto255;
//! # type OprfCs = opaque_ke::Ristretto255;
//! # type KeGroup = opaque_ke::Ristretto255;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # }
//! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default {
//! # type OprfGroup = p256::NistP256;
//! # type OprfCs = p256::NistP256;
//! # type KeGroup = p256::NistP256;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # }
//! # use rand::{rngs::OsRng, RngCore};
//! # let mut client_rng = OsRng;
@@ -186,23 +186,23 @@
//! # use opaque_ke::{
//! # errors::ProtocolError,
//! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ServerSetup,
//! # slow_hash::NoOpHash,
//! # ksf::Identity,
//! # };
//! # use opaque_ke::CipherSuite;
//! # struct Default;
//! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default {
//! # type OprfGroup = opaque_ke::Ristretto255;
//! # type OprfCs = opaque_ke::Ristretto255;
//! # type KeGroup = opaque_ke::Ristretto255;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # }
//! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default {
//! # type OprfGroup = p256::NistP256;
//! # type OprfCs = p256::NistP256;
//! # type KeGroup = p256::NistP256;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # }
//! # use rand::{rngs::OsRng, RngCore};
//! # let mut client_rng = OsRng;
@@ -234,23 +234,23 @@
//! # use opaque_ke::{
//! # errors::ProtocolError,
//! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ServerSetup,
//! # slow_hash::NoOpHash,
//! # ksf::Identity,
//! # };
//! # use opaque_ke::CipherSuite;
//! # struct Default;
//! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default {
//! # type OprfGroup = opaque_ke::Ristretto255;
//! # type OprfCs = opaque_ke::Ristretto255;
//! # type KeGroup = opaque_ke::Ristretto255;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # }
//! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default {
//! # type OprfGroup = p256::NistP256;
//! # type OprfCs = p256::NistP256;
//! # type KeGroup = p256::NistP256;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # }
//! # use rand::{rngs::OsRng, RngCore};
//! # let mut client_rng = OsRng;
@@ -287,23 +287,23 @@
//! # use opaque_ke::{
//! # errors::ProtocolError,
//! # ClientRegistration, ServerRegistration, ServerLogin, CredentialFinalization,
//! # slow_hash::NoOpHash,
//! # ksf::Identity,
//! # };
//! # use opaque_ke::CipherSuite;
//! # struct Default;
//! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default {
//! # type OprfGroup = opaque_ke::Ristretto255;
//! # type OprfCs = opaque_ke::Ristretto255;
//! # type KeGroup = opaque_ke::Ristretto255;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # }
//! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default {
//! # type OprfGroup = p256::NistP256;
//! # type OprfCs = p256::NistP256;
//! # type KeGroup = p256::NistP256;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # }
//! # use rand::{rngs::OsRng, RngCore};
//! use opaque_ke::ClientLogin;
@@ -324,23 +324,23 @@
//! # use opaque_ke::{
//! # errors::ProtocolError,
//! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, CredentialFinalization, ServerSetup,
//! # slow_hash::NoOpHash,
//! # ksf::Identity,
//! # };
//! # use opaque_ke::CipherSuite;
//! # struct Default;
//! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default {
//! # type OprfGroup = opaque_ke::Ristretto255;
//! # type OprfCs = opaque_ke::Ristretto255;
//! # type KeGroup = opaque_ke::Ristretto255;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # }
//! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default {
//! # type OprfGroup = p256::NistP256;
//! # type OprfCs = p256::NistP256;
//! # type KeGroup = p256::NistP256;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # }
//! # use rand::{rngs::OsRng, RngCore};
//! # let mut client_rng = OsRng;
@@ -387,23 +387,23 @@
//! # use opaque_ke::{
//! # errors::ProtocolError,
//! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, ClientLoginFinishParameters, ServerLogin, ServerLoginStartParameters, CredentialFinalization, ServerSetup,
//! # slow_hash::NoOpHash,
//! # ksf::Identity,
//! # };
//! # use opaque_ke::CipherSuite;
//! # struct Default;
//! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default {
//! # type OprfGroup = opaque_ke::Ristretto255;
//! # type OprfCs = opaque_ke::Ristretto255;
//! # type KeGroup = opaque_ke::Ristretto255;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # }
//! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default {
//! # type OprfGroup = p256::NistP256;
//! # type OprfCs = p256::NistP256;
//! # type KeGroup = p256::NistP256;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # }
//! # use rand::{rngs::OsRng, RngCore};
//! # let mut client_rng = OsRng;
@@ -443,23 +443,23 @@
//! # use opaque_ke::{
//! # errors::ProtocolError,
//! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, ClientLoginFinishParameters, ServerLogin, ServerLoginStartParameters, CredentialFinalization, ServerSetup,
//! # slow_hash::NoOpHash,
//! # ksf::Identity,
//! # };
//! # use opaque_ke::CipherSuite;
//! # struct Default;
//! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default {
//! # type OprfGroup = opaque_ke::Ristretto255;
//! # type OprfCs = opaque_ke::Ristretto255;
//! # type KeGroup = opaque_ke::Ristretto255;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # }
//! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default {
//! # type OprfGroup = p256::NistP256;
//! # type OprfCs = p256::NistP256;
//! # type KeGroup = p256::NistP256;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # }
//! # use rand::{rngs::OsRng, RngCore};
//! # let mut client_rng = OsRng;
@@ -539,23 +539,23 @@
//! # use opaque_ke::{
//! # errors::ProtocolError,
//! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, ClientLoginFinishParameters, ServerLogin, ServerLoginStartParameters, CredentialFinalization, ServerSetup,
//! # slow_hash::NoOpHash,
//! # ksf::Identity,
//! # };
//! # use opaque_ke::CipherSuite;
//! # struct Default;
//! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default {
//! # type OprfGroup = opaque_ke::Ristretto255;
//! # type OprfCs = opaque_ke::Ristretto255;
//! # type KeGroup = opaque_ke::Ristretto255;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # }
//! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default {
//! # type OprfGroup = p256::NistP256;
//! # type OprfCs = p256::NistP256;
//! # type KeGroup = p256::NistP256;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # }
//! # use rand::{rngs::OsRng, RngCore};
//! # let mut client_rng = OsRng;
@@ -619,15 +619,15 @@
//! [ClientRegistration::start] and [ClientLogin::start].
//!
//! The export key retains as much secrecy as the password itself, and is
//! similarly derived through an evaluation of the slow hashing function. Hence,
//! only the parties which know the password the client uses during registration
//! and login can recover this secret, as it is never exposed to the server. As
//! a result, the export key can be used (separately from the OPAQUE protocol)
//! to provide confidentiality and integrity to other data which only the client
//! should be able to process. For instance, if the server is expected to
//! maintain any client-side secrets which require a password to access, then
//! this export key can be used to encrypt these secrets so that they remain
//! hidden from the server (see [examples/digital_locker.rs](https://github.com/novifinancial/opaque-ke/blob/main/examples/digital_locker.rs)
//! similarly derived through an evaluation of the key stretching function.
//! Hence, only the parties which know the password the client uses during
//! registration and login can recover this secret, as it is never exposed to
//! the server. As a result, the export key can be used (separately from the
//! OPAQUE protocol) to provide confidentiality and integrity to other data
//! which only the client should be able to process. For instance, if the server
//! is expected to maintain any client-side secrets which require a password to
//! access, then this export key can be used to encrypt these secrets so that
//! they remain hidden from the server (see [examples/digital_locker.rs](https://github.com/novifinancial/opaque-ke/blob/main/examples/digital_locker.rs)
//! for a working example).
//!
//! You can access the export key from the `export_key` field of
@@ -636,23 +636,23 @@
//! # use opaque_ke::{
//! # errors::ProtocolError,
//! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, ClientLoginFinishParameters, ServerLogin, ServerLoginStartParameters, CredentialFinalization, ServerSetup,
//! # slow_hash::NoOpHash,
//! # ksf::Identity,
//! # };
//! # use opaque_ke::CipherSuite;
//! # struct Default;
//! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default {
//! # type OprfGroup = opaque_ke::Ristretto255;
//! # type OprfCs = opaque_ke::Ristretto255;
//! # type KeGroup = opaque_ke::Ristretto255;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # }
//! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default {
//! # type OprfGroup = p256::NistP256;
//! # type OprfCs = p256::NistP256;
//! # type KeGroup = p256::NistP256;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # }
//! # use rand::{rngs::OsRng, RngCore};
//! # let mut client_rng = OsRng;
@@ -717,23 +717,23 @@
//! # use opaque_ke::{
//! # errors::ProtocolError,
//! # ClientRegistration, ClientRegistrationFinishParameters, Identifiers, ServerRegistration, ServerSetup,
//! # slow_hash::NoOpHash,
//! # ksf::Identity,
//! # };
//! # use opaque_ke::CipherSuite;
//! # struct Default;
//! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default {
//! # type OprfGroup = opaque_ke::Ristretto255;
//! # type OprfCs = opaque_ke::Ristretto255;
//! # type KeGroup = opaque_ke::Ristretto255;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # }
//! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default {
//! # type OprfGroup = p256::NistP256;
//! # type OprfCs = p256::NistP256;
//! # type KeGroup = p256::NistP256;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # }
//! # use rand::{rngs::OsRng, RngCore};
//! # let mut client_rng = OsRng;
@@ -765,23 +765,23 @@
//! # use opaque_ke::{
//! # errors::ProtocolError,
//! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, CredentialFinalization, Identifiers, ServerSetup,
//! # slow_hash::NoOpHash,
//! # ksf::Identity,
//! # };
//! # use opaque_ke::CipherSuite;
//! # struct Default;
//! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default {
//! # type OprfGroup = opaque_ke::Ristretto255;
//! # type OprfCs = opaque_ke::Ristretto255;
//! # type KeGroup = opaque_ke::Ristretto255;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # }
//! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default {
//! # type OprfGroup = p256::NistP256;
//! # type OprfCs = p256::NistP256;
//! # type KeGroup = p256::NistP256;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # }
//! # use rand::{rngs::OsRng, RngCore};
//! # let mut client_rng = OsRng;
@@ -824,23 +824,23 @@
//! # use opaque_ke::{
//! # errors::ProtocolError,
//! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, ClientLoginFinishParameters, Identifiers, ServerLogin, ServerLoginStartParameters, CredentialFinalization, ServerSetup,
//! # slow_hash::NoOpHash,
//! # ksf::Identity,
//! # };
//! # use opaque_ke::CipherSuite;
//! # struct Default;
//! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default {
//! # type OprfGroup = opaque_ke::Ristretto255;
//! # type OprfCs = opaque_ke::Ristretto255;
//! # type KeGroup = opaque_ke::Ristretto255;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # }
//! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default {
//! # type OprfGroup = p256::NistP256;
//! # type OprfCs = p256::NistP256;
//! # type KeGroup = p256::NistP256;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # }
//! # use rand::{rngs::OsRng, RngCore};
//! # let mut client_rng = OsRng;
@@ -926,17 +926,17 @@
//! # struct Default;
//! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default {
//! # type OprfGroup = opaque_ke::Ristretto255;
//! # type OprfCs = opaque_ke::Ristretto255;
//! # type KeGroup = opaque_ke::Ristretto255;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # }
//! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default {
//! # type OprfGroup = p256::NistP256;
//! # type OprfCs = p256::NistP256;
//! # type KeGroup = p256::NistP256;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # }
//! # #[derive(Debug)]
//! # struct YourRemoteKeyError;
@@ -944,7 +944,7 @@
//! # struct YourRemoteKey(<<Default as CipherSuite>::KeGroup as KeGroup>::Sk);
//! # impl YourRemoteKey {
//! # fn diffie_hellman(&self, pk: &[u8]) -> Result<GenericArray<u8, <<Default as CipherSuite>::KeGroup as KeGroup>::PkLen>, YourRemoteKeyError> { todo!() }
//! # fn public_key(&self) -> Result<GenericArray<u8, <<Default as CipherSuite>::KeGroup as KeGroup>::PkLen>, YourRemoteKeyError> { Ok(<<Default as CipherSuite>::KeGroup>::serialize_pk(&<<Default as CipherSuite>::KeGroup>::public_key(&self.0))) }
//! # fn public_key(&self) -> Result<GenericArray<u8, <<Default as CipherSuite>::KeGroup as KeGroup>::PkLen>, YourRemoteKeyError> { Ok(<<Default as CipherSuite>::KeGroup>::serialize_pk(<<Default as CipherSuite>::KeGroup>::public_key(self.0))) }
//! # }
//! impl SecretKey<<Default as CipherSuite>::KeGroup> for YourRemoteKey {
//! type Error = YourRemoteKeyError;
@@ -954,13 +954,13 @@
//! &self,
//! pk: PublicKey<<Default as CipherSuite>::KeGroup>,
//! ) -> Result<GenericArray<u8, <<Default as CipherSuite>::KeGroup as KeGroup>::PkLen>, InternalError<Self::Error>> {
//! YourRemoteKey::diffie_hellman(self, &pk.to_bytes()).map_err(InternalError::Custom)
//! YourRemoteKey::diffie_hellman(self, &pk.serialize()).map_err(InternalError::Custom)
//! }
//!
//! fn public_key(
//! &self
//! ) -> Result<PublicKey<<Default as CipherSuite>::KeGroup>, InternalError<Self::Error>> {
//! PublicKey::from_bytes(&YourRemoteKey::public_key(self).map_err(InternalError::Custom)?).map_err(InternalError::into_custom)
//! PublicKey::deserialize(&YourRemoteKey::public_key(self).map_err(InternalError::Custom)?).map_err(InternalError::into_custom)
//! }
//!
//! fn serialize(&self) -> GenericArray<u8, Self::Len> {
@@ -981,12 +981,12 @@
//!
//! # Features
//!
//! - The `slow-hash` feature, when enabled, introduces a dependency on `argon2`
//! and implements the `SlowHash` trait for `Argon2` with a set of default parameters.
//! - The `argon2` feature, when enabled, introduces a dependency on `argon2`
//! and implements the `Ksf` trait for `Argon2` with a set of default parameters.
//! In general, secure instantiations should choose to invoke a memory-hard password
//! hashing function when the client's password is expected to have low entropy,
//! instead of relying on [slow_hash::NoOpHash] as done in the above example. The
//! more computationally intensive the `SlowHash` function is, the more resistant
//! instead of relying on [ksf::Identity] as done in the above example. The
//! more computationally intensive the `Ksf` function is, the more resistant
//! the server's password file records will be against offline dictionary and precomputation
//! attacks; see [the OPAQUE paper](https://eprint.iacr.org/2018/163.pdf) for
//! more details.
@@ -995,24 +995,24 @@
//!
//! - The backend features are re-exported from [curve25519-dalek](https://doc.dalek.rs/curve25519_dalek/index.html#backends-and-features)
//! and allow for selecting the corresponding backend for the curve arithmetic
//! used. The `ristretto255_u64` feature is included as the default. Other
//! features are mapped as `ristretto255_u32`, `ristretto255_fiat_u64` and
//! `ristretto255_fiat_u32`. Any `ristretto255_*` backend feature will enable
//! used. The `ristretto255-u64` feature is included as the default. Other
//! features are mapped as `ristretto255-u32`, `ristretto255-fiat-u64` and
//! `ristretto255-fiat-u32`. Any `ristretto255-*` backend feature will enable
//! the `ristretto255` feature, which can be used too, but keep in mind that
//! `curve25519-dalek` will fail to compile without a selected backend. This
//! enables the use of [`Ristretto255`] as a `KeGroup` and `OprfGroup`.
//! enables the use of [`Ristretto255`] as a `KeGroup` and `OprfCs`.
//!
//! - The `x25519` feature is similar to the `ristretto255` feature and requires
//! to select a backend like `x25519_u64`, other backends are the same as in
//! `ristretto255_*`. This enables [`X25519`] as a `KeGroup`.
//! to select a backend like `x25519-u64`, other backends are the same as in
//! `ristretto255-*`. This enables [`X25519`] as a `KeGroup`.
//!
//! - The `ristretto255_simd` feature is re-exported from [curve25519-dalek](https://doc.dalek.rs/curve25519_dalek/index.html#backends-and-features)
//! - The `ristretto255-simd` feature is re-exported from [curve25519-dalek](https://doc.dalek.rs/curve25519_dalek/index.html#backends-and-features)
//! and enables parallel formulas, using either AVX2 or AVX512-IFMA. This will
//! automatically enable the `ristretto255_u64` feature and requires Rust
//! automatically enable the `ristretto255-u64` feature and requires Rust
//! nightly.
//!
//! - The `p256` feature enables the use of [`p256::NistP256`] as a `KeGroup`
//! and a `OprfGroup` for `CipherSuite`.
//! and a `OprfCs` for `CipherSuite`.
//!
//! - The `bench` feature is used only for running performance benchmarks for
//! this implementation.
@@ -1022,25 +1022,27 @@
#![cfg_attr(not(test), deny(unsafe_code))]
#![no_std]
#![warn(clippy::cargo, missing_docs)]
#![allow(clippy::multiple_crate_versions, type_alias_bounds)]
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
#![allow(type_alias_bounds)]
#[cfg(any(feature = "std", test))]
extern crate std;
#[cfg(feature = "serde")]
extern crate serde_ as serde;
// Error types
pub mod errors;
#[macro_use]
mod impls;
pub mod ciphersuite;
mod envelope;
pub mod hash;
pub mod key_exchange;
pub mod keypair;
pub mod ksf;
mod messages;
mod opaque;
mod serialization;
pub mod slow_hash;
mod util;
#[cfg(test)]
+76 -100
View File
@@ -18,7 +18,6 @@ use generic_array::{ArrayLength, GenericArray};
use rand::{CryptoRng, RngCore};
use subtle::ConstantTimeEq;
use voprf::Group;
use zeroize::{Zeroize, ZeroizeOnDrop};
use crate::ciphersuite::{CipherSuite, OprfGroup, OprfHash};
use crate::envelope::{Envelope, EnvelopeLen};
@@ -27,7 +26,7 @@ use crate::errors::ProtocolError;
use crate::hash::{Hash, OutputSize, ProxyHash};
use crate::key_exchange::group::KeGroup;
use crate::key_exchange::traits::{
FromBytes, Ke1MessageLen, Ke2MessageLen, Ke3MessageLen, KeyExchange, ToBytes,
Deserialize, Ke1MessageLen, Ke2MessageLen, Ke3MessageLen, KeyExchange, Serialize,
};
use crate::key_exchange::tripledh::NonceLen;
use crate::keypair::{PublicKey, SecretKey};
@@ -39,8 +38,13 @@ use crate::opaque::{MaskedResponse, MaskedResponseLen, ServerSetup};
////////////////////////////
/// The message sent by the client to the server, to initiate registration
#[cfg_attr(
feature = "serde",
derive(serde::Deserialize, serde::Serialize),
serde(bound = "", crate = "serde")
)]
#[derive_where(Clone)]
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; voprf::BlindedElement<CS::OprfGroup>)]
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; voprf::BlindedElement<CS::OprfCs>)]
pub struct RegistrationRequest<CS: CipherSuite>
where
<OprfHash<CS> as OutputSizeUser>::OutputSize:
@@ -51,15 +55,18 @@ where
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
/// blinded password information
pub(crate) blinded_element: voprf::BlindedElement<CS::OprfGroup>,
pub(crate) blinded_element: voprf::BlindedElement<CS::OprfCs>,
}
impl_serialize_and_deserialize_for!(RegistrationRequest);
/// The answer sent by the server to the user, upon reception of the
/// registration attempt
#[cfg_attr(
feature = "serde",
derive(serde::Deserialize, serde::Serialize),
serde(bound = "", crate = "serde")
)]
#[derive_where(Clone)]
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; voprf::EvaluationElement<CS::OprfGroup>, <CS::KeGroup as KeGroup>::Pk)]
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; voprf::EvaluationElement<CS::OprfCs>, <CS::KeGroup as KeGroup>::Pk)]
pub struct RegistrationResponse<CS: CipherSuite>
where
<OprfHash<CS> as OutputSizeUser>::OutputSize:
@@ -70,22 +77,19 @@ where
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
/// The server's oprf output
pub(crate) evaluation_element: voprf::EvaluationElement<CS::OprfGroup>,
pub(crate) evaluation_element: voprf::EvaluationElement<CS::OprfCs>,
/// Server's static public key
pub(crate) server_s_pk: PublicKey<CS::KeGroup>,
}
impl_serialize_and_deserialize_for!(
RegistrationResponse
where
// RegistrationResponse: KgPk + KePk
<OprfGroup<CS> as Group>::ElemLen: Add<<CS::KeGroup as KeGroup>::PkLen>,
RegistrationResponseLen<CS>: ArrayLength<u8>,
);
/// The final message from the client, containing sealed cryptographic
/// identifiers
#[derive_where(Clone)]
#[cfg_attr(
feature = "serde",
derive(serde::Deserialize, serde::Serialize),
serde(bound = "", crate = "serde")
)]
#[derive_where(Clone, ZeroizeOnDrop)]
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; <CS::KeGroup as KeGroup>::Pk)]
pub struct RegistrationUpload<CS: CipherSuite>
where
@@ -105,49 +109,24 @@ where
pub(crate) client_s_pk: PublicKey<CS::KeGroup>,
}
impl<CS: CipherSuite> Drop for RegistrationUpload<CS>
where
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
fn drop(&mut self) {
self.masking_key.zeroize();
}
}
impl<CS: CipherSuite> ZeroizeOnDrop for RegistrationUpload<CS>
where
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
}
impl_serialize_and_deserialize_for!(
RegistrationUpload
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>>>:
ArrayLength<u8> | Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength<u8>,
);
/// The message sent by the user to the server, to initiate registration
#[cfg_attr(
feature = "serde",
derive(serde::Deserialize, serde::Serialize),
serde(
bound(
deserialize = "<CS::KeyExchange as KeyExchange<OprfHash<CS>, \
CS::KeGroup>>::KE1Message: serde::Deserialize<'de>",
serialize = "<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE1Message: \
serde::Serialize"
),
crate = "serde"
)
)]
#[derive_where(Clone, ZeroizeOnDrop)]
#[derive_where(
Debug, Eq, Hash, PartialEq;
voprf::BlindedElement<CS::OprfGroup>,
voprf::BlindedElement<CS::OprfCs>,
<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE1Message,
)]
pub struct CredentialRequest<CS: CipherSuite>
@@ -159,24 +138,29 @@ where
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
pub(crate) blinded_element: voprf::BlindedElement<CS::OprfGroup>,
pub(crate) blinded_element: voprf::BlindedElement<CS::OprfCs>,
pub(crate) ke1_message: <CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE1Message,
}
impl_serialize_and_deserialize_for!(
CredentialRequest
where
// CredentialRequest: KgPk + Ke1Message
<OprfGroup<CS> as Group>::ElemLen: Add<Ke1MessageLen<CS>>,
CredentialRequestLen<CS>: ArrayLength<u8>,
);
/// The answer sent by the server to the user, upon reception of the login
/// attempt
#[cfg_attr(
feature = "serde",
derive(serde::Deserialize, serde::Serialize),
serde(
bound(
deserialize = "<CS::KeyExchange as KeyExchange<OprfHash<CS>, \
CS::KeGroup>>::KE2Message: serde::Deserialize<'de>",
serialize = "<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE2Message: \
serde::Serialize"
),
crate = "serde"
)
)]
#[derive_where(Clone)]
#[derive_where(
Debug, Eq, Hash, PartialEq;
voprf::EvaluationElement<CS::OprfGroup>,
voprf::EvaluationElement<CS::OprfCs>,
<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE2Message,
)]
pub struct CredentialResponse<CS: CipherSuite>
@@ -189,32 +173,27 @@ where
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
/// the server's oprf output
pub(crate) evaluation_element: voprf::EvaluationElement<CS::OprfGroup>,
pub(crate) evaluation_element: voprf::EvaluationElement<CS::OprfCs>,
pub(crate) masking_nonce: GenericArray<u8, NonceLen>,
pub(crate) masked_response: MaskedResponse<CS>,
pub(crate) ke2_message: <CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE2Message,
}
impl_serialize_and_deserialize_for!(
CredentialResponse
where
// CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse
<OprfGroup<CS> as Group>::ElemLen: Add<NonceLen>,
Sum<<OprfGroup<CS> as 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
CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>,
CredentialResponseLen<CS>: ArrayLength<u8>,
);
/// The answer sent by the client to the server, upon reception of the sealed
/// envelope
#[cfg_attr(
feature = "serde",
derive(serde::Deserialize, serde::Serialize),
serde(
bound(
deserialize = "<CS::KeyExchange as KeyExchange<OprfHash<CS>, \
CS::KeGroup>>::KE3Message: serde::Deserialize<'de>",
serialize = "<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE3Message: \
serde::Serialize"
),
crate = "serde"
)
)]
#[derive_where(Clone)]
#[derive_where(
Debug, Eq, Hash, PartialEq;
@@ -232,8 +211,6 @@ where
pub(crate) ke3_message: <CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE3Message,
}
impl_serialize_and_deserialize_for!(CredentialFinalization);
////////////////////////////////
// High-level Implementations //
// ========================== //
@@ -253,7 +230,7 @@ where
{
/// Only used for testing purposes
#[cfg(test)]
pub fn get_blinded_element_for_testing(&self) -> voprf::BlindedElement<CS::OprfGroup> {
pub fn get_blinded_element_for_testing(&self) -> voprf::BlindedElement<CS::OprfCs> {
self.blinded_element.clone()
}
@@ -291,7 +268,7 @@ where
RegistrationResponseLen<CS>: ArrayLength<u8>,
{
<OprfGroup<CS> as Group>::serialize_elem(self.evaluation_element.value())
.concat(self.server_s_pk.to_bytes())
.concat(self.server_s_pk.serialize())
}
/// Deserialization from bytes
@@ -347,7 +324,7 @@ where
RegistrationUploadLen<CS>: ArrayLength<u8>,
{
self.client_s_pk
.to_bytes()
.serialize()
.concat(self.masking_key.clone())
.concat(self.envelope.serialize())
}
@@ -405,7 +382,7 @@ where
CredentialRequestLen<CS>: ArrayLength<u8>,
{
<OprfGroup<CS> as Group>::serialize_elem(self.blinded_element.value())
.concat(self.ke1_message.to_bytes())
.concat(self.ke1_message.serialize())
}
pub(crate) fn serialize_iter<'a>(
@@ -424,7 +401,7 @@ where
// Check that the message is actually containing an element of the correct
// subgroup
let blinded_element =
voprf::BlindedElement::<CS::OprfGroup>::deserialize(&checked_slice[..elem_len])?;
voprf::BlindedElement::<CS::OprfCs>::deserialize(&checked_slice[..elem_len])?;
// Throw an error if the identity group element is encountered
if bool::from(<OprfGroup<CS> as Group>::identity_elem().ct_eq(&blinded_element.value())) {
@@ -432,7 +409,7 @@ where
}
let ke1_message =
<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE1Message::from_bytes(
<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE1Message::deserialize(
&checked_slice[elem_len..],
)?;
@@ -444,7 +421,7 @@ where
/// Only used for testing purposes
#[cfg(test)]
pub fn get_blinded_element_for_testing(&self) -> voprf::BlindedElement<CS::OprfGroup> {
pub fn get_blinded_element_for_testing(&self) -> voprf::BlindedElement<CS::OprfCs> {
self.blinded_element.clone()
}
}
@@ -485,7 +462,7 @@ where
<OprfGroup<CS> as Group>::serialize_elem(self.evaluation_element.value())
.concat(self.masking_nonce)
.concat(self.masked_response.serialize())
.concat(self.ke2_message.to_bytes())
.concat(self.ke2_message.serialize())
}
pub(crate) fn serialize_without_ke<'a>(
@@ -516,8 +493,7 @@ where
// Check that the message is actually containing an element of the correct
// subgroup
let beta_bytes = &checked_slice[..elem_len];
let evaluation_element =
voprf::EvaluationElement::<CS::OprfGroup>::deserialize(beta_bytes)?;
let evaluation_element = voprf::EvaluationElement::<CS::OprfCs>::deserialize(beta_bytes)?;
// Throw an error if the identity group element is encountered
if bool::from(<OprfGroup<CS> as Group>::identity_elem().ct_eq(&evaluation_element.value()))
@@ -531,7 +507,7 @@ where
&checked_slice[elem_len + nonce_len..elem_len + nonce_len + masked_response_len],
);
let ke2_message =
<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE2Message::from_bytes(
<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE2Message::deserialize(
&checked_slice[elem_len + nonce_len + masked_response_len..],
)?;
@@ -570,13 +546,13 @@ where
{
/// Serialization into bytes
pub fn serialize(&self) -> GenericArray<u8, CredentialFinalizationLen<CS>> {
self.ke3_message.to_bytes()
self.ke3_message.serialize()
}
/// Deserialization from bytes
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
let ke3_message =
<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE3Message::from_bytes(
<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE3Message::deserialize(
input,
)?;
Ok(Self { ke3_message })
+91 -89
View File
@@ -27,13 +27,13 @@ use crate::errors::{InternalError, ProtocolError};
use crate::hash::{Hash, OutputSize, ProxyHash};
use crate::key_exchange::group::KeGroup;
use crate::key_exchange::traits::{
FromBytes, Ke1MessageLen, Ke1StateLen, Ke2StateLen, KeyExchange, ToBytes,
Deserialize, Ke1MessageLen, Ke1StateLen, Ke2StateLen, KeyExchange, Serialize,
};
use crate::key_exchange::tripledh::NonceLen;
use crate::keypair::{KeyPair, PrivateKey, PublicKey, SecretKey};
use crate::ksf::Ksf;
use crate::messages::{CredentialRequestLen, RegistrationUploadLen};
use crate::serialization::Serialize;
use crate::slow_hash::SlowHash;
use crate::serialization::Input;
use crate::{
CredentialFinalization, CredentialRequest, CredentialResponse, RegistrationRequest,
RegistrationResponse, RegistrationUpload,
@@ -57,15 +57,13 @@ const STR_OPAQUE_DERIVE_KEY_PAIR: &[u8; 20] = b"OPAQUE-DeriveKeyPair";
/// The state elements the server holds upon setup
#[cfg_attr(
feature = "serde",
derive(serde_::Deserialize, serde_::Serialize),
derive(serde::Deserialize, serde::Serialize),
serde(
bound(
deserialize = "<CS::KeGroup as KeGroup>::Pk: serde_::Deserialize<'de>, <CS::KeGroup \
as KeGroup>::Sk: serde_::Deserialize<'de>, S: serde_::Deserialize<'de>",
serialize = "<CS::KeGroup as KeGroup>::Pk: serde_::Serialize, <CS::KeGroup as \
KeGroup>::Sk: serde_::Serialize, S: serde_::Serialize"
deserialize = "S: serde::Deserialize<'de>",
serialize = "S: serde::Serialize"
),
crate = "serde_"
crate = "serde"
)
)]
#[derive_where(Clone)]
@@ -87,11 +85,16 @@ pub struct ServerSetup<
}
/// The state elements the client holds to register itself
#[cfg_attr(
feature = "serde",
derive(serde::Deserialize, serde::Serialize),
serde(bound = "", crate = "serde")
)]
#[derive_where(Clone, ZeroizeOnDrop)]
#[derive_where(
Debug, Eq, Hash, PartialEq;
voprf::NonVerifiableClient<CS::OprfGroup>,
voprf::BlindedElement<CS::OprfGroup>,
voprf::NonVerifiableClient<CS::OprfCs>,
voprf::BlindedElement<CS::OprfCs>,
)]
pub struct ClientRegistration<CS: CipherSuite>
where
@@ -102,19 +105,16 @@ where
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
pub(crate) oprf_client: voprf::NonVerifiableClient<CS::OprfGroup>,
pub(crate) blinded_element: voprf::BlindedElement<CS::OprfGroup>,
pub(crate) oprf_client: voprf::NonVerifiableClient<CS::OprfCs>,
pub(crate) blinded_element: voprf::BlindedElement<CS::OprfCs>,
}
impl_serialize_and_deserialize_for!(
ClientRegistration
where
// ClientRegistration: KgSk + KgPk
<OprfGroup<CS> as Group>::ScalarLen: Add<<OprfGroup<CS> as Group>::ElemLen>,
ClientRegistrationLen<CS>: ArrayLength<u8>,
);
/// The state elements the server holds to record a registration
#[cfg_attr(
feature = "serde",
derive(serde::Deserialize, serde::Serialize),
serde(bound = "", crate = "serde")
)]
#[derive_where(Clone, ZeroizeOnDrop)]
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; <CS::KeGroup as KeGroup>::Pk)]
pub struct ServerRegistration<CS: CipherSuite>(pub(crate) RegistrationUpload<CS>)
@@ -126,25 +126,27 @@ where
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero;
impl_serialize_and_deserialize_for!(
ServerRegistration
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>>>:
ArrayLength<u8> | Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength<u8>,
// ServerRegistration = RegistrationUpload
);
/// The state elements the client holds to perform a login
#[cfg_attr(
feature = "serde",
derive(serde::Deserialize, serde::Serialize),
serde(
bound(
deserialize = "<CS::KeyExchange as KeyExchange<OprfHash<CS>, \
CS::KeGroup>>::KE1Message: serde::Deserialize<'de>, <CS::KeyExchange \
as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE1State: \
serde::Deserialize<'de>",
serialize = "<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE1Message: \
serde::Serialize, <CS::KeyExchange as KeyExchange<OprfHash<CS>, \
CS::KeGroup>>::KE1State: serde::Serialize"
),
crate = "serde"
)
)]
#[derive_where(Clone, ZeroizeOnDrop)]
#[derive_where(
Debug, Eq, Hash, PartialEq;
voprf::NonVerifiableClient<CS::OprfGroup>,
voprf::NonVerifiableClient<CS::OprfCs>,
<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE1State,
CredentialRequest<CS>,
)]
@@ -157,25 +159,25 @@ where
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
pub(crate) oprf_client: voprf::NonVerifiableClient<CS::OprfGroup>,
pub(crate) oprf_client: voprf::NonVerifiableClient<CS::OprfCs>,
pub(crate) ke1_state: <CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE1State,
pub(crate) credential_request: CredentialRequest<CS>,
}
impl_serialize_and_deserialize_for!(
ClientLogin
where
// CredentialRequest: KgPk + Ke1Message
<OprfGroup<CS> as Group>::ElemLen: Add<Ke1MessageLen<CS>>,
CredentialRequestLen<CS>: ArrayLength<u8>,
// ClientLogin: KgSk + CredentialRequest + Ke1State
<OprfGroup<CS> as Group>::ScalarLen: Add<CredentialRequestLen<CS>>,
Sum<<OprfGroup<CS> as Group>::ScalarLen, CredentialRequestLen<CS>>:
ArrayLength<u8> | Add<Ke1StateLen<CS>>,
ClientLoginLen<CS>: ArrayLength<u8>,
);
/// The state elements the server holds to record a login
#[cfg_attr(
feature = "serde",
derive(serde::Deserialize, serde::Serialize),
serde(
bound(
deserialize = "<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE2State: \
serde::Deserialize<'de>",
serialize = "<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE2State: \
serde::Serialize"
),
crate = "serde"
)
)]
#[derive_where(Clone, ZeroizeOnDrop)]
#[derive_where(
Debug, Eq, Hash, PartialEq;
@@ -193,8 +195,6 @@ where
ke2_state: <CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE2State,
}
impl_serialize_and_deserialize_for!(ServerLogin);
////////////////////////////////
// High-level Implementations //
// ========================== //
@@ -376,7 +376,7 @@ where
password,
self.oprf_client.clone(),
registration_response.evaluation_element,
params.slow_hash,
params.ksf,
)?;
let mut masking_key = Output::<OprfHash<CS>>::default();
@@ -450,7 +450,7 @@ where
credential_identifier: &[u8],
) -> Result<ServerRegistrationStartResult<CS>, ProtocolError> {
let oprf_key =
oprf_key_from_seed::<CS::OprfGroup>(&server_setup.oprf_seed, credential_identifier)?;
oprf_key_from_seed::<CS::OprfCs>(&server_setup.oprf_seed, credential_identifier)?;
let server = voprf::NonVerifiableServer::new_with_key(&oprf_key)?;
let evaluation_element = server.evaluate(&message.blinded_element, None)?;
@@ -510,7 +510,7 @@ where
self.oprf_client
.serialize()
.concat(self.credential_request.serialize())
.concat(self.ke1_state.to_bytes())
.concat(self.ke1_state.serialize())
}
/// Deserialization from bytes
@@ -522,7 +522,7 @@ where
check_slice_size(input, client_len + request_len + state_len, "client_login")?;
let ke1_state =
<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE1State::from_bytes(
<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE1State::deserialize(
&checked_slice[client_len + request_len..],
)?;
Ok(Self {
@@ -598,7 +598,7 @@ where
password,
self.oprf_client.clone(),
credential_response.evaluation_element.clone(),
params.slow_hash,
params.ksf,
)?;
let mut masking_key = Output::<OprfHash<CS>>::default();
@@ -638,7 +638,7 @@ where
let blinded_element =
OprfGroup::<CS>::serialize_elem(self.credential_request.blinded_element.value());
let ke1_message = self.credential_request.ke1_message.to_bytes();
let ke1_message = self.credential_request.ke1_message.serialize();
let serialized_credential_request =
CredentialRequest::<CS>::serialize_iter(&blinded_element, &ke1_message);
@@ -682,14 +682,14 @@ where
{
/// Serialization into bytes
pub fn serialize(&self) -> GenericArray<u8, Ke2StateLen<CS>> {
self.ke2_state.to_bytes()
self.ke2_state.serialize()
}
/// Deserialization from bytes
pub fn deserialize(bytes: &[u8]) -> Result<Self, ProtocolError> {
Ok(Self {
ke2_state:
<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE2State::from_bytes(
<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE2State::deserialize(
bytes,
)?,
})
@@ -744,19 +744,19 @@ where
let (id_u, id_s) = bytestrings_from_identifiers::<CS::KeGroup>(
identifiers,
client_s_pk.to_bytes(),
server_s_pk.to_bytes(),
client_s_pk.serialize(),
server_s_pk.serialize(),
)
.map_err(ProtocolError::into_custom)?;
let blinded_element =
OprfGroup::<CS>::serialize_elem(credential_request.blinded_element.value());
let ke1_message = credential_request.ke1_message.to_bytes();
let ke1_message = credential_request.ke1_message.serialize();
let credential_request_bytes =
CredentialRequest::<CS>::serialize_iter(&blinded_element, &ke1_message);
let oprf_key =
oprf_key_from_seed::<CS::OprfGroup>(&server_setup.oprf_seed, credential_identifier)
oprf_key_from_seed::<CS::OprfCs>(&server_setup.oprf_seed, credential_identifier)
.map_err(ProtocolError::into_custom)?;
let server = voprf::NonVerifiableServer::new_with_key(&oprf_key)
.map_err(|e| ProtocolError::into_custom(e.into()))?;
@@ -847,8 +847,8 @@ where
{
/// Specifying the identifiers idU and idS
pub identifiers: Identifiers<'i>,
/// Specifying a configuration for the slow hash
pub slow_hash: Option<&'h CS::SlowHash>,
/// Specifying a configuration for the key stretching function
pub ksf: Option<&'h CS::Ksf>,
}
impl<'i, 'h, CS: CipherSuite> ClientRegistrationFinishParameters<'i, 'h, CS>
@@ -861,11 +861,8 @@ where
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
/// Create a new [`ClientRegistrationFinishParameters`]
pub fn new(identifiers: Identifiers<'i>, slow_hash: Option<&'h CS::SlowHash>) -> Self {
Self {
identifiers,
slow_hash,
}
pub fn new(identifiers: Identifiers<'i>, ksf: Option<&'h CS::Ksf>) -> Self {
Self { identifiers, ksf }
}
}
@@ -968,8 +965,8 @@ where
/// Specifying a user identifier and server identifier that will be matched
/// against the server
pub identifiers: Identifiers<'i>,
/// Specifying a configuration for the slow hash
pub slow_hash: Option<&'h CS::SlowHash>,
/// Specifying a configuration for the key stretching hash
pub ksf: Option<&'h CS::Ksf>,
}
impl<'c, 'i, 'h, CS: CipherSuite> ClientLoginFinishParameters<'c, 'i, 'h, CS>
@@ -985,12 +982,12 @@ where
pub fn new(
context: Option<&'c [u8]>,
identifiers: Identifiers<'i>,
slow_hash: Option<&'h CS::SlowHash>,
ksf: Option<&'h CS::Ksf>,
) -> Self {
Self {
context,
identifiers,
slow_hash,
ksf,
}
}
}
@@ -1060,7 +1057,7 @@ pub struct ServerLoginStartParameters<'c, 'i> {
#[derive_where(Clone)]
#[derive_where(
Debug;
voprf::EvaluationElement<CS::OprfGroup>,
voprf::EvaluationElement<CS::OprfCs>,
<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE2Message,
<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE2State,
)]
@@ -1097,9 +1094,9 @@ where
#[allow(clippy::type_complexity)]
fn get_password_derived_key<CS: CipherSuite>(
input: &[u8],
oprf_client: voprf::NonVerifiableClient<CS::OprfGroup>,
evaluation_element: voprf::EvaluationElement<CS::OprfGroup>,
slow_hash: Option<&CS::SlowHash>,
oprf_client: voprf::NonVerifiableClient<CS::OprfCs>,
evaluation_element: voprf::EvaluationElement<CS::OprfCs>,
ksf: Option<&CS::Ksf>,
) -> Result<(Output<OprfHash<CS>>, Hkdf<OprfHash<CS>>), ProtocolError>
where
<OprfHash<CS> as OutputSizeUser>::OutputSize:
@@ -1111,10 +1108,10 @@ where
{
let oprf_output = oprf_client.finalize(input, &evaluation_element, None)?;
let hardened_output = if let Some(slow_hash) = slow_hash {
slow_hash.hash(oprf_output.clone())
let hardened_output = if let Some(ksf) = ksf {
ksf.hash(oprf_output.clone())
} else {
CS::SlowHash::default().hash(oprf_output.clone())
CS::Ksf::default().hash(oprf_output.clone())
}
.map_err(ProtocolError::from)?;
@@ -1152,6 +1149,11 @@ where
))
}
#[cfg_attr(
feature = "serde",
derive(serde::Deserialize, serde::Serialize),
serde(bound = "", crate = "serde")
)]
#[derive_where(Clone)]
#[derive_where(Debug, Eq, Hash, PartialEq)]
pub(crate) struct MaskedResponse<CS: CipherSuite>
@@ -1235,7 +1237,7 @@ where
for (x1, x2) in xor_pad.iter_mut().zip(
server_s_pk
.to_bytes()
.serialize()
.as_slice()
.iter()
.chain(envelope.serialize().iter()),
@@ -1287,16 +1289,16 @@ pub(crate) fn bytestrings_from_identifiers<KG: KeGroup>(
ids: Identifiers,
client_s_pk: GenericArray<u8, KG::PkLen>,
server_s_pk: GenericArray<u8, KG::PkLen>,
) -> Result<(Serialize<U2, KG::PkLen>, Serialize<U2, KG::PkLen>), ProtocolError> {
) -> Result<(Input<U2, KG::PkLen>, Input<U2, KG::PkLen>), ProtocolError> {
let client_identity = if let Some(client) = ids.client {
Serialize::<U2, _>::from(client)?
Input::<U2, _>::from(client)?
} else {
Serialize::<U2, _>::from_owned(client_s_pk)?
Input::<U2, _>::from_owned(client_s_pk)?
};
let server_identity = if let Some(server) = ids.server {
Serialize::<U2, _>::from(server)?
Input::<U2, _>::from(server)?
} else {
Serialize::<U2, _>::from_owned(server_s_pk)?
Input::<U2, _>::from_owned(server_s_pk)?
};
Ok((client_identity, server_identity))
@@ -1308,7 +1310,7 @@ pub(crate) fn bytestrings_from_identifiers<KG: KeGroup>(
fn blind<CS: CipherSuite, R: RngCore + CryptoRng>(
rng: &mut R,
password: &[u8],
) -> Result<voprf::NonVerifiableClientBlindResult<CS::OprfGroup>, voprf::Error>
) -> Result<voprf::NonVerifiableClientBlindResult<CS::OprfCs>, voprf::Error>
where
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
+23 -27
View File
@@ -45,38 +45,34 @@ pub(crate) fn os2ip(input: &[u8]) -> Result<usize, ProtocolError> {
/// Computes `I2OSP(len(input), max_bytes) || input` and helps hold output
/// without allocation.
pub(crate) struct Serialize<
'a,
L1: ArrayLength<u8>,
L2: ArrayLength<u8> = U0,
L3: ArrayLength<u8> = U0,
> {
pub(crate) struct Input<'a, L1: ArrayLength<u8>, L2: ArrayLength<u8> = U0, L3: ArrayLength<u8> = U0>
{
octet: GenericArray<u8, L1>,
input: Input<'a, L2, L3>,
input: InnerInput<'a, L2, L3>,
}
enum Input<'a, L1: ArrayLength<u8>, L2: ArrayLength<u8>> {
enum InnerInput<'a, L1: ArrayLength<u8>, L2: ArrayLength<u8>> {
Owned(GenericArray<u8, L1>),
Borrowed(&'a [u8]),
Label(([&'a [u8]; 2], PhantomData<L2>)),
}
impl<'a, L1: ArrayLength<u8>, L2: ArrayLength<u8>, L3: ArrayLength<u8>> Serialize<'a, L1, L2, L3> {
impl<'a, L1: ArrayLength<u8>, L2: ArrayLength<u8>, L3: ArrayLength<u8>> Input<'a, L1, L2, L3> {
// Variation of `serialize` that takes a borrowed `input
pub(crate) fn from(input: &'a [u8]) -> Result<Serialize<'a, L1, L2>, ProtocolError> {
Ok(Serialize {
pub(crate) fn from(input: &'a [u8]) -> Result<Input<'a, L1, L2>, ProtocolError> {
Ok(Input {
octet: i2osp::<L1>(input.len())?,
input: Input::Borrowed(input),
input: InnerInput::Borrowed(input),
})
}
// Variation of `serialize` that takes an owned `input`
pub(crate) fn from_owned(
input: GenericArray<u8, L2>,
) -> Result<Serialize<'a, L1, L2>, ProtocolError> {
Ok(Serialize {
) -> Result<Input<'a, L1, L2>, ProtocolError> {
Ok(Input {
octet: i2osp::<L1>(input.len())?,
input: Input::Owned(input),
input: InnerInput::Owned(input),
})
}
@@ -84,10 +80,10 @@ impl<'a, L1: ArrayLength<u8>, L2: ArrayLength<u8>, L3: ArrayLength<u8>> Serializ
pub(crate) fn from_label(
opaque: &'a [u8],
label: &'a [u8],
) -> Result<Serialize<'a, L1, U0, U2>, ProtocolError> {
Ok(Serialize {
) -> Result<Input<'a, L1, U0, U2>, ProtocolError> {
Ok(Input {
octet: i2osp::<L1>(opaque.len() + label.len())?,
input: Input::Label(([opaque, label], PhantomData)),
input: InnerInput::Label(([opaque, label], PhantomData)),
})
}
@@ -96,11 +92,11 @@ impl<'a, L1: ArrayLength<u8>, L2: ArrayLength<u8>, L3: ArrayLength<u8>> Serializ
[self.octet.as_slice()]
.into_iter()
.chain(match &self.input {
Input::Owned(bytes) => [bytes.as_slice()],
Input::Borrowed(bytes) => [*bytes],
Input::Label((iter, _)) => [iter[0]],
InnerInput::Owned(bytes) => [bytes.as_slice()],
InnerInput::Borrowed(bytes) => [*bytes],
InnerInput::Label((iter, _)) => [iter[0]],
})
.chain(if let Input::Label((iter, _)) = &self.input {
.chain(if let InnerInput::Label((iter, _)) = &self.input {
Some(iter[1])
} else {
None
@@ -108,11 +104,11 @@ impl<'a, L1: ArrayLength<u8>, L2: ArrayLength<u8>, L3: ArrayLength<u8>> Serializ
}
}
impl<'a, L1: ArrayLength<u8>, L2: ArrayLength<u8>> Serialize<'a, L1, L2, U0> {
impl<'a, L1: ArrayLength<u8>, L2: ArrayLength<u8>> Input<'a, L1, L2, U0> {
pub(crate) fn to_array_2(&self) -> [&[u8]; 2] {
let input = match &self.input {
Input::Borrowed(value) => value,
Input::Owned(value) => value.as_slice(),
InnerInput::Borrowed(value) => value,
InnerInput::Owned(value) => value.as_slice(),
_ => unreachable!("unexpected `Serialize` constructed with wrong generics"),
};
@@ -120,10 +116,10 @@ impl<'a, L1: ArrayLength<u8>, L2: ArrayLength<u8>> Serialize<'a, L1, L2, U0> {
}
}
impl<'a, L1: ArrayLength<u8>, L2: ArrayLength<u8>> Serialize<'a, L1, L2, U2> {
impl<'a, L1: ArrayLength<u8>, L2: ArrayLength<u8>> Input<'a, L1, L2, U2> {
pub(crate) fn to_array_3(&self) -> [&[u8]; 3] {
match self.input {
Input::Label((label, _)) => [self.octet.as_slice(), label[0], label[1]],
InnerInput::Label((label, _)) => [self.octet.as_slice(), label[0], label[1]],
_ => unreachable!("unexpected `Serialize` constructed with wrong generics"),
}
}
+30 -30
View File
@@ -25,9 +25,9 @@ use crate::errors::*;
use crate::hash::{Hash, OutputSize, ProxyHash};
use crate::key_exchange::group::KeGroup;
use crate::key_exchange::traits::{
FromBytes, Ke1MessageLen, Ke1StateLen, Ke2MessageLen, KeyExchange, ToBytes,
Deserialize, Ke1MessageLen, Ke1StateLen, Ke2MessageLen, KeyExchange, Serialize,
};
use crate::key_exchange::tripledh::{NonceLen, TripleDH};
use crate::key_exchange::tripledh::{NonceLen, TripleDh};
use crate::keypair::{KeyPair, SecretKey};
use crate::messages::CredentialResponseWithoutKeLen;
use crate::opaque::{ClientLoginLen, ClientRegistrationLen, MaskedResponseLen};
@@ -39,19 +39,19 @@ struct Ristretto255;
#[cfg(feature = "ristretto255")]
impl CipherSuite for Ristretto255 {
type OprfGroup = crate::Ristretto255;
type OprfCs = crate::Ristretto255;
type KeGroup = crate::Ristretto255;
type KeyExchange = TripleDH;
type SlowHash = crate::slow_hash::NoOpHash;
type KeyExchange = TripleDh;
type Ksf = crate::ksf::Identity;
}
struct P256;
impl CipherSuite for P256 {
type OprfGroup = ::p256::NistP256;
type OprfCs = ::p256::NistP256;
type KeGroup = ::p256::NistP256;
type KeyExchange = TripleDH;
type SlowHash = crate::slow_hash::NoOpHash;
type KeyExchange = TripleDh;
type Ksf = crate::ksf::Identity;
}
fn random_point<CS: CipherSuite>() -> <CS::KeGroup as KeGroup>::Pk
@@ -65,7 +65,7 @@ where
{
let mut rng = OsRng;
let sk = CS::KeGroup::random_sk(&mut rng);
CS::KeGroup::public_key(&sk)
CS::KeGroup::public_key(sk)
}
#[test]
@@ -85,7 +85,7 @@ fn client_registration_roundtrip() -> Result<(), ProtocolError> {
let pw = b"hunter2";
let mut rng = OsRng;
let blind_result = &voprf::NonVerifiableClient::<CS::OprfGroup>::blind(pw, &mut rng)?;
let blind_result = &voprf::NonVerifiableClient::<CS::OprfCs>::blind(pw, &mut rng)?;
let bytes: Vec<u8> = blind_result
.state
@@ -145,7 +145,7 @@ fn server_registration_roundtrip() -> Result<(), ProtocolError> {
let mock_client_kp = KeyPair::<CS::KeGroup>::generate_random(&mut rng);
// serialization order: oprf_key, public key, envelope
let mut bytes = Vec::<u8>::new();
bytes.extend_from_slice(&mock_client_kp.public().to_bytes());
bytes.extend_from_slice(&mock_client_kp.public().serialize());
bytes.extend_from_slice(&masking_key);
bytes.extend_from_slice(&mock_envelope_bytes);
let reg = ServerRegistration::<CS>::deserialize(&bytes)?;
@@ -173,7 +173,7 @@ fn registration_request_roundtrip() -> Result<(), ProtocolError> {
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
let pt = random_point::<CS>();
let pt_bytes = CS::KeGroup::serialize_pk(&pt);
let pt_bytes = CS::KeGroup::serialize_pk(pt);
let mut input = Vec::new();
input.extend_from_slice(&pt_bytes);
@@ -218,10 +218,10 @@ fn registration_response_roundtrip() -> Result<(), ProtocolError> {
RegistrationResponseLen<CS>: ArrayLength<u8>,
{
let pt = random_point::<CS>();
let beta_bytes = CS::KeGroup::serialize_pk(&pt);
let beta_bytes = CS::KeGroup::serialize_pk(pt);
let mut rng = OsRng;
let skp = KeyPair::<CS::KeGroup>::generate_random(&mut rng);
let pubkey_bytes = skp.public().to_bytes();
let pubkey_bytes = skp.public().serialize();
let mut input = Vec::new();
input.extend_from_slice(&beta_bytes);
@@ -275,7 +275,7 @@ fn registration_upload_roundtrip() -> Result<(), ProtocolError> {
{
let mut rng = OsRng;
let skp = KeyPair::<CS::KeGroup>::generate_random(&mut rng);
let pubkey_bytes = skp.public().to_bytes();
let pubkey_bytes = skp.public().serialize();
let mut key = [0u8; 32];
rng.fill_bytes(&mut key);
@@ -331,7 +331,7 @@ fn credential_request_roundtrip() -> Result<(), ProtocolError> {
{
let mut rng = OsRng;
let alpha = random_point::<CS>();
let alpha_bytes = CS::KeGroup::serialize_pk(&alpha);
let alpha_bytes = CS::KeGroup::serialize_pk(alpha);
let client_e_kp = KeyPair::<CS::KeGroup>::generate_random(&mut rng);
let mut client_nonce = [0u8; NonceLen::USIZE];
@@ -339,7 +339,7 @@ fn credential_request_roundtrip() -> Result<(), ProtocolError> {
let ke1m: Vec<u8> = [
client_nonce.as_ref(),
client_e_kp.public().to_bytes().as_ref(),
client_e_kp.public().serialize().as_ref(),
]
.concat();
@@ -397,7 +397,7 @@ fn credential_response_roundtrip() -> Result<(), ProtocolError> {
CredentialResponseLen<CS>: ArrayLength<u8>,
{
let pt = random_point::<CS>();
let pt_bytes = CS::KeGroup::serialize_pk(&pt);
let pt_bytes = CS::KeGroup::serialize_pk(pt);
let mut rng = OsRng;
@@ -416,7 +416,7 @@ fn credential_response_roundtrip() -> Result<(), ProtocolError> {
let ke2m: Vec<u8> = [
server_nonce.as_ref(),
server_e_kp.public().to_bytes().as_ref(),
server_e_kp.public().serialize().as_ref(),
&mac,
]
.concat();
@@ -523,15 +523,15 @@ fn client_login_roundtrip() -> Result<(), ProtocolError> {
]
.concat();
let blind_result = voprf::NonVerifiableClient::<CS::OprfGroup>::blind(pw, &mut rng)?;
let blind_result = voprf::NonVerifiableClient::<CS::OprfCs>::blind(pw, &mut rng)?;
let credential_request = CredentialRequest::<CS> {
blinded_element: blind_result.message,
ke1_message:
<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE1Message::from_bytes(
<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE1Message::deserialize(
&[
client_nonce.as_ref(),
client_e_kp.public().to_bytes().as_ref(),
client_e_kp.public().serialize().as_ref(),
]
.concat(),
)?,
@@ -577,14 +577,14 @@ fn ke1_message_roundtrip() -> Result<(), ProtocolError> {
let ke1m = [
client_nonce.as_slice(),
client_e_kp.public().to_bytes().as_ref(),
client_e_kp.public().serialize().as_ref(),
]
.concat();
let reg =
<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE1Message::from_bytes(
<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE1Message::deserialize(
&ke1m,
)?;
let reg_bytes = reg.to_bytes();
let reg_bytes = reg.serialize();
assert_eq!(*reg_bytes, ke1m);
Ok(())
@@ -618,16 +618,16 @@ fn ke2_message_roundtrip() -> Result<(), ProtocolError> {
let ke2m: Vec<u8> = [
server_nonce.as_slice(),
server_e_kp.public().to_bytes().as_ref(),
server_e_kp.public().serialize().as_ref(),
&mac,
]
.concat();
let reg =
<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE2Message::from_bytes(
<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE2Message::deserialize(
&ke2m,
)?;
let reg_bytes = reg.to_bytes();
let reg_bytes = reg.serialize();
assert_eq!(*reg_bytes, ke2m);
Ok(())
@@ -658,10 +658,10 @@ fn ke3_message_roundtrip() -> Result<(), ProtocolError> {
let ke3m: Vec<u8> = [mac].concat();
let reg =
<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE3Message::from_bytes(
<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE3Message::deserialize(
&ke3m,
)?;
let reg_bytes = reg.to_bytes();
let reg_bytes = reg.serialize();
assert_eq!(*reg_bytes, ke3m);
Ok(())
+76 -78
View File
@@ -27,14 +27,14 @@ use crate::errors::*;
use crate::hash::{Hash, OutputSize, ProxyHash};
use crate::key_exchange::group::KeGroup;
use crate::key_exchange::traits::{Ke1MessageLen, Ke1StateLen, Ke2MessageLen};
use crate::key_exchange::tripledh::{NonceLen, TripleDH};
use crate::key_exchange::tripledh::{NonceLen, TripleDh};
use crate::keypair::SecretKey;
use crate::ksf::Identity;
use crate::messages::{
CredentialRequestLen, CredentialResponseLen, CredentialResponseWithoutKeLen,
RegistrationResponseLen, RegistrationUploadLen,
};
use crate::opaque::*;
use crate::slow_hash::NoOpHash;
use crate::tests::mock_rng::CycleRng;
use crate::*;
@@ -46,19 +46,19 @@ struct Ristretto255;
#[cfg(feature = "ristretto255")]
impl CipherSuite for Ristretto255 {
type OprfGroup = crate::Ristretto255;
type OprfCs = crate::Ristretto255;
type KeGroup = crate::Ristretto255;
type KeyExchange = TripleDH;
type SlowHash = NoOpHash;
type KeyExchange = TripleDh;
type Ksf = Identity;
}
struct P256;
impl CipherSuite for P256 {
type OprfGroup = p256::NistP256;
type OprfCs = p256::NistP256;
type KeGroup = p256::NistP256;
type KeyExchange = TripleDH;
type SlowHash = NoOpHash;
type KeyExchange = TripleDh;
type Ksf = Identity;
}
#[cfg(all(feature = "x25519", feature = "ristretto255"))]
@@ -66,10 +66,10 @@ struct X25519Ristretto255;
#[cfg(all(feature = "x25519", feature = "ristretto255"))]
impl CipherSuite for X25519Ristretto255 {
type OprfGroup = crate::Ristretto255;
type OprfCs = crate::Ristretto255;
type KeGroup = crate::X25519;
type KeyExchange = TripleDH;
type SlowHash = NoOpHash;
type KeyExchange = TripleDh;
type Ksf = Identity;
}
#[cfg(feature = "x25519")]
@@ -77,10 +77,10 @@ struct X25519P256;
#[cfg(feature = "x25519")]
impl CipherSuite for X25519P256 {
type OprfGroup = p256::NistP256;
type OprfCs = p256::NistP256;
type KeGroup = crate::X25519;
type KeyExchange = TripleDH;
type SlowHash = NoOpHash;
type KeyExchange = TripleDh;
type Ksf = Identity;
}
pub struct TestVectorParameters {
@@ -200,76 +200,76 @@ static TEST_VECTOR_P256: &str = r#"
#[cfg(all(feature = "x25519", feature = "ristretto255"))]
static TEST_VECTOR_X25519_RISTRETTO255: &str = r#"
{
"client_s_pk": "4df1ab49521829e233f34b412d48598d046afa20156f117898b7809b070ab526",
"client_s_sk": "9055cba6082b86d8856b8ac3720c16a7ca07ff3303874149a0b5656e391bb05a",
"client_e_pk": "9bbea5c768383168e385d895007f3eba4ecfbcadef26305449a76b2440465e3d",
"client_e_sk": "388fac72f9c2e9aeeb189963015f7af1692a4a31fefaf06b4ecb66d066d9fe43",
"server_s_pk": "f2f02607a409b5de08ee6e1e51ae674462397997682ea7c48c2d3c762378075b",
"server_s_sk": "c06fed7591d65aa5f6a23cda5d53bde59707bc2d62c2ba61382380b77cae497a",
"server_e_pk": "ee5251c72b241bfa4d926fed7d5082ee31a406e622731550912ac0fce105515f",
"server_e_sk": "b018aa7067155ce9bb6d2fdbc163e706888d8e0cdff1e47f45073556abc8da5a",
"fake_sk": "b8c3c7caec7ef8985a8c84dc183d98e2dbc9c30bd13b86e9c37c810fa0e1cc5e",
"client_s_pk": "f0f51a83591f6749ddfd56c78d9aaa672908713c5fcc8670b3e7341c84218c78",
"client_s_sk": "b4a46dc06b981100c15529e4675babe4ed05444de2fd4fc7dba6d3aaf9fca40a",
"client_e_pk": "cba41b4605abd945351ebbd18aa99d24b1053e70c8c010df7c454fe874b37f74",
"client_e_sk": "7afd7b93bdfff65d1162d44d550afc0b3fb7bf3a3d09ccd170d5d63c97d70c02",
"server_s_pk": "f261e911ebecac75b1a192acaf393a3541ca13572ad81d3d2729ba48718d0c77",
"server_s_sk": "3d8c12aa8f615c4133688da832f177853b7051d2ab87e8ba0c48bfeeb87f7003",
"server_e_pk": "f1ef201d97dfdc7d21a0386d20d62d2a10212586e749b06928a8d48550b04d44",
"server_e_sk": "652d258cc211026e6b1ca51a5b2b5946459bd0926d896c4c46712176d5db7507",
"fake_sk": "c93b7c3f24d51230df51bd96623fb4a142b1eccb75e0d9a9939eb0acf2e37d0b",
"credential_identifier": "637265644964656e746966696572",
"id_u": "696455",
"id_s": "696453",
"password": "70617373776f7264",
"blinding_factor": "d36ed47358b72a28796b5b0fc4f9301a294659da94d394f227e6e9b8ea277c0b",
"oprf_seed": "b430182519702493f1991bbf7506c335b5e6e3899e5f1266a7f4c99dd16bf2efab3355a7e75423c2d0e54ee7cc1c16d3fc8975e47946f4bea95a77a06bfeea7c",
"masking_nonce": "ce8202d2438b73cfe23d5f7bccc172ee6a354d690c1770ef07f4f269978bb0dbd6df845d9d9cb969ec8bf41dadef3835ba1d1dd4360b15ba5ad6cb77b9a53879",
"envelope_nonce": "04c9e2914f5874089839e78eb29d342d3c472c0bdb62e1abedf74bbf505fec79",
"client_nonce": "c01061951b0f6acc314a0cfa2f45b8f2e2125e0f1896fa63c1d97d8f74245c16",
"server_nonce": "50fe3f0de7db78443da1eadb15d36d6645ea3f94ffcc57b862befda2a9bd10a5",
"blinding_factor": "18492200ec40f425a8593c6b3f57d966785abef2e7ec77cc16dbc0112c10eb00",
"oprf_seed": "55d8b3b5c222b1b7bac76574bf13450459cbb7e8b270a58c3b584f39f0bc694df55774ff7d083c69a92f0345622bd49fefa6fe6d99456ea5f9f60c28d07ef870",
"masking_nonce": "c1b2ae7f568e055153527c75972a111525cbb50328eb90f0ed2f2a4cb770c3939b2bf94f689009928ee26af2376269515aaed6aff72c79d07a5f84aec159cb17",
"envelope_nonce": "45e9ab506171882d56a0a3017ccbe24049cd22c2ebb3519a4d1110a4f853e63d",
"client_nonce": "30f07d7239e894136324f33bbfd00f63bcd33bb255bdb072f57591d44c7a1f32",
"server_nonce": "58231100ea33e00550de7ba3b1865dceaaba3835c2ca1ef22365af068590636b",
"context": "636f6e74657874",
"registration_request": "b889d6957f21a33951637b12f12007efc50d7b87811c96b8cc0072a605f1d24c",
"registration_response": "200bcd11d44e9a10541a465ed3b130d4d10632dd7433965578e33d181e321113f2f02607a409b5de08ee6e1e51ae674462397997682ea7c48c2d3c762378075b",
"registration_upload": "79d14f4164e722a8dcabffd4a341104e217d1597eeb414d4e4597d7c4376bf3b23ed2104a05b3ff4a12160f73172bbb195a3a399489bc4092e471e181a524b6c7fb6f955cacb8f8d0db54b89287b496e48b34b1a6204960925469d712c793bd89055cba6082b86d8856b8ac3720c16a7ca07ff3303874149a0b5656e391bb05a9490086c367c3705a0a46a497c797de7e67c0c7d1803e17e1cfd78d949c7b8558fa46da9fb3445bdef5e285a561e04518919387726a1b73660e687bda8a14256",
"credential_request": "b889d6957f21a33951637b12f12007efc50d7b87811c96b8cc0072a605f1d24cc01061951b0f6acc314a0cfa2f45b8f2e2125e0f1896fa63c1d97d8f74245c169bbea5c768383168e385d895007f3eba4ecfbcadef26305449a76b2440465e3d",
"credential_response": "200bcd11d44e9a10541a465ed3b130d4d10632dd7433965578e33d181e321113ce8202d2438b73cfe23d5f7bccc172ee6a354d690c1770ef07f4f269978bb0dbcc6f726f243b5a331e2a5b420866413d0e8b82f391bc4183361508a9f6c1b700e5f182630556f732e466976c2797cc5b05163ee4bb6ce39b1db500f03fe365009e359199926fad26726e438722c45f11beccc0e32e45fc24732f85d1aa9543e1d7c30248a20aad34efe89f8af3e8578071aa362564b5faba808fba9a66a78a26b018aa7067155ce9bb6d2fdbc163e706888d8e0cdff1e47f45073556abc8da5a3b9470912a8c10a2bede335ddbc1198d706acca69ae6ff0a72e195d2575f5b27b32d6099439ef55837e6e817def5ee8230ffb6fcd66d0f23f7169ab49eecfa8d134f2d6db9de03c51034b3a129f84c261234429cc34dfb7afdf3e392b7962b78",
"credential_finalization": "f4133b65451a2b8f7a9cbfaca3f7c06211912fc669ffbe7cd554905b9f4e82a0e841cc97c70c8b964e02d6f665a136db0ad83b249d4f36be4c4944c4596ac696",
"client_registration_state": "d36ed47358b72a28796b5b0fc4f9301a294659da94d394f227e6e9b8ea277c0bb889d6957f21a33951637b12f12007efc50d7b87811c96b8cc0072a605f1d24c",
"client_login_state": "d36ed47358b72a28796b5b0fc4f9301a294659da94d394f227e6e9b8ea277c0bb889d6957f21a33951637b12f12007efc50d7b87811c96b8cc0072a605f1d24cc01061951b0f6acc314a0cfa2f45b8f2e2125e0f1896fa63c1d97d8f74245c169bbea5c768383168e385d895007f3eba4ecfbcadef26305449a76b2440465e3d388fac72f9c2e9aeeb189963015f7af1692a4a31fefaf06b4ecb66d066d9fe43c01061951b0f6acc314a0cfa2f45b8f2e2125e0f1896fa63c1d97d8f74245c16",
"server_login_state": "b87047afce3cb9166d7f96a992d423f3eebb931413775c5373dc18abd6a42f919de37ca5643454b07d84440d77d364c7dd4c9029fb481aa7e34d91f061c38c2b5ba9c3260c4eb1bdfd6ef65e1415b8e227631985d979f0c5860d3076bd8f22a0e009dd6efb4359c414257678101fe91560f15b16461ca79618c09d26f346b0e9776d5589e16dc1d9466d5aa901db05d5cbeb73c2672da3b954046b170f514ce50282b8bccc1d542e902af8486fd37f886f555e56b2f34cc91d658996651eb8b8",
"password_file": "79d14f4164e722a8dcabffd4a341104e217d1597eeb414d4e4597d7c4376bf3b23ed2104a05b3ff4a12160f73172bbb195a3a399489bc4092e471e181a524b6c7fb6f955cacb8f8d0db54b89287b496e48b34b1a6204960925469d712c793bd89055cba6082b86d8856b8ac3720c16a7ca07ff3303874149a0b5656e391bb05a9490086c367c3705a0a46a497c797de7e67c0c7d1803e17e1cfd78d949c7b8558fa46da9fb3445bdef5e285a561e04518919387726a1b73660e687bda8a14256",
"export_key": "9b728dbe104caf7ea3d52a167c74408770b89f883c4ee280ee053fd9ad5aabc62bbe78cbc6bc9230819819ea75d40b8411f914095d4101c1e0d92c71b4e5b29f",
"session_key": "776d5589e16dc1d9466d5aa901db05d5cbeb73c2672da3b954046b170f514ce50282b8bccc1d542e902af8486fd37f886f555e56b2f34cc91d658996651eb8b8"
"registration_request": "68eefa968ee3ad0c69319a8f52f056df368826669cce82ad64462bc24da0787f",
"registration_response": "863ca6ef30989bec1e7411a940d589fa3e8fa3d76c8281ebb2714a6b9b3d4072f261e911ebecac75b1a192acaf393a3541ca13572ad81d3d2729ba48718d0c77",
"registration_upload": "1f658d31ac18d2d1ec1507bfd2b33c9dc5a5ec3840a87c35445be002156da95162c91ab0e7daae9e6e569e2c4ac115f770920043425e2fc941804049da6837c9537a455f91f45fd8c972a0087ec03ba8482773a0ba7dc0cb0690e94c3dabb5f7b4a46dc06b981100c15529e4675babe4ed05444de2fd4fc7dba6d3aaf9fca40a3d5d7de871613d47281ca2c105eba79f925d46b52dfd3448f9ec6acbb71e7280f8cab44110cd1ca7e0a58b25245840e6f9c8856e43c6a23aa073d23c9fcae22f",
"credential_request": "68eefa968ee3ad0c69319a8f52f056df368826669cce82ad64462bc24da0787f18492200ec40f425a8593c6b3f57d966785abef2e7ec77cc16dbc0112c10eb00a84b03fbedd2fcb1ba2b36a851028d6c3c8ad1c1a46e770efe50564ed619b216",
"credential_response": "863ca6ef30989bec1e7411a940d589fa3e8fa3d76c8281ebb2714a6b9b3d4072c1b2ae7f568e055153527c75972a111525cbb50328eb90f0ed2f2a4cb770c3931ccd09a010a76585634ae8baf2e45e1ca487e2dd695c3daac811c750da634d99307533885e23206c2ca5ad643833dad6a37312f453c84d79001b46331f14d73607da4693d6b613c9b8bb51cad8d771cbad5fcbd54742ad81df4249d2367e708027e5a52043afb985128b4050653a7028babc04234f50941ca75dbbfe9ba2556b58231100ea33e00550de7ba3b1865dceaaba3835c2ca1ef22365af068590636bed31200d916f6fa10eb164338687773d1cea70b3676973fad7c9829c3384a54bb810bd56074fa055b2f5888c9a82f4fb0771acca2e6d6934cdb5d68c480529cb110bd0c0c446680a6b0ddf3760ee9a7953931c999386f42f6df55b9c9bcd8060",
"credential_finalization": "5ba9411a863d372c2cca0e8ba1301aaa20e0ee1a68632773ca8546077409c20e10b2381aad9eae1064e1e4f40a56149da7c4e1c951245988315063b883ec659b",
"client_registration_state": "18492200ec40f425a8593c6b3f57d966785abef2e7ec77cc16dbc0112c10eb0068eefa968ee3ad0c69319a8f52f056df368826669cce82ad64462bc24da0787f",
"client_login_state": "18492200ec40f425a8593c6b3f57d966785abef2e7ec77cc16dbc0112c10eb0068eefa968ee3ad0c69319a8f52f056df368826669cce82ad64462bc24da0787f18492200ec40f425a8593c6b3f57d966785abef2e7ec77cc16dbc0112c10eb00a84b03fbedd2fcb1ba2b36a851028d6c3c8ad1c1a46e770efe50564ed619b2164a217cb91a5ecc09d5a2441dfa664c800fcb4fb5eb939ee374ddea2d1bbff10f18492200ec40f425a8593c6b3f57d966785abef2e7ec77cc16dbc0112c10eb00",
"server_login_state": "5a0ee75063406f272b70ca918fc7a3be5446007a697b77c1a1759ec0fe06879bbcb744aa60a641bead6d41877c9f4726f265a8341091f0accf54452759008e70ccf25aa19221560a3d3c4f929d6d30f2c037c9134996e1352e695152172d147c72753c5884f981f66d991c9361082950eb8d71e2ca05b1218abf9623a63a91874f1112b861943faacbedd26dcbd6b589a7db3bcc1a8f2ad9fea08e929d65f08220ec74edb26b1e8d79844cb6b452b3f163608d700061ff5d42bc7fc04eb0b954",
"password_file": "1f658d31ac18d2d1ec1507bfd2b33c9dc5a5ec3840a87c35445be002156da95162c91ab0e7daae9e6e569e2c4ac115f770920043425e2fc941804049da6837c9537a455f91f45fd8c972a0087ec03ba8482773a0ba7dc0cb0690e94c3dabb5f7b4a46dc06b981100c15529e4675babe4ed05444de2fd4fc7dba6d3aaf9fca40a3d5d7de871613d47281ca2c105eba79f925d46b52dfd3448f9ec6acbb71e7280f8cab44110cd1ca7e0a58b25245840e6f9c8856e43c6a23aa073d23c9fcae22f",
"export_key": "4b66b395cc1f92fbf6ba7b6f2b4005d8a922cf712eda153d6c71e475dbbef5dd82558f229c64d214329df488a28926cd9d2908c96c932c1d2857888bbcf5cc62",
"session_key": "4f1112b861943faacbedd26dcbd6b589a7db3bcc1a8f2ad9fea08e929d65f08220ec74edb26b1e8d79844cb6b452b3f163608d700061ff5d42bc7fc04eb0b954"
}
"#;
#[cfg(feature = "x25519")]
static TEST_VECTOR_X25519_P256: &str = r#"
{
"client_s_pk": "54ad295308e561e9549d2662a79a18228784bca512b50a6fd161595dbfa18f54",
"client_s_sk": "20f9d6b90a9463e8432780c647b2dd7f4becf8d174c92a8023f395d01f16515b",
"client_e_pk": "07cb52b7d96fcdcdec4ec1da39dab5210c6abca838af870886a391caf1cc9d7a",
"client_e_sk": "20bdb5e9d5d98fcd9ba5634e03eba34fc728753369ce0234c9826aa88047c259",
"server_s_pk": "4923a63bd059263cb2a69fd3a528191986d9c1f470bfe240d470af628adec277",
"server_s_sk": "88b9fbacb0d38394f61c35408fe05c6734a1a63c5e6a16684095d9cc2f82cb4d",
"server_e_pk": "e8a420fd6ff116cf865035321f91e211609b4a0f013ffd0798ea68bd04267c7a",
"server_e_sk": "20eed40939abf897bdba6d7649893a617762fb3b94e04c247a086dc48448f361",
"fake_sk": "4847b46ae57fa21f9bdf38bb4ee08ed12f64141b21707743ce3bf203cf36416b",
"client_s_pk": "17e8c950fde734deb4468ecb619023a005cba3a85cbbd4a8f43f37101add7279",
"client_s_sk": "393df095fff0eb7249abe3d15416b8c362598be68e28f89456f783d37f54fe02",
"client_e_pk": "99e2464eb85ce67f2e0711036f7ca99022cb73d787c0dc3861d1990dda716649",
"client_e_sk": "f91411fceac1ffc2f86508018c4a3769381b5f778d4c281fe702a24465ff5e0b",
"server_s_pk": "e375d12756de75aaea657cf51cc2db0ebbb4cc63c1bde12def0e37b1f13fa363",
"server_s_sk": "8471298bfe02864e59eecf68a5f1269617e94fe9127f34c1fd69f45b4577cc01",
"server_e_pk": "9bfae7621089efc01944b79a6d112ead2cf4129f1ae34edfe7fe14885f25131b",
"server_e_sk": "ce684f66a099edc3b83ebbe67f8d745e6332f2c5953fa7b2d359a02fcd5e030e",
"fake_sk": "9d3aa4990006276d206c94e0882e28579e65f027f355f9aa6eccbf037e036a00",
"credential_identifier": "637265644964656e746966696572",
"id_u": "696455",
"id_s": "696453",
"password": "70617373776f7264",
"blinding_factor": "1ca386b0d0a0c390c68d8eab341787260fa3ee2a94059d7887ec687eba80ceee",
"oprf_seed": "b78f0138ef05a3df5aef410e7dda3b4972600e4d9f1e3ffa9376778cf31337ad",
"masking_nonce": "669d7a5f0b410805b4a48d81d86e821d925341c5a634581d43225b1f0820d3c13a3633d70a1eb6982b12dbca41db7718f12db87a0896034bc4c3c7c54ac4d647",
"envelope_nonce": "b57ed3206fb154fcfccb1e5effd873e9bce098af031674524c24572116061cc1",
"client_nonce": "f7e2cf7311f3bd310e331dc24a94f319c0dc5f1ae2d3a039b5da60bac9ef6099",
"server_nonce": "daad4ea374a85431b05253e53c5c69f67e0fc8067eaa1d492f8ff045659fe377",
"blinding_factor": "5110d33a36d039bb8ca1329b39993a2366024dec83671bf195a2997f054b5505",
"oprf_seed": "fc9afbdfca56e6b467001ac8263340e1cac82f7f2ccea776d22ba179df0f8538",
"masking_nonce": "cbb2380130d6f4a80f8d1e3f9bde4e431c6e3105aac77a0076dfe6e8e887287074c00fe8180a70d09ccac389331b4b4a0a2702f3239a452ba85b5a1b98c05ac2",
"envelope_nonce": "33d328f8f869e6898c7c1036b29dc94fa14647742e4a10678c2f84836d040a44",
"client_nonce": "18ee6d17f22eb48701ce46967e0b55864ae88b124a43403dfb1d71e4681f5b30",
"server_nonce": "7e868983e4a2f9cc909287d255e3cc94b467c4701d938de643a795fec393e12c",
"context": "636f6e74657874",
"registration_request": "023741a9f45d763159b728738cde140058e6bc3ead289e74b9df6cf2317dc50a36",
"registration_response": "023e084f135edff464f60468dcc18c779ea7cea99daec254499ed082ed086bfe7d4923a63bd059263cb2a69fd3a528191986d9c1f470bfe240d470af628adec277",
"registration_upload": "fee1e2438d269807b7e8b07c5b078f553bab065deb2943ac95119ec04857dc2a8a2e3934463798e276d13a0b3456eb2a98c87968d90c4ae0a51d311fe1655d5f20f9d6b90a9463e8432780c647b2dd7f4becf8d174c92a8023f395d01f16515bc4ddd82e83589cbe9c3b6fdea12acedef29aa7784a2ce0b65685dc352b66c142",
"credential_request": "023741a9f45d763159b728738cde140058e6bc3ead289e74b9df6cf2317dc50a36f7e2cf7311f3bd310e331dc24a94f319c0dc5f1ae2d3a039b5da60bac9ef609907cb52b7d96fcdcdec4ec1da39dab5210c6abca838af870886a391caf1cc9d7a",
"credential_response": "023e084f135edff464f60468dcc18c779ea7cea99daec254499ed082ed086bfe7d669d7a5f0b410805b4a48d81d86e821d925341c5a634581d43225b1f0820d3c15a700199e8446adf51b7f027b5c59ef0847b6e43ab72a6d6de4cf0eb3fe3a2093bdf8d3a50013795f094d651dcd7e9f597904e4940a3629166c2f3f4905e88c3e1f6db8f5244feebd435e5664bd395e9ba78aa93bd7e93863aa052765d4911b420eed40939abf897bdba6d7649893a617762fb3b94e04c247a086dc48448f3618e2b6d1e406e0695a0a7f32f296e45990186c54ab76a3562e7d70faf66ff99759118020c29faab346283f6e0221f7de81def8dc79c6904b5075b098a35c6a50e",
"credential_finalization": "4a6e76c08153d2c07ab695030c6fd3a6f531338e3dc85f75b0af56ee54874e2e",
"client_registration_state": "1ca386b0d0a0c390c68d8eab341787260fa3ee2a94059d7887ec687eba80ceee023741a9f45d763159b728738cde140058e6bc3ead289e74b9df6cf2317dc50a36",
"client_login_state": "1ca386b0d0a0c390c68d8eab341787260fa3ee2a94059d7887ec687eba80ceee023741a9f45d763159b728738cde140058e6bc3ead289e74b9df6cf2317dc50a36f7e2cf7311f3bd310e331dc24a94f319c0dc5f1ae2d3a039b5da60bac9ef609907cb52b7d96fcdcdec4ec1da39dab5210c6abca838af870886a391caf1cc9d7a20bdb5e9d5d98fcd9ba5634e03eba34fc728753369ce0234c9826aa88047c259f7e2cf7311f3bd310e331dc24a94f319c0dc5f1ae2d3a039b5da60bac9ef6099",
"server_login_state": "a4177b3ddccd8634ea0ad95dc9d7287f701fc5354ff53c84cb6205bff831fdeb49b5196d9330ab791ca1eb475a8eb04937430ef87776a7d1c7c4102231e7a1a89c599288d589338b0c99688a2db39f693d5d6f57cee46dc77f3d66af027fed3e",
"password_file": "fee1e2438d269807b7e8b07c5b078f553bab065deb2943ac95119ec04857dc2a8a2e3934463798e276d13a0b3456eb2a98c87968d90c4ae0a51d311fe1655d5f20f9d6b90a9463e8432780c647b2dd7f4becf8d174c92a8023f395d01f16515bc4ddd82e83589cbe9c3b6fdea12acedef29aa7784a2ce0b65685dc352b66c142",
"export_key": "fae7cd4aa438eeaa5f83b0a181ce29d18c9de4eecfd778a42511014c8b536f89",
"session_key": "9c599288d589338b0c99688a2db39f693d5d6f57cee46dc77f3d66af027fed3e"
"registration_request": "028d69a2c03f2edf8f389563c1cc78a3b95a67a20c894bce4359412b210ea52d0f",
"registration_response": "03fc2889add67eeaec390775befef78d8cee5d93bc9ac1186260f809dfe0b639e9e375d12756de75aaea657cf51cc2db0ebbb4cc63c1bde12def0e37b1f13fa363",
"registration_upload": "cef21bd371ce71c76aafd21821509b59ec5faa9b53a8e21bfaa58186d020a812a894afae522fc4e6e251e6a72b832dfdea2284d1e38e1d4356a7ec47449c0a6d393df095fff0eb7249abe3d15416b8c362598be68e28f89456f783d37f54fe02bc8aca098df28e6548308a5cf921fe5a71a5f2b6f85976dd2f1e37fcf5d69126",
"credential_request": "028d69a2c03f2edf8f389563c1cc78a3b95a67a20c894bce4359412b210ea52d0f5110d33a36d039bb8ca1329b39993a2366024dec83671bf195a2997f054b550560761872baf7ae0caa9da19604217d845623437af461d10b78202f1545c3d34b",
"credential_response": "03fc2889add67eeaec390775befef78d8cee5d93bc9ac1186260f809dfe0b639e9cbb2380130d6f4a80f8d1e3f9bde4e431c6e3105aac77a0076dfe6e8e887287099a0886cd4da8ec29e54cde0d14b25d4532e28692acd7a45b751314c08ddc8b14b1d80772fd4a81c35185f8e9a0b89f81ca97cfc0d295caf71cb91f4930c2edb9fe42b1a69fa4f007735ddcb47061a766de2c7321fca1a3fcd6b7f5b3d36b8807e868983e4a2f9cc909287d255e3cc94b467c4701d938de643a795fec393e12c161d7a9bb4eb6a3d914c3dfe7bfcce7c483c54555cb344a8c97694a2eea7fa4019abb329e92ed77475d70d2c016e0cf9fe6f68974d175a0461848c4994d73c43",
"credential_finalization": "273ea776d1e67645fd9e21179032a02fc340087bc2621920be0a960f7a3ef25b",
"client_registration_state": "5110d33a36d039bb8ca1329b39993a2366024dec83671bf195a2997f054b5505028d69a2c03f2edf8f389563c1cc78a3b95a67a20c894bce4359412b210ea52d0f",
"client_login_state": "5110d33a36d039bb8ca1329b39993a2366024dec83671bf195a2997f054b5505028d69a2c03f2edf8f389563c1cc78a3b95a67a20c894bce4359412b210ea52d0f5110d33a36d039bb8ca1329b39993a2366024dec83671bf195a2997f054b550560761872baf7ae0caa9da19604217d845623437af461d10b78202f1545c3d34be546de1f4ded2ab52dc0abf00f500b927ee1033aafc0f3a3e5d2634cd52112005110d33a36d039bb8ca1329b39993a2366024dec83671bf195a2997f054b5505",
"server_login_state": "05a413df0fa949e0308ad3bfffacb7d45bb9edd74314a5015e7b743a22192744504abe829295e3ae661d6ed30dc49d2f44f6ca934412fe6ee773d6514f8247f2082fdd36d18d86c40d32141d4b2e4db654d9c3ce718df531a8c5431e4ba9d292",
"password_file": "cef21bd371ce71c76aafd21821509b59ec5faa9b53a8e21bfaa58186d020a812a894afae522fc4e6e251e6a72b832dfdea2284d1e38e1d4356a7ec47449c0a6d393df095fff0eb7249abe3d15416b8c362598be68e28f89456f783d37f54fe02bc8aca098df28e6548308a5cf921fe5a71a5f2b6f85976dd2f1e37fcf5d69126",
"export_key": "1150751e9cfcf72bcbce59a472957fd06ed79f60ae9db04354bb2d10d3707c26",
"session_key": "082fdd36d18d86c40d32141d4b2e4db654d9c3ce718df531a8c5431e4ba9d292"
}
"#;
@@ -634,13 +634,13 @@ where
let credential_finalization_bytes = client_login_finish_result.message.serialize();
Ok(TestVectorParameters {
client_s_pk: client_s_kp.public().to_bytes().to_vec(),
client_s_pk: client_s_kp.public().serialize().to_vec(),
client_s_sk: client_s_kp.private().serialize().to_vec(),
client_e_pk: client_e_kp.public().to_bytes().to_vec(),
client_e_pk: client_e_kp.public().serialize().to_vec(),
client_e_sk: client_e_kp.private().serialize().to_vec(),
server_s_pk: server_s_kp.public().to_bytes().to_vec(),
server_s_pk: server_s_kp.public().serialize().to_vec(),
server_s_sk: server_s_kp.private().serialize().to_vec(),
server_e_pk: server_e_kp.public().to_bytes().to_vec(),
server_e_pk: server_e_kp.public().serialize().to_vec(),
server_e_sk: server_e_kp.private().serialize().to_vec(),
fake_sk,
credential_identifier: credential_identifier.to_vec(),
@@ -741,8 +741,6 @@ fn test_registration_request() -> Result<(), ProtocolError> {
#[cfg(feature = "serde")]
#[test]
fn test_serialization() -> Result<(), ProtocolError> {
use core::mem;
fn inner<CS: CipherSuite>(test_vector: &str) -> Result<(), ProtocolError>
where
<OprfHash<CS> as OutputSizeUser>::OutputSize:
@@ -762,7 +760,7 @@ fn test_serialization() -> Result<(), ProtocolError> {
bincode::serialize(&client_registration_start_result.message).unwrap();
assert_eq!(
registration_request.len(),
RegistrationRequestLen::<CS>::USIZE + mem::size_of::<usize>()
RegistrationRequestLen::<CS>::USIZE
);
let registration_request: RegistrationRequest<CS> =
bincode::deserialize(&registration_request).unwrap();
@@ -1107,7 +1105,7 @@ fn test_credential_finalization() -> Result<(), ProtocolError> {
assert_eq!(
hex::encode(&parameters.server_s_pk),
hex::encode(&client_login_finish_result.server_s_pk.to_bytes())
hex::encode(&client_login_finish_result.server_s_pk.serialize())
);
assert_eq!(
hex::encode(&parameters.session_key),
@@ -1417,7 +1415,7 @@ fn test_zeroize_server_registration_finish() -> Result<(), ProtocolError> {
#[test]
fn test_zeroize_client_login_start() -> Result<(), ProtocolError> {
fn inner<CS: CipherSuite<KeyExchange = TripleDH>>() -> Result<(), ProtocolError>
fn inner<CS: CipherSuite<KeyExchange = TripleDh>>() -> Result<(), ProtocolError>
where
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
@@ -1537,7 +1535,7 @@ fn test_zeroize_server_login_start() -> Result<(), ProtocolError> {
#[test]
fn test_zeroize_client_login_finish() -> Result<(), ProtocolError> {
fn inner<CS: CipherSuite<KeyExchange = TripleDH>>() -> Result<(), ProtocolError>
fn inner<CS: CipherSuite<KeyExchange = TripleDh>>() -> Result<(), ProtocolError>
where
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
+35 -43
View File
@@ -24,13 +24,13 @@ use crate::errors::*;
use crate::hash::{Hash, OutputSize, ProxyHash};
use crate::key_exchange::group::KeGroup;
use crate::key_exchange::traits::{Ke1MessageLen, Ke2MessageLen};
use crate::key_exchange::tripledh::{NonceLen, TripleDH};
use crate::key_exchange::tripledh::{NonceLen, TripleDh};
use crate::ksf::Identity;
use crate::messages::{
CredentialRequestLen, CredentialResponseLen, CredentialResponseWithoutKeLen,
RegistrationResponseLen, RegistrationUploadLen,
};
use crate::opaque::*;
use crate::slow_hash::NoOpHash;
use crate::tests::mock_rng::CycleRng;
use crate::*;
@@ -110,7 +110,7 @@ where
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 => CS::KeGroup::serialize_sk(CS::KeGroup::random_sk(&mut OsRng)).to_vec(),
}
},
dummy_masking_key: {
@@ -209,62 +209,54 @@ fn tests() -> Result<(), ProtocolError> {
#[cfg(feature = "ristretto255")]
{
struct Ristretto255Sha512NoSlowHash;
impl CipherSuite for Ristretto255Sha512NoSlowHash {
type OprfGroup = crate::Ristretto255;
struct Ristretto255Sha512NoKsf;
impl CipherSuite for Ristretto255Sha512NoKsf {
type OprfCs = crate::Ristretto255;
type KeGroup = crate::Ristretto255;
type KeyExchange = TripleDH;
type SlowHash = NoOpHash;
type KeyExchange = TripleDh;
type Ksf = Identity;
}
let ristretto_real_tvs = json_to_test_vectors!(
rfc,
"Real",
"ristretto255, SHA512",
Ristretto255Sha512NoSlowHash
);
let ristretto_real_tvs =
json_to_test_vectors!(rfc, "Real", "ristretto255, SHA512", Ristretto255Sha512NoKsf);
let ristretto_fake_tvs = json_to_test_vectors!(
rfc,
"Fake",
"ristretto255, SHA512",
Ristretto255Sha512NoSlowHash
);
let ristretto_fake_tvs =
json_to_test_vectors!(rfc, "Fake", "ristretto255, SHA512", Ristretto255Sha512NoKsf);
assert!(
!(ristretto_real_tvs.is_empty() || ristretto_fake_tvs.is_empty()),
"Parsing error"
);
test_registration_request::<Ristretto255Sha512NoSlowHash>(&ristretto_real_tvs)?;
test_registration_response::<Ristretto255Sha512NoSlowHash>(&ristretto_real_tvs)?;
test_registration_upload::<Ristretto255Sha512NoSlowHash>(&ristretto_real_tvs)?;
test_ke1::<Ristretto255Sha512NoSlowHash>(&ristretto_real_tvs)?;
test_ke2::<Ristretto255Sha512NoSlowHash>(&ristretto_real_tvs)?;
test_ke3::<Ristretto255Sha512NoSlowHash>(&ristretto_real_tvs)?;
test_server_login_finish::<Ristretto255Sha512NoSlowHash>(&ristretto_real_tvs)?;
test_fake_vectors::<Ristretto255Sha512NoSlowHash>(&ristretto_fake_tvs)?;
test_registration_request::<Ristretto255Sha512NoKsf>(&ristretto_real_tvs)?;
test_registration_response::<Ristretto255Sha512NoKsf>(&ristretto_real_tvs)?;
test_registration_upload::<Ristretto255Sha512NoKsf>(&ristretto_real_tvs)?;
test_ke1::<Ristretto255Sha512NoKsf>(&ristretto_real_tvs)?;
test_ke2::<Ristretto255Sha512NoKsf>(&ristretto_real_tvs)?;
test_ke3::<Ristretto255Sha512NoKsf>(&ristretto_real_tvs)?;
test_server_login_finish::<Ristretto255Sha512NoKsf>(&ristretto_real_tvs)?;
test_fake_vectors::<Ristretto255Sha512NoKsf>(&ristretto_fake_tvs)?;
}
struct P256Sha256NoSlowHash;
impl CipherSuite for P256Sha256NoSlowHash {
type OprfGroup = p256::NistP256;
struct P256Sha256NoKsf;
impl CipherSuite for P256Sha256NoKsf {
type OprfCs = p256::NistP256;
type KeGroup = p256::NistP256;
type KeyExchange = TripleDH;
type SlowHash = NoOpHash;
type KeyExchange = TripleDh;
type Ksf = Identity;
}
let p256_real_tvs = json_to_test_vectors!(
rfc,
"Real",
"P256_XMD:SHA-256_SSWU_RO_, SHA256",
P256Sha256NoSlowHash
P256Sha256NoKsf
);
let p256_fake_tvs = json_to_test_vectors!(
rfc,
"Fake",
"P256_XMD:SHA-256_SSWU_RO_, SHA256",
P256Sha256NoSlowHash
P256Sha256NoKsf
);
assert!(
@@ -272,14 +264,14 @@ fn tests() -> Result<(), ProtocolError> {
"Parsing error"
);
test_registration_request::<P256Sha256NoSlowHash>(&p256_real_tvs)?;
test_registration_response::<P256Sha256NoSlowHash>(&p256_real_tvs)?;
test_registration_upload::<P256Sha256NoSlowHash>(&p256_real_tvs)?;
test_ke1::<P256Sha256NoSlowHash>(&p256_real_tvs)?;
test_ke2::<P256Sha256NoSlowHash>(&p256_real_tvs)?;
test_ke3::<P256Sha256NoSlowHash>(&p256_real_tvs)?;
test_server_login_finish::<P256Sha256NoSlowHash>(&p256_real_tvs)?;
test_fake_vectors::<P256Sha256NoSlowHash>(&p256_fake_tvs)?;
test_registration_request::<P256Sha256NoKsf>(&p256_real_tvs)?;
test_registration_response::<P256Sha256NoKsf>(&p256_real_tvs)?;
test_registration_upload::<P256Sha256NoKsf>(&p256_real_tvs)?;
test_ke1::<P256Sha256NoKsf>(&p256_real_tvs)?;
test_ke2::<P256Sha256NoKsf>(&p256_real_tvs)?;
test_ke3::<P256Sha256NoKsf>(&p256_real_tvs)?;
test_server_login_finish::<P256Sha256NoKsf>(&p256_real_tvs)?;
test_fake_vectors::<P256Sha256NoKsf>(&p256_fake_tvs)?;
Ok(())
}
+1 -1
View File
@@ -1,3 +1,3 @@
[formatting]
reorder_keys = true
allowed_blank_lines = 1
reorder_keys = true