Skip to main content

rsa/
pkcs1v15.rs

1//! PKCS#1 v1.5 support as described in [RFC8017 § 8.2].
2//!
3//! <div class="warning">
4//! <b>Warning</b>
5//!
6//! PKCS#1 v1.5 padding has a longstanding history of issues generally classed as
7//! [Bleichenbacher Attacks] which were originally discovered in 1998 but keep reappearing in
8//! various forms again and again over the course of decades, including most recently in the 2023
9//! [Marvin Attack], which the `rsa` crate is [still vulnerable] to.
10//!
11//! These attacks can result in complete plaintext recovery for encryption, or signature forgery,
12//! leading to a total failure of either confidentiality or integrity.
13//!
14//! Unless explicitly needed for compatibility reasons, we recommend against using PKCS#1 v1.5,
15//! and suggest using [PSS][`super::pss`] or [OAEP][`super::oaep`] instead (if there is a
16//! requirement to use RSA).
17//! </div>
18//!
19//! [Bleichenbacher Attacks]: https://en.wikipedia.org/wiki/Adaptive_chosen-ciphertext_attack#Practical_attacks
20//! [Marvin Attack]: https://people.redhat.com/~hkario/marvin/
21//! [still vulnerable]: https://github.com/RustCrypto/RSA/issues/626
22//!
23//! # Usage
24//!
25//! See [code example in the toplevel rustdoc](../index.html#pkcs1-v15-signatures).
26//!
27//! [RFC8017 § 8.2]: https://datatracker.ietf.org/doc/html/rfc8017#section-8.2
28
29mod decrypting_key;
30mod encrypting_key;
31mod signature;
32mod signing_key;
33mod verifying_key;
34
35pub use self::{
36    decrypting_key::DecryptingKey, encrypting_key::EncryptingKey, signature::Signature,
37    signing_key::SigningKey, verifying_key::VerifyingKey,
38};
39
40use alloc::{boxed::Box, vec::Vec};
41use const_oid::AssociatedOid;
42use core::fmt::Debug;
43use crypto_bigint::BoxedUint;
44use digest::Digest;
45use rand_core::TryCryptoRng;
46
47use crate::algorithms::pad::{uint_to_be_pad, uint_to_zeroizing_be_pad};
48use crate::algorithms::pkcs1v15::*;
49use crate::algorithms::rsa::{rsa_decrypt_and_check, rsa_encrypt};
50use crate::errors::{Error, Result};
51use crate::key::{self, RsaPrivateKey, RsaPublicKey};
52use crate::traits::{PaddingScheme, PublicKeyParts, SignatureScheme};
53
54/// Encryption using PKCS#1 v1.5 padding.
55#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
56pub struct Pkcs1v15Encrypt;
57
58impl PaddingScheme for Pkcs1v15Encrypt {
59    fn decrypt<Rng: TryCryptoRng + ?Sized>(
60        self,
61        rng: Option<&mut Rng>,
62        priv_key: &RsaPrivateKey,
63        ciphertext: &[u8],
64    ) -> Result<Vec<u8>> {
65        decrypt(rng, priv_key, ciphertext)
66    }
67
68    fn encrypt<Rng: TryCryptoRng + ?Sized>(
69        self,
70        rng: &mut Rng,
71        pub_key: &RsaPublicKey,
72        msg: &[u8],
73    ) -> Result<Vec<u8>> {
74        encrypt(rng, pub_key, msg)
75    }
76}
77
78/// `RSASSA-PKCS1-v1_5`: digital signatures using PKCS#1 v1.5 padding.
79#[derive(Clone, Debug, Eq, PartialEq)]
80pub struct Pkcs1v15Sign {
81    /// Length of hash to use.
82    pub hash_len: Option<usize>,
83
84    /// Prefix.
85    pub prefix: Box<[u8]>,
86}
87
88impl Pkcs1v15Sign {
89    /// Create new PKCS#1 v1.5 padding for the given digest.
90    ///
91    /// The digest must have an [`AssociatedOid`]. Make sure to enable the `oid`
92    /// feature of the relevant digest crate.
93    pub fn new<D>() -> Self
94    where
95        D: Digest + AssociatedOid,
96    {
97        Self {
98            hash_len: Some(<D as Digest>::output_size()),
99            prefix: pkcs1v15_generate_prefix::<D>().into_boxed_slice(),
100        }
101    }
102
103    /// Create new PKCS#1 v1.5 padding for computing an unprefixed signature.
104    ///
105    /// This sets `hash_len` to `None` and uses an empty `prefix`.
106    pub fn new_unprefixed() -> Self {
107        Self {
108            hash_len: None,
109            prefix: Box::new([]),
110        }
111    }
112}
113
114impl SignatureScheme for Pkcs1v15Sign {
115    fn sign<Rng: TryCryptoRng + ?Sized>(
116        self,
117        rng: Option<&mut Rng>,
118        priv_key: &RsaPrivateKey,
119        hashed: &[u8],
120    ) -> Result<Vec<u8>> {
121        if let Some(hash_len) = self.hash_len {
122            if hashed.len() != hash_len {
123                return Err(Error::InputNotHashed);
124            }
125        }
126
127        sign(rng, priv_key, &self.prefix, hashed)
128    }
129
130    fn verify(self, pub_key: &RsaPublicKey, hashed: &[u8], sig: &[u8]) -> Result<()> {
131        if let Some(hash_len) = self.hash_len {
132            if hashed.len() != hash_len {
133                return Err(Error::InputNotHashed);
134            }
135        }
136
137        verify(
138            pub_key,
139            self.prefix.as_ref(),
140            hashed,
141            &BoxedUint::from_be_slice_vartime(sig),
142        )
143    }
144}
145
146/// Encrypts the given message with RSA and the padding
147/// scheme from PKCS#1 v1.5.  The message must be no longer than the
148/// length of the public modulus minus 11 bytes.
149#[inline]
150fn encrypt<R: TryCryptoRng + ?Sized>(
151    rng: &mut R,
152    pub_key: &RsaPublicKey,
153    msg: &[u8],
154) -> Result<Vec<u8>> {
155    key::check_public(pub_key)?;
156
157    let em = pkcs1v15_encrypt_pad(rng, msg, pub_key.size())?;
158    let int = BoxedUint::from_be_slice(&em, pub_key.n_bits_precision())?;
159    uint_to_be_pad(rsa_encrypt(pub_key, &int)?, pub_key.size())
160}
161
162/// Decrypts a plaintext using RSA and the padding scheme from PKCS#1 v1.5.
163///
164/// If an `rng` is passed, it uses RSA blinding to avoid timing side-channel attacks.
165///
166/// Note that whether this function returns an error or not discloses secret
167/// information. If an attacker can cause this function to run repeatedly and
168/// learn whether each instance returned an error then they can decrypt and
169/// forge signatures as if they had the private key. See
170/// `decrypt_session_key` for a way of solving this problem.
171#[inline]
172fn decrypt<R: TryCryptoRng + ?Sized>(
173    rng: Option<&mut R>,
174    priv_key: &RsaPrivateKey,
175    ciphertext: &[u8],
176) -> Result<Vec<u8>> {
177    key::check_public(priv_key)?;
178
179    let ciphertext = BoxedUint::from_be_slice(ciphertext, priv_key.n_bits_precision())?;
180    let em = rsa_decrypt_and_check(priv_key, rng, &ciphertext)?;
181    let em = uint_to_zeroizing_be_pad(em, priv_key.size())?;
182
183    pkcs1v15_encrypt_unpad(em, priv_key.size())
184}
185
186/// Calculates the signature of hashed using
187/// RSASSA-PKCS1-V1_5-SIGN from RSA PKCS#1 v1.5. Note that `hashed` must
188/// be the result of hashing the input message using the given hash
189/// function. If hash is `None`, hashed is signed directly. This isn't
190/// advisable except for interoperability.
191///
192/// If `rng` is not `None` then RSA blinding will be used to avoid timing
193/// side-channel attacks.
194///
195/// This function is deterministic. Thus, if the set of possible
196/// messages is small, an attacker may be able to build a map from
197/// messages to signatures and identify the signed messages. As ever,
198/// signatures provide authenticity, not confidentiality.
199#[inline]
200fn sign<R: TryCryptoRng + ?Sized>(
201    rng: Option<&mut R>,
202    priv_key: &RsaPrivateKey,
203    prefix: &[u8],
204    hashed: &[u8],
205) -> Result<Vec<u8>> {
206    let em = pkcs1v15_sign_pad(prefix, hashed, priv_key.size())?;
207
208    let em = BoxedUint::from_be_slice(&em, priv_key.n_bits_precision())?;
209    uint_to_zeroizing_be_pad(rsa_decrypt_and_check(priv_key, rng, &em)?, priv_key.size())
210}
211
212/// Verifies an RSA PKCS#1 v1.5 signature.
213#[inline]
214fn verify(pub_key: &RsaPublicKey, prefix: &[u8], hashed: &[u8], sig: &BoxedUint) -> Result<()> {
215    let n = pub_key.n();
216    if sig >= n.as_ref() || sig.bits_precision() != pub_key.n_bits_precision() {
217        return Err(Error::Verification);
218    }
219
220    let em = uint_to_be_pad(rsa_encrypt(pub_key, sig)?, pub_key.size())?;
221
222    pkcs1v15_sign_unpad(prefix, hashed, &em, pub_key.size())
223}
224
225mod oid {
226    use const_oid::ObjectIdentifier;
227
228    /// A trait which associates an RSA-specific OID with a type.
229    pub trait RsaSignatureAssociatedOid {
230        /// The OID associated with this type.
231        const OID: ObjectIdentifier;
232    }
233
234    #[cfg(feature = "sha1")]
235    impl RsaSignatureAssociatedOid for sha1::Sha1 {
236        const OID: ObjectIdentifier =
237            const_oid::ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.5");
238    }
239
240    #[cfg(feature = "sha2")]
241    impl RsaSignatureAssociatedOid for sha2::Sha224 {
242        const OID: ObjectIdentifier =
243            const_oid::ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.14");
244    }
245
246    #[cfg(feature = "sha2")]
247    impl RsaSignatureAssociatedOid for sha2::Sha256 {
248        const OID: ObjectIdentifier =
249            const_oid::ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.11");
250    }
251
252    #[cfg(feature = "sha2")]
253    impl RsaSignatureAssociatedOid for sha2::Sha384 {
254        const OID: ObjectIdentifier =
255            const_oid::ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.12");
256    }
257
258    #[cfg(feature = "sha2")]
259    impl RsaSignatureAssociatedOid for sha2::Sha512 {
260        const OID: ObjectIdentifier =
261            const_oid::ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.13");
262    }
263}
264
265pub use oid::RsaSignatureAssociatedOid;
266
267#[cfg(test)]
268mod tests {
269    use super::*;
270    use ::signature::{
271        hazmat::{PrehashSigner, PrehashVerifier},
272        DigestSigner, DigestVerifier, Keypair, RandomizedDigestSigner, RandomizedSigner,
273        SignatureEncoding, Signer, Verifier,
274    };
275    use base64ct::{Base64, Encoding};
276    use hex_literal::hex;
277    use rand::rngs::ChaCha8Rng;
278    use rand_core::{Rng, SeedableRng};
279    use rstest::rstest;
280    use sha1::{Digest, Sha1};
281    use sha2::Sha256;
282    use sha3::Sha3_256;
283
284    use crate::traits::{
285        Decryptor, EncryptingKeypair, PublicKeyParts, RandomizedDecryptor, RandomizedEncryptor,
286    };
287    use crate::{RsaPrivateKey, RsaPublicKey};
288
289    fn get_private_key() -> RsaPrivateKey {
290        // In order to generate new test vectors you'll need the PEM form of this key:
291        // -----BEGIN RSA PRIVATE KEY-----
292        // MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0
293        // fd7Ai2KW5ToIwzFofvJcS/STa6HA5gQenRUCAwEAAQJBAIq9amn00aS0h/CrjXqu
294        // /ThglAXJmZhOMPVn4eiu7/ROixi9sex436MaVeMqSNf7Ex9a8fRNfWss7Sqd9eWu
295        // RTUCIQDasvGASLqmjeffBNLTXV2A5g4t+kLVCpsEIZAycV5GswIhANEPLmax0ME/
296        // EO+ZJ79TJKN5yiGBRsv5yvx5UiHxajEXAiAhAol5N4EUyq6I9w1rYdhPMGpLfk7A
297        // IU2snfRJ6Nq2CQIgFrPsWRCkV+gOYcajD17rEqmuLrdIRexpg8N1DOSXoJ8CIGlS
298        // tAboUGBxTDq3ZroNism3DaMIbKPyYrAqhKov1h5V
299        // -----END RSA PRIVATE KEY-----
300
301        RsaPrivateKey::from_components(
302            BoxedUint::from_be_hex("B2990F49C47DFA8CD400AE6A4D1B8A3B6A13642B23F28B003BFB97790ADE9A4CC82B8B2A81747DDEC08B6296E53A08C331687EF25C4BF4936BA1C0E6041E9D15", 512).unwrap(),
303            BoxedUint::from(65_537u64),
304            BoxedUint::from_be_hex("8ABD6A69F4D1A4B487F0AB8D7AAEFD38609405C999984E30F567E1E8AEEFF44E8B18BDB1EC78DFA31A55E32A48D7FB131F5AF1F44D7D6B2CED2A9DF5E5AE4535", 512).unwrap(),
305            vec![
306                BoxedUint::from_be_hex("DAB2F18048BAA68DE7DF04D2D35D5D80E60E2DFA42D50A9B04219032715E46B3", 256).unwrap(),
307                BoxedUint::from_be_hex("D10F2E66B1D0C13F10EF9927BF5324A379CA218146CBF9CAFC795221F16A3117", 256).unwrap()
308            ],
309        ).unwrap()
310    }
311
312    #[rstest]
313    #[case(
314        "gIcUIoVkD6ATMBk/u/nlCZCCWRKdkfjCgFdo35VpRXLduiKXhNz1XupLLzTXAybEq15juc+EgY5o0DHv/nt3yg==",
315        "x"
316    )]
317    #[case(
318        "Y7TOCSqofGhkRb+jaVRLzK8xw2cSo1IVES19utzv6hwvx+M8kFsoWQm5DzBeJCZTCVDPkTpavUuEbgp8hnUGDw==",
319        "testing."
320    )]
321    #[case(
322        "arReP9DJtEVyV2Dg3dDp4c/PSk1O6lxkoJ8HcFupoRorBZG+7+1fDAwT1olNddFnQMjmkb8vxwmNMoTAT/BFjQ==",
323        "testing.\n"
324    )]
325    #[case(
326        "WtaBXIoGC54+vH0NH0CHHE+dRDOsMc/6BrfFu2lEqcKL9+uDuWaf+Xj9mrbQCjjZcpQuX733zyok/jsnqe/Ftw==",
327        "01234567890123456789012345678901234567890123456789012"
328    )]
329    fn test_decrypt_pkcs1v15(#[case] ciphertext: &str, #[case] plaintext: &str) {
330        let priv_key = get_private_key();
331
332        let out = priv_key
333            .decrypt(Pkcs1v15Encrypt, &Base64::decode_vec(ciphertext).unwrap())
334            .unwrap();
335        assert_eq!(out, plaintext.as_bytes());
336    }
337
338    #[test]
339    fn test_encrypt_decrypt_pkcs1v15() {
340        let mut rng = ChaCha8Rng::from_seed([42; 32]);
341        let priv_key = get_private_key();
342        let k = priv_key.size();
343
344        for i in 1..100 {
345            let mut input = vec![0u8; i * 8];
346            rng.fill_bytes(&mut input);
347            if input.len() > k - 11 {
348                input = input[0..k - 11].to_vec();
349            }
350
351            let pub_key: RsaPublicKey = priv_key.clone().into();
352            let ciphertext = encrypt(&mut rng, &pub_key, &input).unwrap();
353            assert_ne!(input, ciphertext);
354
355            let blind: bool = rng.next_u32() < (1u32 << 31);
356            let blinder = if blind { Some(&mut rng) } else { None };
357            let plaintext = decrypt(blinder, &priv_key, &ciphertext).unwrap();
358            assert_eq!(input, plaintext);
359        }
360    }
361
362    #[rstest]
363    #[case(
364        "gIcUIoVkD6ATMBk/u/nlCZCCWRKdkfjCgFdo35VpRXLduiKXhNz1XupLLzTXAybEq15juc+EgY5o0DHv/nt3yg==",
365        "x"
366    )]
367    #[case(
368        "Y7TOCSqofGhkRb+jaVRLzK8xw2cSo1IVES19utzv6hwvx+M8kFsoWQm5DzBeJCZTCVDPkTpavUuEbgp8hnUGDw==",
369        "testing."
370    )]
371    #[case(
372        "arReP9DJtEVyV2Dg3dDp4c/PSk1O6lxkoJ8HcFupoRorBZG+7+1fDAwT1olNddFnQMjmkb8vxwmNMoTAT/BFjQ==",
373        "testing.\n"
374    )]
375    #[case(
376        "WtaBXIoGC54+vH0NH0CHHE+dRDOsMc/6BrfFu2lEqcKL9+uDuWaf+Xj9mrbQCjjZcpQuX733zyok/jsnqe/Ftw==",
377        "01234567890123456789012345678901234567890123456789012"
378    )]
379    fn test_decrypt_pkcs1v15_traits(#[case] ciphertext: &str, #[case] plaintext: &str) {
380        let priv_key = get_private_key();
381        let decrypting_key = DecryptingKey::new(priv_key);
382
383        let out = decrypting_key
384            .decrypt(&Base64::decode_vec(ciphertext).unwrap())
385            .unwrap();
386        assert_eq!(out, plaintext.as_bytes());
387    }
388
389    #[test]
390    fn test_encrypt_decrypt_pkcs1v15_traits() {
391        let mut rng = ChaCha8Rng::from_seed([42; 32]);
392        let priv_key = get_private_key();
393        let k = priv_key.size();
394        let decrypting_key = DecryptingKey::new(priv_key);
395
396        for i in 1..100 {
397            let mut input = vec![0u8; i * 8];
398            rng.fill_bytes(&mut input);
399            if input.len() > k - 11 {
400                input = input[0..k - 11].to_vec();
401            }
402
403            let encrypting_key = decrypting_key.encrypting_key();
404            let ciphertext = encrypting_key.encrypt_with_rng(&mut rng, &input).unwrap();
405            assert_ne!(input, ciphertext);
406
407            let blind: bool = rng.next_u32() < (1u32 << 31);
408            let plaintext = if blind {
409                decrypting_key
410                    .decrypt_with_rng(&mut rng, &ciphertext)
411                    .unwrap()
412            } else {
413                decrypting_key.decrypt(&ciphertext).unwrap()
414            };
415            assert_eq!(input, plaintext);
416        }
417    }
418
419    #[rstest]
420    #[case("Test.\n", hex!(
421        "a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
422        "6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362ae"))
423    ]
424    fn test_sign_pkcs1v15(#[case] text: &str, #[case] expected: [u8; 64]) {
425        let priv_key = get_private_key();
426
427        let digest = Sha1::digest(text.as_bytes()).to_vec();
428
429        let out = priv_key.sign(Pkcs1v15Sign::new::<Sha1>(), &digest).unwrap();
430        assert_ne!(out, digest);
431        assert_eq!(out, expected);
432
433        let mut rng = ChaCha8Rng::from_seed([42; 32]);
434        let out2 = priv_key
435            .sign_with_rng(&mut rng, Pkcs1v15Sign::new::<Sha1>(), &digest)
436            .unwrap();
437        assert_eq!(out2, expected);
438    }
439
440    #[rstest]
441    #[case("Test.\n", hex!(
442        "a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
443        "6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362ae"))
444    ]
445    fn test_sign_pkcs1v15_signer(#[case] text: &str, #[case] expected: [u8; 64]) {
446        let priv_key = get_private_key();
447
448        let signing_key = SigningKey::<Sha1>::new(priv_key);
449        let out = signing_key.sign(text.as_bytes()).to_bytes();
450        assert_ne!(out.as_ref(), text.as_bytes());
451        assert_ne!(out.as_ref(), &Sha1::digest(text.as_bytes()).to_vec());
452        assert_eq!(out.as_ref(), expected);
453
454        let mut rng = ChaCha8Rng::from_seed([42; 32]);
455        let out2 = signing_key
456            .sign_with_rng(&mut rng, text.as_bytes())
457            .to_bytes();
458        assert_eq!(out2.as_ref(), expected);
459    }
460
461    #[rstest]
462    #[case("Test.\n", hex!(
463        "2ffae3f3e130287b3a1dcb320e46f52e8f3f7969b646932273a7e3a6f2a182ea"
464        "02d42875a7ffa4a148aa311f9e4b562e4e13a2223fb15f4e5bf5f2b206d9451b"))
465    ]
466    fn test_sign_pkcs1v15_signer_sha2_256(#[case] text: &str, #[case] expected: [u8; 64]) {
467        let priv_key = get_private_key();
468        let signing_key = SigningKey::<Sha256>::new(priv_key);
469
470        let out = signing_key.sign(text.as_bytes()).to_bytes();
471        assert_ne!(out.as_ref(), text.as_bytes());
472        assert_eq!(out.as_ref(), expected);
473
474        let mut rng = ChaCha8Rng::from_seed([42; 32]);
475        let out2 = signing_key
476            .sign_with_rng(&mut rng, text.as_bytes())
477            .to_bytes();
478        assert_eq!(out2.as_ref(), expected);
479    }
480
481    #[rstest]
482    #[case("Test.\n", hex!(
483        "55e9fba3354dfb51d2c8111794ea552c86afc2cab154652c03324df8c2c51ba7"
484        "2ff7c14de59a6f9ba50d90c13a7537cc3011948369f1f0ec4a49d21eb7e723f9"))
485    ]
486    fn test_sign_pkcs1v15_signer_sha3_256(#[case] text: &str, #[case] expected: [u8; 64]) {
487        let priv_key = get_private_key();
488        let signing_key = SigningKey::<Sha3_256>::new(priv_key);
489
490        let out = signing_key.sign(text.as_bytes()).to_bytes();
491        assert_ne!(out.as_ref(), text.as_bytes());
492        assert_eq!(out.as_ref(), expected);
493
494        let mut rng = ChaCha8Rng::from_seed([42; 32]);
495        let out2 = signing_key
496            .sign_with_rng(&mut rng, text.as_bytes())
497            .to_bytes();
498        assert_eq!(out2.as_ref(), expected);
499    }
500
501    #[rstest]
502    #[case(
503        "Test.\n", 
504        hex!(
505            "a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
506            "6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362ae"
507        )
508    )]
509    fn test_sign_pkcs1v15_digest_signer(#[case] text: &str, #[case] expected: [u8; 64]) {
510        let priv_key = get_private_key();
511        let signing_key = SigningKey::new(priv_key);
512
513        let mut digest = Sha1::new();
514        digest.update(text.as_bytes());
515        let out = signing_key
516            .sign_digest(|digest: &mut Sha1| digest.update(text.as_bytes()))
517            .to_bytes();
518        assert_ne!(out.as_ref(), text.as_bytes());
519        assert_ne!(out.as_ref(), &Sha1::digest(text.as_bytes()).to_vec());
520        assert_eq!(out.as_ref(), expected);
521
522        let mut rng = ChaCha8Rng::from_seed([42; 32]);
523        let out2 = signing_key
524            .sign_digest_with_rng(&mut rng, |digest: &mut Sha1| digest.update(text.as_bytes()))
525            .to_bytes();
526        assert_eq!(out2.as_ref(), expected);
527    }
528
529    #[rstest]
530    #[case(
531        "Test.\n",
532        hex!(
533            "a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
534            "6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362ae"
535        ),
536        true
537    )]
538    #[case(
539        "Test.\n",
540        hex!(
541            "a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
542            "6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362af"
543        ),
544        false
545    )]
546    fn test_verify_pkcs1v15(#[case] text: &str, #[case] sig: [u8; 64], #[case] expected: bool) {
547        let priv_key = get_private_key();
548        let pub_key: RsaPublicKey = priv_key.into();
549
550        let digest = Sha1::digest(text.as_bytes()).to_vec();
551
552        let result = pub_key.verify(Pkcs1v15Sign::new::<Sha1>(), &digest, &sig);
553        match expected {
554            true => result.expect("failed to verify"),
555            false => {
556                result.expect_err("expected verifying error");
557            }
558        }
559    }
560
561    #[rstest]
562    #[case(
563        "Test.\n",
564        hex!(
565            "a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
566            "6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362ae"
567        ),
568        true
569    )]
570    #[case(
571        "Test.\n",
572        hex!(
573            "a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
574            "6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362af"
575        ),
576        false
577    )]
578    fn test_verify_pkcs1v15_signer(
579        #[case] text: &str,
580        #[case] sig: [u8; 64],
581        #[case] expected: bool,
582    ) {
583        let priv_key = get_private_key();
584
585        let pub_key: RsaPublicKey = priv_key.into();
586        let verifying_key = VerifyingKey::<Sha1>::new(pub_key);
587
588        let result = verifying_key.verify(
589            text.as_bytes(),
590            &Signature::try_from(sig.as_slice()).unwrap(),
591        );
592        match expected {
593            true => result.expect("failed to verify"),
594            false => {
595                result.expect_err("expected verifying error");
596            }
597        }
598    }
599
600    #[rstest]
601    #[case(
602        "Test.\n",
603        hex!(
604            "a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
605            "6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362ae"
606        ),
607        true
608    )]
609    #[case(
610        "Test.\n",
611        hex!(
612            "a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
613            "6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362af"
614        ),
615        false
616    )]
617    fn test_verify_pkcs1v15_digest_signer(
618        #[case] text: &str,
619        #[case] sig: [u8; 64],
620        #[case] expected: bool,
621    ) {
622        let priv_key = get_private_key();
623
624        let pub_key: RsaPublicKey = priv_key.into();
625        let verifying_key = VerifyingKey::new(pub_key);
626
627        let result = verifying_key.verify_digest(
628            |digest: &mut Sha1| {
629                digest.update(text.as_bytes());
630                Ok(())
631            },
632            &Signature::try_from(sig.as_slice()).unwrap(),
633        );
634        match expected {
635            true => result.expect("failed to verify"),
636            false => {
637                result.expect_err("expected verifying error");
638            }
639        }
640    }
641
642    #[test]
643    fn test_unpadded_signature() {
644        let msg = b"Thu Dec 19 18:06:16 EST 2013\n";
645        let expected_sig = Base64::decode_vec("pX4DR8azytjdQ1rtUiC040FjkepuQut5q2ZFX1pTjBrOVKNjgsCDyiJDGZTCNoh9qpXYbhl7iEym30BWWwuiZg==").unwrap();
646        let priv_key = get_private_key();
647
648        let sig = priv_key.sign(Pkcs1v15Sign::new_unprefixed(), msg).unwrap();
649        assert_eq!(expected_sig, sig);
650
651        let pub_key: RsaPublicKey = priv_key.into();
652        pub_key
653            .verify(Pkcs1v15Sign::new_unprefixed(), msg, &sig)
654            .expect("failed to verify");
655    }
656
657    #[test]
658    fn test_unpadded_signature_hazmat() {
659        let msg = b"Thu Dec 19 18:06:16 EST 2013\n";
660        let expected_sig = Base64::decode_vec("pX4DR8azytjdQ1rtUiC040FjkepuQut5q2ZFX1pTjBrOVKNjgsCDyiJDGZTCNoh9qpXYbhl7iEym30BWWwuiZg==").unwrap();
661        let priv_key = get_private_key();
662
663        let signing_key = SigningKey::<Sha1>::new_unprefixed(priv_key);
664        let sig = signing_key
665            .sign_prehash(msg)
666            .expect("Failure during sign")
667            .to_bytes();
668        assert_eq!(sig.as_ref(), expected_sig);
669
670        let verifying_key = signing_key.verifying_key();
671        verifying_key
672            .verify_prehash(msg, &Signature::try_from(expected_sig.as_slice()).unwrap())
673            .expect("failed to verify");
674    }
675}