rsa/pkcs1v15/
signing_key.rs

1use super::{oid, pkcs1v15_generate_prefix, sign, Signature, VerifyingKey};
2use crate::{dummy_rng::DummyRng, Result, RsaPrivateKey};
3use alloc::vec::Vec;
4use core::marker::PhantomData;
5use digest::Digest;
6use pkcs8::{
7    spki::{
8        der::AnyRef, AlgorithmIdentifierRef, AssociatedAlgorithmIdentifier,
9        SignatureAlgorithmIdentifier,
10    },
11    AssociatedOid, EncodePrivateKey, SecretDocument,
12};
13use rand_core::CryptoRngCore;
14use signature::{
15    hazmat::PrehashSigner, DigestSigner, Keypair, RandomizedDigestSigner, RandomizedSigner, Signer,
16};
17use zeroize::ZeroizeOnDrop;
18
19/// Signing key for `RSASSA-PKCS1-v1_5` signatures as described in [RFC8017 § 8.2].
20///
21/// [RFC8017 § 8.2]: https://datatracker.ietf.org/doc/html/rfc8017#section-8.2
22#[derive(Debug, Clone)]
23pub struct SigningKey<D>
24where
25    D: Digest,
26{
27    inner: RsaPrivateKey,
28    prefix: Vec<u8>,
29    phantom: PhantomData<D>,
30}
31
32impl<D> SigningKey<D>
33where
34    D: Digest + AssociatedOid,
35{
36    /// Create a new signing key with a prefix for the digest `D`.
37    pub fn new(key: RsaPrivateKey) -> Self {
38        Self {
39            inner: key,
40            prefix: pkcs1v15_generate_prefix::<D>(),
41            phantom: Default::default(),
42        }
43    }
44
45    /// Generate a new signing key with a prefix for the digest `D`.
46    pub fn random<R: CryptoRngCore + ?Sized>(rng: &mut R, bit_size: usize) -> Result<Self> {
47        Ok(Self {
48            inner: RsaPrivateKey::new(rng, bit_size)?,
49            prefix: pkcs1v15_generate_prefix::<D>(),
50            phantom: Default::default(),
51        })
52    }
53
54    /// Create a new signing key with a prefix for the digest `D`.
55    #[deprecated(since = "0.9.0", note = "use SigningKey::new instead")]
56    pub fn new_with_prefix(key: RsaPrivateKey) -> Self {
57        Self::new(key)
58    }
59
60    /// Generate a new signing key with a prefix for the digest `D`.
61    #[deprecated(since = "0.9.0", note = "use SigningKey::random instead")]
62    pub fn random_with_prefix<R: CryptoRngCore + ?Sized>(
63        rng: &mut R,
64        bit_size: usize,
65    ) -> Result<Self> {
66        Self::random(rng, bit_size)
67    }
68}
69
70impl<D> SigningKey<D>
71where
72    D: Digest,
73{
74    /// Create a new signing key from the give RSA private key with an empty prefix.
75    ///
76    /// ## Note: unprefixed signatures are uncommon
77    ///
78    /// In most cases you'll want to use [`SigningKey::new`].
79    pub fn new_unprefixed(key: RsaPrivateKey) -> Self {
80        Self {
81            inner: key,
82            prefix: Vec::new(),
83            phantom: Default::default(),
84        }
85    }
86
87    /// Generate a new signing key with an empty prefix.
88    pub fn random_unprefixed<R: CryptoRngCore + ?Sized>(
89        rng: &mut R,
90        bit_size: usize,
91    ) -> Result<Self> {
92        Ok(Self {
93            inner: RsaPrivateKey::new(rng, bit_size)?,
94            prefix: Vec::new(),
95            phantom: Default::default(),
96        })
97    }
98}
99
100//
101// `*Signer` trait impls
102//
103
104impl<D> DigestSigner<D, Signature> for SigningKey<D>
105where
106    D: Digest,
107{
108    fn try_sign_digest(&self, digest: D) -> signature::Result<Signature> {
109        sign::<DummyRng>(None, &self.inner, &self.prefix, &digest.finalize())?
110            .as_slice()
111            .try_into()
112    }
113}
114
115impl<D> PrehashSigner<Signature> for SigningKey<D>
116where
117    D: Digest,
118{
119    fn sign_prehash(&self, prehash: &[u8]) -> signature::Result<Signature> {
120        sign::<DummyRng>(None, &self.inner, &self.prefix, prehash)?
121            .as_slice()
122            .try_into()
123    }
124}
125
126impl<D> RandomizedDigestSigner<D, Signature> for SigningKey<D>
127where
128    D: Digest,
129{
130    fn try_sign_digest_with_rng(
131        &self,
132        rng: &mut impl CryptoRngCore,
133        digest: D,
134    ) -> signature::Result<Signature> {
135        sign(Some(rng), &self.inner, &self.prefix, &digest.finalize())?
136            .as_slice()
137            .try_into()
138    }
139}
140
141impl<D> RandomizedSigner<Signature> for SigningKey<D>
142where
143    D: Digest,
144{
145    fn try_sign_with_rng(
146        &self,
147        rng: &mut impl CryptoRngCore,
148        msg: &[u8],
149    ) -> signature::Result<Signature> {
150        sign(Some(rng), &self.inner, &self.prefix, &D::digest(msg))?
151            .as_slice()
152            .try_into()
153    }
154}
155
156impl<D> Signer<Signature> for SigningKey<D>
157where
158    D: Digest,
159{
160    fn try_sign(&self, msg: &[u8]) -> signature::Result<Signature> {
161        sign::<DummyRng>(None, &self.inner, &self.prefix, &D::digest(msg))?
162            .as_slice()
163            .try_into()
164    }
165}
166
167//
168// Other trait impls
169//
170
171impl<D> AsRef<RsaPrivateKey> for SigningKey<D>
172where
173    D: Digest,
174{
175    fn as_ref(&self) -> &RsaPrivateKey {
176        &self.inner
177    }
178}
179
180impl<D> AssociatedAlgorithmIdentifier for SigningKey<D>
181where
182    D: Digest,
183{
184    type Params = AnyRef<'static>;
185
186    const ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = pkcs1::ALGORITHM_ID;
187}
188
189impl<D> EncodePrivateKey for SigningKey<D>
190where
191    D: Digest,
192{
193    fn to_pkcs8_der(&self) -> pkcs8::Result<SecretDocument> {
194        self.inner.to_pkcs8_der()
195    }
196}
197
198impl<D> From<RsaPrivateKey> for SigningKey<D>
199where
200    D: Digest,
201{
202    fn from(key: RsaPrivateKey) -> Self {
203        Self::new_unprefixed(key)
204    }
205}
206
207impl<D> From<SigningKey<D>> for RsaPrivateKey
208where
209    D: Digest,
210{
211    fn from(key: SigningKey<D>) -> Self {
212        key.inner
213    }
214}
215
216impl<D> Keypair for SigningKey<D>
217where
218    D: Digest,
219{
220    type VerifyingKey = VerifyingKey<D>;
221
222    fn verifying_key(&self) -> Self::VerifyingKey {
223        VerifyingKey {
224            inner: self.inner.to_public_key(),
225            prefix: self.prefix.clone(),
226            phantom: Default::default(),
227        }
228    }
229}
230
231impl<D> SignatureAlgorithmIdentifier for SigningKey<D>
232where
233    D: Digest + oid::RsaSignatureAssociatedOid,
234{
235    type Params = AnyRef<'static>;
236
237    const SIGNATURE_ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> =
238        AlgorithmIdentifierRef {
239            oid: D::OID,
240            parameters: Some(AnyRef::NULL),
241        };
242}
243
244impl<D> TryFrom<pkcs8::PrivateKeyInfo<'_>> for SigningKey<D>
245where
246    D: Digest + AssociatedOid,
247{
248    type Error = pkcs8::Error;
249
250    fn try_from(private_key_info: pkcs8::PrivateKeyInfo<'_>) -> pkcs8::Result<Self> {
251        RsaPrivateKey::try_from(private_key_info).map(Self::new)
252    }
253}
254
255impl<D> ZeroizeOnDrop for SigningKey<D> where D: Digest {}