Implement serde serialization and deserialization to follow Rust's standards.

This commit is contained in:
Marcelin Dupraz
2021-06-12 23:24:27 -07:00
committed by Kevin Lewi
parent 940d1dcdb2
commit 055e76a115
6 changed files with 143 additions and 1 deletions
Generated
+11
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+9
View File
@@ -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
+69
View File
@@ -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;
+36
View File
@@ -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, &parameters.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(&registration_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(&registration_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());