Skip to content

Commit f1e596b

Browse files
committed
RSA: add support for signature traits
Implement Signature, Signer and Verifier traits from signature crate. Signed-off-by: Dmitry Baryshkov <[email protected]>
1 parent 9212322 commit f1e596b

File tree

6 files changed

+588
-4
lines changed

6 files changed

+588
-4
lines changed

Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ subtle = { version = "2.1.1", default-features = false }
2323
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"] }
26+
signature = { version = "1.5", default-features = false , features = ["rand-preview"] }
2627
zeroize = { version = "1", features = ["alloc"] }
2728

2829
# Temporary workaround until https://github.com/dignifiedquire/num-bigint/pull/42 lands
@@ -55,7 +56,7 @@ default = ["std", "pem"]
5556
nightly = ["num-bigint/nightly"]
5657
serde = ["num-bigint/serde", "serde_crate"]
5758
expose-internals = []
58-
std = ["digest/std", "pkcs1/std", "pkcs8/std", "rand_core/std"]
59+
std = ["digest/std", "pkcs1/std", "pkcs8/std", "rand_core/std", "signature/std"]
5960
pem = ["pkcs1/pem", "pkcs8/pem"]
6061
pkcs5 = ["pkcs8/encryption"]
6162
getrandom = ["rand_core/getrandom"]

src/errors.rs

+14
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,17 @@ impl From<pkcs8::Error> for Error {
6464
Error::Pkcs8(err)
6565
}
6666
}
67+
68+
#[cfg(feature = "std")]
69+
impl From<Error> for signature::Error {
70+
fn from(err: Error) -> Self {
71+
Self::from_source(err)
72+
}
73+
}
74+
75+
#[cfg(not(feature = "std"))]
76+
impl From<Error> for signature::Error {
77+
fn from(_err: Error) -> Self {
78+
Self::new()
79+
}
80+
}

src/lib.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -163,9 +163,12 @@ mod dummy_rng;
163163
mod encoding;
164164
mod key;
165165
mod oaep;
166-
mod pkcs1v15;
167-
mod pss;
166+
pub mod pkcs1v15;
167+
pub mod pss;
168168
mod raw;
169+
mod signature;
170+
171+
pub use self::signature::Signature;
169172

170173
pub use pkcs1;
171174
pub use pkcs8;

src/pkcs1v15.rs

+249
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
use alloc::vec;
22
use alloc::vec::Vec;
33
use rand_core::{CryptoRng, RngCore};
4+
use signature::{RandomizedSigner, Signer, Verifier};
45
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
56
use zeroize::Zeroizing;
67

8+
use crate::dummy_rng::DummyRng;
79
use crate::errors::{Error, Result};
810
use crate::hash::Hash;
911
use crate::key::{self, PrivateKey, PublicKey};
12+
use crate::{PublicKeyParts, RsaPrivateKey, RsaPublicKey};
13+
14+
pub use crate::Signature;
1015

1116
// Encrypts the given message with RSA and the padding
1217
// scheme from PKCS#1 v1.5. The message must be no longer than the
@@ -214,6 +219,162 @@ fn non_zero_random_bytes<R: RngCore + CryptoRng>(rng: &mut R, data: &mut [u8]) {
214219
}
215220
}
216221

222+
pub struct RsaPkcs1v15SigningKey {
223+
inner: RsaPrivateKey,
224+
hash: Option<Hash>,
225+
}
226+
227+
impl<'a> RsaPkcs1v15SigningKey {
228+
pub(crate) fn key(&'a self) -> &'a RsaPrivateKey {
229+
&self.inner
230+
}
231+
232+
pub(crate) fn hash(&self) -> Option<Hash> {
233+
self.hash
234+
}
235+
}
236+
237+
impl From<RsaPrivateKey> for RsaPkcs1v15SigningKey {
238+
fn from(key: RsaPrivateKey) -> Self {
239+
Self {
240+
inner: key,
241+
hash: None,
242+
}
243+
}
244+
}
245+
246+
impl From<&RsaPrivateKey> for RsaPkcs1v15SigningKey {
247+
fn from(key: &RsaPrivateKey) -> Self {
248+
Self {
249+
inner: RsaPrivateKey::from_components(
250+
key.n().clone(),
251+
key.e().clone(),
252+
key.d().clone(),
253+
key.primes().clone().to_vec(),
254+
)
255+
.unwrap(),
256+
hash: None,
257+
}
258+
}
259+
}
260+
261+
impl From<(RsaPrivateKey, Hash)> for RsaPkcs1v15SigningKey {
262+
fn from(data: (RsaPrivateKey, Hash)) -> Self {
263+
let key = data.0;
264+
let hash = data.1;
265+
Self {
266+
inner: key,
267+
hash: Some(hash),
268+
}
269+
}
270+
}
271+
272+
impl From<(&RsaPrivateKey, Hash)> for RsaPkcs1v15SigningKey {
273+
fn from(data: (&RsaPrivateKey, Hash)) -> Self {
274+
let key = data.0;
275+
let hash = data.1;
276+
Self {
277+
inner: RsaPrivateKey::from_components(
278+
key.n().clone(),
279+
key.e().clone(),
280+
key.d().clone(),
281+
key.primes().clone().to_vec(),
282+
)
283+
.unwrap(),
284+
hash: Some(hash),
285+
}
286+
}
287+
}
288+
289+
impl Signer<Signature> for RsaPkcs1v15SigningKey {
290+
fn try_sign(&self, digest: &[u8]) -> signature::Result<Signature> {
291+
sign::<DummyRng, _>(None, &self.inner, self.hash.as_ref(), digest)
292+
.map(|v| v.into())
293+
.map_err(|e| e.into())
294+
}
295+
}
296+
297+
impl RandomizedSigner<Signature> for RsaPkcs1v15SigningKey {
298+
fn try_sign_with_rng(
299+
&self,
300+
mut rng: impl CryptoRng + RngCore,
301+
digest: &[u8],
302+
) -> signature::Result<Signature> {
303+
sign(Some(&mut rng), &self.inner, self.hash.as_ref(), digest)
304+
.map(|v| v.into())
305+
.map_err(|e| e.into())
306+
}
307+
}
308+
309+
pub struct RsaPkcs1v15VerifyingKey {
310+
inner: RsaPublicKey,
311+
hash: Option<Hash>,
312+
}
313+
314+
impl From<RsaPublicKey> for RsaPkcs1v15VerifyingKey {
315+
fn from(key: RsaPublicKey) -> Self {
316+
Self {
317+
inner: key,
318+
hash: None,
319+
}
320+
}
321+
}
322+
323+
impl From<&RsaPublicKey> for RsaPkcs1v15VerifyingKey {
324+
fn from(key: &RsaPublicKey) -> Self {
325+
Self {
326+
inner: RsaPublicKey::new(key.n().clone(), key.e().clone()).unwrap(),
327+
hash: None,
328+
}
329+
}
330+
}
331+
332+
impl From<(RsaPublicKey, Hash)> for RsaPkcs1v15VerifyingKey {
333+
fn from(data: (RsaPublicKey, Hash)) -> Self {
334+
let key = data.0;
335+
let hash = data.1;
336+
Self {
337+
inner: key,
338+
hash: Some(hash),
339+
}
340+
}
341+
}
342+
343+
impl From<(&RsaPublicKey, Hash)> for RsaPkcs1v15VerifyingKey {
344+
fn from(data: (&RsaPublicKey, Hash)) -> Self {
345+
let key = data.0;
346+
let hash = data.1;
347+
Self {
348+
inner: RsaPublicKey::new(key.n().clone(), key.e().clone()).unwrap(),
349+
hash: Some(hash),
350+
}
351+
}
352+
}
353+
354+
impl From<RsaPkcs1v15SigningKey> for RsaPkcs1v15VerifyingKey {
355+
fn from(key: RsaPkcs1v15SigningKey) -> Self {
356+
Self {
357+
inner: key.key().into(),
358+
hash: key.hash(),
359+
}
360+
}
361+
}
362+
363+
impl From<&RsaPkcs1v15SigningKey> for RsaPkcs1v15VerifyingKey {
364+
fn from(key: &RsaPkcs1v15SigningKey) -> Self {
365+
Self {
366+
inner: key.key().into(),
367+
hash: key.hash(),
368+
}
369+
}
370+
}
371+
372+
impl Verifier<Signature> for RsaPkcs1v15VerifyingKey {
373+
fn verify(&self, msg: &[u8], signature: &Signature) -> signature::Result<()> {
374+
verify(&self.inner, self.hash.as_ref(), msg, signature.as_ref()).map_err(|e| e.into())
375+
}
376+
}
377+
217378
#[cfg(test)]
218379
mod tests {
219380
use super::*;
@@ -224,6 +385,7 @@ mod tests {
224385
use num_traits::Num;
225386
use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng};
226387
use sha1::{Digest, Sha1};
388+
use signature::{RandomizedSigner, Signature, Signer, Verifier};
227389

228390
use crate::{Hash, PaddingScheme, PublicKey, PublicKeyParts, RsaPrivateKey, RsaPublicKey};
229391

@@ -348,6 +510,32 @@ mod tests {
348510
}
349511
}
350512

513+
#[test]
514+
fn test_sign_pkcs1v15_signer() {
515+
let priv_key = get_private_key();
516+
517+
let tests = [(
518+
"Test.\n",
519+
hex!(
520+
"a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
521+
"6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362ae"
522+
),
523+
)];
524+
525+
for (text, expected) in &tests {
526+
let digest = Sha1::digest(text.as_bytes()).to_vec();
527+
528+
let signing_key: RsaPkcs1v15SigningKey = (&priv_key, Hash::SHA1).into();
529+
let out = signing_key.sign(&digest);
530+
assert_ne!(out.as_ref(), digest);
531+
assert_eq!(out.as_ref(), expected);
532+
533+
let mut rng = ChaCha8Rng::from_seed([42; 32]);
534+
let out2 = signing_key.sign_with_rng(&mut rng, &digest);
535+
assert_eq!(out2.as_ref(), expected);
536+
}
537+
}
538+
351539
#[test]
352540
fn test_verify_pkcs1v15() {
353541
let priv_key = get_private_key();
@@ -390,6 +578,45 @@ mod tests {
390578
}
391579
}
392580

581+
#[test]
582+
fn test_verify_pkcs1v15_signer() {
583+
let priv_key = get_private_key();
584+
585+
let tests = [
586+
(
587+
"Test.\n",
588+
hex!(
589+
"a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
590+
"6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362ae"
591+
),
592+
true,
593+
),
594+
(
595+
"Test.\n",
596+
hex!(
597+
"a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
598+
"6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362af"
599+
),
600+
false,
601+
),
602+
];
603+
let pub_key: RsaPublicKey = priv_key.into();
604+
let verifying_key: RsaPkcs1v15VerifyingKey = (&pub_key, Hash::SHA1).into();
605+
606+
for (text, sig, expected) in &tests {
607+
let digest = Sha1::digest(text.as_bytes()).to_vec();
608+
609+
let result = verifying_key.verify(&digest, &Signature::from_bytes(sig).unwrap());
610+
match expected {
611+
true => result.expect("failed to verify"),
612+
false => {
613+
result.expect_err("expected verifying error");
614+
()
615+
}
616+
}
617+
}
618+
}
619+
393620
#[test]
394621
fn test_unpadded_signature() {
395622
let msg = b"Thu Dec 19 18:06:16 EST 2013\n";
@@ -406,4 +633,26 @@ mod tests {
406633
.verify(PaddingScheme::new_pkcs1v15_sign(None), msg, &sig)
407634
.expect("failed to verify");
408635
}
636+
637+
#[test]
638+
fn test_unpadded_signature_signer() {
639+
let msg = b"Thu Dec 19 18:06:16 EST 2013\n";
640+
let expected_sig = Base64::decode_vec("pX4DR8azytjdQ1rtUiC040FjkepuQut5q2ZFX1pTjBrOVKNjgsCDyiJDGZTCNoh9qpXYbhl7iEym30BWWwuiZg==").unwrap();
641+
let priv_key = get_private_key();
642+
643+
let signing_key: RsaPkcs1v15SigningKey = (&priv_key).into();
644+
let sig = signing_key.sign(msg);
645+
assert_eq!(sig.as_ref(), expected_sig);
646+
647+
let verifying_key: RsaPkcs1v15VerifyingKey = (&signing_key).into();
648+
verifying_key
649+
.verify(msg, &Signature::from_bytes(&expected_sig).unwrap())
650+
.expect("failed to verify");
651+
652+
let mut rng = ChaCha8Rng::from_seed([42; 32]);
653+
let sig = signing_key.sign_with_rng(&mut rng, msg);
654+
assert_eq!(sig.as_ref(), expected_sig);
655+
656+
verifying_key.verify(msg, &sig).expect("failed to verify");
657+
}
409658
}

0 commit comments

Comments
 (0)