1mod blinded_signing_key;
13mod signature;
14mod signing_key;
15mod verifying_key;
16
17pub use self::{
18 blinded_signing_key::BlindedSigningKey, signature::Signature, signing_key::SigningKey,
19 verifying_key::VerifyingKey,
20};
21
22use alloc::{boxed::Box, vec::Vec};
23use core::fmt::{self, Debug};
24
25use const_oid::{AssociatedOid, ObjectIdentifier};
26use digest::{Digest, DynDigest, FixedOutputReset};
27use num_bigint::BigUint;
28use pkcs1::RsaPssParams;
29use pkcs8::spki::{der::Any, AlgorithmIdentifierOwned};
30use rand_core::CryptoRngCore;
31
32use crate::algorithms::pad::{uint_to_be_pad, uint_to_zeroizing_be_pad};
33use crate::algorithms::pss::*;
34use crate::algorithms::rsa::{rsa_decrypt_and_check, rsa_encrypt};
35use crate::errors::{Error, Result};
36use crate::traits::PublicKeyParts;
37use crate::traits::SignatureScheme;
38use crate::{RsaPrivateKey, RsaPublicKey};
39
40pub struct Pss {
42 pub blinded: bool,
44
45 pub digest: Box<dyn DynDigest + Send + Sync>,
47
48 pub salt_len: usize,
50}
51
52impl Pss {
53 pub fn new<T: 'static + Digest + DynDigest + Send + Sync>() -> Self {
56 Self::new_with_salt::<T>(<T as Digest>::output_size())
57 }
58
59 pub fn new_with_salt<T: 'static + Digest + DynDigest + Send + Sync>(len: usize) -> Self {
61 Self {
62 blinded: false,
63 digest: Box::new(T::new()),
64 salt_len: len,
65 }
66 }
67
68 pub fn new_blinded<T: 'static + Digest + DynDigest + Send + Sync>() -> Self {
71 Self::new_blinded_with_salt::<T>(<T as Digest>::output_size())
72 }
73
74 pub fn new_blinded_with_salt<T: 'static + Digest + DynDigest + Send + Sync>(
77 len: usize,
78 ) -> Self {
79 Self {
80 blinded: true,
81 digest: Box::new(T::new()),
82 salt_len: len,
83 }
84 }
85}
86
87impl SignatureScheme for Pss {
88 fn sign<Rng: CryptoRngCore>(
89 mut self,
90 rng: Option<&mut Rng>,
91 priv_key: &RsaPrivateKey,
92 hashed: &[u8],
93 ) -> Result<Vec<u8>> {
94 sign(
95 rng.ok_or(Error::InvalidPaddingScheme)?,
96 self.blinded,
97 priv_key,
98 hashed,
99 self.salt_len,
100 &mut *self.digest,
101 )
102 }
103
104 fn verify(mut self, pub_key: &RsaPublicKey, hashed: &[u8], sig: &[u8]) -> Result<()> {
105 verify(
106 pub_key,
107 hashed,
108 &BigUint::from_bytes_be(sig),
109 sig.len(),
110 &mut *self.digest,
111 self.salt_len,
112 )
113 }
114}
115
116impl Debug for Pss {
117 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118 f.debug_struct("PSS")
119 .field("blinded", &self.blinded)
120 .field("digest", &"...")
121 .field("salt_len", &self.salt_len)
122 .finish()
123 }
124}
125
126pub(crate) fn verify(
127 pub_key: &RsaPublicKey,
128 hashed: &[u8],
129 sig: &BigUint,
130 sig_len: usize,
131 digest: &mut dyn DynDigest,
132 salt_len: usize,
133) -> Result<()> {
134 if sig_len != pub_key.size() {
135 return Err(Error::Verification);
136 }
137
138 let mut em = uint_to_be_pad(rsa_encrypt(pub_key, sig)?, pub_key.size())?;
139
140 emsa_pss_verify(hashed, &mut em, salt_len, digest, pub_key.n().bits())
141}
142
143pub(crate) fn verify_digest<D>(
144 pub_key: &RsaPublicKey,
145 hashed: &[u8],
146 sig: &BigUint,
147 sig_len: usize,
148 salt_len: usize,
149) -> Result<()>
150where
151 D: Digest + FixedOutputReset,
152{
153 if sig >= pub_key.n() || sig_len != pub_key.size() {
154 return Err(Error::Verification);
155 }
156
157 let mut em = uint_to_be_pad(rsa_encrypt(pub_key, sig)?, pub_key.size())?;
158
159 emsa_pss_verify_digest::<D>(hashed, &mut em, salt_len, pub_key.n().bits())
160}
161
162pub(crate) fn sign<T: CryptoRngCore>(
168 rng: &mut T,
169 blind: bool,
170 priv_key: &RsaPrivateKey,
171 hashed: &[u8],
172 salt_len: usize,
173 digest: &mut dyn DynDigest,
174) -> Result<Vec<u8>> {
175 let mut salt = vec![0; salt_len];
176 rng.fill_bytes(&mut salt[..]);
177
178 sign_pss_with_salt(blind.then_some(rng), priv_key, hashed, &salt, digest)
179}
180
181pub(crate) fn sign_digest<T: CryptoRngCore + ?Sized, D: Digest + FixedOutputReset>(
182 rng: &mut T,
183 blind: bool,
184 priv_key: &RsaPrivateKey,
185 hashed: &[u8],
186 salt_len: usize,
187) -> Result<Vec<u8>> {
188 let mut salt = vec![0; salt_len];
189 rng.fill_bytes(&mut salt[..]);
190
191 sign_pss_with_salt_digest::<_, D>(blind.then_some(rng), priv_key, hashed, &salt)
192}
193
194fn sign_pss_with_salt<T: CryptoRngCore>(
200 blind_rng: Option<&mut T>,
201 priv_key: &RsaPrivateKey,
202 hashed: &[u8],
203 salt: &[u8],
204 digest: &mut dyn DynDigest,
205) -> Result<Vec<u8>> {
206 let em_bits = priv_key.n().bits() - 1;
207 let em = emsa_pss_encode(hashed, em_bits, salt, digest)?;
208
209 uint_to_zeroizing_be_pad(
210 rsa_decrypt_and_check(priv_key, blind_rng, &BigUint::from_bytes_be(&em))?,
211 priv_key.size(),
212 )
213}
214
215fn sign_pss_with_salt_digest<T: CryptoRngCore + ?Sized, D: Digest + FixedOutputReset>(
216 blind_rng: Option<&mut T>,
217 priv_key: &RsaPrivateKey,
218 hashed: &[u8],
219 salt: &[u8],
220) -> Result<Vec<u8>> {
221 let em_bits = priv_key.n().bits() - 1;
222 let em = emsa_pss_encode_digest::<D>(hashed, em_bits, salt)?;
223
224 uint_to_zeroizing_be_pad(
225 rsa_decrypt_and_check(priv_key, blind_rng, &BigUint::from_bytes_be(&em))?,
226 priv_key.size(),
227 )
228}
229
230pub fn get_default_pss_signature_algo_id<D>() -> pkcs8::spki::Result<AlgorithmIdentifierOwned>
232where
233 D: Digest + AssociatedOid,
234{
235 let salt_len: u8 = <D as Digest>::output_size() as u8;
236 get_pss_signature_algo_id::<D>(salt_len)
237}
238
239fn get_pss_signature_algo_id<D>(salt_len: u8) -> pkcs8::spki::Result<AlgorithmIdentifierOwned>
240where
241 D: Digest + AssociatedOid,
242{
243 const ID_RSASSA_PSS: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.10");
244
245 let pss_params = RsaPssParams::new::<D>(salt_len);
246
247 Ok(AlgorithmIdentifierOwned {
248 oid: ID_RSASSA_PSS,
249 parameters: Some(Any::encode_from(&pss_params)?),
250 })
251}
252
253#[cfg(test)]
254mod test {
255 use crate::pss::{BlindedSigningKey, Pss, Signature, SigningKey, VerifyingKey};
256 use crate::{RsaPrivateKey, RsaPublicKey};
257
258 use hex_literal::hex;
259 use num_bigint::BigUint;
260 use num_traits::{FromPrimitive, Num};
261 use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng};
262 use sha1::{Digest, Sha1};
263 use signature::hazmat::{PrehashVerifier, RandomizedPrehashSigner};
264 use signature::{DigestVerifier, Keypair, RandomizedDigestSigner, RandomizedSigner, Verifier};
265
266 fn get_private_key() -> RsaPrivateKey {
267 RsaPrivateKey::from_components(
279 BigUint::from_str_radix("9353930466774385905609975137998169297361893554149986716853295022578535724979677252958524466350471210367835187480748268864277464700638583474144061408845077", 10).unwrap(),
280 BigUint::from_u64(65537).unwrap(),
281 BigUint::from_str_radix("7266398431328116344057699379749222532279343923819063639497049039389899328538543087657733766554155839834519529439851673014800261285757759040931985506583861", 10).unwrap(),
282 vec![
283 BigUint::from_str_radix("98920366548084643601728869055592650835572950932266967461790948584315647051443",10).unwrap(),
284 BigUint::from_str_radix("94560208308847015747498523884063394671606671904944666360068158221458669711639", 10).unwrap()
285 ],
286 ).unwrap()
287 }
288
289 #[test]
290 fn test_verify_pss() {
291 let priv_key = get_private_key();
292
293 let tests = [
294 (
295 "test\n",
296 hex!(
297 "6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae"
298 "30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962f"
299 ),
300 true,
301 ),
302 (
303 "test\n",
304 hex!(
305 "6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae"
306 "30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962e"
307 ),
308 false,
309 ),
310 ];
311 let pub_key: RsaPublicKey = priv_key.into();
312
313 for (text, sig, expected) in &tests {
314 let digest = Sha1::digest(text.as_bytes()).to_vec();
315 let result = pub_key.verify(Pss::new::<Sha1>(), &digest, sig);
316 match expected {
317 true => result.expect("failed to verify"),
318 false => {
319 result.expect_err("expected verifying error");
320 }
321 }
322 }
323 }
324
325 #[test]
326 fn test_verify_pss_signer() {
327 let priv_key = get_private_key();
328
329 let tests = [
330 (
331 "test\n",
332 hex!(
333 "6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae"
334 "30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962f"
335 ),
336 true,
337 ),
338 (
339 "test\n",
340 hex!(
341 "6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae"
342 "30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962e"
343 ),
344 false,
345 ),
346 ];
347 let pub_key: RsaPublicKey = priv_key.into();
348 let verifying_key: VerifyingKey<Sha1> = VerifyingKey::new(pub_key);
349
350 for (text, sig, expected) in &tests {
351 let result = verifying_key.verify(
352 text.as_bytes(),
353 &Signature::try_from(sig.as_slice()).unwrap(),
354 );
355 match expected {
356 true => result.expect("failed to verify"),
357 false => {
358 result.expect_err("expected verifying error");
359 }
360 }
361 }
362 }
363
364 #[test]
365 fn test_verify_pss_digest_signer() {
366 let priv_key = get_private_key();
367
368 let tests = [
369 (
370 "test\n",
371 hex!(
372 "6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae"
373 "30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962f"
374 ),
375 true,
376 ),
377 (
378 "test\n",
379 hex!(
380 "6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae"
381 "30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962e"
382 ),
383 false,
384 ),
385 ];
386 let pub_key: RsaPublicKey = priv_key.into();
387 let verifying_key = VerifyingKey::new(pub_key);
388
389 for (text, sig, expected) in &tests {
390 let mut digest = Sha1::new();
391 digest.update(text.as_bytes());
392 let result =
393 verifying_key.verify_digest(digest, &Signature::try_from(sig.as_slice()).unwrap());
394 match expected {
395 true => result.expect("failed to verify"),
396 false => {
397 result.expect_err("expected verifying error");
398 }
399 }
400 }
401 }
402
403 #[test]
404 fn test_sign_and_verify_roundtrip() {
405 let priv_key = get_private_key();
406
407 let tests = ["test\n"];
408 let rng = ChaCha8Rng::from_seed([42; 32]);
409
410 for test in &tests {
411 let digest = Sha1::digest(test.as_bytes()).to_vec();
412 let sig = priv_key
413 .sign_with_rng(&mut rng.clone(), Pss::new::<Sha1>(), &digest)
414 .expect("failed to sign");
415
416 priv_key
417 .to_public_key()
418 .verify(Pss::new::<Sha1>(), &digest, &sig)
419 .expect("failed to verify");
420 }
421 }
422
423 #[test]
424 fn test_sign_blinded_and_verify_roundtrip() {
425 let priv_key = get_private_key();
426
427 let tests = ["test\n"];
428 let rng = ChaCha8Rng::from_seed([42; 32]);
429
430 for test in &tests {
431 let digest = Sha1::digest(test.as_bytes()).to_vec();
432 let sig = priv_key
433 .sign_with_rng(&mut rng.clone(), Pss::new_blinded::<Sha1>(), &digest)
434 .expect("failed to sign");
435
436 priv_key
437 .to_public_key()
438 .verify(Pss::new::<Sha1>(), &digest, &sig)
439 .expect("failed to verify");
440 }
441 }
442
443 #[test]
444 fn test_sign_and_verify_roundtrip_signer() {
445 let priv_key = get_private_key();
446
447 let tests = ["test\n"];
448 let mut rng = ChaCha8Rng::from_seed([42; 32]);
449 let signing_key = SigningKey::<Sha1>::new(priv_key);
450 let verifying_key = signing_key.verifying_key();
451
452 for test in &tests {
453 let sig = signing_key.sign_with_rng(&mut rng, test.as_bytes());
454 verifying_key
455 .verify(test.as_bytes(), &sig)
456 .expect("failed to verify");
457 }
458 }
459
460 #[test]
461 fn test_sign_and_verify_roundtrip_blinded_signer() {
462 let priv_key = get_private_key();
463
464 let tests = ["test\n"];
465 let mut rng = ChaCha8Rng::from_seed([42; 32]);
466 let signing_key = BlindedSigningKey::<Sha1>::new(priv_key);
467 let verifying_key = signing_key.verifying_key();
468
469 for test in &tests {
470 let sig = signing_key.sign_with_rng(&mut rng, test.as_bytes());
471 verifying_key
472 .verify(test.as_bytes(), &sig)
473 .expect("failed to verify");
474 }
475 }
476
477 #[test]
478 fn test_sign_and_verify_roundtrip_digest_signer() {
479 let priv_key = get_private_key();
480
481 let tests = ["test\n"];
482 let mut rng = ChaCha8Rng::from_seed([42; 32]);
483 let signing_key = SigningKey::new(priv_key);
484 let verifying_key = signing_key.verifying_key();
485
486 for test in &tests {
487 let mut digest = Sha1::new();
488 digest.update(test.as_bytes());
489 let sig = signing_key.sign_digest_with_rng(&mut rng, digest);
490
491 let mut digest = Sha1::new();
492 digest.update(test.as_bytes());
493 verifying_key
494 .verify_digest(digest, &sig)
495 .expect("failed to verify");
496 }
497 }
498
499 #[test]
500 fn test_sign_and_verify_roundtrip_blinded_digest_signer() {
501 let priv_key = get_private_key();
502
503 let tests = ["test\n"];
504 let mut rng = ChaCha8Rng::from_seed([42; 32]);
505 let signing_key = BlindedSigningKey::<Sha1>::new(priv_key);
506 let verifying_key = signing_key.verifying_key();
507
508 for test in &tests {
509 let mut digest = Sha1::new();
510 digest.update(test.as_bytes());
511 let sig = signing_key.sign_digest_with_rng(&mut rng, digest);
512
513 let mut digest = Sha1::new();
514 digest.update(test.as_bytes());
515 verifying_key
516 .verify_digest(digest, &sig)
517 .expect("failed to verify");
518 }
519 }
520
521 #[test]
522 fn test_verify_pss_hazmat() {
523 let priv_key = get_private_key();
524
525 let tests = [
526 (
527 Sha1::digest("test\n"),
528 hex!(
529 "6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae"
530 "30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962f"
531 ),
532 true,
533 ),
534 (
535 Sha1::digest("test\n"),
536 hex!(
537 "6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae"
538 "30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962e"
539 ),
540 false,
541 ),
542 ];
543 let pub_key: RsaPublicKey = priv_key.into();
544 let verifying_key = VerifyingKey::<Sha1>::new(pub_key);
545
546 for (text, sig, expected) in &tests {
547 let result = verifying_key
548 .verify_prehash(text.as_ref(), &Signature::try_from(sig.as_slice()).unwrap());
549 match expected {
550 true => result.expect("failed to verify"),
551 false => {
552 result.expect_err("expected verifying error");
553 }
554 }
555 }
556 }
557
558 #[test]
559 fn test_sign_and_verify_pss_hazmat() {
560 let priv_key = get_private_key();
561
562 let tests = [Sha1::digest("test\n")];
563 let mut rng = ChaCha8Rng::from_seed([42; 32]);
564 let signing_key = SigningKey::<Sha1>::new(priv_key);
565 let verifying_key = signing_key.verifying_key();
566
567 for test in &tests {
568 let sig = signing_key
569 .sign_prehash_with_rng(&mut rng, &test)
570 .expect("failed to sign");
571 verifying_key
572 .verify_prehash(&test, &sig)
573 .expect("failed to verify");
574 }
575 }
576
577 #[test]
578 fn test_sign_and_verify_pss_blinded_hazmat() {
579 let priv_key = get_private_key();
580
581 let tests = [Sha1::digest("test\n")];
582 let mut rng = ChaCha8Rng::from_seed([42; 32]);
583 let signing_key = BlindedSigningKey::<Sha1>::new(priv_key);
584 let verifying_key = signing_key.verifying_key();
585
586 for test in &tests {
587 let sig = signing_key
588 .sign_prehash_with_rng(&mut rng, &test)
589 .expect("failed to sign");
590 verifying_key
591 .verify_prehash(&test, &sig)
592 .expect("failed to verify");
593 }
594 }
595
596 #[test]
597 fn test_sign_and_verify_2049bit_key() {
599 let plaintext = "Hello\n";
600 let rng = ChaCha8Rng::from_seed([42; 32]);
601 let priv_key = RsaPrivateKey::new(&mut rng.clone(), 2049).unwrap();
602
603 let digest = Sha1::digest(plaintext.as_bytes()).to_vec();
604 let sig = priv_key
605 .sign_with_rng(&mut rng.clone(), Pss::new::<Sha1>(), &digest)
606 .expect("failed to sign");
607
608 priv_key
609 .to_public_key()
610 .verify(Pss::new::<Sha1>(), &digest, &sig)
611 .expect("failed to verify");
612 }
613}