Skip to content

Commit 09391ca

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 09391ca

File tree

4 files changed

+140
-48
lines changed

4 files changed

+140
-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

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

src/lib.rs

+23-22
Original file line numberDiff line numberDiff line change
@@ -47,28 +47,29 @@
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(feature = "sha2", doc = r#"
51+
Using PKCS1v15 signatures
52+
```
53+
use rsa::{Hash, RsaPrivateKey};
54+
use rsa::pkcs1v15::{SigningKey, VerifyingKey};
55+
use sha2::{Digest, Sha256};
56+
use signature::{RandomizedSigner, Signature, Verifier};
57+
58+
let mut rng = rand::thread_rng();
59+
60+
let bits = 2048;
61+
let private_key = RsaPrivateKey::new(&mut rng, bits).expect("failed to generate a key");
62+
let signing_key = SigningKey::<Sha256>::new_with_hash(private_key);
63+
let verifying_key: VerifyingKey<_> = (&signing_key).into();
64+
65+
// Sign
66+
let data = b"hello world";
67+
let signature = signing_key.sign_with_rng(&mut rng, data);
68+
assert_ne!(signature.as_bytes(), data);
69+
70+
// Verify
71+
verifying_key.verify(data, &signature).expect("failed to verify");
72+
```"#)]
7273
//!
7374
//! Using PSS signatures
7475
//! ```

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::get_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::get_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)