Skip to content

Commit efb9749

Browse files
committed
Implement DigestSigner/Verifier for PKCS1v15 structs
Implement the experimental (preview) DigestSigner and DigestVerifier traits for the PKCS1v15 structs. Signed-off-by: Dmitry Baryshkov <[email protected]>
1 parent 65da94d commit efb9749

File tree

2 files changed

+119
-2
lines changed

2 files changed

+119
-2
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ digest = { version = "0.10.0", default-features = false, features = ["alloc"] }
2424
pkcs1 = { version = "0.4", default-features = false, features = ["pkcs8", "alloc"] }
2525
pkcs8 = { version = "0.9", default-features = false, features = ["alloc"] }
2626
#To keep the rand_core versions properly pinnen, specify exact version
27-
signature = { version = ">=1.5, <1.7", default-features = false , features = ["rand-preview"] }
27+
signature = { version = ">=1.5, <1.7", default-features = false , features = ["digest-preview", "rand-preview"] }
2828
zeroize = { version = "1", features = ["alloc"] }
2929

3030
# Temporary workaround until https://github.com/dignifiedquire/num-bigint/pull/42 lands

src/pkcs1v15.rs

Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ use core::fmt::{Debug, Display, Formatter, LowerHex, UpperHex};
44
use core::marker::PhantomData;
55
use digest::Digest;
66
use rand_core::{CryptoRng, RngCore};
7-
use signature::{RandomizedSigner, Signature as SignSignature, Signer, Verifier};
7+
use signature::{
8+
DigestSigner, DigestVerifier, RandomizedDigestSigner, RandomizedSigner,
9+
Signature as SignSignature, Signer, Verifier,
10+
};
811
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
912
use zeroize::Zeroizing;
1013

@@ -356,6 +359,37 @@ where
356359
}
357360
}
358361

362+
impl<D> DigestSigner<D, Signature> for SigningKey<D>
363+
where
364+
D: Digest,
365+
{
366+
fn try_sign_digest(&self, digest: D) -> signature::Result<Signature> {
367+
sign::<DummyRng, _>(None, &self.inner, self.hash.as_ref(), &digest.finalize())
368+
.map(|v| v.into())
369+
.map_err(|e| e.into())
370+
}
371+
}
372+
373+
impl<D> RandomizedDigestSigner<D, Signature> for SigningKey<D>
374+
where
375+
D: Digest,
376+
{
377+
fn try_sign_digest_with_rng(
378+
&self,
379+
mut rng: impl CryptoRng + RngCore,
380+
digest: D,
381+
) -> signature::Result<Signature> {
382+
sign(
383+
Some(&mut rng),
384+
&self.inner,
385+
self.hash.as_ref(),
386+
&digest.finalize(),
387+
)
388+
.map(|v| v.into())
389+
.map_err(|e| e.into())
390+
}
391+
}
392+
359393
pub struct VerifyingKey<D>
360394
where
361395
D: Digest,
@@ -427,6 +461,21 @@ where
427461
}
428462
}
429463

464+
impl<D> DigestVerifier<D, Signature> for VerifyingKey<D>
465+
where
466+
D: Digest,
467+
{
468+
fn verify_digest(&self, digest: D, signature: &Signature) -> signature::Result<()> {
469+
verify(
470+
&self.inner,
471+
self.hash.as_ref(),
472+
&digest.finalize(),
473+
signature.as_ref(),
474+
)
475+
.map_err(|e| e.into())
476+
}
477+
}
478+
430479
#[cfg(test)]
431480
mod tests {
432481
use super::*;
@@ -588,6 +637,36 @@ mod tests {
588637
}
589638
}
590639

640+
#[test]
641+
fn test_sign_pkcs1v15_digest_signer() {
642+
let priv_key = get_private_key();
643+
644+
let tests = [(
645+
"Test.\n",
646+
hex!(
647+
"a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
648+
"6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362ae"
649+
),
650+
)];
651+
652+
let signing_key = SigningKey::new_with_hash(priv_key, Hash::SHA1);
653+
654+
for (text, expected) in &tests {
655+
let mut digest = Sha1::new();
656+
digest.update(text.as_bytes());
657+
let out = signing_key.sign_digest(digest);
658+
assert_ne!(out.as_ref(), text.as_bytes());
659+
assert_ne!(out.as_ref(), &Sha1::digest(text.as_bytes()).to_vec());
660+
assert_eq!(out.as_ref(), expected);
661+
662+
let mut rng = ChaCha8Rng::from_seed([42; 32]);
663+
let mut digest = Sha1::new();
664+
digest.update(text.as_bytes());
665+
let out2 = signing_key.sign_digest_with_rng(&mut rng, digest);
666+
assert_eq!(out2.as_ref(), expected);
667+
}
668+
}
669+
591670
#[test]
592671
fn test_verify_pkcs1v15() {
593672
let priv_key = get_private_key();
@@ -668,6 +747,44 @@ mod tests {
668747
}
669748
}
670749

750+
#[test]
751+
fn test_verify_pkcs1v15_digest_signer() {
752+
let priv_key = get_private_key();
753+
754+
let tests = [
755+
(
756+
"Test.\n",
757+
hex!(
758+
"a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
759+
"6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362ae"
760+
),
761+
true,
762+
),
763+
(
764+
"Test.\n",
765+
hex!(
766+
"a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
767+
"6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362af"
768+
),
769+
false,
770+
),
771+
];
772+
let pub_key: RsaPublicKey = priv_key.into();
773+
let verifying_key = VerifyingKey::new_with_hash(pub_key, Hash::SHA1);
774+
775+
for (text, sig, expected) in &tests {
776+
let mut digest = Sha1::new();
777+
digest.update(text.as_bytes());
778+
let result = verifying_key.verify_digest(digest, &Signature::from_bytes(sig).unwrap());
779+
match expected {
780+
true => result.expect("failed to verify"),
781+
false => {
782+
result.expect_err("expected verifying error");
783+
()
784+
}
785+
}
786+
}
787+
}
671788
#[test]
672789
fn test_unpadded_signature() {
673790
let msg = b"Thu Dec 19 18:06:16 EST 2013\n";

0 commit comments

Comments
 (0)