Skip to content

Commit d68e273

Browse files
authored
Update RSA signature traits implementations (#179)
- Change the `SigningKey` and `VerifiyingKey` implementations accept raw message rather than pre-hashed message. - Implement the experimental (preview) `DigestSigner` and `DigestVerifier` traits for the PKCS1v15 structs. - Implement the experimental (preview) `RandomizedDigestSigner` and `DigestVerifier` traits for the PSS structs. Signed-off-by: Dmitry Baryshkov <[email protected]>
1 parent eb8bc22 commit d68e273

File tree

6 files changed

+781
-158
lines changed

6 files changed

+781
-158
lines changed

Cargo.toml

+8-3
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,17 @@ 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
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/algorithms.rs

+32-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use alloc::vec;
2-
use digest::DynDigest;
2+
use digest::{Digest, DynDigest, FixedOutputReset};
33
use num_bigint::traits::ModInverse;
44
use num_bigint::{BigUint, RandPrime};
55
#[allow(unused_imports)]
@@ -165,6 +165,37 @@ pub fn mgf1_xor(out: &mut [u8], digest: &mut dyn DynDigest, seed: &[u8]) {
165165
}
166166
}
167167

168+
/// Mask generation function.
169+
///
170+
/// Panics if out is larger than 2**32. This is in accordance with RFC 8017 - PKCS #1 B.2.1
171+
pub fn mgf1_xor_digest<D>(out: &mut [u8], digest: &mut D, seed: &[u8])
172+
where
173+
D: Digest + FixedOutputReset,
174+
{
175+
let mut counter = [0u8; 4];
176+
let mut i = 0;
177+
178+
const MAX_LEN: u64 = core::u32::MAX as u64 + 1;
179+
assert!(out.len() as u64 <= MAX_LEN);
180+
181+
while i < out.len() {
182+
Digest::update(digest, seed);
183+
Digest::update(digest, counter);
184+
185+
let digest_output = digest.finalize_reset();
186+
let mut j = 0;
187+
loop {
188+
if j >= digest_output.len() || i >= out.len() {
189+
break;
190+
}
191+
192+
out[i] ^= digest_output[j];
193+
j += 1;
194+
i += 1;
195+
}
196+
inc_counter(&mut counter);
197+
}
198+
}
168199
fn inc_counter(counter: &mut [u8; 4]) {
169200
for i in (0..4).rev() {
170201
counter[i] = counter[i].wrapping_add(1);

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

+30-28
Original file line numberDiff line numberDiff line change
@@ -47,29 +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::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 digest = Sha256::digest(data).to_vec();
67-
//! let signature = signing_key.sign_with_rng(&mut rng, &digest);
68-
//! assert_ne!(signature.as_bytes(), data);
69-
//!
70-
//! // Verify
71-
//! verifying_key.verify(&digest, &signature).expect("failed to verify");
72-
//! ```
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+
)]
7376
//!
7477
//! Using PSS signatures
7578
//! ```
@@ -82,17 +85,16 @@
8285
//!
8386
//! let bits = 2048;
8487
//! let private_key = RsaPrivateKey::new(&mut rng, bits).expect("failed to generate a key");
85-
//! let signing_key = BlindedSigningKey::new(private_key, Box::new(Sha256::new()));
86-
//! let verifying_key: VerifyingKey = (&signing_key).into();
88+
//! let signing_key = BlindedSigningKey::<Sha256>::new(private_key);
89+
//! let verifying_key: VerifyingKey<_> = (&signing_key).into();
8790
//!
8891
//! // Sign
8992
//! let data = b"hello world";
90-
//! let digest = Sha256::digest(data).to_vec();
91-
//! let signature = signing_key.sign_with_rng(&mut rng, &digest);
93+
//! let signature = signing_key.sign_with_rng(&mut rng, data);
9294
//! assert_ne!(signature.as_bytes(), data);
9395
//!
9496
//! // Verify
95-
//! verifying_key.verify(&digest, &signature).expect("failed to verify");
97+
//! verifying_key.verify(data, &signature).expect("failed to verify");
9698
//! ```
9799
//!
98100
//! ## PKCS#1 RSA Key Encoding

0 commit comments

Comments
 (0)