diff --git a/Cargo.lock b/Cargo.lock index 1fd1cb333..d23041fd5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1258,11 +1258,12 @@ dependencies = [ name = "sec1" version = "0.3.0-pre.3" dependencies = [ + "base16ct 0.1.1", "der 0.6.0-pre.4", "generic-array", "hex-literal", "pkcs8 0.9.0-pre.3", - "serde", + "serdect", "subtle", "tempfile", "zeroize", @@ -1329,7 +1330,7 @@ dependencies = [ name = "serdect" version = "0.1.0" dependencies = [ - "base16ct 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "base16ct 0.1.1", "bincode", "ciborium", "hex-literal", diff --git a/sec1/Cargo.toml b/sec1/Cargo.toml index 9604a805a..09d1bc409 100644 --- a/sec1/Cargo.toml +++ b/sec1/Cargo.toml @@ -16,10 +16,11 @@ edition = "2021" rust-version = "1.57" [dependencies] +base16ct = { version = "0.1.1", optional = true, default-features = false, path = "../base16ct" } der = { version = "=0.6.0-pre.4", optional = true, features = ["oid"], path = "../der" } generic-array = { version = "0.14.4", optional = true, default-features = false } pkcs8 = { version = "=0.9.0-pre.3", optional = true, default-features = false, path = "../pkcs8" } -serde = { version = "1.0.16", optional = true, default-features = false } +serdect = { version = "0.1", optional = true, default-features = false, features = ["alloc"], path = "../serdect" } subtle = { version = "2", optional = true, default-features = false } zeroize = { version = "1", optional = true, default-features = false } @@ -31,7 +32,8 @@ tempfile = "3" default = ["der", "point"] alloc = ["der/alloc", "pkcs8/alloc", "zeroize/alloc"] pem = ["alloc", "der/pem", "pkcs8/pem"] -point = ["generic-array"] +point = ["base16ct", "generic-array"] +serde = ["serdect"] std = ["der/std", "alloc"] [package.metadata.docs.rs] diff --git a/sec1/src/lib.rs b/sec1/src/lib.rs index c92e54fb9..229d25762 100644 --- a/sec1/src/lib.rs +++ b/sec1/src/lib.rs @@ -63,6 +63,9 @@ pub use pkcs8; #[cfg(feature = "pkcs8")] use pkcs8::ObjectIdentifier; +#[cfg(all(doc, feature = "serde"))] +use serdect::serde; + /// Algorithm [`ObjectIdentifier`] for elliptic curve public key cryptography /// (`id-ecPublicKey`). /// diff --git a/sec1/src/point.rs b/sec1/src/point.rs index 8568c64af..eb0d2ca62 100644 --- a/sec1/src/point.rs +++ b/sec1/src/point.rs @@ -6,6 +6,7 @@ //! [SEC1: Elliptic Curve Cryptography]: https://www.secg.org/sec1-v2.pdf use crate::{Error, Result}; +use base16ct::HexDisplay; use core::{ cmp::Ordering, fmt::{self, Debug}, @@ -21,7 +22,7 @@ use generic_array::{ use alloc::boxed::Box; #[cfg(feature = "serde")] -use serde::{de, ser, Deserialize, Serialize}; +use serdect::serde::{de, ser, Deserialize, Serialize}; #[cfg(feature = "subtle")] use subtle::{Choice, ConditionallySelectable}; @@ -348,10 +349,7 @@ where Size: ModulusSize, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - for byte in self.as_bytes() { - write!(f, "{:02x}", byte)?; - } - Ok(()) + write!(f, "{:x}", HexDisplay(self.as_bytes())) } } @@ -360,10 +358,7 @@ where Size: ModulusSize, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - for byte in self.as_bytes() { - write!(f, "{:02X}", byte)?; - } - Ok(()) + write!(f, "{:X}", HexDisplay(self.as_bytes())) } } @@ -378,41 +373,10 @@ where type Err = Error; fn from_str(hex: &str) -> Result { - let mut buffer = GenericArray::::default(); - let decoded_len = hex.as_bytes().len() / 2; - - if hex.as_bytes().len() % 2 != 0 || decoded_len > buffer.len() { - return Err(Error::PointEncoding); - } - - let mut upper_case = None; - - // Ensure all characters are valid and case is not mixed - for &byte in hex.as_bytes() { - match byte { - b'0'..=b'9' => (), - b'a'..=b'z' => match upper_case { - Some(true) => return Err(Error::PointEncoding), - Some(false) => (), - None => upper_case = Some(false), - }, - b'A'..=b'Z' => match upper_case { - Some(true) => (), - Some(false) => return Err(Error::PointEncoding), - None => upper_case = Some(true), - }, - _ => return Err(Error::PointEncoding), - } - } - - for (digit, byte) in hex.as_bytes().chunks_exact(2).zip(buffer.iter_mut()) { - *byte = str::from_utf8(digit) - .ok() - .and_then(|s| u8::from_str_radix(s, 16).ok()) - .ok_or(Error::PointEncoding)?; - } - - Self::from_bytes(&buffer[..decoded_len]) + let mut buf = GenericArray::::default(); + base16ct::mixed::decode(hex, &mut buf) + .map_err(|_| Error::PointEncoding) + .and_then(Self::from_bytes) } } @@ -422,25 +386,11 @@ impl Serialize for EncodedPoint where Size: ModulusSize, { - #[cfg(not(feature = "alloc"))] fn serialize(&self, serializer: S) -> core::result::Result where S: ser::Serializer, { - self.as_bytes().serialize(serializer) - } - - #[cfg(feature = "alloc")] - fn serialize(&self, serializer: S) -> core::result::Result - where - S: ser::Serializer, - { - use alloc::string::ToString; - if serializer.is_human_readable() { - self.to_string().serialize(serializer) - } else { - self.as_bytes().serialize(serializer) - } + serdect::slice::serialize_hex_upper_or_bin(&self.as_bytes(), serializer) } } @@ -450,30 +400,12 @@ impl<'de, Size> Deserialize<'de> for EncodedPoint where Size: ModulusSize, { - #[cfg(not(feature = "alloc"))] - fn deserialize(deserializer: D) -> core::result::Result - where - D: de::Deserializer<'de>, - { - use de::Error; - <&[u8]>::deserialize(deserializer) - .and_then(|slice| Self::from_bytes(slice).map_err(D::Error::custom)) - } - - #[cfg(feature = "alloc")] fn deserialize(deserializer: D) -> core::result::Result where D: de::Deserializer<'de>, { - use de::Error; - if deserializer.is_human_readable() { - <&str>::deserialize(deserializer)? - .parse() - .map_err(D::Error::custom) - } else { - <&[u8]>::deserialize(deserializer) - .and_then(|bytes| Self::from_bytes(bytes).map_err(D::Error::custom)) - } + let bytes = serdect::slice::deserialize_hex_or_bin_vec(deserializer)?; + Self::from_bytes(&bytes).map_err(de::Error::custom) } } diff --git a/serdect/Cargo.toml b/serdect/Cargo.toml index bcf529fe7..799d30416 100644 --- a/serdect/Cargo.toml +++ b/serdect/Cargo.toml @@ -15,8 +15,8 @@ edition = "2021" rust-version = "1.56" [dependencies] -base16ct = { version = "0.1.1", default-features = false } -serde = { version = "1", default-features = false } +base16ct = { version = "0.1.1", default-features = false, path = "../base16ct" } +serde = { version = "1.0.96", default-features = false } # optional features zeroize = { version = "1", optional = true, default-features = false }