1use crate::{Error, Mpint, Result, public::RsaPublicKey};
4use core::fmt::{self, Debug};
5use ctutils::{Choice, CtEq};
6use encoding::{CheckedSum, Decode, Encode, Reader, Writer};
7use zeroize::Zeroize;
8
9#[cfg(feature = "rsa")]
10use {
11 encoding::Uint,
12 rand_core::CryptoRng,
13 rsa::{pkcs1v15, traits::PrivateKeyParts},
14 sha2::{Digest, digest::const_oid::AssociatedOid},
15};
16
17#[derive(Clone)]
19pub struct RsaPrivateKey {
20 d: Mpint,
22
23 iqmp: Mpint,
25
26 p: Mpint,
28
29 q: Mpint,
31}
32
33impl RsaPrivateKey {
34 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 #[must_use]
53 pub fn d(&self) -> &Mpint {
54 &self.d
55 }
56
57 #[must_use]
59 pub fn iqmp(&self) -> &Mpint {
60 &self.iqmp
61 }
62
63 #[must_use]
65 pub fn p(&self) -> &Mpint {
66 &self.p
67 }
68
69 #[must_use]
71 pub fn q(&self) -> &Mpint {
72 &self.q
73 }
74}
75
76impl CtEq for RsaPrivateKey {
77 fn ct_eq(&self, other: &Self) -> Choice {
78 self.d.ct_eq(&other.d)
79 & self.iqmp.ct_eq(&self.iqmp)
80 & self.p.ct_eq(&other.p)
81 & self.q.ct_eq(&other.q)
82 }
83}
84
85impl Debug for RsaPrivateKey {
86 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87 f.debug_struct("RsaPrivateKey").finish_non_exhaustive()
88 }
89}
90
91impl Drop for RsaPrivateKey {
92 fn drop(&mut self) {
93 self.d.zeroize();
94 self.iqmp.zeroize();
95 self.p.zeroize();
96 self.q.zeroize();
97 }
98}
99
100impl Decode for RsaPrivateKey {
101 type Error = Error;
102
103 fn decode(reader: &mut impl Reader) -> Result<Self> {
104 let d = Mpint::decode(reader)?;
105 let iqmp = Mpint::decode(reader)?;
106 let p = Mpint::decode(reader)?;
107 let q = Mpint::decode(reader)?;
108 Self::new(d, iqmp, p, q)
109 }
110}
111
112impl Encode for RsaPrivateKey {
113 fn encoded_len(&self) -> encoding::Result<usize> {
114 [
115 self.d.encoded_len()?,
116 self.iqmp.encoded_len()?,
117 self.p.encoded_len()?,
118 self.q.encoded_len()?,
119 ]
120 .checked_sum()
121 }
122
123 fn encode(&self, writer: &mut impl Writer) -> encoding::Result<()> {
124 self.d.encode(writer)?;
125 self.iqmp.encode(writer)?;
126 self.p.encode(writer)?;
127 self.q.encode(writer)?;
128 Ok(())
129 }
130}
131
132impl Eq for RsaPrivateKey {}
133impl PartialEq for RsaPrivateKey {
134 fn eq(&self, other: &Self) -> bool {
135 self.ct_eq(other).into()
136 }
137}
138
139#[derive(Clone)]
141pub struct RsaKeypair {
142 public: RsaPublicKey,
144
145 private: RsaPrivateKey,
147}
148
149impl RsaKeypair {
150 #[cfg(feature = "rsa")]
152 #[expect(clippy::missing_errors_doc, reason = "TODO")]
153 pub fn random<R: CryptoRng + ?Sized>(rng: &mut R, bit_size: usize) -> Result<Self> {
154 rsa::RsaPrivateKey::new(rng, bit_size)?.try_into()
155 }
156
157 pub fn new(public: RsaPublicKey, private: RsaPrivateKey) -> Result<Self> {
162 Ok(Self { public, private })
164 }
165
166 #[must_use]
168 pub fn key_size(&self) -> u32 {
169 self.public.key_size()
170 }
171
172 #[must_use]
174 pub fn public(&self) -> &RsaPublicKey {
175 &self.public
176 }
177
178 #[must_use]
180 pub fn private(&self) -> &RsaPrivateKey {
181 &self.private
182 }
183}
184
185impl CtEq for RsaKeypair {
186 fn ct_eq(&self, other: &Self) -> Choice {
187 Choice::from(u8::from(self.public == other.public)) & self.private.ct_eq(&other.private)
188 }
189}
190
191impl Debug for RsaKeypair {
192 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
193 f.debug_struct("RsaKeypair")
194 .field("public", &self.public)
195 .finish_non_exhaustive()
196 }
197}
198
199impl Decode for RsaKeypair {
200 type Error = Error;
201
202 fn decode(reader: &mut impl Reader) -> Result<Self> {
203 let n = Mpint::decode(reader)?;
204 let e = Mpint::decode(reader)?;
205 let public = RsaPublicKey::new(e, n)?;
206 let private = RsaPrivateKey::decode(reader)?;
207 Self::new(public, private)
208 }
209}
210
211impl Encode for RsaKeypair {
212 fn encoded_len(&self) -> encoding::Result<usize> {
213 [
214 self.public.n().encoded_len()?,
215 self.public.e().encoded_len()?,
216 self.private.encoded_len()?,
217 ]
218 .checked_sum()
219 }
220
221 fn encode(&self, writer: &mut impl Writer) -> encoding::Result<()> {
222 self.public.n().encode(writer)?;
223 self.public.e().encode(writer)?;
224 self.private.encode(writer)
225 }
226}
227
228impl Eq for RsaKeypair {}
229impl PartialEq for RsaKeypair {
230 fn eq(&self, other: &Self) -> bool {
231 self.ct_eq(other).into()
232 }
233}
234
235impl From<RsaKeypair> for RsaPublicKey {
236 fn from(keypair: RsaKeypair) -> RsaPublicKey {
237 keypair.public
238 }
239}
240
241impl From<&RsaKeypair> for RsaPublicKey {
242 fn from(keypair: &RsaKeypair) -> RsaPublicKey {
243 keypair.public.clone()
244 }
245}
246
247#[cfg(feature = "rsa")]
248impl TryFrom<RsaKeypair> for rsa::RsaPrivateKey {
249 type Error = Error;
250
251 fn try_from(key: RsaKeypair) -> Result<rsa::RsaPrivateKey> {
252 rsa::RsaPrivateKey::try_from(&key)
253 }
254}
255
256#[cfg(feature = "rsa")]
257impl TryFrom<&RsaKeypair> for rsa::RsaPrivateKey {
258 type Error = Error;
259
260 fn try_from(key: &RsaKeypair) -> Result<rsa::RsaPrivateKey> {
261 let ret = rsa::RsaPrivateKey::from_components(
262 Uint::try_from(key.public.n())?,
263 Uint::try_from(key.public.e())?,
264 Uint::try_from(&key.private.d)?,
265 vec![
266 Uint::try_from(&key.private.p)?,
267 Uint::try_from(&key.private.q)?,
268 ],
269 )?;
270
271 Ok(ret)
272 }
273}
274
275#[cfg(feature = "rsa")]
276impl TryFrom<rsa::RsaPrivateKey> for RsaKeypair {
277 type Error = Error;
278
279 fn try_from(key: rsa::RsaPrivateKey) -> Result<RsaKeypair> {
280 RsaKeypair::try_from(&key)
281 }
282}
283
284#[cfg(feature = "rsa")]
285impl TryFrom<&rsa::RsaPrivateKey> for RsaKeypair {
286 type Error = Error;
287
288 fn try_from(key: &rsa::RsaPrivateKey) -> Result<RsaKeypair> {
289 if key.primes().len() > 2 {
291 return Err(Error::Crypto);
292 }
293
294 let public = RsaPublicKey::try_from(key.to_public_key())?;
295
296 let p = &key.primes()[0];
297 let q = &key.primes()[1];
298 let iqmp = key.crt_coefficient().ok_or(Error::Crypto)?;
299
300 let private = RsaPrivateKey {
301 d: key.d().into(),
302 iqmp: iqmp.into(),
303 p: p.into(),
304 q: q.into(),
305 };
306
307 Ok(RsaKeypair { public, private })
308 }
309}
310
311#[cfg(feature = "rsa")]
312impl<D> TryFrom<&RsaKeypair> for pkcs1v15::SigningKey<D>
313where
314 D: Digest + AssociatedOid,
315{
316 type Error = Error;
317
318 fn try_from(keypair: &RsaKeypair) -> Result<pkcs1v15::SigningKey<D>> {
319 Ok(pkcs1v15::SigningKey::new(keypair.try_into()?))
320 }
321}