Implement serde serialization and deserialization to follow Rust's standards.
This commit is contained in:
committed by
Kevin Lewi
parent
940d1dcdb2
commit
055e76a115
Generated
+11
@@ -40,6 +40,15 @@ version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bit-set"
|
||||
version = "0.5.2"
|
||||
@@ -562,6 +571,7 @@ version = "0.5.1-pre.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64",
|
||||
"bincode",
|
||||
"chacha20poly1305",
|
||||
"criterion",
|
||||
"curve25519-dalek",
|
||||
@@ -577,6 +587,7 @@ dependencies = [
|
||||
"rand 0.8.3",
|
||||
"rustyline",
|
||||
"scrypt",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"subtle",
|
||||
|
||||
+5
-1
@@ -10,13 +10,15 @@ edition = "2018"
|
||||
readme = "README.md"
|
||||
|
||||
[features]
|
||||
default = ["u64_backend"]
|
||||
default = ["u64_backend", "serialize"]
|
||||
slow-hash = ["scrypt"]
|
||||
bench = []
|
||||
u64_backend = ["curve25519-dalek/u64_backend"]
|
||||
u32_backend = ["curve25519-dalek/u32_backend"]
|
||||
serialize = ["serde", "base64"]
|
||||
|
||||
[dependencies]
|
||||
base64 = { version = "0.13", optional = true }
|
||||
curve25519-dalek = { version = "3.0.0", default-features = false, features = ["std"] }
|
||||
digest = "0.9.0"
|
||||
displaydoc = "0.1.7"
|
||||
@@ -26,6 +28,7 @@ hkdf = "0.10.0"
|
||||
hmac = "0.10.1"
|
||||
rand = "0.8"
|
||||
scrypt = { version = "0.5.0", optional = true }
|
||||
serde = { version = "1", optional = true }
|
||||
subtle = { version = "2.3.0", default-features = false }
|
||||
thiserror = "1.0.22"
|
||||
zeroize = { version = "1.1.1", features = ["zeroize_derive"] }
|
||||
@@ -33,6 +36,7 @@ zeroize = { version = "1.1.1", features = ["zeroize_derive"] }
|
||||
[dev-dependencies]
|
||||
anyhow = "1.0.35"
|
||||
base64 = "0.13.0"
|
||||
bincode = "1"
|
||||
chacha20poly1305 = "0.7.1"
|
||||
criterion = "0.3.3"
|
||||
hex = "0.4.2"
|
||||
|
||||
@@ -13,6 +13,7 @@ use crate::{
|
||||
PakeError, ProtocolError,
|
||||
},
|
||||
group::Group,
|
||||
impl_serialize_and_deserialize_for,
|
||||
key_exchange::traits::{KeyExchange, ToBytes},
|
||||
keypair::{Key, KeyPair, SizedBytesExt},
|
||||
};
|
||||
@@ -47,6 +48,8 @@ impl<CS: CipherSuite> RegistrationRequest<CS> {
|
||||
}
|
||||
}
|
||||
|
||||
impl_serialize_and_deserialize_for!(RegistrationRequest);
|
||||
|
||||
/// The answer sent by the server to the user, upon reception of the
|
||||
/// registration attempt
|
||||
pub struct RegistrationResponse<CS: CipherSuite> {
|
||||
@@ -81,6 +84,8 @@ impl<CS: CipherSuite> RegistrationResponse<CS> {
|
||||
}
|
||||
}
|
||||
|
||||
impl_serialize_and_deserialize_for!(RegistrationResponse);
|
||||
|
||||
/// The final message from the client, containing sealed cryptographic
|
||||
/// identifiers
|
||||
pub struct RegistrationUpload<CS: CipherSuite> {
|
||||
@@ -122,6 +127,8 @@ impl<CS: CipherSuite> RegistrationUpload<CS> {
|
||||
}
|
||||
}
|
||||
|
||||
impl_serialize_and_deserialize_for!(RegistrationUpload);
|
||||
|
||||
/// The message sent by the user to the server, to initiate registration
|
||||
pub struct CredentialRequest<CS: CipherSuite> {
|
||||
/// blinded password information
|
||||
@@ -159,6 +166,8 @@ impl<CS: CipherSuite> CredentialRequest<CS> {
|
||||
}
|
||||
}
|
||||
|
||||
impl_serialize_and_deserialize_for!(CredentialRequest);
|
||||
|
||||
/// The answer sent by the server to the user, upon reception of the
|
||||
/// login attempt
|
||||
pub struct CredentialResponse<CS: CipherSuite> {
|
||||
@@ -229,6 +238,8 @@ impl<CS: CipherSuite> CredentialResponse<CS> {
|
||||
}
|
||||
}
|
||||
|
||||
impl_serialize_and_deserialize_for!(CredentialResponse);
|
||||
|
||||
/// The answer sent by the client to the server, upon reception of the
|
||||
/// sealed envelope
|
||||
pub struct CredentialFinalization<CS: CipherSuite> {
|
||||
@@ -248,3 +259,5 @@ impl<CS: CipherSuite> CredentialFinalization<CS> {
|
||||
Ok(Self { ke3_message })
|
||||
}
|
||||
}
|
||||
|
||||
impl_serialize_and_deserialize_for!(CredentialFinalization);
|
||||
|
||||
@@ -11,6 +11,7 @@ use crate::{
|
||||
errors::{utils::check_slice_size_atleast, InternalPakeError, PakeError, ProtocolError},
|
||||
group::Group,
|
||||
hash::Hash,
|
||||
impl_serialize_and_deserialize_for,
|
||||
key_exchange::traits::{KeyExchange, ToBytesWithPointers},
|
||||
keypair::{Key, KeyPair, SizedBytesExt},
|
||||
map_to_curve::GroupWithMapToCurve,
|
||||
@@ -83,6 +84,8 @@ impl<CS: CipherSuite> ClientRegistration<CS> {
|
||||
}
|
||||
}
|
||||
|
||||
impl_serialize_and_deserialize_for!(ClientRegistration);
|
||||
|
||||
/// Optional parameters for client registration finish
|
||||
pub enum ClientRegistrationFinishParameters {
|
||||
/// Specifying the identifiers idU and idS (corresponding to custom identifier mode)
|
||||
@@ -385,6 +388,8 @@ impl<CS: CipherSuite> ServerRegistration<CS> {
|
||||
}
|
||||
}
|
||||
|
||||
impl_serialize_and_deserialize_for!(ServerRegistration);
|
||||
|
||||
// Login
|
||||
// =====
|
||||
|
||||
@@ -454,6 +459,8 @@ impl<CS: CipherSuite> ClientLogin<CS> {
|
||||
}
|
||||
}
|
||||
|
||||
impl_serialize_and_deserialize_for!(ClientLogin);
|
||||
|
||||
/// Optional parameters for client login start
|
||||
pub enum ClientLoginStartParameters {
|
||||
/// Specifying a plaintext info field that will be sent to the server
|
||||
@@ -880,6 +887,8 @@ impl<CS: CipherSuite> ServerLogin<CS> {
|
||||
}
|
||||
}
|
||||
|
||||
impl_serialize_and_deserialize_for!(ServerLogin);
|
||||
|
||||
// Zeroize on drop implementations
|
||||
|
||||
// This can't be derived because of the use of a phantom parameter
|
||||
|
||||
@@ -53,5 +53,74 @@ pub(crate) fn tokenize(input: &[u8], size_bytes: usize) -> Result<(Vec<u8>, Vec<
|
||||
))
|
||||
}
|
||||
|
||||
/// Inner macro used for deriving `serde`'s `Serialize` and `Deserialize` traits.
|
||||
#[cfg(feature = "serialize")]
|
||||
#[macro_export]
|
||||
macro_rules! impl_serialize_and_deserialize_for {
|
||||
($t:ident) => {
|
||||
#[cfg(feature = "serialize")]
|
||||
impl<CS: CipherSuite> serde::Serialize for $t<CS> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
if serializer.is_human_readable() {
|
||||
serializer.serialize_str(&base64::encode(&self.serialize()))
|
||||
} else {
|
||||
serializer.serialize_bytes(&self.serialize())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
impl<'de, CS: CipherSuite> serde::Deserialize<'de> for $t<CS> {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
if deserializer.is_human_readable() {
|
||||
let s = <&str>::deserialize(deserializer)?;
|
||||
$t::<CS>::deserialize(&base64::decode(s).map_err(serde::de::Error::custom)?)
|
||||
.map_err(serde::de::Error::custom)
|
||||
} else {
|
||||
struct ByteVisitor<CS: CipherSuite> {
|
||||
marker: std::marker::PhantomData<CS>,
|
||||
}
|
||||
impl<'de, CS: CipherSuite> serde::de::Visitor<'de> for ByteVisitor<CS> {
|
||||
type Value = $t<CS>;
|
||||
fn expecting(
|
||||
&self,
|
||||
formatter: &mut std::fmt::Formatter,
|
||||
) -> std::fmt::Result {
|
||||
formatter.write_str(std::concat!(
|
||||
"the byte representation of a ",
|
||||
std::stringify!($t)
|
||||
))
|
||||
}
|
||||
|
||||
fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
$t::<CS>::deserialize(value).map_err(|_| {
|
||||
serde::de::Error::invalid_value(
|
||||
serde::de::Unexpected::Bytes(value),
|
||||
&std::concat!(
|
||||
"invalid byte sequence for ",
|
||||
std::stringify!($t)
|
||||
),
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
deserializer.deserialize_bytes(ByteVisitor::<CS> {
|
||||
marker: std::marker::PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
@@ -450,6 +450,42 @@ fn test_registration_request() -> Result<(), ProtocolError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
#[test]
|
||||
fn test_serialization() -> Result<(), ProtocolError> {
|
||||
let parameters = populate_test_vectors(&serde_json::from_str(TEST_VECTOR).unwrap());
|
||||
let mut rng = CycleRng::new(parameters.blinding_factor.to_vec());
|
||||
let client_registration_start_result =
|
||||
ClientRegistration::<RistrettoSha5123dhNoSlowHash>::start(&mut rng, ¶meters.password)?;
|
||||
{
|
||||
// Test the json serialization (human-readable, base64).
|
||||
let registration_request_json =
|
||||
serde_json::to_string(&client_registration_start_result.message).unwrap();
|
||||
assert_eq!(
|
||||
registration_request_json,
|
||||
r#""FLqG5TAYzlUH0r+y2YrT9g4wLYJr/zQQpexmnI4e8X0=""#
|
||||
);
|
||||
let registration_request: RegistrationRequest<RistrettoSha5123dhNoSlowHash> =
|
||||
serde_json::from_str(®istration_request_json).unwrap();
|
||||
assert_eq!(
|
||||
hex::encode(client_registration_start_result.message.serialize()),
|
||||
hex::encode(registration_request.serialize()),
|
||||
);
|
||||
}
|
||||
{
|
||||
// Test the bincode serialization (binary).
|
||||
let registration_request_bin =
|
||||
bincode::serialize(&client_registration_start_result.message).unwrap();
|
||||
assert_eq!(registration_request_bin.len(), 40);
|
||||
let registration_request: RegistrationRequest<RistrettoSha5123dhNoSlowHash> =
|
||||
bincode::deserialize(®istration_request_bin).unwrap();
|
||||
assert_eq!(
|
||||
hex::encode(client_registration_start_result.message.serialize()),
|
||||
hex::encode(registration_request.serialize()),
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
#[test]
|
||||
fn test_registration_response() -> Result<(), ProtocolError> {
|
||||
let parameters = populate_test_vectors(&serde_json::from_str(TEST_VECTOR).unwrap());
|
||||
|
||||
Reference in New Issue
Block a user