From 6e97a82a34fcf2599589f59dfcb9f93ce7ae556e Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 22 Sep 2022 19:03:46 +0300 Subject: [PATCH] feat: iplement hazmat signature traits for PSS keys Implement PrehashSigner and PrehashVerifier traits for PSS key structures. Signed-off-by: Dmitry Baryshkov --- Cargo.toml | 2 +- src/pss.rs | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 9991c68..41c7855 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ subtle = { version = "2.1.1", default-features = false } digest = { version = "0.10.5", default-features = false, features = ["alloc", "oid"] } pkcs1 = { version = "0.4", default-features = false, features = ["pkcs8", "alloc"] } pkcs8 = { version = "0.9", default-features = false, features = ["alloc"] } -signature = { version = "1.6.2", default-features = false , features = ["digest-preview", "rand-preview"] } +signature = { version = "1.6.4", default-features = false , features = ["digest-preview", "rand-preview"] } zeroize = { version = "1", features = ["alloc"] } # Temporary workaround until https://github.com/dignifiedquire/num-bigint/pull/42 lands diff --git a/src/pss.rs b/src/pss.rs index cca2463..55eaeee 100644 --- a/src/pss.rs +++ b/src/pss.rs @@ -6,6 +6,8 @@ use core::marker::PhantomData; use core::ops::Deref; use digest::{Digest, DynDigest, FixedOutputReset}; use rand_core::{CryptoRng, RngCore}; +#[cfg(feature = "hazmat")] +use signature::hazmat::{PrehashVerifier, RandomizedPrehashSigner}; use signature::{ DigestVerifier, RandomizedDigestSigner, RandomizedSigner, Signature as SignSignature, Verifier, }; @@ -607,6 +609,22 @@ where } } +#[cfg(feature = "hazmat")] +impl RandomizedPrehashSigner for SigningKey +where + D: Digest + FixedOutputReset, +{ + fn sign_prehash_with_rng( + &self, + mut rng: impl CryptoRng + RngCore, + prehash: &[u8], + ) -> signature::Result { + sign_digest::<_, _, D>(&mut rng, false, &self.inner, prehash, self.salt_len) + .map(|v| v.into()) + .map_err(|e| e.into()) + } +} + impl AsRef for SigningKey where D: Digest, @@ -705,6 +723,22 @@ where } } +#[cfg(feature = "hazmat")] +impl RandomizedPrehashSigner for BlindedSigningKey +where + D: Digest + FixedOutputReset, +{ + fn sign_prehash_with_rng( + &self, + mut rng: impl CryptoRng + RngCore, + prehash: &[u8], + ) -> signature::Result { + sign_digest::<_, _, D>(&mut rng, true, &self.inner, prehash, self.salt_len) + .map(|v| v.into()) + .map_err(|e| e.into()) + } +} + impl AsRef for BlindedSigningKey where D: Digest, @@ -821,6 +855,16 @@ where } } +#[cfg(feature = "hazmat")] +impl PrehashVerifier for VerifyingKey +where + D: Digest + FixedOutputReset, +{ + fn verify_prehash(&self, prehash: &[u8], signature: &Signature) -> signature::Result<()> { + verify_digest::<_, D>(&self.inner, prehash, signature.as_ref()).map_err(|e| e.into()) + } +} + impl AsRef for VerifyingKey where D: Digest, @@ -840,6 +884,8 @@ mod test { use num_traits::{FromPrimitive, Num}; use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng}; use sha1::{Digest, Sha1}; + #[cfg(feature = "hazmat")] + use signature::hazmat::{PrehashVerifier, RandomizedPrehashSigner}; use signature::{ DigestVerifier, RandomizedDigestSigner, RandomizedSigner, Signature, Verifier, }; @@ -1093,4 +1139,77 @@ mod test { .expect("failed to verify"); } } + + #[cfg(feature = "hazmat")] + #[test] + fn test_verify_pss_hazmat() { + let priv_key = get_private_key(); + + let tests = [ + ( + Sha1::digest("test\n"), + hex!( + "6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae" + "30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962f" + ), + true, + ), + ( + Sha1::digest("test\n"), + hex!( + "6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae" + "30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962e" + ), + false, + ), + ]; + let pub_key: RsaPublicKey = priv_key.into(); + let verifying_key = VerifyingKey::::new(pub_key); + + for (text, sig, expected) in &tests { + let result = verifying_key.verify_prehash(text.as_ref(), &Signature::from_bytes(sig).unwrap()); + match expected { + true => result.expect("failed to verify"), + false => { + result.expect_err("expected verifying error"); + } + } + } + } + + #[cfg(feature = "hazmat")] + #[test] + fn test_sign_and_verify_pss_hazmat() { + let priv_key = get_private_key(); + + let tests = [Sha1::digest("test\n")]; + let mut rng = ChaCha8Rng::from_seed([42; 32]); + let signing_key = SigningKey::::new(priv_key); + let verifying_key = VerifyingKey::from(&signing_key); + + for test in &tests { + let sig = signing_key.sign_prehash_with_rng(&mut rng, &test).expect("failed to sign"); + verifying_key + .verify_prehash(&test, &sig) + .expect("failed to verify"); + } + } + + #[cfg(feature = "hazmat")] + #[test] + fn test_sign_and_verify_pss_blinded_hazmat() { + let priv_key = get_private_key(); + + let tests = [Sha1::digest("test\n")]; + let mut rng = ChaCha8Rng::from_seed([42; 32]); + let signing_key = BlindedSigningKey::::new(priv_key); + let verifying_key = VerifyingKey::from(&signing_key); + + for test in &tests { + let sig = signing_key.sign_prehash_with_rng(&mut rng, &test).expect("failed to sign"); + verifying_key + .verify_prehash(&test, &sig) + .expect("failed to verify"); + } + } }