ssh_key_fork_arti/private/
rsa.rs1use 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#[derive(Clone)]
18pub struct RsaPrivateKey {
19 pub d: Mpint,
21
22 pub iqmp: Mpint,
24
25 pub p: Mpint,
27
28 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#[derive(Clone)]
92pub struct RsaKeypair {
93 pub public: RsaPublicKey,
95
96 pub private: RsaPrivateKey,
98}
99
100impl RsaKeypair {
101 #[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 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}