1use super::ed25519::Ed25519Keypair;
4use crate::{
5 checked::CheckedSum, decode::Decode, encode::Encode, public, reader::Reader, writer::Writer,
6 Algorithm, Error, Result,
7};
8
9#[cfg(feature = "alloc")]
10use {
11 super::{DsaKeypair, RsaKeypair, SkEd25519},
12 alloc::vec::Vec,
13};
14
15#[cfg(feature = "ecdsa")]
16use super::EcdsaKeypair;
17
18#[cfg(all(feature = "alloc", feature = "ecdsa"))]
19use super::SkEcdsaSha2NistP256;
20
21#[cfg(feature = "subtle")]
22use subtle::{Choice, ConstantTimeEq};
23
24#[derive(Clone, Debug)]
30#[non_exhaustive]
31pub enum KeypairData {
32 #[cfg(feature = "alloc")]
34 #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
35 Dsa(DsaKeypair),
36
37 #[cfg(feature = "ecdsa")]
39 #[cfg_attr(docsrs, doc(cfg(feature = "ecdsa")))]
40 Ecdsa(EcdsaKeypair),
41
42 Ed25519(Ed25519Keypair),
44
45 #[cfg(feature = "alloc")]
47 #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
48 Encrypted(Vec<u8>),
49
50 #[cfg(feature = "alloc")]
52 #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
53 Rsa(RsaKeypair),
54
55 #[cfg(all(feature = "alloc", feature = "ecdsa"))]
59 #[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", feature = "ecdsa"))))]
60 SkEcdsaSha2NistP256(SkEcdsaSha2NistP256),
61
62 #[cfg(feature = "alloc")]
66 #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
67 SkEd25519(SkEd25519),
68}
69
70impl KeypairData {
71 pub fn algorithm(&self) -> Result<Algorithm> {
73 Ok(match self {
74 #[cfg(feature = "alloc")]
75 Self::Dsa(_) => Algorithm::Dsa,
76 #[cfg(feature = "ecdsa")]
77 Self::Ecdsa(key) => key.algorithm(),
78 Self::Ed25519(_) => Algorithm::Ed25519,
79 #[cfg(feature = "alloc")]
80 Self::Encrypted(_) => return Err(Error::Encrypted),
81 #[cfg(feature = "alloc")]
82 Self::Rsa(_) => Algorithm::Rsa { hash: None },
83 #[cfg(all(feature = "alloc", feature = "ecdsa"))]
84 Self::SkEcdsaSha2NistP256(_) => Algorithm::SkEcdsaSha2NistP256,
85 #[cfg(feature = "alloc")]
86 Self::SkEd25519(_) => Algorithm::SkEd25519,
87 })
88 }
89
90 #[cfg(feature = "alloc")]
92 #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
93 pub fn dsa(&self) -> Option<&DsaKeypair> {
94 match self {
95 Self::Dsa(key) => Some(key),
96 _ => None,
97 }
98 }
99
100 #[cfg(feature = "ecdsa")]
102 #[cfg_attr(docsrs, doc(cfg(feature = "ecdsa")))]
103 pub fn ecdsa(&self) -> Option<&EcdsaKeypair> {
104 match self {
105 Self::Ecdsa(keypair) => Some(keypair),
106 _ => None,
107 }
108 }
109
110 pub fn ed25519(&self) -> Option<&Ed25519Keypair> {
112 match self {
113 Self::Ed25519(key) => Some(key),
114 #[allow(unreachable_patterns)]
115 _ => None,
116 }
117 }
118
119 #[cfg(feature = "alloc")]
121 #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
122 pub fn encrypted(&self) -> Option<&[u8]> {
123 match self {
124 Self::Encrypted(ciphertext) => Some(ciphertext),
125 _ => None,
126 }
127 }
128
129 #[cfg(feature = "alloc")]
131 #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
132 pub fn rsa(&self) -> Option<&RsaKeypair> {
133 match self {
134 Self::Rsa(key) => Some(key),
135 _ => None,
136 }
137 }
138
139 #[cfg(all(feature = "alloc", feature = "ecdsa"))]
141 #[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", feature = "ecdsa"))))]
142 pub fn sk_ecdsa_p256(&self) -> Option<&SkEcdsaSha2NistP256> {
143 match self {
144 Self::SkEcdsaSha2NistP256(sk) => Some(sk),
145 _ => None,
146 }
147 }
148
149 #[cfg(feature = "alloc")]
151 #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
152 pub fn sk_ed25519(&self) -> Option<&SkEd25519> {
153 match self {
154 Self::SkEd25519(sk) => Some(sk),
155 _ => None,
156 }
157 }
158
159 #[cfg(feature = "alloc")]
161 #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
162 pub fn is_dsa(&self) -> bool {
163 matches!(self, Self::Dsa(_))
164 }
165
166 #[cfg(feature = "ecdsa")]
168 #[cfg_attr(docsrs, doc(cfg(feature = "ecdsa")))]
169 pub fn is_ecdsa(&self) -> bool {
170 matches!(self, Self::Ecdsa(_))
171 }
172
173 pub fn is_ed25519(&self) -> bool {
175 matches!(self, Self::Ed25519(_))
176 }
177
178 #[cfg(not(feature = "alloc"))]
180 pub fn is_encrypted(&self) -> bool {
181 false
182 }
183
184 #[cfg(feature = "alloc")]
186 pub fn is_encrypted(&self) -> bool {
187 matches!(self, Self::Encrypted(_))
188 }
189
190 #[cfg(feature = "alloc")]
192 #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
193 pub fn is_rsa(&self) -> bool {
194 matches!(self, Self::Rsa(_))
195 }
196
197 #[cfg(all(feature = "alloc", feature = "ecdsa"))]
199 #[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", feature = "ecdsa"))))]
200 pub fn is_sk_ecdsa_p256(&self) -> bool {
201 matches!(self, Self::SkEcdsaSha2NistP256(_))
202 }
203
204 #[cfg(feature = "alloc")]
206 #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
207 pub fn is_sk_ed25519(&self) -> bool {
208 matches!(self, Self::SkEd25519(_))
209 }
210
211 pub(super) fn checkint(&self) -> u32 {
216 let bytes = match self {
217 #[cfg(feature = "alloc")]
218 Self::Dsa(dsa) => dsa.private.as_bytes(),
219 #[cfg(feature = "ecdsa")]
220 Self::Ecdsa(ecdsa) => ecdsa.private_key_bytes(),
221 Self::Ed25519(ed25519) => ed25519.private.as_ref(),
222 #[cfg(feature = "alloc")]
223 Self::Encrypted(ciphertext) => ciphertext.as_ref(),
224 #[cfg(feature = "alloc")]
225 Self::Rsa(rsa) => rsa.private.d.as_bytes(),
226 #[cfg(all(feature = "alloc", feature = "ecdsa"))]
227 Self::SkEcdsaSha2NistP256(sk) => sk.key_handle(),
228 #[cfg(feature = "alloc")]
229 Self::SkEd25519(sk) => sk.key_handle(),
230 };
231
232 let mut n = 0u32;
233
234 for chunk in bytes.chunks_exact(4) {
235 n ^= u32::from_be_bytes(chunk.try_into().expect("not 4 bytes"));
236 }
237
238 n
239 }
240}
241
242impl Decode for KeypairData {
243 fn decode(reader: &mut impl Reader) -> Result<Self> {
244 match Algorithm::decode(reader)? {
245 #[cfg(feature = "alloc")]
246 Algorithm::Dsa => DsaKeypair::decode(reader).map(Self::Dsa),
247 #[cfg(feature = "ecdsa")]
248 Algorithm::Ecdsa { curve } => match EcdsaKeypair::decode(reader)? {
249 keypair if keypair.curve() == curve => Ok(Self::Ecdsa(keypair)),
250 _ => Err(Error::Algorithm),
251 },
252 Algorithm::Ed25519 => Ed25519Keypair::decode(reader).map(Self::Ed25519),
253 #[cfg(feature = "alloc")]
254 Algorithm::Rsa { .. } => RsaKeypair::decode(reader).map(Self::Rsa),
255 #[cfg(all(feature = "alloc", feature = "ecdsa"))]
256 Algorithm::SkEcdsaSha2NistP256 => {
257 SkEcdsaSha2NistP256::decode(reader).map(Self::SkEcdsaSha2NistP256)
258 }
259 #[cfg(feature = "alloc")]
260 Algorithm::SkEd25519 => SkEd25519::decode(reader).map(Self::SkEd25519),
261 #[allow(unreachable_patterns)]
262 _ => Err(Error::Algorithm),
263 }
264 }
265}
266
267impl Encode for KeypairData {
268 fn encoded_len(&self) -> Result<usize> {
269 let key_len = match self {
270 #[cfg(feature = "alloc")]
271 Self::Dsa(key) => key.encoded_len()?,
272 #[cfg(feature = "ecdsa")]
273 Self::Ecdsa(key) => key.encoded_len()?,
274 Self::Ed25519(key) => key.encoded_len()?,
275 #[cfg(feature = "alloc")]
276 Self::Encrypted(ciphertext) => return Ok(ciphertext.len()),
277 #[cfg(feature = "alloc")]
278 Self::Rsa(key) => key.encoded_len()?,
279 #[cfg(all(feature = "alloc", feature = "ecdsa"))]
280 Self::SkEcdsaSha2NistP256(sk) => sk.encoded_len()?,
281 #[cfg(feature = "alloc")]
282 Self::SkEd25519(sk) => sk.encoded_len()?,
283 };
284
285 [self.algorithm()?.encoded_len()?, key_len].checked_sum()
286 }
287
288 fn encode(&self, writer: &mut impl Writer) -> Result<()> {
289 if !self.is_encrypted() {
290 self.algorithm()?.encode(writer)?;
291 }
292
293 match self {
294 #[cfg(feature = "alloc")]
295 Self::Dsa(key) => key.encode(writer),
296 #[cfg(feature = "ecdsa")]
297 Self::Ecdsa(key) => key.encode(writer),
298 Self::Ed25519(key) => key.encode(writer),
299 #[cfg(feature = "alloc")]
300 Self::Encrypted(ciphertext) => writer.write(ciphertext),
301 #[cfg(feature = "alloc")]
302 Self::Rsa(key) => key.encode(writer),
303 #[cfg(all(feature = "alloc", feature = "ecdsa"))]
304 Self::SkEcdsaSha2NistP256(sk) => sk.encode(writer),
305 #[cfg(feature = "alloc")]
306 Self::SkEd25519(sk) => sk.encode(writer),
307 }
308 }
309}
310
311impl TryFrom<&KeypairData> for public::KeyData {
312 type Error = Error;
313
314 fn try_from(keypair_data: &KeypairData) -> Result<public::KeyData> {
315 Ok(match keypair_data {
316 #[cfg(feature = "alloc")]
317 KeypairData::Dsa(dsa) => public::KeyData::Dsa(dsa.into()),
318 #[cfg(feature = "ecdsa")]
319 KeypairData::Ecdsa(ecdsa) => public::KeyData::Ecdsa(ecdsa.into()),
320 KeypairData::Ed25519(ed25519) => public::KeyData::Ed25519(ed25519.into()),
321 #[cfg(feature = "alloc")]
322 KeypairData::Encrypted(_) => return Err(Error::Encrypted),
323 #[cfg(feature = "alloc")]
324 KeypairData::Rsa(rsa) => public::KeyData::Rsa(rsa.into()),
325 #[cfg(all(feature = "alloc", feature = "ecdsa"))]
326 KeypairData::SkEcdsaSha2NistP256(sk) => {
327 public::KeyData::SkEcdsaSha2NistP256(sk.public().clone())
328 }
329 #[cfg(feature = "alloc")]
330 KeypairData::SkEd25519(sk) => public::KeyData::SkEd25519(sk.public().clone()),
331 })
332 }
333}
334
335#[cfg(feature = "alloc")]
336#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
337impl From<DsaKeypair> for KeypairData {
338 fn from(keypair: DsaKeypair) -> KeypairData {
339 Self::Dsa(keypair)
340 }
341}
342
343#[cfg(feature = "ecdsa")]
344#[cfg_attr(docsrs, doc(cfg(feature = "ecdsa")))]
345impl From<EcdsaKeypair> for KeypairData {
346 fn from(keypair: EcdsaKeypair) -> KeypairData {
347 Self::Ecdsa(keypair)
348 }
349}
350
351impl From<Ed25519Keypair> for KeypairData {
352 fn from(keypair: Ed25519Keypair) -> KeypairData {
353 Self::Ed25519(keypair)
354 }
355}
356
357#[cfg(feature = "alloc")]
358#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
359impl From<RsaKeypair> for KeypairData {
360 fn from(keypair: RsaKeypair) -> KeypairData {
361 Self::Rsa(keypair)
362 }
363}
364
365#[cfg(all(feature = "alloc", feature = "ecdsa"))]
366#[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", feature = "ecdsa"))))]
367impl From<SkEcdsaSha2NistP256> for KeypairData {
368 fn from(keypair: SkEcdsaSha2NistP256) -> KeypairData {
369 Self::SkEcdsaSha2NistP256(keypair)
370 }
371}
372
373#[cfg(feature = "alloc")]
374#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
375impl From<SkEd25519> for KeypairData {
376 fn from(keypair: SkEd25519) -> KeypairData {
377 Self::SkEd25519(keypair)
378 }
379}
380
381#[cfg(feature = "subtle")]
382#[cfg_attr(docsrs, doc(cfg(feature = "subtle")))]
383impl ConstantTimeEq for KeypairData {
384 fn ct_eq(&self, other: &Self) -> Choice {
385 match (self, other) {
387 #[cfg(feature = "alloc")]
388 (Self::Dsa(a), Self::Dsa(b)) => a.ct_eq(b),
389 #[cfg(feature = "ecdsa")]
390 (Self::Ecdsa(a), Self::Ecdsa(b)) => a.ct_eq(b),
391 (Self::Ed25519(a), Self::Ed25519(b)) => a.ct_eq(b),
392 #[cfg(feature = "alloc")]
393 (Self::Encrypted(a), Self::Encrypted(b)) => a.ct_eq(b),
394 #[cfg(feature = "alloc")]
395 (Self::Rsa(a), Self::Rsa(b)) => a.ct_eq(b),
396 #[cfg(all(feature = "alloc", feature = "ecdsa"))]
397 (Self::SkEcdsaSha2NistP256(a), Self::SkEcdsaSha2NistP256(b)) => {
398 Choice::from((a == b) as u8)
401 }
402 #[cfg(feature = "alloc")]
403 (Self::SkEd25519(a), Self::SkEd25519(b)) => {
404 Choice::from((a == b) as u8)
407 }
408 _ => Choice::from(0),
409 }
410 }
411}
412
413#[cfg(feature = "subtle")]
414#[cfg_attr(docsrs, doc(cfg(feature = "subtle")))]
415impl PartialEq for KeypairData {
416 fn eq(&self, other: &Self) -> bool {
417 self.ct_eq(other).into()
418 }
419}
420
421#[cfg(feature = "subtle")]
422#[cfg_attr(docsrs, doc(cfg(feature = "subtle")))]
423impl Eq for KeypairData {}