Skip to main content

rsa/
pss.rs

1//! Support for the [Probabilistic Signature Scheme] (PSS) a.k.a. RSASSA-PSS.
2//!
3//! Designed by Mihir Bellare and Phillip Rogaway. Specified in [RFC8017 § 8.1].
4//!
5//! # Usage
6//!
7//! See [code example in the toplevel rustdoc](../index.html#pss-signatures).
8//!
9//! [Probabilistic Signature Scheme]: https://en.wikipedia.org/wiki/Probabilistic_signature_scheme
10//! [RFC8017 § 8.1]: https://datatracker.ietf.org/doc/html/rfc8017#section-8.1
11
12#[cfg(feature = "alloc")]
13mod blinded_signing_key;
14mod generic_signing_key;
15mod signature;
16#[cfg(feature = "alloc")]
17mod signing_key;
18mod verifying_key;
19
20pub use self::generic_signing_key::GenericSigningKey;
21#[cfg(feature = "alloc")]
22pub use self::{blinded_signing_key::BlindedSigningKey, signing_key::SigningKey};
23
24#[cfg(feature = "alloc")]
25pub use self::{signature::Signature, verifying_key::VerifyingKey};
26pub use self::{
27    signature::{GenericSignature, SignatureBytes},
28    verifying_key::GenericVerifyingKey,
29};
30
31#[cfg(feature = "alloc")]
32use alloc::{vec, vec::Vec};
33use core::fmt::{self, Debug};
34#[cfg(feature = "alloc")]
35use crypto_bigint::BoxedUint;
36
37use digest::{Digest, FixedOutputReset};
38use rand_core::TryCryptoRng;
39
40#[cfg(feature = "alloc")]
41use crate::algorithms::pad::{uint_to_be_pad, uint_to_be_pad_into, uint_to_zeroizing_be_pad};
42use crate::algorithms::pss::*;
43#[cfg(feature = "alloc")]
44use crate::algorithms::rsa::rsa_decrypt_and_check;
45#[cfg(feature = "alloc")]
46use crate::algorithms::rsa::rsa_encrypt;
47use crate::errors::{Error, Result};
48use crate::traits::{PublicKeyParts, SignatureScheme, UnsignedModularInt};
49#[cfg(feature = "alloc")]
50use crate::RsaPrivateKey;
51#[cfg(feature = "alloc")]
52use crate::RsaPublicKey;
53
54#[cfg(feature = "encoding")]
55use {
56    crate::encoding::ID_RSASSA_PSS,
57    const_oid::AssociatedOid,
58    pkcs1::RsaPssParams,
59    spki::{der::Any, AlgorithmIdentifierOwned},
60};
61
62/// Digital signatures using PSS padding.
63pub struct Pss<D> {
64    /// Create blinded signatures.
65    pub blinded: bool,
66
67    /// Digest type to use.
68    pub digest: D,
69
70    /// Salt length.
71    /// Required for signing, optional for verifying.
72    pub salt_len: Option<usize>,
73}
74
75impl<D> Default for Pss<D>
76where
77    D: Digest,
78{
79    fn default() -> Self {
80        Self::new()
81    }
82}
83
84impl<D> Pss<D>
85where
86    D: Digest,
87{
88    /// New PSS padding for the given digest.
89    /// Digest output size is used as a salt length.
90    pub fn new() -> Self {
91        Self::new_with_salt(<D as Digest>::output_size())
92    }
93
94    /// New PSS padding for the given digest with a salt value of the given length.
95    pub fn new_with_salt(len: usize) -> Self {
96        Self {
97            blinded: false,
98            digest: D::new(),
99            salt_len: Some(len),
100        }
101    }
102
103    /// New PSS padding for blinded signatures (RSA-BSSA) for the given digest.
104    /// Digest output size is used as a salt length.
105    pub fn new_blinded() -> Self {
106        Self::new_blinded_with_salt(<D as Digest>::output_size())
107    }
108
109    /// New PSS padding for blinded signatures (RSA-BSSA) for the given digest
110    /// with a salt value of the given length.
111    pub fn new_blinded_with_salt(len: usize) -> Self {
112        Self {
113            blinded: true,
114            digest: D::new(),
115            salt_len: Some(len),
116        }
117    }
118}
119
120#[cfg(feature = "alloc")]
121impl<D> SignatureScheme for Pss<D>
122where
123    D: Digest + FixedOutputReset,
124{
125    #[cfg(feature = "alloc")]
126    fn sign<Rng: TryCryptoRng + ?Sized>(
127        mut self,
128        rng: Option<&mut Rng>,
129        priv_key: &RsaPrivateKey,
130        hashed: &[u8],
131    ) -> Result<Vec<u8>> {
132        sign(
133            rng.ok_or(Error::InvalidPaddingScheme)?,
134            self.blinded,
135            priv_key,
136            hashed,
137            self.salt_len.expect("salt_len to be Some"),
138            &mut self.digest,
139        )
140    }
141
142    fn verify<K, T>(mut self, pub_key: &K, hashed: &[u8], sig: &[u8]) -> Result<()>
143    where
144        T: UnsignedModularInt,
145        K: PublicKeyParts<T>,
146    {
147        if sig.len() != pub_key.size() {
148            return Err(Error::Verification);
149        }
150        let sig = T::try_from_be_bytes_vartime(sig).map_err(|_| Error::Verification)?;
151        if sig >= *pub_key.n().as_ref() || sig.bits_precision() != pub_key.n_bits_precision() {
152            return Err(Error::Verification);
153        }
154
155        let mut em = vec![0u8; pub_key.size()];
156        let em_len =
157            uint_to_be_pad_into(rsa_encrypt(pub_key, &sig)?, pub_key.size(), &mut em)?.len();
158
159        emsa_pss_verify(
160            hashed,
161            &mut em[..em_len],
162            self.salt_len,
163            &mut self.digest,
164            pub_key.n().bits() as _,
165        )
166    }
167}
168
169impl<D> Debug for Pss<D> {
170    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
171        f.debug_struct("PSS")
172            .field("blinded", &self.blinded)
173            .field("digest", &"...")
174            .field("salt_len", &self.salt_len)
175            .finish()
176    }
177}
178
179#[cfg(feature = "alloc")]
180#[allow(dead_code)]
181pub(crate) fn verify<D>(
182    pub_key: &RsaPublicKey,
183    hashed: &[u8],
184    sig: &BoxedUint,
185    sig_len: usize,
186    digest: &mut D,
187    salt_len: Option<usize>,
188) -> Result<()>
189where
190    D: Digest + FixedOutputReset,
191{
192    if sig_len != pub_key.size() {
193        return Err(Error::Verification);
194    }
195    let raw = rsa_encrypt(pub_key, sig)?;
196    let mut em = uint_to_be_pad(raw, pub_key.size())?;
197
198    emsa_pss_verify(hashed, &mut em, salt_len, digest, pub_key.n().bits() as _)
199}
200
201#[cfg(feature = "alloc")]
202#[allow(dead_code)]
203pub(crate) fn verify_digest<D>(
204    pub_key: &RsaPublicKey,
205    hashed: &[u8],
206    sig: &BoxedUint,
207    salt_len: Option<usize>,
208) -> Result<()>
209where
210    D: Digest + FixedOutputReset,
211{
212    let mut storage = vec![0u8; pub_key.size()];
213    verify_digest_into::<D, _, BoxedUint>(pub_key, hashed, sig, salt_len, &mut storage)
214}
215
216/// `storage` must be at least `pub_key.size()` bytes.
217pub fn verify_digest_into<D, K, T>(
218    pub_key: &K,
219    hashed: &[u8],
220    sig: &T,
221    salt_len: Option<usize>,
222    storage: &mut [u8],
223) -> crate::Result<()>
224where
225    D: digest::Digest + digest::FixedOutputReset,
226    K: crate::traits::PublicKeyParts<T>,
227    T: crate::traits::UnsignedModularInt,
228{
229    if sig >= pub_key.n().as_ref() || sig.bits_precision() != pub_key.n_bits_precision() {
230        return Err(crate::Error::Verification);
231    }
232    let padded_len = pub_key.size();
233    let em = crate::algorithms::pad::uint_to_be_pad_into(
234        crate::algorithms::rsa::rsa_encrypt(pub_key, sig)?,
235        padded_len,
236        storage,
237    )?;
238    // `uint_to_be_pad_into` returns an immutable slice into `storage`; PSS
239    // verify wants `&mut [u8]`. Drop the borrow and re-slice mutably.
240    let em_len = em.len();
241    emsa_pss_verify_digest::<D>(
242        hashed,
243        &mut storage[..em_len],
244        salt_len,
245        pub_key.n().bits() as _,
246    )
247}
248
249/// SignPSS calculates the signature of hashed using RSASSA-PSS.
250///
251/// Note that hashed must be the result of hashing the input message using the
252/// given hash function. The opts argument may be nil, in which case sensible
253/// defaults are used.
254#[cfg(feature = "alloc")]
255pub(crate) fn sign<T, D>(
256    rng: &mut T,
257    blind: bool,
258    priv_key: &RsaPrivateKey,
259    hashed: &[u8],
260    salt_len: usize,
261    digest: &mut D,
262) -> Result<Vec<u8>>
263where
264    T: TryCryptoRng + ?Sized,
265    D: Digest + FixedOutputReset,
266{
267    let mut salt = vec![0; salt_len];
268    rng.try_fill_bytes(&mut salt[..]).map_err(|_| Error::Rng)?;
269
270    sign_pss_with_salt(blind.then_some(rng), priv_key, hashed, &salt, digest)
271}
272
273#[cfg(feature = "alloc")]
274pub(crate) fn sign_digest<T, D>(
275    rng: &mut T,
276    blind: bool,
277    priv_key: &RsaPrivateKey,
278    hashed: &[u8],
279    salt_len: usize,
280) -> Result<Vec<u8>>
281where
282    T: TryCryptoRng + ?Sized,
283    D: Digest + FixedOutputReset,
284{
285    let mut salt = vec![0; salt_len];
286    rng.try_fill_bytes(&mut salt[..]).map_err(|_| Error::Rng)?;
287
288    sign_pss_with_salt_digest::<_, D>(blind.then_some(rng), priv_key, hashed, &salt)
289}
290
291/// signPSSWithSalt calculates the signature of hashed using PSS with specified salt.
292///
293/// Note that hashed must be the result of hashing the input message using the
294/// given hash function. salt is a random sequence of bytes whose length will be
295/// later used to verify the signature.
296#[cfg(feature = "alloc")]
297fn sign_pss_with_salt<T, D>(
298    blind_rng: Option<&mut T>,
299    priv_key: &RsaPrivateKey,
300    hashed: &[u8],
301    salt: &[u8],
302    digest: &mut D,
303) -> Result<Vec<u8>>
304where
305    T: TryCryptoRng + ?Sized,
306    D: Digest + FixedOutputReset,
307{
308    let em_bits = priv_key.n().bits() - 1;
309
310    let em = emsa_pss_encode(hashed, em_bits as _, salt, digest)?;
311
312    let em = BoxedUint::from_be_slice(&em, priv_key.n_bits_precision())?;
313    let raw = rsa_decrypt_and_check(priv_key, blind_rng, &em)?;
314    uint_to_zeroizing_be_pad(raw, priv_key.size())
315}
316
317#[cfg(feature = "alloc")]
318fn sign_pss_with_salt_digest<T, D>(
319    blind_rng: Option<&mut T>,
320    priv_key: &RsaPrivateKey,
321    hashed: &[u8],
322    salt: &[u8],
323) -> Result<Vec<u8>>
324where
325    T: TryCryptoRng + ?Sized,
326    D: Digest + FixedOutputReset,
327{
328    let em_bits = priv_key.n().bits() - 1;
329    let em = emsa_pss_encode_digest::<D>(hashed, em_bits as _, salt)?;
330
331    let em = BoxedUint::from_be_slice(&em, priv_key.n_bits_precision())?;
332    uint_to_zeroizing_be_pad(
333        rsa_decrypt_and_check(priv_key, blind_rng, &em)?,
334        priv_key.size(),
335    )
336}
337
338/// Returns the [`AlgorithmIdentifierOwned`] associated with PSS signature using a given digest.
339#[cfg(feature = "encoding")]
340pub fn get_default_pss_signature_algo_id<D>() -> spki::Result<AlgorithmIdentifierOwned>
341where
342    D: Digest + AssociatedOid,
343{
344    let salt_len: u8 = <D as Digest>::output_size() as u8;
345    get_pss_signature_algo_id::<D>(salt_len)
346}
347
348#[cfg(feature = "encoding")]
349fn get_pss_signature_algo_id<D>(salt_len: u8) -> spki::Result<AlgorithmIdentifierOwned>
350where
351    D: Digest + AssociatedOid,
352{
353    let pss_params = RsaPssParams::new::<D>(salt_len);
354
355    Ok(AlgorithmIdentifierOwned {
356        oid: ID_RSASSA_PSS,
357        parameters: Some(Any::encode_from(&pss_params)?),
358    })
359}
360
361#[cfg(all(test, feature = "encoding"))]
362mod test {
363    use crate::pss::{BlindedSigningKey, Pss, Signature, SigningKey, VerifyingKey};
364    use crate::{RsaPrivateKey, RsaPublicKey};
365
366    use crate::traits::PublicKeyParts;
367    use hex_literal::hex;
368    use pkcs1::DecodeRsaPrivateKey;
369    use rand::rngs::ChaCha8Rng;
370    use rand_core::SeedableRng;
371    use rstest::rstest;
372    use sha1::{Digest, Sha1};
373    use signature::hazmat::{PrehashVerifier, RandomizedPrehashSigner};
374    use signature::{DigestVerifier, Keypair, RandomizedDigestSigner, RandomizedSigner, Verifier};
375
376    fn get_private_key() -> RsaPrivateKey {
377        // In order to generate new test vectors you'll need the PEM form of this key:
378        // -----BEGIN RSA PRIVATE KEY-----
379        // MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0
380        // fd7Ai2KW5ToIwzFofvJcS/STa6HA5gQenRUCAwEAAQJBAIq9amn00aS0h/CrjXqu
381        // /ThglAXJmZhOMPVn4eiu7/ROixi9sex436MaVeMqSNf7Ex9a8fRNfWss7Sqd9eWu
382        // RTUCIQDasvGASLqmjeffBNLTXV2A5g4t+kLVCpsEIZAycV5GswIhANEPLmax0ME/
383        // EO+ZJ79TJKN5yiGBRsv5yvx5UiHxajEXAiAhAol5N4EUyq6I9w1rYdhPMGpLfk7A
384        // IU2snfRJ6Nq2CQIgFrPsWRCkV+gOYcajD17rEqmuLrdIRexpg8N1DOSXoJ8CIGlS
385        // tAboUGBxTDq3ZroNism3DaMIbKPyYrAqhKov1h5V
386        // -----END RSA PRIVATE KEY-----
387
388        let pem = r#"
389-----BEGIN RSA PRIVATE KEY-----
390MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0
391fd7Ai2KW5ToIwzFofvJcS/STa6HA5gQenRUCAwEAAQJBAIq9amn00aS0h/CrjXqu
392/ThglAXJmZhOMPVn4eiu7/ROixi9sex436MaVeMqSNf7Ex9a8fRNfWss7Sqd9eWu
393RTUCIQDasvGASLqmjeffBNLTXV2A5g4t+kLVCpsEIZAycV5GswIhANEPLmax0ME/
394EO+ZJ79TJKN5yiGBRsv5yvx5UiHxajEXAiAhAol5N4EUyq6I9w1rYdhPMGpLfk7A
395IU2snfRJ6Nq2CQIgFrPsWRCkV+gOYcajD17rEqmuLrdIRexpg8N1DOSXoJ8CIGlS
396tAboUGBxTDq3ZroNism3DaMIbKPyYrAqhKov1h5V
397-----END RSA PRIVATE KEY-----"#;
398
399        RsaPrivateKey::from_pkcs1_pem(pem).unwrap()
400    }
401
402    #[rstest]
403    #[case(
404        "test\n",
405        hex!(
406            "6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae"
407            "30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962f"
408        ),
409        true,
410    )]
411    #[case(
412        "test\n",
413        hex!(
414            "6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae"
415            "30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962e"
416        ),
417        false,
418    )]
419    fn test_verify_pss(#[case] text: &str, #[case] sig: [u8; 64], #[case] expected: bool) {
420        let priv_key = get_private_key();
421        let pub_key: RsaPublicKey = priv_key.into();
422
423        let digest = Sha1::digest(text.as_bytes()).to_vec();
424        let result = pub_key.verify(Pss::<Sha1>::new(), &digest, &sig);
425
426        match expected {
427            true => result.expect("failed to verify"),
428            false => {
429                result.expect_err("expected verifying error");
430            }
431        }
432    }
433
434    #[rstest]
435    #[case(
436        "test\n",
437        hex!(
438            "6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae"
439            "30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962f"
440        ),
441        true,
442    )]
443    #[case(
444        "test\n",
445        hex!(
446            "6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae"
447            "30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962e"
448        ),
449        false,
450    )]
451    fn test_verify_pss_signer(#[case] text: &str, #[case] sig: [u8; 64], #[case] expected: bool) {
452        let priv_key = get_private_key();
453        let pub_key: RsaPublicKey = priv_key.into();
454        let verifying_key: VerifyingKey<Sha1> = VerifyingKey::new(pub_key);
455
456        let result = verifying_key.verify(
457            text.as_bytes(),
458            &Signature::try_from(sig.as_slice()).unwrap(),
459        );
460        match expected {
461            true => result.expect("failed to verify"),
462            false => {
463                result.expect_err("expected verifying error");
464            }
465        }
466    }
467
468    #[rstest]
469    #[case(
470        "test\n",
471        hex!(
472            "6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae"
473            "30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962f"
474        ),
475        true,
476    )]
477    #[case(
478        "test\n",
479        hex!(
480            "6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae"
481            "30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962e"
482        ),
483        false,
484    )]
485    fn test_verify_pss_digest_signer(
486        #[case] text: &str,
487        #[case] sig: [u8; 64],
488        #[case] expected: bool,
489    ) {
490        let priv_key = get_private_key();
491        let pub_key: RsaPublicKey = priv_key.into();
492        let verifying_key = VerifyingKey::new(pub_key);
493
494        let result = verifying_key.verify_digest(
495            |digest: &mut Sha1| {
496                digest.update(text.as_bytes());
497                Ok(())
498            },
499            &Signature::try_from(sig.as_slice()).unwrap(),
500        );
501        match expected {
502            true => result.expect("failed to verify"),
503            false => {
504                result.expect_err("expected verifying error");
505            }
506        }
507    }
508
509    #[rstest]
510    #[case("test\n")]
511    fn test_sign_and_verify_roundtrip(#[case] test: &str) {
512        let priv_key = get_private_key();
513
514        let mut rng = ChaCha8Rng::from_seed([42; 32]);
515
516        let digest = Sha1::digest(test.as_bytes()).to_vec();
517        let sig = priv_key
518            .sign_with_rng(&mut rng, Pss::<Sha1>::new(), &digest)
519            .expect("failed to sign");
520
521        priv_key
522            .to_public_key()
523            .verify(Pss::<Sha1>::new(), &digest, &sig)
524            .expect("failed to verify");
525    }
526
527    #[rstest]
528    #[case("test\n")]
529    fn test_sign_blinded_and_verify_roundtrip(#[case] test: &str) {
530        let priv_key = get_private_key();
531
532        let mut rng = ChaCha8Rng::from_seed([42; 32]);
533
534        let digest = Sha1::digest(test.as_bytes()).to_vec();
535        let sig = priv_key
536            .sign_with_rng(&mut rng, Pss::<Sha1>::new_blinded(), &digest)
537            .expect("failed to sign");
538
539        priv_key
540            .to_public_key()
541            .verify(Pss::<Sha1>::new(), &digest, &sig)
542            .expect("failed to verify");
543    }
544
545    #[rstest]
546    #[case("test\n")]
547    fn test_sign_and_verify_roundtrip_signer(#[case] test: &str) {
548        let priv_key = get_private_key();
549
550        let mut rng = ChaCha8Rng::from_seed([42; 32]);
551        let signing_key = SigningKey::<Sha1>::new(priv_key);
552        let verifying_key = signing_key.verifying_key();
553
554        let sig = signing_key.sign_with_rng(&mut rng, test.as_bytes());
555        verifying_key
556            .verify(test.as_bytes(), &sig)
557            .expect("failed to verify");
558    }
559
560    #[rstest]
561    #[case("test\n")]
562    fn test_sign_and_verify_roundtrip_blinded_signer(#[case] test: &str) {
563        let priv_key = get_private_key();
564
565        let mut rng = ChaCha8Rng::from_seed([42; 32]);
566        let signing_key = BlindedSigningKey::<Sha1>::new(priv_key);
567        let verifying_key = signing_key.verifying_key();
568
569        let sig = signing_key.sign_with_rng(&mut rng, test.as_bytes());
570        verifying_key
571            .verify(test.as_bytes(), &sig)
572            .expect("failed to verify");
573    }
574
575    #[rstest]
576    #[case("test\n")]
577    fn test_sign_and_verify_roundtrip_digest_signer(#[case] test: &str) {
578        let priv_key = get_private_key();
579
580        let mut rng = ChaCha8Rng::from_seed([42; 32]);
581        let signing_key = SigningKey::new(priv_key);
582        let verifying_key = signing_key.verifying_key();
583
584        let sig = signing_key
585            .sign_digest_with_rng(&mut rng, |digest: &mut Sha1| digest.update(test.as_bytes()));
586
587        verifying_key
588            .verify_digest(
589                |digest: &mut Sha1| {
590                    digest.update(test.as_bytes());
591                    Ok(())
592                },
593                &sig,
594            )
595            .expect("failed to verify");
596    }
597
598    #[rstest]
599    #[case("test\n")]
600    fn test_sign_and_verify_roundtrip_blinded_digest_signer(#[case] test: &str) {
601        let priv_key = get_private_key();
602
603        let mut rng = ChaCha8Rng::from_seed([42; 32]);
604        let signing_key = BlindedSigningKey::<Sha1>::new(priv_key);
605        let verifying_key = signing_key.verifying_key();
606
607        let sig = signing_key
608            .sign_digest_with_rng(&mut rng, |digest: &mut Sha1| digest.update(test.as_bytes()));
609
610        verifying_key
611            .verify_digest(
612                |digest: &mut Sha1| {
613                    digest.update(test.as_bytes());
614                    Ok(())
615                },
616                &sig,
617            )
618            .expect("failed to verify");
619    }
620
621    #[rstest]
622    #[case(
623        "test\n",
624        hex!(
625            "6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae"
626            "30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962f"
627        ),
628        true
629    )]
630    #[case(
631        "test\n",
632        hex!(
633            "6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae"
634            "30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962e"
635        ),
636        false
637    )]
638    fn test_verify_pss_hazmat(#[case] text: &str, #[case] sig: [u8; 64], #[case] expected: bool) {
639        let text = Sha1::digest(text);
640        let priv_key = get_private_key();
641
642        let pub_key: RsaPublicKey = priv_key.into();
643        let verifying_key = VerifyingKey::<Sha1>::new(pub_key);
644
645        let result = verifying_key
646            .verify_prehash(text.as_ref(), &Signature::try_from(sig.as_slice()).unwrap());
647        match expected {
648            true => result.expect("failed to verify"),
649            false => {
650                result.expect_err("expected verifying error");
651            }
652        }
653    }
654
655    #[rstest]
656    #[case("test\n")]
657    fn test_sign_and_verify_pss_hazmat(#[case] test: &str) {
658        let test = &Sha1::digest(test);
659        let priv_key = get_private_key();
660
661        let mut rng = ChaCha8Rng::from_seed([42; 32]);
662        let signing_key = SigningKey::<Sha1>::new(priv_key);
663        let verifying_key = signing_key.verifying_key();
664
665        let sig = signing_key
666            .sign_prehash_with_rng(&mut rng, test)
667            .expect("failed to sign");
668        verifying_key
669            .verify_prehash(test, &sig)
670            .expect("failed to verify");
671    }
672
673    #[rstest]
674    #[case("test\n")]
675    fn test_sign_and_verify_pss_blinded_hazmat(#[case] test: &str) {
676        let priv_key = get_private_key();
677
678        let test = &Sha1::digest(test);
679        let mut rng = ChaCha8Rng::from_seed([42; 32]);
680        let signing_key = BlindedSigningKey::<Sha1>::new(priv_key);
681        let verifying_key = signing_key.verifying_key();
682
683        let sig = signing_key
684            .sign_prehash_with_rng(&mut rng, test)
685            .expect("failed to sign");
686        verifying_key
687            .verify_prehash(test, &sig)
688            .expect("failed to verify");
689    }
690
691    #[test]
692    #[cfg(feature = "keygen")]
693    // Tests the corner case where the key is multiple of 8 + 1 bits long
694    fn test_sign_and_verify_2049bit_key() {
695        let plaintext = "Hello\n";
696        let mut rng = ChaCha8Rng::from_seed([42; 32]);
697        for i in 0..10 {
698            println!("round {i}");
699            let priv_key = RsaPrivateKey::new(&mut rng, 2049).unwrap();
700
701            let digest = Sha1::digest(plaintext.as_bytes()).to_vec();
702            let sig = priv_key
703                .sign_with_rng(&mut rng, Pss::<Sha1>::new(), &digest)
704                .expect("failed to sign");
705
706            priv_key
707                .to_public_key()
708                .verify(Pss::<Sha1>::new(), &digest, &sig)
709                .expect("failed to verify");
710        }
711    }
712
713    // Tests the case where the salt length used for signing differs from the default length
714    // while the verifier uses auto-detection.
715    #[rstest]
716    #[case("test\n")]
717    fn test_sign_and_verify_pss_differing_salt_len(#[case] test: &str) {
718        let priv_key = get_private_key();
719
720        let mut rng = ChaCha8Rng::from_seed([42; 32]);
721
722        // signing keys using different salt lengths
723        let signing_keys = [
724            // default salt length
725            SigningKey::<Sha1>::new(priv_key.clone()),
726            // maximum salt length
727            SigningKey::<Sha1>::new_with_salt_len(
728                priv_key.clone(),
729                priv_key.size() - Sha1::output_size() - 2,
730            ),
731            // unsalted
732            SigningKey::<Sha1>::new_with_salt_len(priv_key.clone(), 0),
733        ];
734
735        // verifying key uses default salt length strategy
736        let verifying_key = VerifyingKey::<Sha1>::new_with_auto_salt_len(priv_key.to_public_key());
737
738        for signing_key in &signing_keys {
739            let sig = signing_key.sign_with_rng(&mut rng, test.as_bytes());
740            verifying_key
741                .verify(test.as_bytes(), &sig)
742                .expect("verification to succeed");
743        }
744    }
745}