ssh_key/private/
rsa.rs

1//! Rivest–Shamir–Adleman (RSA) private keys.
2
3use crate::{Error, Mpint, Result, public::RsaPublicKey};
4use core::fmt;
5use encoding::{CheckedSum, Decode, Encode, Reader, Writer};
6use subtle::{Choice, ConstantTimeEq};
7use zeroize::Zeroize;
8
9#[cfg(feature = "rsa")]
10use {
11    encoding::Uint,
12    rand_core::CryptoRng,
13    rsa::{
14        pkcs1v15,
15        traits::{PrivateKeyParts, PublicKeyParts},
16    },
17    sha2::{Digest, digest::const_oid::AssociatedOid},
18};
19
20/// RSA private key.
21#[derive(Clone)]
22pub struct RsaPrivateKey {
23    /// RSA private exponent.
24    d: Mpint,
25
26    /// CRT coefficient: `(inverse of q) mod p`.
27    iqmp: Mpint,
28
29    /// First prime factor of `n`.
30    p: Mpint,
31
32    /// Second prime factor of `n`.
33    q: Mpint,
34}
35
36impl RsaPrivateKey {
37    /// Create a new RSA private key with the following components:
38    ///
39    /// - `d`: RSA private exponent.
40    /// - `iqmp`: CRT coefficient: `(inverse of q) mod p`.
41    /// - `p`: First prime factor of `n`.
42    /// - `q`: Second prime factor of `n`.
43    pub fn new(d: Mpint, iqmp: Mpint, p: Mpint, q: Mpint) -> Result<Self> {
44        if d.is_positive() && iqmp.is_positive() && p.is_positive() && q.is_positive() {
45            Ok(Self { d, iqmp, p, q })
46        } else {
47            Err(Error::FormatEncoding)
48        }
49    }
50
51    /// RSA private exponent.
52    pub fn d(&self) -> &Mpint {
53        &self.d
54    }
55
56    /// CRT coefficient: `(inverse of q) mod p`.
57    pub fn iqmp(&self) -> &Mpint {
58        &self.iqmp
59    }
60
61    /// First prime factor of `n`.
62    pub fn p(&self) -> &Mpint {
63        &self.p
64    }
65
66    /// Second prime factor of `n`.
67    pub fn q(&self) -> &Mpint {
68        &self.q
69    }
70}
71
72impl ConstantTimeEq for RsaPrivateKey {
73    fn ct_eq(&self, other: &Self) -> Choice {
74        self.d.ct_eq(&other.d)
75            & self.iqmp.ct_eq(&self.iqmp)
76            & self.p.ct_eq(&other.p)
77            & self.q.ct_eq(&other.q)
78    }
79}
80
81impl Eq for RsaPrivateKey {}
82
83impl PartialEq for RsaPrivateKey {
84    fn eq(&self, other: &Self) -> bool {
85        self.ct_eq(other).into()
86    }
87}
88
89impl Decode for RsaPrivateKey {
90    type Error = Error;
91
92    fn decode(reader: &mut impl Reader) -> Result<Self> {
93        let d = Mpint::decode(reader)?;
94        let iqmp = Mpint::decode(reader)?;
95        let p = Mpint::decode(reader)?;
96        let q = Mpint::decode(reader)?;
97        Self::new(d, iqmp, p, q)
98    }
99}
100
101impl Encode for RsaPrivateKey {
102    fn encoded_len(&self) -> encoding::Result<usize> {
103        [
104            self.d.encoded_len()?,
105            self.iqmp.encoded_len()?,
106            self.p.encoded_len()?,
107            self.q.encoded_len()?,
108        ]
109        .checked_sum()
110    }
111
112    fn encode(&self, writer: &mut impl Writer) -> encoding::Result<()> {
113        self.d.encode(writer)?;
114        self.iqmp.encode(writer)?;
115        self.p.encode(writer)?;
116        self.q.encode(writer)?;
117        Ok(())
118    }
119}
120
121impl Drop for RsaPrivateKey {
122    fn drop(&mut self) {
123        self.d.zeroize();
124        self.iqmp.zeroize();
125        self.p.zeroize();
126        self.q.zeroize();
127    }
128}
129
130/// RSA private/public keypair.
131#[derive(Clone)]
132pub struct RsaKeypair {
133    /// Public key.
134    public: RsaPublicKey,
135
136    /// Private key.
137    private: RsaPrivateKey,
138}
139
140impl RsaKeypair {
141    /// Minimum allowed RSA key size.
142    #[cfg(feature = "rsa")]
143    pub(crate) const MIN_KEY_SIZE: usize = 2048;
144
145    /// Generate a random RSA keypair of the given size.
146    #[cfg(feature = "rsa")]
147    pub fn random<R: CryptoRng + ?Sized>(rng: &mut R, bit_size: usize) -> Result<Self> {
148        if bit_size >= Self::MIN_KEY_SIZE {
149            rsa::RsaPrivateKey::new(rng, bit_size)?.try_into()
150        } else {
151            Err(Error::Crypto)
152        }
153    }
154
155    /// Create a new keypair from the given `public` and `private` key components.
156    pub fn new(public: RsaPublicKey, private: RsaPrivateKey) -> Result<Self> {
157        // TODO(tarcieri): perform validation that the public and private components match?
158        Ok(Self { public, private })
159    }
160
161    /// Get the size of the RSA modulus in bits.
162    pub fn key_size(&self) -> u32 {
163        self.public.key_size()
164    }
165
166    /// Get the public component of the keypair.
167    pub fn public(&self) -> &RsaPublicKey {
168        &self.public
169    }
170
171    /// Get the private component of the keypair.
172    pub fn private(&self) -> &RsaPrivateKey {
173        &self.private
174    }
175}
176
177impl ConstantTimeEq for RsaKeypair {
178    fn ct_eq(&self, other: &Self) -> Choice {
179        Choice::from((self.public == other.public) as u8) & self.private.ct_eq(&other.private)
180    }
181}
182
183impl Eq for RsaKeypair {}
184
185impl PartialEq for RsaKeypair {
186    fn eq(&self, other: &Self) -> bool {
187        self.ct_eq(other).into()
188    }
189}
190
191impl Decode for RsaKeypair {
192    type Error = Error;
193
194    fn decode(reader: &mut impl Reader) -> Result<Self> {
195        let n = Mpint::decode(reader)?;
196        let e = Mpint::decode(reader)?;
197        let public = RsaPublicKey::new(e, n)?;
198        let private = RsaPrivateKey::decode(reader)?;
199        Self::new(public, private)
200    }
201}
202
203impl Encode for RsaKeypair {
204    fn encoded_len(&self) -> encoding::Result<usize> {
205        [
206            self.public.n().encoded_len()?,
207            self.public.e().encoded_len()?,
208            self.private.encoded_len()?,
209        ]
210        .checked_sum()
211    }
212
213    fn encode(&self, writer: &mut impl Writer) -> encoding::Result<()> {
214        self.public.n().encode(writer)?;
215        self.public.e().encode(writer)?;
216        self.private.encode(writer)
217    }
218}
219
220impl From<RsaKeypair> for RsaPublicKey {
221    fn from(keypair: RsaKeypair) -> RsaPublicKey {
222        keypair.public
223    }
224}
225
226impl From<&RsaKeypair> for RsaPublicKey {
227    fn from(keypair: &RsaKeypair) -> RsaPublicKey {
228        keypair.public.clone()
229    }
230}
231
232impl fmt::Debug for RsaKeypair {
233    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
234        f.debug_struct("RsaKeypair")
235            .field("public", &self.public)
236            .finish_non_exhaustive()
237    }
238}
239
240#[cfg(feature = "rsa")]
241impl TryFrom<RsaKeypair> for rsa::RsaPrivateKey {
242    type Error = Error;
243
244    fn try_from(key: RsaKeypair) -> Result<rsa::RsaPrivateKey> {
245        rsa::RsaPrivateKey::try_from(&key)
246    }
247}
248
249#[cfg(feature = "rsa")]
250impl TryFrom<&RsaKeypair> for rsa::RsaPrivateKey {
251    type Error = Error;
252
253    fn try_from(key: &RsaKeypair) -> Result<rsa::RsaPrivateKey> {
254        let ret = rsa::RsaPrivateKey::from_components(
255            Uint::try_from(key.public.n())?,
256            Uint::try_from(key.public.e())?,
257            Uint::try_from(&key.private.d)?,
258            vec![
259                Uint::try_from(&key.private.p)?,
260                Uint::try_from(&key.private.q)?,
261            ],
262        )?;
263
264        if ret.size().saturating_mul(8) >= RsaKeypair::MIN_KEY_SIZE {
265            Ok(ret)
266        } else {
267            Err(Error::Crypto)
268        }
269    }
270}
271
272#[cfg(feature = "rsa")]
273impl TryFrom<rsa::RsaPrivateKey> for RsaKeypair {
274    type Error = Error;
275
276    fn try_from(key: rsa::RsaPrivateKey) -> Result<RsaKeypair> {
277        RsaKeypair::try_from(&key)
278    }
279}
280
281#[cfg(feature = "rsa")]
282impl TryFrom<&rsa::RsaPrivateKey> for RsaKeypair {
283    type Error = Error;
284
285    fn try_from(key: &rsa::RsaPrivateKey) -> Result<RsaKeypair> {
286        // Multi-prime keys are not supported
287        if key.primes().len() > 2 {
288            return Err(Error::Crypto);
289        }
290
291        let public = RsaPublicKey::try_from(key.to_public_key())?;
292
293        let p = &key.primes()[0];
294        let q = &key.primes()[1];
295        let iqmp = key.crt_coefficient().ok_or(Error::Crypto)?;
296
297        let private = RsaPrivateKey {
298            d: key.d().try_into()?,
299            iqmp: iqmp.try_into()?,
300            p: p.try_into()?,
301            q: q.try_into()?,
302        };
303
304        Ok(RsaKeypair { public, private })
305    }
306}
307
308#[cfg(feature = "rsa")]
309impl<D> TryFrom<&RsaKeypair> for pkcs1v15::SigningKey<D>
310where
311    D: Digest + AssociatedOid,
312{
313    type Error = Error;
314
315    fn try_from(keypair: &RsaKeypair) -> Result<pkcs1v15::SigningKey<D>> {
316        Ok(pkcs1v15::SigningKey::new(keypair.try_into()?))
317    }
318}