Skip to content

Commit

Permalink
added serdect support (#420)
Browse files Browse the repository at this point in the history
Co-authored-by: Tony Arcieri <bascule@gmail.com>
  • Loading branch information
LWEdslev and tarcieri committed Apr 5, 2024
1 parent e54fb7d commit 4512b5a
Show file tree
Hide file tree
Showing 15 changed files with 661 additions and 82 deletions.
37 changes: 27 additions & 10 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ zeroize = { version = "1.5", features = ["alloc"] }

# optional dependencies
sha1 = { version = "=0.11.0-pre.3", optional = true, default-features = false, features = ["oid"] }
serdect = { version = "0.2.0", optional = true }
sha2 = { version = "=0.11.0-pre.3", optional = true, default-features = false, features = ["oid"] }
serde = { version = "1.0.184", optional = true, default-features = false, features = ["derive"] }

Expand All @@ -52,7 +53,7 @@ default = ["std", "pem", "u64_digit"]
hazmat = []
getrandom = ["rand_core/getrandom"]
nightly = ["num-bigint/nightly"]
serde = ["dep:serde", "num-bigint/serde"]
serde = ["dep:serde", "dep:serdect", "num-bigint/serde"]
pem = ["pkcs1/pem", "pkcs8/pem"]
pkcs5 = ["pkcs8/encryption"]
u64_digit = ["num-bigint/u64_digit"]
Expand Down
2 changes: 1 addition & 1 deletion src/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use zeroize::Zeroizing;
pub const ID_RSASSA_PSS: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.10");

/// Verify that the `AlgorithmIdentifier` for a key is correct.
fn verify_algorithm_id(algorithm: &pkcs8::AlgorithmIdentifierRef) -> pkcs8::spki::Result<()> {
pub(crate) fn verify_algorithm_id(algorithm: &pkcs8::AlgorithmIdentifierRef) -> pkcs8::spki::Result<()> {
match algorithm.oid {
pkcs1::ALGORITHM_OID => {
if algorithm.parameters_any()? != pkcs8::der::asn1::Null.into() {
Expand Down
120 changes: 61 additions & 59 deletions src/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@ use num_bigint::{BigInt, BigUint};
use num_integer::Integer;
use num_traits::{FromPrimitive, One, ToPrimitive};
use rand_core::CryptoRngCore;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use zeroize::{Zeroize, ZeroizeOnDrop};
#[cfg(feature = "serde")]
use {
serdect::serde::{de, ser, Deserialize, Serialize},
spki::{EncodePublicKey, DecodePublicKey},
pkcs8::{EncodePrivateKey, DecodePrivateKey}
};

use crate::algorithms::generate::generate_multi_prime_key_with_exp;
use crate::algorithms::rsa::{
Expand All @@ -23,7 +27,6 @@ use crate::CrtValue;

/// Represents the public part of an RSA key.
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct RsaPublicKey {
/// Modulus: product of prime numbers `p` and `q`
n: BigUint,
Expand All @@ -36,7 +39,6 @@ pub struct RsaPublicKey {

/// Represents a whole RSA key, public and private parts.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct RsaPrivateKey {
/// Public components of the private key.
pubkey_components: RsaPublicKey,
Expand All @@ -45,7 +47,6 @@ pub struct RsaPrivateKey {
/// Prime factors of N, contains >= 2 elements.
pub(crate) primes: Vec<BigUint>,
/// precomputed values to speed up private operations
#[cfg_attr(feature = "serde", serde(skip))]
pub(crate) precomputed: Option<PrecomputedValues>,
}

Expand Down Expand Up @@ -531,6 +532,50 @@ fn check_public_with_max_size(public_key: &impl PublicKeyParts, max_size: usize)
Ok(())
}

#[cfg(feature = "serde")]
impl Serialize for RsaPublicKey {
fn serialize<S>(&self, serializer: S) -> core::prelude::v1::Result<S::Ok, S::Error>
where
S: serdect::serde::Serializer,
{
let der = self.to_public_key_der().map_err(ser::Error::custom)?;
serdect::slice::serialize_hex_lower_or_bin(&der, serializer)
}
}

#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for RsaPublicKey {
fn deserialize<D>(deserializer: D) -> core::prelude::v1::Result<Self, D::Error>
where
D: serdect::serde::Deserializer<'de>,
{
let der_bytes = serdect::slice::deserialize_hex_or_bin_vec(deserializer)?;
Self::from_public_key_der(&der_bytes).map_err(de::Error::custom)
}
}

#[cfg(feature = "serde")]
impl Serialize for RsaPrivateKey {
fn serialize<S>(&self, serializer: S) -> core::prelude::v1::Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
let der = self.to_pkcs8_der().map_err(ser::Error::custom)?;
serdect::slice::serialize_hex_lower_or_bin(&der.as_bytes(), serializer)
}
}

#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for RsaPrivateKey {
fn deserialize<D>(deserializer: D) -> core::prelude::v1::Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
let der_bytes = serdect::slice::deserialize_hex_or_bin_vec(deserializer)?;
Self::from_pkcs8_der(&der_bytes).map_err(de::Error::custom)
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -640,66 +685,23 @@ mod tests {
#[cfg(feature = "serde")]
fn test_serde() {
use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng};
use serde_test::{assert_tokens, Token};
use serde_test::{assert_tokens, Configure, Token};

let mut rng = ChaCha8Rng::from_seed([42; 32]);
let priv_key = RsaPrivateKey::new(&mut rng, 64).expect("failed to generate key");

let priv_tokens = [
Token::Struct {
name: "RsaPrivateKey",
len: 3,
},
Token::Str("pubkey_components"),
Token::Struct {
name: "RsaPublicKey",
len: 2,
},
Token::Str("n"),
Token::Seq { len: Some(2) },
Token::U32(3814409919),
Token::U32(3429654832),
Token::SeqEnd,
Token::Str("e"),
Token::Seq { len: Some(1) },
Token::U32(65537),
Token::SeqEnd,
Token::StructEnd,
Token::Str("d"),
Token::Seq { len: Some(2) },
Token::U32(1482162201),
Token::U32(1675500232),
Token::SeqEnd,
Token::Str("primes"),
Token::Seq { len: Some(2) },
Token::Seq { len: Some(1) },
Token::U32(4133289821),
Token::SeqEnd,
Token::Seq { len: Some(1) },
Token::U32(3563808971),
Token::SeqEnd,
Token::SeqEnd,
Token::StructEnd,
];
assert_tokens(&priv_key, &priv_tokens);

let priv_tokens = [
Token::Struct {
name: "RsaPublicKey",
len: 2,
},
Token::Str("n"),
Token::Seq { len: Some(2) },
Token::U32(3814409919),
Token::U32(3429654832),
Token::SeqEnd,
Token::Str("e"),
Token::Seq { len: Some(1) },
Token::U32(65537),
Token::SeqEnd,
Token::StructEnd,
Token::Str("3054020100300d06092a864886f70d01010105000440303e020100020900cc6c6130e35b46bf0203010001020863de1ac858580019020500f65cff5d020500d46b68cb02046d9a09f102047b4e3a4f020500f45065cc")
];
assert_tokens(&RsaPublicKey::from(priv_key), &priv_tokens);
assert_tokens(&priv_key.clone().readable(), &priv_tokens);

let priv_tokens = [Token::Str(
"3024300d06092a864886f70d01010105000313003010020900cc6c6130e35b46bf0203010001",
)];
assert_tokens(
&RsaPublicKey::from(priv_key.clone()).readable(),
&priv_tokens,
);
}

#[test]
Expand Down
44 changes: 44 additions & 0 deletions src/oaep/decrypting_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,15 @@ use alloc::{
use core::marker::PhantomData;
use digest::{Digest, FixedOutputReset};
use rand_core::CryptoRngCore;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use zeroize::ZeroizeOnDrop;

/// Decryption key for PKCS#1 v1.5 decryption as described in [RFC8017 § 7.1].
///
/// [RFC8017 § 7.1]: https://datatracker.ietf.org/doc/html/rfc8017#section-7.1
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct DecryptingKey<D, MGD = D>
where
D: Digest,
Expand Down Expand Up @@ -94,3 +97,44 @@ where
MGD: Digest + FixedOutputReset,
{
}

impl<D, MGD> PartialEq for DecryptingKey<D, MGD>
where
D: Digest,
MGD: Digest + FixedOutputReset,
{
fn eq(&self, other: &Self) -> bool {
self.inner == other.inner && self.label == other.label
}
}

#[cfg(test)]
mod tests {
#[test]
#[cfg(feature = "serde")]
fn test_serde() {
use super::*;
use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng};
use serde_test::{assert_tokens, Configure, Token};
use sha2::Sha256;

let mut rng = ChaCha8Rng::from_seed([42; 32]);
let decrypting_key = DecryptingKey::<Sha256>::new(
RsaPrivateKey::new(&mut rng, 64).expect("failed to generate key"),
);

let tokens = [
Token::Struct { name: "DecryptingKey", len: 4 },
Token::Str("inner"),
Token::Str("3054020100300d06092a864886f70d01010105000440303e020100020900cc6c6130e35b46bf0203010001020863de1ac858580019020500f65cff5d020500d46b68cb02046d9a09f102047b4e3a4f020500f45065cc"),
Token::Str("label"),
Token::None,
Token::Str("phantom"),
Token::UnitStruct { name: "PhantomData", },
Token::Str("mg_phantom"),
Token::UnitStruct { name: "PhantomData", },
Token::StructEnd,
];
assert_tokens(&decrypting_key.readable(), &tokens);
}
}

0 comments on commit 4512b5a

Please sign in to comment.