askar_crypto/alg/
any.rs

1use alloc::{boxed::Box, sync::Arc};
2use core::{
3    any::{Any, TypeId},
4    fmt::Debug,
5    panic::{RefUnwindSafe, UnwindSafe},
6};
7
8#[cfg(feature = "aes")]
9use super::{
10    aes::{A128CbcHs256, A128Gcm, A128Kw, A256CbcHs512, A256Gcm, A256Kw, AesKey, AesType},
11    AesTypes,
12};
13
14#[cfg(feature = "bls")]
15use super::{
16    bls::{BlsKeyPair, BlsPublicKeyType, G1, G2},
17    BlsCurves,
18};
19
20#[cfg(feature = "chacha")]
21use super::{
22    chacha20::{Chacha20Key, Chacha20Type, C20P, XC20P},
23    Chacha20Types,
24};
25
26#[cfg(feature = "ed25519")]
27use super::ed25519::{self, Ed25519KeyPair};
28#[cfg(feature = "ed25519")]
29use super::x25519::{self, X25519KeyPair};
30
31#[cfg(feature = "k256")]
32use super::k256::{self, K256KeyPair};
33
34#[cfg(feature = "p256")]
35use super::p256::{self, P256KeyPair};
36
37#[cfg(feature = "p384")]
38use super::p384::{self, P384KeyPair};
39
40#[cfg(feature = "p256_hardware")]
41use super::p256_hardware::P256HardwareKeyPair;
42
43use super::{HasKeyAlg, HasKeyBackend, KeyAlg};
44use crate::{
45    backend::KeyBackend,
46    buffer::{ResizeBuffer, SecretBytes, WriteBuffer},
47    encrypt::{KeyAeadInPlace, KeyAeadParams},
48    error::Error,
49    jwk::{FromJwk, JwkEncoder, JwkParts, ToJwk},
50    kdf::{KeyDerivation, KeyExchange},
51    random::KeyMaterial,
52    repr::{KeyGen, KeyPublicBytes, KeySecretBytes, ToPublicBytes, ToSecretBytes},
53    sign::{KeySigVerify, KeySign, SignatureType},
54};
55
56#[cfg(any(
57    feature = "k256",
58    feature = "p256",
59    feature = "p384",
60    feature = "p256_hardware"
61))]
62use super::EcCurves;
63
64#[cfg(any(feature = "aes", feature = "chacha"))]
65use crate::kdf::{FromKeyDerivation, FromKeyExchange};
66
67#[derive(Debug)]
68pub struct KeyT<T: AnyKeyAlg + Send + Sync + RefUnwindSafe + UnwindSafe + ?Sized>(T);
69
70/// The type-erased representation for a concrete key instance
71pub type AnyKey = KeyT<dyn AnyKeyAlg + Send + Sync + RefUnwindSafe + UnwindSafe>;
72
73impl AnyKey {
74    pub fn algorithm(&self) -> KeyAlg {
75        self.0.algorithm()
76    }
77
78    pub fn backend(&self) -> KeyBackend {
79        self.0.key_backend()
80    }
81
82    fn assume<K: AnyKeyAlg>(&self) -> &K {
83        self.downcast_ref().expect("Error assuming key type")
84    }
85
86    #[inline]
87    pub fn downcast_ref<K: AnyKeyAlg>(&self) -> Option<&K> {
88        self.0.as_any().downcast_ref()
89    }
90
91    #[inline]
92    pub fn key_type_id(&self) -> TypeId {
93        self.0.as_any().type_id()
94    }
95
96    #[inline]
97    pub fn key_id(&self) -> Result<SecretBytes, Error> {
98        get_key_id_any(self)
99    }
100}
101
102/// Create `AnyKey` instances from various sources
103pub trait AnyKeyCreate: Sized {
104    /// Generate a new key from a key material generator for the given key algorithm.
105    fn generate_with_rng(alg: KeyAlg, rng: impl KeyMaterial) -> Result<Self, Error>;
106
107    /// Generate a new key with an id for the given key algorithm.
108    fn generate_for_hardware(alg: KeyAlg) -> Result<Self, Error>;
109
110    /// Get a key by id for hardware-based key
111    fn get_with_id(alg: KeyAlg, id: &str) -> Result<Self, Error>;
112
113    /// Generate a new random key for the given key algorithm.
114    #[cfg(feature = "getrandom")]
115    fn random(alg: KeyAlg) -> Result<Self, Error> {
116        Self::generate_with_rng(alg, crate::random::default_rng())
117    }
118
119    /// Generate a new random key for the given key algorithm.
120    fn random_det(alg: KeyAlg, seed: &[u8]) -> Result<Self, Error> {
121        Self::generate_with_rng(alg, crate::random::RandomDet::new(seed))
122    }
123
124    /// Load a public key from its byte representation
125    fn from_public_bytes(alg: KeyAlg, public: &[u8]) -> Result<Self, Error>;
126
127    /// Load a secret key or keypair from its byte representation
128    fn from_secret_bytes(alg: KeyAlg, secret: &[u8]) -> Result<Self, Error>;
129
130    /// Convert from a concrete key instance
131    fn from_key<K: HasKeyAlg + HasKeyBackend + Send + Sync + RefUnwindSafe + UnwindSafe + 'static>(
132        key: K,
133    ) -> Self;
134
135    /// Create a new key instance from a key exchange
136    fn from_key_exchange<Sk, Pk>(alg: KeyAlg, secret: &Sk, public: &Pk) -> Result<Self, Error>
137    where
138        Sk: KeyExchange<Pk> + ?Sized,
139        Pk: ?Sized;
140
141    /// Create a new key instance from a key derivation
142    fn from_key_derivation(alg: KeyAlg, derive: impl KeyDerivation) -> Result<Self, Error>;
143
144    /// Derive the corresponding key for the provided key algorithm
145    fn convert_key(&self, alg: KeyAlg) -> Result<Self, Error>;
146}
147
148impl AnyKeyCreate for Box<AnyKey> {
149    fn generate_with_rng(alg: KeyAlg, rng: impl KeyMaterial) -> Result<Self, Error> {
150        generate_any_with_rng(alg, rng)
151    }
152
153    fn generate_for_hardware(alg: KeyAlg) -> Result<Self, Error> {
154        generate_any_for_hardware(alg)
155    }
156
157    fn get_with_id(alg: KeyAlg, id: &str) -> Result<Self, Error> {
158        get_any_with_id(alg, id)
159    }
160
161    fn from_public_bytes(alg: KeyAlg, public: &[u8]) -> Result<Self, Error> {
162        from_public_bytes_any(alg, public)
163    }
164
165    fn from_secret_bytes(alg: KeyAlg, secret: &[u8]) -> Result<Self, Error> {
166        from_secret_bytes_any(alg, secret)
167    }
168
169    #[inline(always)]
170    fn from_key<
171        K: HasKeyAlg + HasKeyBackend + Send + Sync + RefUnwindSafe + UnwindSafe + 'static,
172    >(
173        key: K,
174    ) -> Self {
175        Box::new(KeyT(key))
176    }
177
178    fn from_key_exchange<Sk, Pk>(alg: KeyAlg, secret: &Sk, public: &Pk) -> Result<Self, Error>
179    where
180        Sk: KeyExchange<Pk> + ?Sized,
181        Pk: ?Sized,
182    {
183        from_key_exchange_any(alg, secret, public)
184    }
185
186    fn from_key_derivation(alg: KeyAlg, derive: impl KeyDerivation) -> Result<Self, Error> {
187        from_key_derivation_any(alg, derive)
188    }
189
190    fn convert_key(&self, alg: KeyAlg) -> Result<Self, Error> {
191        convert_key_any(self, alg)
192    }
193}
194
195impl AnyKeyCreate for Arc<AnyKey> {
196    fn generate_with_rng(alg: KeyAlg, rng: impl KeyMaterial) -> Result<Self, Error> {
197        generate_any_with_rng(alg, rng)
198    }
199
200    fn generate_for_hardware(alg: KeyAlg) -> Result<Self, Error> {
201        generate_any_for_hardware(alg)
202    }
203
204    fn get_with_id(alg: KeyAlg, id: &str) -> Result<Self, Error> {
205        get_any_with_id(alg, id)
206    }
207
208    fn from_public_bytes(alg: KeyAlg, public: &[u8]) -> Result<Self, Error> {
209        from_public_bytes_any(alg, public)
210    }
211
212    fn from_secret_bytes(alg: KeyAlg, secret: &[u8]) -> Result<Self, Error> {
213        from_secret_bytes_any(alg, secret)
214    }
215
216    #[inline(always)]
217    fn from_key<
218        K: HasKeyAlg + HasKeyBackend + Send + Sync + RefUnwindSafe + UnwindSafe + 'static,
219    >(
220        key: K,
221    ) -> Self {
222        Arc::new(KeyT(key))
223    }
224
225    fn from_key_exchange<Sk, Pk>(alg: KeyAlg, secret: &Sk, public: &Pk) -> Result<Self, Error>
226    where
227        Sk: KeyExchange<Pk> + ?Sized,
228        Pk: ?Sized,
229    {
230        from_key_exchange_any(alg, secret, public)
231    }
232
233    fn from_key_derivation(alg: KeyAlg, derive: impl KeyDerivation) -> Result<Self, Error> {
234        from_key_derivation_any(alg, derive)
235    }
236
237    fn convert_key(&self, alg: KeyAlg) -> Result<Self, Error> {
238        convert_key_any(self, alg)
239    }
240}
241
242#[inline]
243fn generate_any_with_rng<R: AllocKey>(alg: KeyAlg, rng: impl KeyMaterial) -> Result<R, Error> {
244    match alg {
245        #[cfg(feature = "aes")]
246        KeyAlg::Aes(AesTypes::A128Gcm) => AesKey::<A128Gcm>::generate(rng).map(R::alloc_key),
247        #[cfg(feature = "aes")]
248        KeyAlg::Aes(AesTypes::A256Gcm) => AesKey::<A256Gcm>::generate(rng).map(R::alloc_key),
249        #[cfg(feature = "aes")]
250        KeyAlg::Aes(AesTypes::A128CbcHs256) => {
251            AesKey::<A128CbcHs256>::generate(rng).map(R::alloc_key)
252        }
253        #[cfg(feature = "aes")]
254        KeyAlg::Aes(AesTypes::A256CbcHs512) => {
255            AesKey::<A256CbcHs512>::generate(rng).map(R::alloc_key)
256        }
257        #[cfg(feature = "aes")]
258        KeyAlg::Aes(AesTypes::A128Kw) => AesKey::<A128Kw>::generate(rng).map(R::alloc_key),
259        #[cfg(feature = "aes")]
260        KeyAlg::Aes(AesTypes::A256Kw) => AesKey::<A256Kw>::generate(rng).map(R::alloc_key),
261        #[cfg(feature = "bls")]
262        KeyAlg::Bls12_381(BlsCurves::G1) => BlsKeyPair::<G1>::generate(rng).map(R::alloc_key),
263        #[cfg(feature = "bls")]
264        KeyAlg::Bls12_381(BlsCurves::G2) => BlsKeyPair::<G2>::generate(rng).map(R::alloc_key),
265        #[cfg(feature = "chacha")]
266        KeyAlg::Chacha20(Chacha20Types::C20P) => {
267            Chacha20Key::<C20P>::generate(rng).map(R::alloc_key)
268        }
269        #[cfg(feature = "chacha")]
270        KeyAlg::Chacha20(Chacha20Types::XC20P) => {
271            Chacha20Key::<XC20P>::generate(rng).map(R::alloc_key)
272        }
273        #[cfg(feature = "ed25519")]
274        KeyAlg::Ed25519 => Ed25519KeyPair::generate(rng).map(R::alloc_key),
275        #[cfg(feature = "ed25519")]
276        KeyAlg::X25519 => X25519KeyPair::generate(rng).map(R::alloc_key),
277        #[cfg(feature = "k256")]
278        KeyAlg::EcCurve(EcCurves::Secp256k1) => K256KeyPair::generate(rng).map(R::alloc_key),
279        #[cfg(feature = "p256")]
280        KeyAlg::EcCurve(EcCurves::Secp256r1) => P256KeyPair::generate(rng).map(R::alloc_key),
281        #[cfg(feature = "p384")]
282        KeyAlg::EcCurve(EcCurves::Secp384r1) => P384KeyPair::generate(rng).map(R::alloc_key),
283        #[allow(unreachable_patterns)]
284        _ => Err(err_msg!(
285            Unsupported,
286            "Unsupported algorithm for key generation with rng"
287        )),
288    }
289}
290
291#[inline]
292fn generate_any_for_hardware<R: AllocKey>(alg: KeyAlg) -> Result<R, Error> {
293    match alg {
294        #[cfg(feature = "p256_hardware")]
295        KeyAlg::EcCurve(EcCurves::Secp256r1) => P256HardwareKeyPair::generate(
296            uuid::Uuid::new_v4()
297                .hyphenated()
298                .encode_lower(&mut uuid::Uuid::encode_buffer()),
299        )
300        .map(R::alloc_key),
301        _ => Err(err_msg!(
302            Unsupported,
303            "Unsupported algorithm for key generation with id"
304        )),
305    }
306}
307
308#[inline]
309fn get_any_with_id<R: AllocKey>(alg: KeyAlg, _id: &str) -> Result<R, Error> {
310    let key = match alg {
311        #[cfg(feature = "p256_hardware")]
312        KeyAlg::EcCurve(EcCurves::Secp256r1) => P256HardwareKeyPair::from_id(_id).map(R::alloc_key),
313        _ => Err(err_msg!(
314            Unsupported,
315            "Unsupported algorithm for key retrieval by id"
316        )),
317    }?;
318
319    Ok(key)
320}
321
322#[inline]
323fn from_public_bytes_any<R: AllocKey>(alg: KeyAlg, public: &[u8]) -> Result<R, Error> {
324    match alg {
325        #[cfg(feature = "bls")]
326        KeyAlg::Bls12_381(BlsCurves::G1) => {
327            BlsKeyPair::<G1>::from_public_bytes(public).map(R::alloc_key)
328        }
329        #[cfg(feature = "bls")]
330        KeyAlg::Bls12_381(BlsCurves::G2) => {
331            BlsKeyPair::<G2>::from_public_bytes(public).map(R::alloc_key)
332        }
333        #[cfg(feature = "ed25519")]
334        KeyAlg::Ed25519 => Ed25519KeyPair::from_public_bytes(public).map(R::alloc_key),
335        #[cfg(feature = "ed25519")]
336        KeyAlg::X25519 => X25519KeyPair::from_public_bytes(public).map(R::alloc_key),
337        #[cfg(feature = "k256")]
338        KeyAlg::EcCurve(EcCurves::Secp256k1) => {
339            K256KeyPair::from_public_bytes(public).map(R::alloc_key)
340        }
341        #[cfg(feature = "p256")]
342        KeyAlg::EcCurve(EcCurves::Secp256r1) => {
343            P256KeyPair::from_public_bytes(public).map(R::alloc_key)
344        }
345        #[cfg(feature = "p384")]
346        KeyAlg::EcCurve(EcCurves::Secp384r1) => {
347            P384KeyPair::from_public_bytes(public).map(R::alloc_key)
348        }
349        #[allow(unreachable_patterns)]
350        _ => Err(err_msg!(
351            Unsupported,
352            "Unsupported algorithm for public key import"
353        )),
354    }
355}
356
357#[inline]
358fn from_secret_bytes_any<R: AllocKey>(alg: KeyAlg, secret: &[u8]) -> Result<R, Error> {
359    match alg {
360        #[cfg(feature = "aes")]
361        KeyAlg::Aes(AesTypes::A128Gcm) => {
362            AesKey::<A128Gcm>::from_secret_bytes(secret).map(R::alloc_key)
363        }
364        #[cfg(feature = "aes")]
365        KeyAlg::Aes(AesTypes::A256Gcm) => {
366            AesKey::<A256Gcm>::from_secret_bytes(secret).map(R::alloc_key)
367        }
368        #[cfg(feature = "aes")]
369        KeyAlg::Aes(AesTypes::A128CbcHs256) => {
370            AesKey::<A128CbcHs256>::from_secret_bytes(secret).map(R::alloc_key)
371        }
372        #[cfg(feature = "aes")]
373        KeyAlg::Aes(AesTypes::A256CbcHs512) => {
374            AesKey::<A256CbcHs512>::from_secret_bytes(secret).map(R::alloc_key)
375        }
376        #[cfg(feature = "aes")]
377        KeyAlg::Aes(AesTypes::A128Kw) => {
378            AesKey::<A128Kw>::from_secret_bytes(secret).map(R::alloc_key)
379        }
380        #[cfg(feature = "aes")]
381        KeyAlg::Aes(AesTypes::A256Kw) => {
382            AesKey::<A256Kw>::from_secret_bytes(secret).map(R::alloc_key)
383        }
384        #[cfg(feature = "bls")]
385        KeyAlg::Bls12_381(BlsCurves::G1) => {
386            BlsKeyPair::<G1>::from_secret_bytes(secret).map(R::alloc_key)
387        }
388        #[cfg(feature = "bls")]
389        KeyAlg::Bls12_381(BlsCurves::G2) => {
390            BlsKeyPair::<G2>::from_secret_bytes(secret).map(R::alloc_key)
391        }
392        #[cfg(feature = "chacha")]
393        KeyAlg::Chacha20(Chacha20Types::C20P) => {
394            Chacha20Key::<C20P>::from_secret_bytes(secret).map(R::alloc_key)
395        }
396        #[cfg(feature = "chacha")]
397        KeyAlg::Chacha20(Chacha20Types::XC20P) => {
398            Chacha20Key::<XC20P>::from_secret_bytes(secret).map(R::alloc_key)
399        }
400        #[cfg(feature = "ed25519")]
401        KeyAlg::Ed25519 => Ed25519KeyPair::from_secret_bytes(secret).map(R::alloc_key),
402        #[cfg(feature = "ed25519")]
403        KeyAlg::X25519 => X25519KeyPair::from_secret_bytes(secret).map(R::alloc_key),
404        #[cfg(feature = "k256")]
405        KeyAlg::EcCurve(EcCurves::Secp256k1) => {
406            K256KeyPair::from_secret_bytes(secret).map(R::alloc_key)
407        }
408        #[cfg(feature = "p256")]
409        KeyAlg::EcCurve(EcCurves::Secp256r1) => {
410            P256KeyPair::from_secret_bytes(secret).map(R::alloc_key)
411        }
412        #[cfg(feature = "p384")]
413        KeyAlg::EcCurve(EcCurves::Secp384r1) => {
414            P384KeyPair::from_secret_bytes(secret).map(R::alloc_key)
415        }
416        #[allow(unreachable_patterns)]
417        _ => Err(err_msg!(
418            Unsupported,
419            "Unsupported algorithm for secret key import"
420        )),
421    }
422}
423
424#[cfg(any(feature = "aes", feature = "chacha"))]
425#[inline]
426fn from_key_exchange_any<R, Sk, Pk>(alg: KeyAlg, secret: &Sk, public: &Pk) -> Result<R, Error>
427where
428    R: AllocKey,
429    Sk: KeyExchange<Pk> + ?Sized,
430    Pk: ?Sized,
431{
432    match alg {
433        #[cfg(feature = "aes")]
434        KeyAlg::Aes(AesTypes::A128Gcm) => {
435            AesKey::<A128Gcm>::from_key_exchange(secret, public).map(R::alloc_key)
436        }
437        #[cfg(feature = "aes")]
438        KeyAlg::Aes(AesTypes::A256Gcm) => {
439            AesKey::<A256Gcm>::from_key_exchange(secret, public).map(R::alloc_key)
440        }
441        #[cfg(feature = "aes")]
442        KeyAlg::Aes(AesTypes::A128CbcHs256) => {
443            AesKey::<A128CbcHs256>::from_key_exchange(secret, public).map(R::alloc_key)
444        }
445        #[cfg(feature = "aes")]
446        KeyAlg::Aes(AesTypes::A256CbcHs512) => {
447            AesKey::<A256CbcHs512>::from_key_exchange(secret, public).map(R::alloc_key)
448        }
449        #[cfg(feature = "aes")]
450        KeyAlg::Aes(AesTypes::A128Kw) => {
451            AesKey::<A128Kw>::from_key_exchange(secret, public).map(R::alloc_key)
452        }
453        #[cfg(feature = "aes")]
454        KeyAlg::Aes(AesTypes::A256Kw) => {
455            AesKey::<A256Kw>::from_key_exchange(secret, public).map(R::alloc_key)
456        }
457        #[cfg(feature = "chacha")]
458        KeyAlg::Chacha20(Chacha20Types::C20P) => {
459            Chacha20Key::<C20P>::from_key_exchange(secret, public).map(R::alloc_key)
460        }
461        #[cfg(feature = "chacha")]
462        KeyAlg::Chacha20(Chacha20Types::XC20P) => {
463            Chacha20Key::<XC20P>::from_key_exchange(secret, public).map(R::alloc_key)
464        }
465        #[allow(unreachable_patterns)]
466        _ => Err(err_msg!(
467            Unsupported,
468            "Unsupported algorithm for key exchange"
469        )),
470    }
471}
472
473#[cfg(not(any(feature = "aes", feature = "chacha")))]
474#[inline]
475fn from_key_exchange_any<R, Sk: ?Sized, Pk: ?Sized>(
476    _alg: KeyAlg,
477    _secret: &Sk,
478    _public: &Pk,
479) -> Result<R, Error> {
480    return Err(err_msg!(
481        Unsupported,
482        "Unsupported algorithm for key exchange"
483    ));
484}
485
486#[cfg(any(feature = "aes", feature = "chacha"))]
487#[inline]
488fn from_key_derivation_any<R: AllocKey>(
489    alg: KeyAlg,
490    derive: impl KeyDerivation,
491) -> Result<R, Error> {
492    match alg {
493        #[cfg(feature = "aes")]
494        KeyAlg::Aes(AesTypes::A128Gcm) => {
495            AesKey::<A128Gcm>::from_key_derivation(derive).map(R::alloc_key)
496        }
497        #[cfg(feature = "aes")]
498        KeyAlg::Aes(AesTypes::A256Gcm) => {
499            AesKey::<A256Gcm>::from_key_derivation(derive).map(R::alloc_key)
500        }
501        #[cfg(feature = "aes")]
502        KeyAlg::Aes(AesTypes::A128CbcHs256) => {
503            AesKey::<A128CbcHs256>::from_key_derivation(derive).map(R::alloc_key)
504        }
505        #[cfg(feature = "aes")]
506        KeyAlg::Aes(AesTypes::A256CbcHs512) => {
507            AesKey::<A256CbcHs512>::from_key_derivation(derive).map(R::alloc_key)
508        }
509        #[cfg(feature = "aes")]
510        KeyAlg::Aes(AesTypes::A128Kw) => {
511            AesKey::<A128Kw>::from_key_derivation(derive).map(R::alloc_key)
512        }
513        #[cfg(feature = "aes")]
514        KeyAlg::Aes(AesTypes::A256Kw) => {
515            AesKey::<A256Kw>::from_key_derivation(derive).map(R::alloc_key)
516        }
517        #[cfg(feature = "chacha")]
518        KeyAlg::Chacha20(Chacha20Types::C20P) => {
519            Chacha20Key::<C20P>::from_key_derivation(derive).map(R::alloc_key)
520        }
521        #[cfg(feature = "chacha")]
522        KeyAlg::Chacha20(Chacha20Types::XC20P) => {
523            Chacha20Key::<XC20P>::from_key_derivation(derive).map(R::alloc_key)
524        }
525        #[allow(unreachable_patterns)]
526        _ => Err(err_msg!(
527            Unsupported,
528            "Unsupported algorithm for key derivation"
529        )),
530    }
531}
532
533#[cfg(not(any(feature = "aes", feature = "chacha")))]
534fn from_key_derivation_any<R: AllocKey>(
535    _alg: KeyAlg,
536    _derive: impl KeyDerivation,
537) -> Result<R, Error> {
538    return Err(err_msg!(
539        Unsupported,
540        "Unsupported algorithm for key derivation"
541    ));
542}
543
544#[inline]
545fn convert_key_any<R: AllocKey>(key: &AnyKey, alg: KeyAlg) -> Result<R, Error> {
546    match (key.algorithm(), alg) {
547        #[cfg(feature = "bls")]
548        (KeyAlg::Bls12_381(BlsCurves::G1), KeyAlg::Bls12_381(BlsCurves::G2)) => Ok(R::alloc_key(
549            BlsKeyPair::<G2>::try_from(key.assume::<BlsKeyPair<G1>>())?,
550        )),
551        #[cfg(feature = "bls")]
552        (KeyAlg::Bls12_381(BlsCurves::G2), KeyAlg::Bls12_381(BlsCurves::G1)) => Ok(R::alloc_key(
553            BlsKeyPair::<G1>::try_from(key.assume::<BlsKeyPair<G2>>())?,
554        )),
555        #[cfg(feature = "ed25519")]
556        (KeyAlg::Ed25519, KeyAlg::X25519) => Ok(<X25519KeyPair as TryFrom<_>>::try_from(
557            key.assume::<Ed25519KeyPair>(),
558        )
559        .map(R::alloc_key)?),
560        #[allow(unreachable_patterns)]
561        _ => Err(err_msg!(
562            Unsupported,
563            "Unsupported key conversion operation"
564        )),
565    }
566}
567
568#[inline]
569fn get_key_id_any(key: &AnyKey) -> Result<SecretBytes, Error> {
570    match key.algorithm() {
571        #[cfg(feature = "p256_hardware")]
572        KeyAlg::EcCurve(EcCurves::Secp256r1) => {
573            Ok(key.assume::<P256HardwareKeyPair>().key_id.clone())
574        }
575        #[allow(unreachable_patterns)]
576        _ => Err(err_msg!(Unsupported, "Unsupported get key id operation")),
577    }
578}
579
580impl FromJwk for Box<AnyKey> {
581    fn from_jwk_parts(jwk: JwkParts<'_>) -> Result<Self, Error> {
582        from_jwk_any(jwk)
583    }
584}
585
586impl FromJwk for Arc<AnyKey> {
587    fn from_jwk_parts(jwk: JwkParts<'_>) -> Result<Self, Error> {
588        from_jwk_any(jwk)
589    }
590}
591
592#[inline]
593fn from_jwk_any<R: AllocKey>(jwk: JwkParts<'_>) -> Result<R, Error> {
594    match (jwk.kty, jwk.crv.as_ref(), jwk.alg.as_ref()) {
595        #[cfg(feature = "aes")]
596        ("oct", _, A128Gcm::JWK_ALG) => AesKey::<A128Gcm>::from_jwk_parts(jwk).map(R::alloc_key),
597        #[cfg(feature = "aes")]
598        ("oct", _, A256Gcm::JWK_ALG) => AesKey::<A256Gcm>::from_jwk_parts(jwk).map(R::alloc_key),
599        #[cfg(feature = "aes")]
600        ("oct", _, A128CbcHs256::JWK_ALG) => {
601            AesKey::<A128CbcHs256>::from_jwk_parts(jwk).map(R::alloc_key)
602        }
603        #[cfg(feature = "aes")]
604        ("oct", _, A256CbcHs512::JWK_ALG) => {
605            AesKey::<A256CbcHs512>::from_jwk_parts(jwk).map(R::alloc_key)
606        }
607        #[cfg(feature = "aes")]
608        ("oct", _, A128Kw::JWK_ALG) => AesKey::<A128Kw>::from_jwk_parts(jwk).map(R::alloc_key),
609        #[cfg(feature = "aes")]
610        ("oct", _, A256Kw::JWK_ALG) => AesKey::<A256Kw>::from_jwk_parts(jwk).map(R::alloc_key),
611        #[cfg(feature = "bls")]
612        ("EC", G1::JWK_CURVE, _) => BlsKeyPair::<G1>::from_jwk_parts(jwk).map(R::alloc_key),
613        #[cfg(feature = "bls")]
614        ("EC", G2::JWK_CURVE, _) => BlsKeyPair::<G2>::from_jwk_parts(jwk).map(R::alloc_key),
615        #[cfg(feature = "bls")]
616        ("OKP", G1::JWK_CURVE_OKP, _) => BlsKeyPair::<G1>::from_jwk_parts(jwk).map(R::alloc_key),
617        #[cfg(feature = "bls")]
618        ("OKP", G2::JWK_CURVE_OKP, _) => BlsKeyPair::<G2>::from_jwk_parts(jwk).map(R::alloc_key),
619        #[cfg(feature = "chacha")]
620        ("oct", _, C20P::JWK_ALG) => Chacha20Key::<C20P>::from_jwk_parts(jwk).map(R::alloc_key),
621        #[cfg(feature = "chacha")]
622        ("oct", _, XC20P::JWK_ALG) => Chacha20Key::<XC20P>::from_jwk_parts(jwk).map(R::alloc_key),
623        #[cfg(feature = "ed25519")]
624        ("OKP", ed25519::JWK_CURVE, _) => Ed25519KeyPair::from_jwk_parts(jwk).map(R::alloc_key),
625        #[cfg(feature = "ed25519")]
626        ("OKP", x25519::JWK_CURVE, _) => X25519KeyPair::from_jwk_parts(jwk).map(R::alloc_key),
627        #[cfg(feature = "k256")]
628        ("EC", k256::JWK_CURVE, _) => K256KeyPair::from_jwk_parts(jwk).map(R::alloc_key),
629        #[cfg(feature = "p256")]
630        ("EC", p256::JWK_CURVE, _) => P256KeyPair::from_jwk_parts(jwk).map(R::alloc_key),
631        #[cfg(feature = "p384")]
632        ("EC", p384::JWK_CURVE, _) => P384KeyPair::from_jwk_parts(jwk).map(R::alloc_key),
633        _ => Err(err_msg!(Unsupported, "Unsupported JWK for key import")),
634    }
635}
636
637macro_rules! match_key_alg {
638    ($slf:expr, $ty:ty, $($kty:ident),+ $(,$errmsg:literal)?) => {{
639        fn matcher(key: &AnyKey) -> Result<$ty, Error> {
640            #[allow(unused_variables)]
641            let alg = key.algorithm();
642            match_key_alg!(@ $($kty)+ ; key, alg);
643            return Err(err_msg!(Unsupported $(,$errmsg)?))
644        }
645        matcher($slf)
646    }};
647    (@ ; $key:ident, $alg:ident) => {()};
648    (@ Aes $($rest:ident)*; $key:ident, $alg:ident) => {{
649        #[cfg(feature = "aes")]
650        if $alg == KeyAlg::Aes(AesTypes::A128Gcm) {
651            return Ok($key.assume::<AesKey<A128Gcm>>());
652        }
653        #[cfg(feature = "aes")]
654        if $alg == KeyAlg::Aes(AesTypes::A256Gcm) {
655            return Ok($key.assume::<AesKey<A256Gcm>>());
656        }
657        #[cfg(feature = "aes")]
658        if $alg == KeyAlg::Aes(AesTypes::A128CbcHs256) {
659            return Ok($key.assume::<AesKey<A128CbcHs256>>());
660        }
661        #[cfg(feature = "aes")]
662        if $alg == KeyAlg::Aes(AesTypes::A256CbcHs512) {
663            return Ok($key.assume::<AesKey<A256CbcHs512>>());
664        }
665        #[cfg(feature = "aes")]
666        if $alg == KeyAlg::Aes(AesTypes::A128Kw) {
667            return Ok($key.assume::<AesKey<A128Kw>>());
668        }
669        #[cfg(feature = "aes")]
670        if $alg == KeyAlg::Aes(AesTypes::A256Kw) {
671            return Ok($key.assume::<AesKey<A256Kw>>());
672        }
673        match_key_alg!(@ $($rest)*; $key, $alg)
674    }};
675    (@ Bls $($rest:ident)*; $key:ident, $alg:ident) => {{
676        #[cfg(feature = "bls")]
677        if $alg == KeyAlg::Bls12_381(BlsCurves::G1) {
678            return Ok($key.assume::<BlsKeyPair<G1>>());
679        }
680        #[cfg(feature = "bls")]
681        if $alg == KeyAlg::Bls12_381(BlsCurves::G2) {
682            return Ok($key.assume::<BlsKeyPair<G2>>());
683        }
684        match_key_alg!(@ $($rest)*; $key, $alg)
685    }};
686    (@ Chacha $($rest:ident)*; $key:ident, $alg:ident) => {{
687        #[cfg(feature = "chacha")]
688        if $alg == KeyAlg::Chacha20(Chacha20Types::C20P) {
689            return Ok($key.assume::<Chacha20Key<C20P>>());
690        }
691        #[cfg(feature = "chacha")]
692        if $alg == KeyAlg::Chacha20(Chacha20Types::XC20P) {
693            return Ok($key.assume::<Chacha20Key<XC20P>>());
694        }
695        match_key_alg!(@ $($rest)*; $key, $alg)
696    }};
697    (@ Ed25519 $($rest:ident)*; $key:ident, $alg:ident) => {{
698        #[cfg(feature = "ed25519")]
699        if $alg == KeyAlg::Ed25519 {
700            return Ok($key.assume::<Ed25519KeyPair>())
701        }
702        match_key_alg!(@ $($rest)*; $key, $alg)
703    }};
704    (@ X25519 $($rest:ident)*; $key:ident, $alg:ident) => {{
705        #[cfg(feature = "ed25519")]
706        if $alg == KeyAlg::X25519 {
707            return Ok($key.assume::<X25519KeyPair>())
708        }
709        match_key_alg!(@ $($rest)*; $key, $alg)
710    }};
711    (@ K256 $($rest:ident)*; $key:ident, $alg:ident) => {{
712        #[cfg(feature = "k256")]
713        if $alg == KeyAlg::EcCurve(EcCurves::Secp256k1) {
714            return Ok($key.assume::<K256KeyPair>())
715        }
716        match_key_alg!(@ $($rest)*; $key, $alg)
717    }};
718    (@ P256 $($rest:ident)*; $key:ident, $alg:ident) => {{
719        #[cfg(feature = "p256")]
720        if $alg == KeyAlg::EcCurve(EcCurves::Secp256r1) && $key.backend() == KeyBackend::Software {
721            return Ok($key.assume::<P256KeyPair>())
722        }
723        match_key_alg!(@ $($rest)*; $key, $alg)
724    }};
725    (@ P256Hardware $($rest:ident)*; $key:ident, $alg:ident) => {{
726        #[cfg(feature = "p256_hardware")]
727        if $alg == KeyAlg::EcCurve(EcCurves::Secp256r1) && $key.backend() == KeyBackend::SecureElement {
728            return Ok($key.assume::<P256HardwareKeyPair>())
729        }
730        match_key_alg!(@ $($rest)*; $key, $alg)
731    }};
732    (@ P384 $($rest:ident)*; $key:ident, $alg:ident) => {{
733        #[cfg(feature = "p384")]
734        if $alg == KeyAlg::EcCurve(EcCurves::Secp384r1) {
735            return Ok($key.assume::<P384KeyPair>())
736        }
737        match_key_alg!(@ $($rest)*; $key, $alg)
738    }};
739}
740
741impl AnyKey {
742    fn key_as_aead(&self) -> Result<&dyn KeyAeadInPlace, Error> {
743        match_key_alg! {
744            self,
745            &dyn KeyAeadInPlace,
746            Aes,
747            Chacha,
748            "AEAD is not supported for this key type"
749        }
750    }
751
752    fn key_to_secret(&self) -> Result<&dyn ToSecretBytes, Error> {
753        match_key_alg! {
754            self,
755            &dyn ToSecretBytes,
756            Aes,
757            Bls,
758            Chacha,
759            Ed25519,
760            K256,
761            P256,
762            P384,
763            X25519,
764            "Secret key export is not supported for this key type"
765        }
766    }
767
768    fn key_to_public(&self) -> Result<&dyn ToPublicBytes, Error> {
769        match_key_alg! {
770            self,
771            &dyn ToPublicBytes,
772            Bls,
773            Ed25519,
774            K256,
775            P256,
776            P256Hardware,
777            P384,
778            X25519,
779            "Public key export is not supported for this key type"
780        }
781    }
782}
783
784impl ToPublicBytes for AnyKey {
785    fn public_bytes_length(&self) -> Result<usize, Error> {
786        self.key_to_public()?.public_bytes_length()
787    }
788
789    fn write_public_bytes(&self, out: &mut dyn WriteBuffer) -> Result<(), Error> {
790        self.key_to_public()?.write_public_bytes(out)
791    }
792}
793
794impl ToSecretBytes for AnyKey {
795    fn secret_bytes_length(&self) -> Result<usize, Error> {
796        self.key_to_secret()?.secret_bytes_length()
797    }
798
799    fn write_secret_bytes(&self, out: &mut dyn WriteBuffer) -> Result<(), Error> {
800        self.key_to_secret()?.write_secret_bytes(out)
801    }
802}
803
804impl KeyExchange for AnyKey {
805    fn write_key_exchange(&self, other: &AnyKey, out: &mut dyn WriteBuffer) -> Result<(), Error> {
806        if self.key_type_id() != other.key_type_id() {
807            return Err(err_msg!(Unsupported, "Unsupported key exchange"));
808        }
809        match self.algorithm() {
810            #[cfg(feature = "ed25519")]
811            KeyAlg::X25519 => Ok(self
812                .assume::<X25519KeyPair>()
813                .write_key_exchange(other.assume::<X25519KeyPair>(), out)?),
814            #[cfg(feature = "k256")]
815            KeyAlg::EcCurve(EcCurves::Secp256k1) => Ok(self
816                .assume::<K256KeyPair>()
817                .write_key_exchange(other.assume::<K256KeyPair>(), out)?),
818            #[cfg(feature = "p256")]
819            KeyAlg::EcCurve(EcCurves::Secp256r1) => Ok(self
820                .assume::<P256KeyPair>()
821                .write_key_exchange(other.assume::<P256KeyPair>(), out)?),
822            #[cfg(feature = "p384")]
823            KeyAlg::EcCurve(EcCurves::Secp384r1) => Ok(self
824                .assume::<P384KeyPair>()
825                .write_key_exchange(other.assume::<P384KeyPair>(), out)?),
826            #[allow(unreachable_patterns)]
827            _ => {
828                let _ = out;
829                Err(err_msg!(Unsupported, "Unsupported key exchange"))
830            }
831        }
832    }
833}
834
835impl KeyAeadInPlace for AnyKey {
836    fn encrypt_in_place(
837        &self,
838        buffer: &mut dyn ResizeBuffer,
839        nonce: &[u8],
840        aad: &[u8],
841    ) -> Result<usize, Error> {
842        self.key_as_aead()?.encrypt_in_place(buffer, nonce, aad)
843    }
844
845    fn decrypt_in_place(
846        &self,
847        buffer: &mut dyn ResizeBuffer,
848        nonce: &[u8],
849        aad: &[u8],
850    ) -> Result<(), Error> {
851        self.key_as_aead()?.decrypt_in_place(buffer, nonce, aad)
852    }
853
854    fn aead_params(&self) -> KeyAeadParams {
855        if let Ok(key) = self.key_as_aead() {
856            key.aead_params()
857        } else {
858            KeyAeadParams::default()
859        }
860    }
861
862    fn aead_padding(&self, msg_len: usize) -> usize {
863        if let Ok(key) = self.key_as_aead() {
864            key.aead_padding(msg_len)
865        } else {
866            0
867        }
868    }
869}
870
871impl ToJwk for AnyKey {
872    fn encode_jwk(&self, enc: &mut dyn JwkEncoder) -> Result<(), Error> {
873        let key = match_key_alg! {
874            self,
875            &dyn ToJwk,
876            Aes,
877            Bls,
878            Chacha,
879            Ed25519,
880            K256,
881            P256,
882            P256Hardware,
883            P384,
884            X25519,
885            "JWK export is not supported for this key type"
886        }?;
887        key.encode_jwk(enc)
888    }
889}
890
891impl KeySign for AnyKey {
892    fn write_signature(
893        &self,
894        message: &[u8],
895        sig_type: Option<SignatureType>,
896        out: &mut dyn WriteBuffer,
897    ) -> Result<(), Error> {
898        let key = match_key_alg! {
899            self,
900            &dyn KeySign,
901            Ed25519,
902            K256,
903            P256,
904            P256Hardware,
905            P384,
906            "Signing is not supported for this key type"
907        }?;
908        key.write_signature(message, sig_type, out)
909    }
910}
911
912impl KeySigVerify for AnyKey {
913    fn verify_signature(
914        &self,
915        message: &[u8],
916        signature: &[u8],
917        sig_type: Option<SignatureType>,
918    ) -> Result<bool, Error> {
919        let key = match_key_alg! {
920            self,
921            &dyn KeySigVerify,
922            Ed25519,
923            K256,
924            P256,
925            P256Hardware,
926            P384,
927            "Signature verification is not supported for this key type"
928        }?;
929        key.verify_signature(message, signature, sig_type)
930    }
931}
932
933// may want to implement in-place initialization to avoid copies
934trait AllocKey {
935    fn alloc_key<K: AnyKeyAlg + Send + Sync + RefUnwindSafe + UnwindSafe>(key: K) -> Self;
936}
937
938impl AllocKey for Arc<AnyKey> {
939    #[inline(always)]
940    fn alloc_key<K: AnyKeyAlg + Send + Sync + RefUnwindSafe + UnwindSafe>(key: K) -> Self {
941        Self::from_key(key)
942    }
943}
944
945impl AllocKey for Box<AnyKey> {
946    #[inline(always)]
947    fn alloc_key<K: AnyKeyAlg + Send + Sync + RefUnwindSafe + UnwindSafe>(key: K) -> Self {
948        Self::from_key(key)
949    }
950}
951
952pub trait AnyKeyAlg: HasKeyAlg + HasKeyBackend + 'static {
953    fn as_any(&self) -> &dyn Any;
954}
955
956// implement for all concrete key types
957impl<K: HasKeyAlg + HasKeyBackend + Sized + 'static> AnyKeyAlg for K {
958    fn as_any(&self) -> &dyn Any {
959        self
960    }
961}
962
963#[cfg(test)]
964mod tests {
965    #[allow(unused_imports)]
966    use super::*;
967
968    // FIXME - add a custom key type for testing, to allow feature independence
969
970    #[cfg(feature = "ed25519")]
971    #[test]
972    fn ed25519_as_any() {
973        let key = Box::<AnyKey>::random(KeyAlg::Ed25519).unwrap();
974        assert_eq!(key.algorithm(), KeyAlg::Ed25519);
975        assert_eq!(key.key_type_id(), TypeId::of::<Ed25519KeyPair>());
976        let _ = key.to_jwk_public(None).unwrap();
977    }
978
979    #[cfg(feature = "aes")]
980    #[test]
981    fn key_exchange_any() {
982        let alice = Box::<AnyKey>::random(KeyAlg::X25519).unwrap();
983        let bob = Box::<AnyKey>::random(KeyAlg::X25519).unwrap();
984        let exch_a = alice.key_exchange_bytes(&bob).unwrap();
985        let exch_b = bob.key_exchange_bytes(&alice).unwrap();
986        assert_eq!(exch_a, exch_b);
987
988        let _aes_key =
989            Box::<AnyKey>::from_key_exchange(KeyAlg::Aes(AesTypes::A256Gcm), &*alice, &*bob)
990                .unwrap();
991    }
992
993    #[cfg(feature = "chacha")]
994    #[test]
995    fn key_encrypt_any() {
996        use crate::buffer::SecretBytes;
997        let message = b"test message";
998        let mut data = SecretBytes::from(&message[..]);
999
1000        let key = Box::<AnyKey>::random(KeyAlg::Chacha20(Chacha20Types::XC20P)).unwrap();
1001        let nonce = [0u8; 24]; // size varies by algorithm
1002        key.encrypt_in_place(&mut data, &nonce, &[]).unwrap();
1003        assert_ne!(data, &message[..]);
1004        key.decrypt_in_place(&mut data, &nonce, &[]).unwrap();
1005        assert_eq!(data, &message[..]);
1006    }
1007}