Skip to content

Commit 841f744

Browse files
committed
pkcs1: remove duplication between Digest generic and hash argument
There is an information duplication when the keys are expected to generate signatures over the ASN.1-prefixed data: SigningKey::<Sha256>::new_with_hash(private_key, Hash::SHA2_256); Remove this duplication by adding the AssociatedHash trait and implementing it for sha1/sha2/sha3 types. Note, this trait should morph into DynAssociatedOid trait and be implemented directly for the corresponding digest implementations. Signed-off-by: Dmitry Baryshkov <[email protected]>
1 parent 4750052 commit 841f744

File tree

4 files changed

+125
-48
lines changed

4 files changed

+125
-48
lines changed

Cargo.toml

+7-2
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ zeroize = { version = "1", features = ["alloc"] }
3030
# Temporary workaround until https://github.com/dignifiedquire/num-bigint/pull/42 lands
3131
smallvec = { version = "1.6.1", default-features = false }
3232

33+
# Temporary until the link from Digest to OID is moved to corresponding crates
34+
sha1 = { version = "0.10.1", default-features = false, optional = true }
35+
sha2 = { version = "0.10.2", default-features = false, optional = true }
36+
sha3 = { version = "0.10.1", default-features = false, optional = true }
37+
3338
[dependencies.serde_crate]
3439
package = "serde"
3540
optional = true
@@ -53,7 +58,7 @@ sha3 = { version = "0.10.1", default-features = false }
5358
name = "key"
5459

5560
[features]
56-
default = ["std", "pem"]
61+
default = ["std", "pem", "sha2"]
5762
nightly = ["num-bigint/nightly"]
5863
serde = ["num-bigint/serde", "serde_crate"]
5964
expose-internals = []
@@ -63,7 +68,7 @@ pkcs5 = ["pkcs8/encryption"]
6368
getrandom = ["rand_core/getrandom"]
6469

6570
[package.metadata.docs.rs]
66-
features = ["std", "pem", "serde", "expose-internals"]
71+
features = ["std", "pem", "serde", "expose-internals", "sha1", "sha2", "sha3"]
6772
rustdoc-args = ["--cfg", "docsrs"]
6873

6974
[profile.dev]

src/hash.rs

+52
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,55 @@ impl Hash {
8383
}
8484
}
8585
}
86+
87+
/* FIXME: This trait should be refactored into per-digest implementations returning OID */
88+
pub trait AssociatedHash {
89+
const HASH: Hash;
90+
}
91+
92+
#[cfg(feature = "sha1")]
93+
impl AssociatedHash for sha1::Sha1 {
94+
const HASH: Hash = Hash::SHA1;
95+
}
96+
97+
#[cfg(feature = "sha2")]
98+
impl AssociatedHash for sha2::Sha224 {
99+
const HASH: Hash = Hash::SHA2_224;
100+
}
101+
102+
#[cfg(feature = "sha2")]
103+
impl AssociatedHash for sha2::Sha256 {
104+
const HASH: Hash = Hash::SHA2_256;
105+
}
106+
107+
#[cfg(feature = "sha2")]
108+
impl AssociatedHash for sha2::Sha384 {
109+
const HASH: Hash = Hash::SHA2_384;
110+
}
111+
112+
#[cfg(feature = "sha2")]
113+
impl AssociatedHash for sha2::Sha512 {
114+
const HASH: Hash = Hash::SHA2_512;
115+
}
116+
117+
/*
118+
#[cfg(feature = "sha3")]
119+
impl AssociatedHash for sha3::Sha3_224 {
120+
const HASH: Hash = Hash::SHA3_224;
121+
}
122+
*/
123+
124+
#[cfg(feature = "sha3")]
125+
impl AssociatedHash for sha3::Sha3_256 {
126+
const HASH: Hash = Hash::SHA3_256;
127+
}
128+
129+
#[cfg(feature = "sha3")]
130+
impl AssociatedHash for sha3::Sha3_384 {
131+
const HASH: Hash = Hash::SHA3_384;
132+
}
133+
134+
#[cfg(feature = "sha3")]
135+
impl AssociatedHash for sha3::Sha3_512 {
136+
const HASH: Hash = Hash::SHA3_512;
137+
}

src/lib.rs

+26-22
Original file line numberDiff line numberDiff line change
@@ -47,28 +47,32 @@
4747
//! assert_eq!(&data[..], &dec_data[..]);
4848
//! ```
4949
//!
50-
//! Using PKCS1v15 signatures
51-
//! ```
52-
//! use rsa::{Hash, RsaPrivateKey};
53-
//! use rsa::pkcs1v15::{SigningKey, VerifyingKey};
54-
//! use sha2::{Digest, Sha256};
55-
//! use signature::{RandomizedSigner, Signature, Verifier};
56-
//!
57-
//! let mut rng = rand::thread_rng();
58-
//!
59-
//! let bits = 2048;
60-
//! let private_key = RsaPrivateKey::new(&mut rng, bits).expect("failed to generate a key");
61-
//! let signing_key = SigningKey::<Sha256>::new_with_hash(private_key, Hash::SHA2_256);
62-
//! let verifying_key: VerifyingKey<_> = (&signing_key).into();
63-
//!
64-
//! // Sign
65-
//! let data = b"hello world";
66-
//! let signature = signing_key.sign_with_rng(&mut rng, data);
67-
//! assert_ne!(signature.as_bytes(), data);
68-
//!
69-
//! // Verify
70-
//! verifying_key.verify(data, &signature).expect("failed to verify");
71-
//! ```
50+
#![cfg_attr(
51+
feature = "sha2",
52+
doc = r#"
53+
Using PKCS1v15 signatures
54+
```
55+
use rsa::{Hash, RsaPrivateKey};
56+
use rsa::pkcs1v15::{SigningKey, VerifyingKey};
57+
use sha2::{Digest, Sha256};
58+
use signature::{RandomizedSigner, Signature, Verifier};
59+
60+
let mut rng = rand::thread_rng();
61+
62+
let bits = 2048;
63+
let private_key = RsaPrivateKey::new(&mut rng, bits).expect("failed to generate a key");
64+
let signing_key = SigningKey::<Sha256>::new_with_prefix(private_key);
65+
let verifying_key: VerifyingKey<_> = (&signing_key).into();
66+
67+
// Sign
68+
let data = b"hello world";
69+
let signature = signing_key.sign_with_rng(&mut rng, data);
70+
assert_ne!(signature.as_bytes(), data);
71+
72+
// Verify
73+
verifying_key.verify(data, &signature).expect("failed to verify");
74+
```"#
75+
)]
7276
//!
7377
//! Using PSS signatures
7478
//! ```

src/pkcs1v15.rs

+40-24
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use zeroize::Zeroizing;
1313

1414
use crate::dummy_rng::DummyRng;
1515
use crate::errors::{Error, Result};
16-
use crate::hash::Hash;
16+
use crate::hash::{AssociatedHash, Hash};
1717
use crate::key::{self, PrivateKey, PublicKey};
1818
use crate::{RsaPrivateKey, RsaPublicKey};
1919

@@ -318,11 +318,16 @@ where
318318
phantom: Default::default(),
319319
}
320320
}
321+
}
321322

322-
pub fn new_with_hash(key: RsaPrivateKey, hash: Hash) -> Self {
323+
impl<D> SigningKey<D>
324+
where
325+
D: Digest + AssociatedHash,
326+
{
327+
pub fn new_with_prefix(key: RsaPrivateKey) -> Self {
323328
Self {
324329
inner: key,
325-
hash: Some(hash),
330+
hash: Some(D::HASH),
326331
phantom: Default::default(),
327332
}
328333
}
@@ -410,11 +415,16 @@ where
410415
phantom: Default::default(),
411416
}
412417
}
418+
}
413419

414-
pub fn new_with_hash(key: RsaPublicKey, hash: Hash) -> Self {
420+
impl<D> VerifyingKey<D>
421+
where
422+
D: Digest + AssociatedHash,
423+
{
424+
pub fn new_with_prefix(key: RsaPublicKey) -> Self {
415425
Self {
416426
inner: key,
417-
hash: Some(hash),
427+
hash: Some(D::HASH),
418428
phantom: Default::default(),
419429
}
420430
}
@@ -486,6 +496,8 @@ mod tests {
486496
use num_traits::Num;
487497
use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng};
488498
use sha1::{Digest, Sha1};
499+
#[cfg(feature = "sha2")]
500+
use sha2::Sha256;
489501
use signature::{RandomizedSigner, Signature, Signer, Verifier};
490502

491503
use crate::{Hash, PaddingScheme, PublicKey, PublicKeyParts, RsaPrivateKey, RsaPublicKey};
@@ -611,19 +623,20 @@ mod tests {
611623
}
612624
}
613625

626+
#[cfg(feature = "sha2")]
614627
#[test]
615628
fn test_sign_pkcs1v15_signer() {
616629
let priv_key = get_private_key();
617630

618631
let tests = [(
619632
"Test.\n",
620633
hex!(
621-
"a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
622-
"6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362ae"
634+
"2ffae3f3e130287b3a1dcb320e46f52e8f3f7969b646932273a7e3a6f2a182ea"
635+
"02d42875a7ffa4a148aa311f9e4b562e4e13a2223fb15f4e5bf5f2b206d9451b"
623636
),
624637
)];
625638

626-
let signing_key = SigningKey::<Sha1>::new_with_hash(priv_key, Hash::SHA1);
639+
let signing_key = SigningKey::<Sha256>::new_with_prefix(priv_key);
627640

628641
for (text, expected) in &tests {
629642
let out = signing_key.sign(text.as_bytes());
@@ -637,30 +650,31 @@ mod tests {
637650
}
638651
}
639652

653+
#[cfg(feature = "sha2")]
640654
#[test]
641655
fn test_sign_pkcs1v15_digest_signer() {
642656
let priv_key = get_private_key();
643657

644658
let tests = [(
645659
"Test.\n",
646660
hex!(
647-
"a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
648-
"6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362ae"
661+
"2ffae3f3e130287b3a1dcb320e46f52e8f3f7969b646932273a7e3a6f2a182ea"
662+
"02d42875a7ffa4a148aa311f9e4b562e4e13a2223fb15f4e5bf5f2b206d9451b"
649663
),
650664
)];
651665

652-
let signing_key = SigningKey::new_with_hash(priv_key, Hash::SHA1);
666+
let signing_key = SigningKey::new_with_prefix(priv_key);
653667

654668
for (text, expected) in &tests {
655-
let mut digest = Sha1::new();
669+
let mut digest = Sha256::new();
656670
digest.update(text.as_bytes());
657671
let out = signing_key.sign_digest(digest);
658672
assert_ne!(out.as_ref(), text.as_bytes());
659673
assert_ne!(out.as_ref(), &Sha1::digest(text.as_bytes()).to_vec());
660674
assert_eq!(out.as_ref(), expected);
661675

662676
let mut rng = ChaCha8Rng::from_seed([42; 32]);
663-
let mut digest = Sha1::new();
677+
let mut digest = Sha256::new();
664678
digest.update(text.as_bytes());
665679
let out2 = signing_key.sign_digest_with_rng(&mut rng, digest);
666680
assert_eq!(out2.as_ref(), expected);
@@ -709,6 +723,7 @@ mod tests {
709723
}
710724
}
711725

726+
#[cfg(feature = "sha2")]
712727
#[test]
713728
fn test_verify_pkcs1v15_signer() {
714729
let priv_key = get_private_key();
@@ -717,22 +732,22 @@ mod tests {
717732
(
718733
"Test.\n",
719734
hex!(
720-
"a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
721-
"6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362ae"
735+
"2ffae3f3e130287b3a1dcb320e46f52e8f3f7969b646932273a7e3a6f2a182ea"
736+
"02d42875a7ffa4a148aa311f9e4b562e4e13a2223fb15f4e5bf5f2b206d9451b"
722737
),
723738
true,
724739
),
725740
(
726741
"Test.\n",
727742
hex!(
728-
"a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
729-
"6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362af"
743+
"2ffae3f3e130287b3a1dcb320e46f52e8f3f7969b646932273a7e3a6f2a182ea"
744+
"02d42875a7ffa4a148aa311f9e4b562e4e13a2223fb15f4e5bf5f2b206d9451c"
730745
),
731746
false,
732747
),
733748
];
734749
let pub_key: RsaPublicKey = priv_key.into();
735-
let verifying_key = VerifyingKey::<Sha1>::new_with_hash(pub_key, Hash::SHA1);
750+
let verifying_key = VerifyingKey::<Sha256>::new_with_prefix(pub_key);
736751

737752
for (text, sig, expected) in &tests {
738753
let result =
@@ -747,6 +762,7 @@ mod tests {
747762
}
748763
}
749764

765+
#[cfg(feature = "sha2")]
750766
#[test]
751767
fn test_verify_pkcs1v15_digest_signer() {
752768
let priv_key = get_private_key();
@@ -755,25 +771,25 @@ mod tests {
755771
(
756772
"Test.\n",
757773
hex!(
758-
"a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
759-
"6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362ae"
774+
"2ffae3f3e130287b3a1dcb320e46f52e8f3f7969b646932273a7e3a6f2a182ea"
775+
"02d42875a7ffa4a148aa311f9e4b562e4e13a2223fb15f4e5bf5f2b206d9451b"
760776
),
761777
true,
762778
),
763779
(
764780
"Test.\n",
765781
hex!(
766-
"a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
767-
"6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362af"
782+
"2ffae3f3e130287b3a1dcb320e46f52e8f3f7969b646932273a7e3a6f2a182ea"
783+
"02d42875a7ffa4a148aa311f9e4b562e4e13a2223fb15f4e5bf5f2b206d9451c"
768784
),
769785
false,
770786
),
771787
];
772788
let pub_key: RsaPublicKey = priv_key.into();
773-
let verifying_key = VerifyingKey::new_with_hash(pub_key, Hash::SHA1);
789+
let verifying_key = VerifyingKey::new_with_prefix(pub_key);
774790

775791
for (text, sig, expected) in &tests {
776-
let mut digest = Sha1::new();
792+
let mut digest = Sha256::new();
777793
digest.update(text.as_bytes());
778794
let result = verifying_key.verify_digest(digest, &Signature::from_bytes(sig).unwrap());
779795
match expected {

0 commit comments

Comments
 (0)