Addressing various TODOs and minor cleanups (#127)
This commit is contained in:
Generated
-46
@@ -389,12 +389,6 @@ version = "1.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
|
||||
|
||||
[[package]]
|
||||
name = "fiat-crypto"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0f6ab97095615857b6ad00a8330fff0e443f1def9fd357cef82d0ca0677b616b"
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
@@ -613,7 +607,6 @@ dependencies = [
|
||||
"curve25519-dalek",
|
||||
"digest",
|
||||
"displaydoc",
|
||||
"fiat-crypto",
|
||||
"generic-array",
|
||||
"generic-bytes",
|
||||
"generic-bytes-derive",
|
||||
@@ -630,7 +623,6 @@ dependencies = [
|
||||
"sha2",
|
||||
"subtle",
|
||||
"thiserror",
|
||||
"x25519-dalek",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
@@ -1023,18 +1015,6 @@ dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
version = "0.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.1.0"
|
||||
@@ -1255,34 +1235,8 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "x25519-dalek"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc614d95359fd7afc321b66d2107ede58b246b844cf5d8a0adcca413e439f088"
|
||||
dependencies = [
|
||||
"curve25519-dalek",
|
||||
"rand_core",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05f33972566adbd2d3588b0491eb94b98b43695c4ef897903470ede4f3f5a28a"
|
||||
dependencies = [
|
||||
"zeroize_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeroize_derive"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de251eec69fc7c1bc3923403d18ececb929380e016afe103da75f396704f8ca2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
+3
-5
@@ -13,14 +13,13 @@ readme = "README.md"
|
||||
default = ["u64_backend"]
|
||||
slow-hash = ["scrypt"]
|
||||
bench = []
|
||||
u64_backend = ["curve25519-dalek/u64_backend", "x25519-dalek/u64_backend"]
|
||||
u32_backend = ["curve25519-dalek/u32_backend", "x25519-dalek/u32_backend"]
|
||||
u64_backend = ["curve25519-dalek/u64_backend"]
|
||||
u32_backend = ["curve25519-dalek/u32_backend"]
|
||||
|
||||
[dependencies]
|
||||
curve25519-dalek = { version = "3.0.0", default-features = false, features = ["std"] }
|
||||
digest = "0.9.0"
|
||||
displaydoc = "0.1.7"
|
||||
fiat-crypto = { version = "0.1.5"}
|
||||
generic-array = "0.14.4"
|
||||
generic-bytes = { version = "0.1.0" }
|
||||
generic-bytes-derive = { version = "0.1.0" }
|
||||
@@ -28,10 +27,8 @@ hkdf = "0.10.0"
|
||||
hmac = "0.10.1"
|
||||
rand_core = "0.5.1"
|
||||
scrypt = { version = "0.5.0", optional = true }
|
||||
sha2 = "0.9.2"
|
||||
subtle = { version = "2.3.0", default-features = false }
|
||||
thiserror = "1.0.22"
|
||||
x25519-dalek = { version = "1.1.0", default-features = false, features = ["std"] }
|
||||
zeroize = "1.1.1"
|
||||
|
||||
[dev-dependencies]
|
||||
@@ -42,6 +39,7 @@ criterion = "0.3.3"
|
||||
hex = "0.4.2"
|
||||
lazy_static = "1.4.0"
|
||||
serde_json = "1.0.60"
|
||||
sha2 = "0.9.2"
|
||||
proptest = "0.10.1"
|
||||
rand = "0.7"
|
||||
rustyline = "7.0.0"
|
||||
|
||||
@@ -34,9 +34,9 @@ use std::process::exit;
|
||||
|
||||
use opaque_ke::{
|
||||
ciphersuite::CipherSuite, ClientLogin, ClientLoginFinishParameters, ClientLoginStartParameters,
|
||||
ClientRegistration, ClientRegistrationFinishParameters, CredentialRequest, CredentialResponse,
|
||||
RegistrationRequest, RegistrationResponse, RegistrationUpload, ServerLogin,
|
||||
ServerLoginStartParameters, ServerRegistration,
|
||||
ClientRegistration, ClientRegistrationFinishParameters, CredentialFinalization,
|
||||
CredentialRequest, CredentialResponse, RegistrationRequest, RegistrationResponse,
|
||||
RegistrationUpload, ServerLogin, ServerLoginStartParameters, ServerRegistration,
|
||||
};
|
||||
|
||||
// The ciphersuite trait allows to specify the underlying primitives
|
||||
@@ -173,9 +173,27 @@ fn open_locker(
|
||||
return Err(String::from("Incorrect password, please try again."));
|
||||
}
|
||||
let client_login_finish_result = result.unwrap();
|
||||
let credential_finalization_bytes = client_login_finish_result.message.serialize();
|
||||
|
||||
// Decrypt contents of locker
|
||||
let plaintext = decrypt(&client_login_finish_result.export_key, &locker.contents);
|
||||
// Client sends credential_finalization_bytes to server
|
||||
|
||||
let server_login_finish_result = server_login_start_result
|
||||
.state
|
||||
.finish(CredentialFinalization::deserialize(&credential_finalization_bytes[..]).unwrap())
|
||||
.unwrap();
|
||||
|
||||
// Server sends locker contents, encrypted under the session key, to the client
|
||||
let encrypted_locker_contents =
|
||||
encrypt(&server_login_finish_result.shared_secret, &locker.contents);
|
||||
|
||||
// Client decrypts contents of locker, first under the shared secret, and then under the export key
|
||||
let plaintext = decrypt(
|
||||
&client_login_finish_result.export_key,
|
||||
&decrypt(
|
||||
&client_login_finish_result.shared_secret,
|
||||
&encrypted_locker_contents,
|
||||
),
|
||||
);
|
||||
String::from_utf8(plaintext).map_err(|_| String::from("UTF8 error"))
|
||||
}
|
||||
|
||||
|
||||
@@ -100,6 +100,9 @@ pub(crate) struct Envelope<D: Hash> {
|
||||
hmac: GenericArray<u8, <D as Digest>::OutputSize>,
|
||||
}
|
||||
|
||||
// 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 contents.
|
||||
pub(crate) struct OpenedEnvelope<D: Hash> {
|
||||
pub(crate) client_s_sk: Vec<u8>,
|
||||
pub(crate) export_key: GenericArray<u8, <D as Digest>::OutputSize>,
|
||||
|
||||
@@ -21,7 +21,6 @@ pub trait KeyExchange<D: Hash, G: Group> {
|
||||
type KE3Message: for<'r> TryFrom<&'r [u8], Error = PakeError> + ToBytes;
|
||||
|
||||
fn generate_ke1<R: RngCore + CryptoRng>(
|
||||
l1_component: Vec<u8>,
|
||||
info: Vec<u8>,
|
||||
rng: &mut R,
|
||||
) -> Result<(Self::KE1State, Self::KE1Message), ProtocolError>;
|
||||
@@ -44,6 +43,7 @@ pub trait KeyExchange<D: Hash, G: Group> {
|
||||
l2_component: Vec<u8>,
|
||||
ke2_message: Self::KE2Message,
|
||||
ke1_state: &Self::KE1State,
|
||||
serialized_credential_request: &[u8],
|
||||
server_s_pk: Key,
|
||||
client_s_sk: Key,
|
||||
id_u: Vec<u8>,
|
||||
|
||||
@@ -28,7 +28,6 @@ use rand_core::{CryptoRng, RngCore};
|
||||
use std::convert::TryFrom;
|
||||
|
||||
const KEY_LEN: usize = 32;
|
||||
pub(crate) const NONCE_LEN: usize = 32;
|
||||
pub(crate) type NonceLen = U32;
|
||||
|
||||
static STR_3DH: &[u8] = b"3DH keys";
|
||||
@@ -51,15 +50,14 @@ impl<D: Hash, G: Group> KeyExchange<D, G> for TripleDH {
|
||||
type KE3Message = KE3Message<<D as FixedOutput>::OutputSize>;
|
||||
|
||||
fn generate_ke1<R: RngCore + CryptoRng>(
|
||||
alpha_bytes: Vec<u8>,
|
||||
info: Vec<u8>,
|
||||
rng: &mut R,
|
||||
) -> Result<(Self::KE1State, Self::KE1Message), ProtocolError> {
|
||||
let client_e_kp = KeyPair::<G>::generate_random(rng);
|
||||
let client_nonce: GenericArray<u8, NonceLen> = {
|
||||
let mut client_nonce_bytes = [0u8; NONCE_LEN];
|
||||
let mut client_nonce_bytes = vec![0u8; NonceLen::to_usize()];
|
||||
rng.fill_bytes(&mut client_nonce_bytes);
|
||||
client_nonce_bytes.into()
|
||||
GenericArray::clone_from_slice(&client_nonce_bytes)
|
||||
};
|
||||
|
||||
let ke1_message = KE1Message {
|
||||
@@ -68,14 +66,10 @@ impl<D: Hash, G: Group> KeyExchange<D, G> for TripleDH {
|
||||
client_e_pk: client_e_kp.public().clone(),
|
||||
};
|
||||
|
||||
// TODO: must match the serialization of a credential request, could be done more cleanly
|
||||
let serialized_credential_request = [alpha_bytes, ke1_message.to_bytes()].concat();
|
||||
|
||||
Ok((
|
||||
KE1State {
|
||||
client_e_sk: client_e_kp.private().clone(),
|
||||
client_nonce,
|
||||
serialized_credential_request,
|
||||
},
|
||||
ke1_message,
|
||||
))
|
||||
@@ -95,9 +89,9 @@ impl<D: Hash, G: Group> KeyExchange<D, G> for TripleDH {
|
||||
) -> Result<(Vec<u8>, Self::KE2State, Self::KE2Message), ProtocolError> {
|
||||
let server_e_kp = KeyPair::<G>::generate_random(rng);
|
||||
let server_nonce: GenericArray<u8, NonceLen> = {
|
||||
let mut server_nonce_bytes = [0u8; NONCE_LEN];
|
||||
let mut server_nonce_bytes = vec![0u8; NonceLen::to_usize()];
|
||||
rng.fill_bytes(&mut server_nonce_bytes);
|
||||
server_nonce_bytes.into()
|
||||
GenericArray::clone_from_slice(&server_nonce_bytes)
|
||||
};
|
||||
|
||||
let (session_secret, km2, ke2, km3) = derive_3dh_keys::<D, G>(
|
||||
@@ -169,6 +163,7 @@ impl<D: Hash, G: Group> KeyExchange<D, G> for TripleDH {
|
||||
l2_component: Vec<u8>,
|
||||
ke2_message: Self::KE2Message,
|
||||
ke1_state: &Self::KE1State,
|
||||
serialized_credential_request: &[u8],
|
||||
server_s_pk: Key,
|
||||
client_s_sk: Key,
|
||||
id_u: Vec<u8>,
|
||||
@@ -190,7 +185,7 @@ impl<D: Hash, G: Group> KeyExchange<D, G> for TripleDH {
|
||||
)?;
|
||||
|
||||
let transcript: Vec<u8> = [
|
||||
&ke1_state.serialized_credential_request[..],
|
||||
&serialized_credential_request,
|
||||
&l2_component[..],
|
||||
&ke2_message.to_bytes_without_mac(),
|
||||
]
|
||||
@@ -258,7 +253,7 @@ impl<D: Hash, G: Group> KeyExchange<D, G> for TripleDH {
|
||||
}
|
||||
|
||||
fn ke2_message_size() -> usize {
|
||||
NONCE_LEN + KEY_LEN + <<D as FixedOutput>::OutputSize as Unsigned>::to_usize()
|
||||
NonceLen::to_usize() + KEY_LEN + <<D as FixedOutput>::OutputSize as Unsigned>::to_usize()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,7 +262,6 @@ impl<D: Hash, G: Group> KeyExchange<D, G> for TripleDH {
|
||||
pub struct KE1State {
|
||||
client_e_sk: Key,
|
||||
client_nonce: GenericArray<u8, NonceLen>,
|
||||
serialized_credential_request: Vec<u8>,
|
||||
}
|
||||
|
||||
/// The first key exchange message
|
||||
@@ -282,26 +276,21 @@ impl TryFrom<&[u8]> for KE1State {
|
||||
type Error = PakeError;
|
||||
|
||||
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
|
||||
let checked_bytes = check_slice_size_atleast(bytes, KEY_LEN + NONCE_LEN, "ke1_state")?;
|
||||
let nonce_len = NonceLen::to_usize();
|
||||
let checked_bytes = check_slice_size_atleast(bytes, KEY_LEN + nonce_len, "ke1_state")?;
|
||||
|
||||
Ok(Self {
|
||||
client_e_sk: Key::from_bytes(&checked_bytes[..KEY_LEN])?,
|
||||
client_nonce: GenericArray::clone_from_slice(
|
||||
&checked_bytes[KEY_LEN..KEY_LEN + NONCE_LEN],
|
||||
&checked_bytes[KEY_LEN..KEY_LEN + nonce_len],
|
||||
),
|
||||
serialized_credential_request: checked_bytes[KEY_LEN + NONCE_LEN..].to_vec(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ToBytes for KE1State {
|
||||
fn to_bytes(&self) -> Vec<u8> {
|
||||
let output: Vec<u8> = [
|
||||
&self.client_e_sk.to_arr(),
|
||||
&self.client_nonce[..],
|
||||
&self.serialized_credential_request[..],
|
||||
]
|
||||
.concat();
|
||||
let output: Vec<u8> = [&self.client_e_sk.to_arr(), &self.client_nonce[..]].concat();
|
||||
output
|
||||
}
|
||||
}
|
||||
@@ -321,15 +310,16 @@ impl TryFrom<&[u8]> for KE1Message {
|
||||
type Error = PakeError;
|
||||
|
||||
fn try_from(ke1_message_bytes: &[u8]) -> Result<Self, Self::Error> {
|
||||
let nonce_len = NonceLen::to_usize();
|
||||
let checked_nonce =
|
||||
check_slice_size_atleast(ke1_message_bytes, NONCE_LEN, "ke1_message nonce")?;
|
||||
check_slice_size_atleast(ke1_message_bytes, nonce_len, "ke1_message nonce")?;
|
||||
|
||||
let (info, remainder) = tokenize(&checked_nonce[NONCE_LEN..], 2)?;
|
||||
let (info, remainder) = tokenize(&checked_nonce[nonce_len..], 2)?;
|
||||
|
||||
let checked_client_e_pk = check_slice_size(&remainder, KEY_LEN, "ke1_message client_e_pk")?;
|
||||
|
||||
Ok(Self {
|
||||
client_nonce: GenericArray::clone_from_slice(&checked_nonce[..NONCE_LEN]),
|
||||
client_nonce: GenericArray::clone_from_slice(&checked_nonce[..nonce_len]),
|
||||
info,
|
||||
client_e_pk: Key::from_bytes(&checked_client_e_pk)?,
|
||||
})
|
||||
@@ -401,9 +391,10 @@ impl<HashLen: ArrayLength<u8>> TryFrom<&[u8]> for KE2Message<HashLen> {
|
||||
type Error = PakeError;
|
||||
|
||||
fn try_from(input: &[u8]) -> Result<Self, Self::Error> {
|
||||
let checked_nonce = check_slice_size_atleast(input, NONCE_LEN, "ke2_message nonce")?;
|
||||
let nonce_len = NonceLen::to_usize();
|
||||
let checked_nonce = check_slice_size_atleast(input, nonce_len, "ke2_message nonce")?;
|
||||
let checked_server_e_pk = check_slice_size_atleast(
|
||||
&checked_nonce[NONCE_LEN..],
|
||||
&checked_nonce[nonce_len..],
|
||||
KEY_LEN,
|
||||
"ke2_message server_e_pk",
|
||||
)?;
|
||||
@@ -411,7 +402,7 @@ impl<HashLen: ArrayLength<u8>> TryFrom<&[u8]> for KE2Message<HashLen> {
|
||||
let checked_mac = check_slice_size(&remainder, HashLen::to_usize(), "ke1_message mac")?;
|
||||
|
||||
Ok(Self {
|
||||
server_nonce: GenericArray::clone_from_slice(&checked_nonce[..NONCE_LEN]),
|
||||
server_nonce: GenericArray::clone_from_slice(&checked_nonce[..nonce_len]),
|
||||
server_e_pk: Key::from_bytes(&checked_server_e_pk[..KEY_LEN])?,
|
||||
e_info,
|
||||
mac: GenericArray::clone_from_slice(&checked_mac),
|
||||
|
||||
@@ -37,7 +37,6 @@ impl GroupWithMapToCurve for RistrettoPoint {
|
||||
// Implements the hash_to_ristretto255() function from
|
||||
// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-10.txt
|
||||
fn map_to_curve<H: Hash>(msg: &[u8], dst: &[u8]) -> Result<Self, InternalPakeError> {
|
||||
// FIXME use generic_array and turn this into a compile-time error if size mismatch
|
||||
let uniform_bytes =
|
||||
expand_message_xmd::<H>(msg, dst, <H as Digest>::OutputSize::to_usize())?;
|
||||
Ok(<Self as Group>::hash_to_curve(
|
||||
|
||||
+18
-6
@@ -259,12 +259,24 @@ pub struct CredentialResponse<CS: CipherSuite> {
|
||||
impl<CS: CipherSuite> CredentialResponse<CS> {
|
||||
/// Serialization into bytes
|
||||
pub fn serialize(&self) -> Vec<u8> {
|
||||
let mut credential_response: Vec<u8> = Vec::new();
|
||||
credential_response.extend_from_slice(&self.beta.to_arr());
|
||||
credential_response.extend_from_slice(&serialize(&self.server_s_pk.to_arr().to_vec(), 2));
|
||||
credential_response.extend_from_slice(&self.envelope.to_bytes());
|
||||
credential_response.extend_from_slice(&self.ke2_message.to_bytes());
|
||||
credential_response
|
||||
[
|
||||
Self::serialize_without_ke(&self.beta, &self.server_s_pk, &self.envelope),
|
||||
self.ke2_message.to_bytes(),
|
||||
]
|
||||
.concat()
|
||||
}
|
||||
|
||||
pub(crate) fn serialize_without_ke(
|
||||
beta: &CS::Group,
|
||||
server_s_pk: &Key,
|
||||
envelope: &Envelope<CS::Hash>,
|
||||
) -> Vec<u8> {
|
||||
[
|
||||
&beta.to_arr(),
|
||||
&serialize(&server_s_pk.to_arr().to_vec(), 2)[..],
|
||||
&envelope.to_bytes(),
|
||||
]
|
||||
.concat()
|
||||
}
|
||||
|
||||
/// Deserialization from bytes
|
||||
|
||||
+20
-17
@@ -408,6 +408,7 @@ pub struct ClientLogin<CS: CipherSuite> {
|
||||
/// token containing the client's password and the blinding factor
|
||||
token: oprf::Token<CS::Group>,
|
||||
ke1_state: <CS::KeyExchange as KeyExchange<CS::Hash, CS::Group>>::KE1State,
|
||||
serialized_credential_request: Vec<u8>,
|
||||
}
|
||||
|
||||
impl<CS: CipherSuite> TryFrom<&[u8]> for ClientLogin<CS> {
|
||||
@@ -427,7 +428,8 @@ impl<CS: CipherSuite> TryFrom<&[u8]> for ClientLogin<CS> {
|
||||
let blinding_factor_bytes = GenericArray::from_slice(&checked_slice[..scalar_len]);
|
||||
let blinding_factor = CS::Group::from_scalar_slice(blinding_factor_bytes)?;
|
||||
|
||||
let (ke1_state_bytes, password) = tokenize(&checked_slice[scalar_len..], 2)?;
|
||||
let (serialized_credential_request, remainder) = tokenize(&checked_slice[scalar_len..], 2)?;
|
||||
let (ke1_state_bytes, password) = tokenize(&remainder, 2)?;
|
||||
|
||||
let ke1_state = <CS::KeyExchange as KeyExchange<CS::Hash, CS::Group>>::KE1State::try_from(
|
||||
&ke1_state_bytes[..],
|
||||
@@ -438,6 +440,7 @@ impl<CS: CipherSuite> TryFrom<&[u8]> for ClientLogin<CS> {
|
||||
blind: blinding_factor,
|
||||
},
|
||||
ke1_state,
|
||||
serialized_credential_request,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -447,6 +450,7 @@ impl<CS: CipherSuite> ClientLogin<CS> {
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
let output: Vec<u8> = [
|
||||
&CS::Group::scalar_as_bytes(&self.token.blind)[..],
|
||||
&serialize(&self.serialized_credential_request, 2),
|
||||
&serialize(&self.ke1_state.to_bytes(), 2),
|
||||
&self.token.data,
|
||||
]
|
||||
@@ -536,14 +540,18 @@ impl<CS: CipherSuite> ClientLogin<CS> {
|
||||
|
||||
let (token, alpha) = oprf::blind::<R, CS::Group, CS::Hash>(&password, rng)?;
|
||||
|
||||
let (ke1_state, ke1_message) =
|
||||
CS::KeyExchange::generate_ke1(alpha.to_arr().to_vec(), info, rng)?;
|
||||
let (ke1_state, ke1_message) = CS::KeyExchange::generate_ke1(info, rng)?;
|
||||
|
||||
let l1 = CredentialRequest { alpha, ke1_message };
|
||||
let credential_request = CredentialRequest { alpha, ke1_message };
|
||||
let serialized_credential_request = credential_request.serialize();
|
||||
|
||||
Ok(ClientLoginStartResult {
|
||||
message: l1,
|
||||
state: Self { token, ke1_state },
|
||||
message: credential_request,
|
||||
state: Self {
|
||||
token,
|
||||
ke1_state,
|
||||
serialized_credential_request,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -627,6 +635,7 @@ impl<CS: CipherSuite> ClientLogin<CS> {
|
||||
l2_bytes,
|
||||
l2.ke2_message,
|
||||
&self.ke1_state,
|
||||
&self.serialized_credential_request,
|
||||
l2.server_s_pk.clone(),
|
||||
client_s_sk,
|
||||
id_u,
|
||||
@@ -772,21 +781,15 @@ impl<CS: CipherSuite> ServerLogin<CS> {
|
||||
|
||||
let l1_bytes = &l1.to_bytes();
|
||||
let beta = oprf::evaluate(l1.alpha, &password_file.oprf_key);
|
||||
|
||||
let server_s_pk = KeyPair::<CS::Group>::public_from_private(&server_s_sk);
|
||||
|
||||
// TODO: must match serialization of credential response, could be done more cleanly
|
||||
let l2_component: Vec<u8> = [
|
||||
&beta.to_arr()[..],
|
||||
&serialize(&server_s_pk.to_arr()[..], 2),
|
||||
&envelope.to_bytes()[..],
|
||||
]
|
||||
.concat();
|
||||
let credential_response_component =
|
||||
CredentialResponse::<CS>::serialize_without_ke(&beta, &server_s_pk, &envelope);
|
||||
|
||||
let (plain_info, ke2_state, ke2_message) = CS::KeyExchange::generate_ke2(
|
||||
rng,
|
||||
l1_bytes.to_vec(),
|
||||
l2_component,
|
||||
credential_response_component,
|
||||
l1.ke1_message,
|
||||
client_s_pk,
|
||||
server_s_sk.clone(),
|
||||
@@ -795,7 +798,7 @@ impl<CS: CipherSuite> ServerLogin<CS> {
|
||||
e_info,
|
||||
)?;
|
||||
|
||||
let l2 = CredentialResponse {
|
||||
let credential_response = CredentialResponse {
|
||||
beta,
|
||||
server_s_pk,
|
||||
envelope,
|
||||
@@ -804,7 +807,7 @@ impl<CS: CipherSuite> ServerLogin<CS> {
|
||||
|
||||
Ok(ServerLoginStartResult {
|
||||
plain_info,
|
||||
message: l2,
|
||||
message: credential_response,
|
||||
state: Self {
|
||||
_cs: PhantomData,
|
||||
ke2_state,
|
||||
|
||||
@@ -22,7 +22,6 @@ pub(crate) fn i2osp(input: usize, length: usize) -> Vec<u8> {
|
||||
// Corresponds to the OS2IP() function from RFC8017
|
||||
pub(crate) fn os2ip(input: &[u8]) -> Result<usize, PakeError> {
|
||||
if input.len() > std::mem::size_of::<usize>() {
|
||||
// TODO:: check RFC compliance in refusing this
|
||||
return Err(PakeError::SerializationError);
|
||||
}
|
||||
|
||||
|
||||
+18
-10
@@ -9,7 +9,7 @@ use crate::{
|
||||
group::Group,
|
||||
key_exchange::{
|
||||
traits::{KeyExchange, ToBytes},
|
||||
tripledh::{TripleDH, NONCE_LEN},
|
||||
tripledh::{NonceLen, TripleDH},
|
||||
},
|
||||
opaque::*,
|
||||
serialization::{i2osp, os2ip, serialize},
|
||||
@@ -17,6 +17,7 @@ use crate::{
|
||||
};
|
||||
|
||||
use curve25519_dalek::ristretto::RistrettoPoint;
|
||||
use generic_array::typenum::Unsigned;
|
||||
use generic_bytes::SizedBytes;
|
||||
use proptest::{collection::vec, prelude::*};
|
||||
use rand_core::{OsRng, RngCore};
|
||||
@@ -79,7 +80,7 @@ fn server_registration_roundtrip() {
|
||||
// Construct a mock envelope
|
||||
let mut mock_envelope_bytes = Vec::new();
|
||||
mock_envelope_bytes.extend_from_slice(&[0; 1]); // mode = 0
|
||||
mock_envelope_bytes.extend_from_slice(&[0; NONCE_LEN]); // empty nonce
|
||||
mock_envelope_bytes.extend_from_slice(&vec![0; NonceLen::to_usize()]); // empty nonce
|
||||
mock_envelope_bytes.extend_from_slice(&[0, 0]); // empty ciphertext
|
||||
mock_envelope_bytes.extend_from_slice(&[0; MAC_SIZE]); // length-MAC_SIZE hmac
|
||||
|
||||
@@ -168,7 +169,7 @@ fn login_first_message_roundtrip() {
|
||||
let alpha_bytes = alpha.to_arr().to_vec();
|
||||
|
||||
let client_e_kp = Default::generate_random_keypair(&mut rng);
|
||||
let mut client_nonce = [0u8; NONCE_LEN];
|
||||
let mut client_nonce = vec![0u8; NonceLen::to_usize()];
|
||||
rng.fill_bytes(&mut client_nonce);
|
||||
|
||||
let mut info = [0u8; MAX_INFO_LENGTH];
|
||||
@@ -218,7 +219,7 @@ fn login_second_message_roundtrip() {
|
||||
let server_e_kp = Default::generate_random_keypair(&mut rng);
|
||||
let mut mac = [0u8; MAC_SIZE];
|
||||
rng.fill_bytes(&mut mac);
|
||||
let mut server_nonce = [0u8; NONCE_LEN];
|
||||
let mut server_nonce = vec![0u8; NonceLen::to_usize()];
|
||||
rng.fill_bytes(&mut server_nonce);
|
||||
|
||||
let mut e_info = [0u8; MAX_INFO_LENGTH];
|
||||
@@ -264,13 +265,20 @@ fn client_login_roundtrip() {
|
||||
let sc = <RistrettoPoint as Group>::random_scalar(&mut rng);
|
||||
|
||||
let client_e_kp = Default::generate_random_keypair(&mut rng);
|
||||
let mut client_nonce = [0u8; NONCE_LEN];
|
||||
let mut client_nonce = vec![0u8; NonceLen::to_usize()];
|
||||
rng.fill_bytes(&mut client_nonce);
|
||||
|
||||
let l1_data = [&sc.to_bytes()[..], &client_nonce, client_e_kp.public()].concat();
|
||||
let serialized_credential_request = b"serialized credential_request".to_vec();
|
||||
let l1_data = [client_e_kp.private().to_arr().to_vec(), client_nonce].concat();
|
||||
|
||||
// serialization order: scalar, password, ke1_state
|
||||
let bytes: Vec<u8> = [&sc.as_bytes()[..], &serialize(&l1_data, 2), &pw[..]].concat();
|
||||
// serialization order: scalar, credential_request, ke1_state, password
|
||||
let bytes: Vec<u8> = [
|
||||
&sc.as_bytes()[..],
|
||||
&serialize(&serialized_credential_request, 2),
|
||||
&serialize(&l1_data, 2),
|
||||
&pw[..],
|
||||
]
|
||||
.concat();
|
||||
let reg = ClientLogin::<Default>::try_from(&bytes[..]).unwrap();
|
||||
let reg_bytes = reg.to_bytes();
|
||||
assert_eq!(reg_bytes, bytes);
|
||||
@@ -281,7 +289,7 @@ fn ke1_message_roundtrip() {
|
||||
let mut rng = OsRng;
|
||||
|
||||
let client_e_kp = Default::generate_random_keypair(&mut rng);
|
||||
let mut client_nonce = [0u8; NONCE_LEN];
|
||||
let mut client_nonce = vec![0u8; NonceLen::to_usize()];
|
||||
rng.fill_bytes(&mut client_nonce);
|
||||
|
||||
let mut info = [0u8; MAX_INFO_LENGTH];
|
||||
@@ -307,7 +315,7 @@ fn ke2_message_roundtrip() {
|
||||
let server_e_kp = Default::generate_random_keypair(&mut rng);
|
||||
let mut mac = [0u8; MAC_SIZE];
|
||||
rng.fill_bytes(&mut mac);
|
||||
let mut server_nonce = [0u8; NONCE_LEN];
|
||||
let mut server_nonce = vec![0u8; NonceLen::to_usize()];
|
||||
rng.fill_bytes(&mut server_nonce);
|
||||
let mut e_info = [0u8; MAX_INFO_LENGTH];
|
||||
rng.fill_bytes(&mut e_info);
|
||||
|
||||
+15
-15
@@ -7,7 +7,7 @@ use crate::{
|
||||
ciphersuite::CipherSuite,
|
||||
errors::*,
|
||||
group::Group,
|
||||
key_exchange::tripledh::{TripleDH, NONCE_LEN},
|
||||
key_exchange::tripledh::{NonceLen, TripleDH},
|
||||
keypair::Key,
|
||||
opaque::*,
|
||||
slow_hash::NoOpHash,
|
||||
@@ -15,6 +15,7 @@ use crate::{
|
||||
*,
|
||||
};
|
||||
use curve25519_dalek::ristretto::RistrettoPoint;
|
||||
use generic_array::typenum::Unsigned;
|
||||
use generic_bytes::SizedBytes;
|
||||
use rand_core::{OsRng, RngCore};
|
||||
use serde_json::Value;
|
||||
@@ -92,7 +93,7 @@ static TEST_VECTOR: &str = r#"
|
||||
"credential_response": "2e9bf80e5c101ee2d391ff2aec06af97af17f443fc93a5cc98189681cb943d700020b67d948b98eecfb516a626fab94170e490ccd90da05fce94a016c4d5d6b7136a015dba53e994e82b6d76353341102791cdfb1c2b460e1f913c5741a9c8cf2017c90022f11b89b207eb0735f2bdb2a9968bc9d7c1c962fd0274b4fc1fff2466c769d3710586a3a21ac8ecf13aafe2dc5460eb2f52d8f760396a17beeaf1ef3d1e4e50dd906555832fc51fc474554cb9ff063f6685f9043efc08fd6816666833d68d3b0eb6d913cc5ceb7687d80293005e7f9452ce104d1bac6598dd2265f184cacd558d6b3142103d44b03f3886fe3e419b1b96521fa5a706bb1a4e003907daa381960d664a0006a0f4de671e13c37b24e29138ff9d3df3d55c3b822fedee8dcefd643a1deab7cda5aa1c20f31a0c2a1823c8de3e793f50b257833788b75609fb6c5c4a9cad225f3a981c4ff7b2",
|
||||
"credential_finalization": "0640114ec21fbad6da11c61dfa77a48026646a2a1bd091ef5c9dc46b45f9e53c72f5d714e026d808b6de8911947eef437e9f6a6e969e1ea13f2f4880adc7c879",
|
||||
"client_registration_state": "a70b37951d84ed312a0a8e025b71eafdd362b4e7db872881762d506a271b6e0770617373776f7264",
|
||||
"client_login_state": "a70b37951d84ed312a0a8e025b71eafdd362b4e7db872881762d506a271b6e0700a728fb3aadbc2716844d8de562d35e61914da734dcea0fa6ebd79603ef9eff4e01488244dbf75f86ebaa30307773d3e0eabccb91be349abef8a69c458dbf236e4cecf819ef83351e4c75e016ef845b62a12c14f397328960574935a42e04e0fa42488244dbf75f86ebaa30307773d3e0eabccb91be349abef8a69c458dbf236e4c0005696e666f3108973113b27d6f2291aaaeb92f34a8438d279a48b1b412bddbf2785be660e47970617373776f7264",
|
||||
"client_login_state": "a70b37951d84ed312a0a8e025b71eafdd362b4e7db872881762d506a271b6e070067ecf819ef83351e4c75e016ef845b62a12c14f397328960574935a42e04e0fa42488244dbf75f86ebaa30307773d3e0eabccb91be349abef8a69c458dbf236e4c0005696e666f3108973113b27d6f2291aaaeb92f34a8438d279a48b1b412bddbf2785be660e479004028fb3aadbc2716844d8de562d35e61914da734dcea0fa6ebd79603ef9eff4e01488244dbf75f86ebaa30307773d3e0eabccb91be349abef8a69c458dbf236e4c70617373776f7264",
|
||||
"server_registration_state": "1eaf3cdd64da67e17e3364182f00ed0c323bfb44b20a1b7e0025a0334ab6d40d",
|
||||
"server_login_state": "4952acf61167e6d0e799572827724fdf8c80bda8c62ac28deb68d125661dade2cc1136e634d5fb93f1de4d170ae3e2f5885e333ac3b72d630ab56618c2247fa4d5968eefd69cd270ed14fbcb39627fea9a93cd18175e1b5cfceb06f705bbcb5ecddcd0602aacd7cb358f3273b1099895210bf8baa37d2fab5ed8c092fe9e5739bc6c50cf08ca7d4f4107d48057507480e0c9534b4f04d77cd5156cbd112565d8a2d5beaa473003dcf8dd82d4046648a701c72afeed0f627fcb782627dfaed3ca",
|
||||
"password_file": "1eaf3cdd64da67e17e3364182f00ed0c323bfb44b20a1b7e0025a0334ab6d40dba8c7e239ed64ea1e6068b52cbd5a34ba6f55d635d20a4593884dc271865ea63015dba53e994e82b6d76353341102791cdfb1c2b460e1f913c5741a9c8cf2017c90022f11b89b207eb0735f2bdb2a9968bc9d7c1c962fd0274b4fc1fff2466c769d3710586a3a21ac8ecf13aafe2dc5460eb2f52d8f760396a17beeaf1ef3d1e4e50dd906555832fc51fc474554cb9ff063f6685f9043efc08fd6816666833d68d3b0eb6d9",
|
||||
@@ -274,9 +275,9 @@ fn generate_parameters<CS: CipherSuite>() -> TestVectorParameters {
|
||||
rng.fill_bytes(&mut oprf_key_raw);
|
||||
let mut envelope_nonce = [0u8; 32];
|
||||
rng.fill_bytes(&mut envelope_nonce);
|
||||
let mut client_nonce = [0u8; NONCE_LEN];
|
||||
let mut client_nonce = vec![0u8; NonceLen::to_usize()];
|
||||
rng.fill_bytes(&mut client_nonce);
|
||||
let mut server_nonce = [0u8; NONCE_LEN];
|
||||
let mut server_nonce = vec![0u8; NonceLen::to_usize()];
|
||||
rng.fill_bytes(&mut server_nonce);
|
||||
|
||||
let blinding_factor = CS::Group::random_scalar(&mut rng);
|
||||
@@ -451,8 +452,8 @@ fn test_registration_response() -> Result<(), ProtocolError> {
|
||||
let server_registration_start_result =
|
||||
ServerRegistration::<RistrettoSha5123dhNoSlowHash>::start(
|
||||
&mut oprf_key_rng,
|
||||
RegistrationRequest::deserialize(¶meters.registration_request[..]).unwrap(),
|
||||
&Key::try_from(¶meters.server_s_pk[..]).unwrap(),
|
||||
RegistrationRequest::deserialize(¶meters.registration_request[..])?,
|
||||
&Key::try_from(¶meters.server_s_pk[..])?,
|
||||
)?;
|
||||
assert_eq!(
|
||||
hex::encode(parameters.registration_response),
|
||||
@@ -477,7 +478,7 @@ fn test_registration_upload() -> Result<(), ProtocolError> {
|
||||
)?
|
||||
.finish(
|
||||
&mut finish_registration_rng,
|
||||
RegistrationResponse::deserialize(¶meters.registration_response[..]).unwrap(),
|
||||
RegistrationResponse::deserialize(¶meters.registration_response[..])?,
|
||||
ClientRegistrationFinishParameters::WithIdentifiers(parameters.id_u, parameters.id_s),
|
||||
)?;
|
||||
|
||||
@@ -500,8 +501,9 @@ fn test_password_file() -> Result<(), ProtocolError> {
|
||||
let server_registration = ServerRegistration::<RistrettoSha5123dhNoSlowHash>::try_from(
|
||||
¶meters.server_registration_state[..],
|
||||
)?;
|
||||
let password_file = server_registration
|
||||
.finish(RegistrationUpload::deserialize(¶meters.registration_upload[..]).unwrap())?;
|
||||
let password_file = server_registration.finish(RegistrationUpload::deserialize(
|
||||
¶meters.registration_upload[..],
|
||||
)?)?;
|
||||
|
||||
assert_eq!(
|
||||
hex::encode(parameters.password_file),
|
||||
@@ -545,12 +547,11 @@ fn test_credential_response() -> Result<(), ProtocolError> {
|
||||
CycleRng::new([parameters.server_e_sk, parameters.server_nonce].concat());
|
||||
let server_login_start_result = ServerLogin::<RistrettoSha5123dhNoSlowHash>::start(
|
||||
&mut server_e_sk_and_nonce_rng,
|
||||
ServerRegistration::try_from(¶meters.password_file[..]).unwrap(),
|
||||
&Key::try_from(¶meters.server_s_sk[..]).unwrap(),
|
||||
ServerRegistration::try_from(¶meters.password_file[..])?,
|
||||
&Key::try_from(¶meters.server_s_sk[..])?,
|
||||
CredentialRequest::<RistrettoSha5123dhNoSlowHash>::deserialize(
|
||||
¶meters.credential_request[..],
|
||||
)
|
||||
.unwrap(),
|
||||
)?,
|
||||
ServerLoginStartParameters::WithInfoAndIdentifiers(
|
||||
parameters.einfo2.to_vec(),
|
||||
parameters.id_u,
|
||||
@@ -577,8 +578,7 @@ fn test_credential_finalization() -> Result<(), ProtocolError> {
|
||||
let parameters = populate_test_vectors(&serde_json::from_str(TEST_VECTOR).unwrap());
|
||||
|
||||
let client_login_finish_result =
|
||||
ClientLogin::<RistrettoSha5123dhNoSlowHash>::try_from(¶meters.client_login_state[..])
|
||||
.unwrap()
|
||||
ClientLogin::<RistrettoSha5123dhNoSlowHash>::try_from(¶meters.client_login_state[..])?
|
||||
.finish(
|
||||
CredentialResponse::<RistrettoSha5123dhNoSlowHash>::deserialize(
|
||||
¶meters.credential_response[..],
|
||||
|
||||
Reference in New Issue
Block a user