1use 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#[derive(Clone)]
22pub struct RsaPrivateKey {
23 d: Mpint,
25
26 iqmp: Mpint,
28
29 p: Mpint,
31
32 q: Mpint,
34}
35
36impl RsaPrivateKey {
37 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 pub fn d(&self) -> &Mpint {
53 &self.d
54 }
55
56 pub fn iqmp(&self) -> &Mpint {
58 &self.iqmp
59 }
60
61 pub fn p(&self) -> &Mpint {
63 &self.p
64 }
65
66 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#[derive(Clone)]
132pub struct RsaKeypair {
133 public: RsaPublicKey,
135
136 private: RsaPrivateKey,
138}
139
140impl RsaKeypair {
141 #[cfg(feature = "rsa")]
143 pub(crate) const MIN_KEY_SIZE: usize = 2048;
144
145 #[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 pub fn new(public: RsaPublicKey, private: RsaPrivateKey) -> Result<Self> {
157 Ok(Self { public, private })
159 }
160
161 pub fn key_size(&self) -> u32 {
163 self.public.key_size()
164 }
165
166 pub fn public(&self) -> &RsaPublicKey {
168 &self.public
169 }
170
171 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 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}