Skip to main content

ssh_key_fork_arti/private/
rsa.rs

1//! Rivest–Shamir–Adleman (RSA) private keys.
2
3use crate::{public::RsaPublicKey, Error, Mpint, Result};
4use core::fmt;
5use encoding::{CheckedSum, Decode, Encode, Reader, Writer};
6use subtle::{Choice, ConstantTimeEq};
7use zeroize::Zeroize;
8
9#[cfg(feature = "rsa")]
10use {
11    rand_core::CryptoRngCore,
12    rsa::{pkcs1v15, traits::PrivateKeyParts},
13    sha2::{digest::const_oid::AssociatedOid, Digest},
14};
15
16/// RSA private key.
17#[derive(Clone)]
18pub struct RsaPrivateKey {
19    /// RSA private exponent.
20    pub d: Mpint,
21
22    /// CRT coefficient: `(inverse of q) mod p`.
23    pub iqmp: Mpint,
24
25    /// First prime factor of `n`.
26    pub p: Mpint,
27
28    /// Second prime factor of `n`.
29    pub q: Mpint,
30}
31
32impl ConstantTimeEq for RsaPrivateKey {
33    fn ct_eq(&self, other: &Self) -> Choice {
34        self.d.ct_eq(&other.d)
35            & self.iqmp.ct_eq(&self.iqmp)
36            & self.p.ct_eq(&other.p)
37            & self.q.ct_eq(&other.q)
38    }
39}
40
41impl Eq for RsaPrivateKey {}
42
43impl PartialEq for RsaPrivateKey {
44    fn eq(&self, other: &Self) -> bool {
45        self.ct_eq(other).into()
46    }
47}
48
49impl Decode for RsaPrivateKey {
50    type Error = Error;
51
52    fn decode(reader: &mut impl Reader) -> Result<Self> {
53        let d = Mpint::decode(reader)?;
54        let iqmp = Mpint::decode(reader)?;
55        let p = Mpint::decode(reader)?;
56        let q = Mpint::decode(reader)?;
57        Ok(Self { d, iqmp, p, q })
58    }
59}
60
61impl Encode for RsaPrivateKey {
62    fn encoded_len(&self) -> encoding::Result<usize> {
63        [
64            self.d.encoded_len()?,
65            self.iqmp.encoded_len()?,
66            self.p.encoded_len()?,
67            self.q.encoded_len()?,
68        ]
69        .checked_sum()
70    }
71
72    fn encode(&self, writer: &mut impl Writer) -> encoding::Result<()> {
73        self.d.encode(writer)?;
74        self.iqmp.encode(writer)?;
75        self.p.encode(writer)?;
76        self.q.encode(writer)?;
77        Ok(())
78    }
79}
80
81impl Drop for RsaPrivateKey {
82    fn drop(&mut self) {
83        self.d.zeroize();
84        self.iqmp.zeroize();
85        self.p.zeroize();
86        self.q.zeroize();
87    }
88}
89
90/// RSA private/public keypair.
91#[derive(Clone)]
92pub struct RsaKeypair {
93    /// Public key.
94    pub public: RsaPublicKey,
95
96    /// Private key.
97    pub private: RsaPrivateKey,
98}
99
100impl RsaKeypair {
101    /// Generate a random RSA keypair of the given size.
102    #[cfg(feature = "rsa")]
103    pub fn random(rng: &mut impl CryptoRngCore, bit_size: usize) -> Result<Self> {
104        rsa::RsaPrivateKey::new(rng, bit_size)?.try_into()
105    }
106}
107
108impl ConstantTimeEq for RsaKeypair {
109    fn ct_eq(&self, other: &Self) -> Choice {
110        Choice::from((self.public == other.public) as u8) & self.private.ct_eq(&other.private)
111    }
112}
113
114impl Eq for RsaKeypair {}
115
116impl PartialEq for RsaKeypair {
117    fn eq(&self, other: &Self) -> bool {
118        self.ct_eq(other).into()
119    }
120}
121
122impl Decode for RsaKeypair {
123    type Error = Error;
124
125    fn decode(reader: &mut impl Reader) -> Result<Self> {
126        let n = Mpint::decode(reader)?;
127        let e = Mpint::decode(reader)?;
128        let public = RsaPublicKey { n, e };
129        let private = RsaPrivateKey::decode(reader)?;
130        Ok(RsaKeypair { public, private })
131    }
132}
133
134impl Encode for RsaKeypair {
135    fn encoded_len(&self) -> encoding::Result<usize> {
136        [
137            self.public.n.encoded_len()?,
138            self.public.e.encoded_len()?,
139            self.private.encoded_len()?,
140        ]
141        .checked_sum()
142    }
143
144    fn encode(&self, writer: &mut impl Writer) -> encoding::Result<()> {
145        self.public.n.encode(writer)?;
146        self.public.e.encode(writer)?;
147        self.private.encode(writer)
148    }
149}
150
151impl From<RsaKeypair> for RsaPublicKey {
152    fn from(keypair: RsaKeypair) -> RsaPublicKey {
153        keypair.public
154    }
155}
156
157impl From<&RsaKeypair> for RsaPublicKey {
158    fn from(keypair: &RsaKeypair) -> RsaPublicKey {
159        keypair.public.clone()
160    }
161}
162
163impl fmt::Debug for RsaKeypair {
164    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
165        f.debug_struct("RsaKeypair")
166            .field("public", &self.public)
167            .finish_non_exhaustive()
168    }
169}
170
171#[cfg(feature = "rsa")]
172impl TryFrom<RsaKeypair> for rsa::RsaPrivateKey {
173    type Error = Error;
174
175    fn try_from(key: RsaKeypair) -> Result<rsa::RsaPrivateKey> {
176        rsa::RsaPrivateKey::try_from(&key)
177    }
178}
179
180#[cfg(feature = "rsa")]
181impl TryFrom<&RsaKeypair> for rsa::RsaPrivateKey {
182    type Error = Error;
183
184    fn try_from(key: &RsaKeypair) -> Result<rsa::RsaPrivateKey> {
185        let ret = rsa::RsaPrivateKey::from_components(
186            rsa::BigUint::try_from(&key.public.n)?,
187            rsa::BigUint::try_from(&key.public.e)?,
188            rsa::BigUint::try_from(&key.private.d)?,
189            vec![
190                rsa::BigUint::try_from(&key.private.p)?,
191                rsa::BigUint::try_from(&key.private.q)?,
192            ],
193        )?;
194
195        Ok(ret)
196    }
197}
198
199#[cfg(feature = "rsa")]
200impl TryFrom<rsa::RsaPrivateKey> for RsaKeypair {
201    type Error = Error;
202
203    fn try_from(key: rsa::RsaPrivateKey) -> Result<RsaKeypair> {
204        RsaKeypair::try_from(&key)
205    }
206}
207
208#[cfg(feature = "rsa")]
209impl TryFrom<&rsa::RsaPrivateKey> for RsaKeypair {
210    type Error = Error;
211
212    fn try_from(key: &rsa::RsaPrivateKey) -> Result<RsaKeypair> {
213        // Multi-prime keys are not supported
214        if key.primes().len() > 2 {
215            return Err(Error::Crypto);
216        }
217
218        let public = RsaPublicKey::try_from(key.to_public_key())?;
219
220        let p = &key.primes()[0];
221        let q = &key.primes()[1];
222        let iqmp = key.crt_coefficient().ok_or(Error::Crypto)?;
223
224        let private = RsaPrivateKey {
225            d: key.d().try_into()?,
226            iqmp: iqmp.try_into()?,
227            p: p.try_into()?,
228            q: q.try_into()?,
229        };
230
231        Ok(RsaKeypair { public, private })
232    }
233}
234
235#[cfg(feature = "rsa")]
236impl<D> TryFrom<&RsaKeypair> for pkcs1v15::SigningKey<D>
237where
238    D: Digest + AssociatedOid,
239{
240    type Error = Error;
241
242    fn try_from(keypair: &RsaKeypair) -> Result<pkcs1v15::SigningKey<D>> {
243        Ok(pkcs1v15::SigningKey::new(keypair.try_into()?))
244    }
245}