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, G1G2, 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 = "bls")]
266        KeyAlg::Bls12_381(BlsCurves::G1G2) => BlsKeyPair::<G1G2>::generate(rng).map(R::alloc_key),
267        #[cfg(feature = "chacha")]
268        KeyAlg::Chacha20(Chacha20Types::C20P) => {
269            Chacha20Key::<C20P>::generate(rng).map(R::alloc_key)
270        }
271        #[cfg(feature = "chacha")]
272        KeyAlg::Chacha20(Chacha20Types::XC20P) => {
273            Chacha20Key::<XC20P>::generate(rng).map(R::alloc_key)
274        }
275        #[cfg(feature = "ed25519")]
276        KeyAlg::Ed25519 => Ed25519KeyPair::generate(rng).map(R::alloc_key),
277        #[cfg(feature = "ed25519")]
278        KeyAlg::X25519 => X25519KeyPair::generate(rng).map(R::alloc_key),
279        #[cfg(feature = "k256")]
280        KeyAlg::EcCurve(EcCurves::Secp256k1) => K256KeyPair::generate(rng).map(R::alloc_key),
281        #[cfg(feature = "p256")]
282        KeyAlg::EcCurve(EcCurves::Secp256r1) => P256KeyPair::generate(rng).map(R::alloc_key),
283        #[cfg(feature = "p384")]
284        KeyAlg::EcCurve(EcCurves::Secp384r1) => P384KeyPair::generate(rng).map(R::alloc_key),
285        #[allow(unreachable_patterns)]
286        _ => Err(err_msg!(
287            Unsupported,
288            "Unsupported algorithm for key generation with rng"
289        )),
290    }
291}
292
293#[inline]
294fn generate_any_for_hardware<R: AllocKey>(alg: KeyAlg) -> Result<R, Error> {
295    match alg {
296        #[cfg(feature = "p256_hardware")]
297        KeyAlg::EcCurve(EcCurves::Secp256r1) => P256HardwareKeyPair::generate(
298            uuid::Uuid::new_v4()
299                .hyphenated()
300                .encode_lower(&mut uuid::Uuid::encode_buffer()),
301        )
302        .map(R::alloc_key),
303        _ => Err(err_msg!(
304            Unsupported,
305            "Unsupported algorithm for key generation with id"
306        )),
307    }
308}
309
310#[inline]
311fn get_any_with_id<R: AllocKey>(alg: KeyAlg, _id: &str) -> Result<R, Error> {
312    let key = match alg {
313        #[cfg(feature = "p256_hardware")]
314        KeyAlg::EcCurve(EcCurves::Secp256r1) => P256HardwareKeyPair::from_id(_id).map(R::alloc_key),
315        _ => Err(err_msg!(
316            Unsupported,
317            "Unsupported algorithm for key retrieval by id"
318        )),
319    }?;
320
321    Ok(key)
322}
323
324#[inline]
325fn from_public_bytes_any<R: AllocKey>(alg: KeyAlg, public: &[u8]) -> Result<R, Error> {
326    match alg {
327        #[cfg(feature = "bls")]
328        KeyAlg::Bls12_381(BlsCurves::G1) => {
329            BlsKeyPair::<G1>::from_public_bytes(public).map(R::alloc_key)
330        }
331        #[cfg(feature = "bls")]
332        KeyAlg::Bls12_381(BlsCurves::G2) => {
333            BlsKeyPair::<G2>::from_public_bytes(public).map(R::alloc_key)
334        }
335        #[cfg(feature = "bls")]
336        KeyAlg::Bls12_381(BlsCurves::G1G2) => {
337            BlsKeyPair::<G1G2>::from_public_bytes(public).map(R::alloc_key)
338        }
339        #[cfg(feature = "ed25519")]
340        KeyAlg::Ed25519 => Ed25519KeyPair::from_public_bytes(public).map(R::alloc_key),
341        #[cfg(feature = "ed25519")]
342        KeyAlg::X25519 => X25519KeyPair::from_public_bytes(public).map(R::alloc_key),
343        #[cfg(feature = "k256")]
344        KeyAlg::EcCurve(EcCurves::Secp256k1) => {
345            K256KeyPair::from_public_bytes(public).map(R::alloc_key)
346        }
347        #[cfg(feature = "p256")]
348        KeyAlg::EcCurve(EcCurves::Secp256r1) => {
349            P256KeyPair::from_public_bytes(public).map(R::alloc_key)
350        }
351        #[cfg(feature = "p384")]
352        KeyAlg::EcCurve(EcCurves::Secp384r1) => {
353            P384KeyPair::from_public_bytes(public).map(R::alloc_key)
354        }
355        #[allow(unreachable_patterns)]
356        _ => Err(err_msg!(
357            Unsupported,
358            "Unsupported algorithm for public key import"
359        )),
360    }
361}
362
363#[inline]
364fn from_secret_bytes_any<R: AllocKey>(alg: KeyAlg, secret: &[u8]) -> Result<R, Error> {
365    match alg {
366        #[cfg(feature = "aes")]
367        KeyAlg::Aes(AesTypes::A128Gcm) => {
368            AesKey::<A128Gcm>::from_secret_bytes(secret).map(R::alloc_key)
369        }
370        #[cfg(feature = "aes")]
371        KeyAlg::Aes(AesTypes::A256Gcm) => {
372            AesKey::<A256Gcm>::from_secret_bytes(secret).map(R::alloc_key)
373        }
374        #[cfg(feature = "aes")]
375        KeyAlg::Aes(AesTypes::A128CbcHs256) => {
376            AesKey::<A128CbcHs256>::from_secret_bytes(secret).map(R::alloc_key)
377        }
378        #[cfg(feature = "aes")]
379        KeyAlg::Aes(AesTypes::A256CbcHs512) => {
380            AesKey::<A256CbcHs512>::from_secret_bytes(secret).map(R::alloc_key)
381        }
382        #[cfg(feature = "aes")]
383        KeyAlg::Aes(AesTypes::A128Kw) => {
384            AesKey::<A128Kw>::from_secret_bytes(secret).map(R::alloc_key)
385        }
386        #[cfg(feature = "aes")]
387        KeyAlg::Aes(AesTypes::A256Kw) => {
388            AesKey::<A256Kw>::from_secret_bytes(secret).map(R::alloc_key)
389        }
390        #[cfg(feature = "bls")]
391        KeyAlg::Bls12_381(BlsCurves::G1) => {
392            BlsKeyPair::<G1>::from_secret_bytes(secret).map(R::alloc_key)
393        }
394        #[cfg(feature = "bls")]
395        KeyAlg::Bls12_381(BlsCurves::G2) => {
396            BlsKeyPair::<G2>::from_secret_bytes(secret).map(R::alloc_key)
397        }
398        #[cfg(feature = "bls")]
399        KeyAlg::Bls12_381(BlsCurves::G1G2) => {
400            BlsKeyPair::<G1G2>::from_secret_bytes(secret).map(R::alloc_key)
401        }
402        #[cfg(feature = "chacha")]
403        KeyAlg::Chacha20(Chacha20Types::C20P) => {
404            Chacha20Key::<C20P>::from_secret_bytes(secret).map(R::alloc_key)
405        }
406        #[cfg(feature = "chacha")]
407        KeyAlg::Chacha20(Chacha20Types::XC20P) => {
408            Chacha20Key::<XC20P>::from_secret_bytes(secret).map(R::alloc_key)
409        }
410        #[cfg(feature = "ed25519")]
411        KeyAlg::Ed25519 => Ed25519KeyPair::from_secret_bytes(secret).map(R::alloc_key),
412        #[cfg(feature = "ed25519")]
413        KeyAlg::X25519 => X25519KeyPair::from_secret_bytes(secret).map(R::alloc_key),
414        #[cfg(feature = "k256")]
415        KeyAlg::EcCurve(EcCurves::Secp256k1) => {
416            K256KeyPair::from_secret_bytes(secret).map(R::alloc_key)
417        }
418        #[cfg(feature = "p256")]
419        KeyAlg::EcCurve(EcCurves::Secp256r1) => {
420            P256KeyPair::from_secret_bytes(secret).map(R::alloc_key)
421        }
422        #[cfg(feature = "p384")]
423        KeyAlg::EcCurve(EcCurves::Secp384r1) => {
424            P384KeyPair::from_secret_bytes(secret).map(R::alloc_key)
425        }
426        #[allow(unreachable_patterns)]
427        _ => Err(err_msg!(
428            Unsupported,
429            "Unsupported algorithm for secret key import"
430        )),
431    }
432}
433
434#[cfg(any(feature = "aes", feature = "chacha"))]
435#[inline]
436fn from_key_exchange_any<R, Sk, Pk>(alg: KeyAlg, secret: &Sk, public: &Pk) -> Result<R, Error>
437where
438    R: AllocKey,
439    Sk: KeyExchange<Pk> + ?Sized,
440    Pk: ?Sized,
441{
442    match alg {
443        #[cfg(feature = "aes")]
444        KeyAlg::Aes(AesTypes::A128Gcm) => {
445            AesKey::<A128Gcm>::from_key_exchange(secret, public).map(R::alloc_key)
446        }
447        #[cfg(feature = "aes")]
448        KeyAlg::Aes(AesTypes::A256Gcm) => {
449            AesKey::<A256Gcm>::from_key_exchange(secret, public).map(R::alloc_key)
450        }
451        #[cfg(feature = "aes")]
452        KeyAlg::Aes(AesTypes::A128CbcHs256) => {
453            AesKey::<A128CbcHs256>::from_key_exchange(secret, public).map(R::alloc_key)
454        }
455        #[cfg(feature = "aes")]
456        KeyAlg::Aes(AesTypes::A256CbcHs512) => {
457            AesKey::<A256CbcHs512>::from_key_exchange(secret, public).map(R::alloc_key)
458        }
459        #[cfg(feature = "aes")]
460        KeyAlg::Aes(AesTypes::A128Kw) => {
461            AesKey::<A128Kw>::from_key_exchange(secret, public).map(R::alloc_key)
462        }
463        #[cfg(feature = "aes")]
464        KeyAlg::Aes(AesTypes::A256Kw) => {
465            AesKey::<A256Kw>::from_key_exchange(secret, public).map(R::alloc_key)
466        }
467        #[cfg(feature = "chacha")]
468        KeyAlg::Chacha20(Chacha20Types::C20P) => {
469            Chacha20Key::<C20P>::from_key_exchange(secret, public).map(R::alloc_key)
470        }
471        #[cfg(feature = "chacha")]
472        KeyAlg::Chacha20(Chacha20Types::XC20P) => {
473            Chacha20Key::<XC20P>::from_key_exchange(secret, public).map(R::alloc_key)
474        }
475        #[allow(unreachable_patterns)]
476        _ => Err(err_msg!(
477            Unsupported,
478            "Unsupported algorithm for key exchange"
479        )),
480    }
481}
482
483#[cfg(not(any(feature = "aes", feature = "chacha")))]
484#[inline]
485fn from_key_exchange_any<R, Sk: ?Sized, Pk: ?Sized>(
486    _alg: KeyAlg,
487    _secret: &Sk,
488    _public: &Pk,
489) -> Result<R, Error> {
490    return Err(err_msg!(
491        Unsupported,
492        "Unsupported algorithm for key exchange"
493    ));
494}
495
496#[cfg(any(feature = "aes", feature = "chacha"))]
497#[inline]
498fn from_key_derivation_any<R: AllocKey>(
499    alg: KeyAlg,
500    derive: impl KeyDerivation,
501) -> Result<R, Error> {
502    match alg {
503        #[cfg(feature = "aes")]
504        KeyAlg::Aes(AesTypes::A128Gcm) => {
505            AesKey::<A128Gcm>::from_key_derivation(derive).map(R::alloc_key)
506        }
507        #[cfg(feature = "aes")]
508        KeyAlg::Aes(AesTypes::A256Gcm) => {
509            AesKey::<A256Gcm>::from_key_derivation(derive).map(R::alloc_key)
510        }
511        #[cfg(feature = "aes")]
512        KeyAlg::Aes(AesTypes::A128CbcHs256) => {
513            AesKey::<A128CbcHs256>::from_key_derivation(derive).map(R::alloc_key)
514        }
515        #[cfg(feature = "aes")]
516        KeyAlg::Aes(AesTypes::A256CbcHs512) => {
517            AesKey::<A256CbcHs512>::from_key_derivation(derive).map(R::alloc_key)
518        }
519        #[cfg(feature = "aes")]
520        KeyAlg::Aes(AesTypes::A128Kw) => {
521            AesKey::<A128Kw>::from_key_derivation(derive).map(R::alloc_key)
522        }
523        #[cfg(feature = "aes")]
524        KeyAlg::Aes(AesTypes::A256Kw) => {
525            AesKey::<A256Kw>::from_key_derivation(derive).map(R::alloc_key)
526        }
527        #[cfg(feature = "chacha")]
528        KeyAlg::Chacha20(Chacha20Types::C20P) => {
529            Chacha20Key::<C20P>::from_key_derivation(derive).map(R::alloc_key)
530        }
531        #[cfg(feature = "chacha")]
532        KeyAlg::Chacha20(Chacha20Types::XC20P) => {
533            Chacha20Key::<XC20P>::from_key_derivation(derive).map(R::alloc_key)
534        }
535        #[allow(unreachable_patterns)]
536        _ => Err(err_msg!(
537            Unsupported,
538            "Unsupported algorithm for key derivation"
539        )),
540    }
541}
542
543#[cfg(not(any(feature = "aes", feature = "chacha")))]
544fn from_key_derivation_any<R: AllocKey>(
545    _alg: KeyAlg,
546    _derive: impl KeyDerivation,
547) -> Result<R, Error> {
548    return Err(err_msg!(
549        Unsupported,
550        "Unsupported algorithm for key derivation"
551    ));
552}
553
554#[inline]
555fn convert_key_any<R: AllocKey>(key: &AnyKey, alg: KeyAlg) -> Result<R, Error> {
556    match (key.algorithm(), alg) {
557        #[cfg(feature = "bls")]
558        (KeyAlg::Bls12_381(BlsCurves::G1G2), KeyAlg::Bls12_381(BlsCurves::G1)) => Ok(R::alloc_key(
559            BlsKeyPair::<G1>::from(key.assume::<BlsKeyPair<G1G2>>()),
560        )),
561        #[cfg(feature = "bls")]
562        (KeyAlg::Bls12_381(BlsCurves::G1G2), KeyAlg::Bls12_381(BlsCurves::G2)) => Ok(R::alloc_key(
563            BlsKeyPair::<G2>::from(key.assume::<BlsKeyPair<G1G2>>()),
564        )),
565        #[cfg(feature = "ed25519")]
566        (KeyAlg::Ed25519, KeyAlg::X25519) => Ok(<X25519KeyPair as TryFrom<_>>::try_from(
567            key.assume::<Ed25519KeyPair>(),
568        )
569        .map(R::alloc_key)?),
570        #[allow(unreachable_patterns)]
571        _ => Err(err_msg!(
572            Unsupported,
573            "Unsupported key conversion operation"
574        )),
575    }
576}
577
578#[inline]
579fn get_key_id_any(key: &AnyKey) -> Result<SecretBytes, Error> {
580    match key.algorithm() {
581        #[cfg(feature = "p256_hardware")]
582        KeyAlg::EcCurve(EcCurves::Secp256r1) => {
583            Ok(key.assume::<P256HardwareKeyPair>().key_id.clone())
584        }
585        #[allow(unreachable_patterns)]
586        _ => Err(err_msg!(Unsupported, "Unsupported get key id operation")),
587    }
588}
589
590impl FromJwk for Box<AnyKey> {
591    fn from_jwk_parts(jwk: JwkParts<'_>) -> Result<Self, Error> {
592        from_jwk_any(jwk)
593    }
594}
595
596impl FromJwk for Arc<AnyKey> {
597    fn from_jwk_parts(jwk: JwkParts<'_>) -> Result<Self, Error> {
598        from_jwk_any(jwk)
599    }
600}
601
602#[inline]
603fn from_jwk_any<R: AllocKey>(jwk: JwkParts<'_>) -> Result<R, Error> {
604    match (jwk.kty, jwk.crv.as_ref(), jwk.alg.as_ref()) {
605        #[cfg(feature = "aes")]
606        ("oct", _, A128Gcm::JWK_ALG) => AesKey::<A128Gcm>::from_jwk_parts(jwk).map(R::alloc_key),
607        #[cfg(feature = "aes")]
608        ("oct", _, A256Gcm::JWK_ALG) => AesKey::<A256Gcm>::from_jwk_parts(jwk).map(R::alloc_key),
609        #[cfg(feature = "aes")]
610        ("oct", _, A128CbcHs256::JWK_ALG) => {
611            AesKey::<A128CbcHs256>::from_jwk_parts(jwk).map(R::alloc_key)
612        }
613        #[cfg(feature = "aes")]
614        ("oct", _, A256CbcHs512::JWK_ALG) => {
615            AesKey::<A256CbcHs512>::from_jwk_parts(jwk).map(R::alloc_key)
616        }
617        #[cfg(feature = "aes")]
618        ("oct", _, A128Kw::JWK_ALG) => AesKey::<A128Kw>::from_jwk_parts(jwk).map(R::alloc_key),
619        #[cfg(feature = "aes")]
620        ("oct", _, A256Kw::JWK_ALG) => AesKey::<A256Kw>::from_jwk_parts(jwk).map(R::alloc_key),
621        #[cfg(feature = "bls")]
622        ("OKP" | "EC", G1::JWK_CURVE, _) => BlsKeyPair::<G1>::from_jwk_parts(jwk).map(R::alloc_key),
623        #[cfg(feature = "bls")]
624        ("OKP" | "EC", G2::JWK_CURVE, _) => BlsKeyPair::<G2>::from_jwk_parts(jwk).map(R::alloc_key),
625        #[cfg(feature = "bls")]
626        ("OKP" | "EC", G1G2::JWK_CURVE, _) => {
627            BlsKeyPair::<G1G2>::from_jwk_parts(jwk).map(R::alloc_key)
628        }
629        #[cfg(feature = "chacha")]
630        ("oct", _, C20P::JWK_ALG) => Chacha20Key::<C20P>::from_jwk_parts(jwk).map(R::alloc_key),
631        #[cfg(feature = "chacha")]
632        ("oct", _, XC20P::JWK_ALG) => Chacha20Key::<XC20P>::from_jwk_parts(jwk).map(R::alloc_key),
633        #[cfg(feature = "ed25519")]
634        ("OKP", ed25519::JWK_CURVE, _) => Ed25519KeyPair::from_jwk_parts(jwk).map(R::alloc_key),
635        #[cfg(feature = "ed25519")]
636        ("OKP", x25519::JWK_CURVE, _) => X25519KeyPair::from_jwk_parts(jwk).map(R::alloc_key),
637        #[cfg(feature = "k256")]
638        ("EC", k256::JWK_CURVE, _) => K256KeyPair::from_jwk_parts(jwk).map(R::alloc_key),
639        #[cfg(feature = "p256")]
640        ("EC", p256::JWK_CURVE, _) => P256KeyPair::from_jwk_parts(jwk).map(R::alloc_key),
641        #[cfg(feature = "p384")]
642        ("EC", p384::JWK_CURVE, _) => P384KeyPair::from_jwk_parts(jwk).map(R::alloc_key),
643        _ => Err(err_msg!(Unsupported, "Unsupported JWK for key import")),
644    }
645}
646
647macro_rules! match_key_alg {
648    ($slf:expr, $ty:ty, $($kty:ident),+ $(,$errmsg:literal)?) => {{
649        fn matcher(key: &AnyKey) -> Result<$ty, Error> {
650            #[allow(unused_variables)]
651            let alg = key.algorithm();
652            match_key_alg!(@ $($kty)+ ; key, alg);
653            return Err(err_msg!(Unsupported $(,$errmsg)?))
654        }
655        matcher($slf)
656    }};
657    (@ ; $key:ident, $alg:ident) => {()};
658    (@ Aes $($rest:ident)*; $key:ident, $alg:ident) => {{
659        #[cfg(feature = "aes")]
660        if $alg == KeyAlg::Aes(AesTypes::A128Gcm) {
661            return Ok($key.assume::<AesKey<A128Gcm>>());
662        }
663        #[cfg(feature = "aes")]
664        if $alg == KeyAlg::Aes(AesTypes::A256Gcm) {
665            return Ok($key.assume::<AesKey<A256Gcm>>());
666        }
667        #[cfg(feature = "aes")]
668        if $alg == KeyAlg::Aes(AesTypes::A128CbcHs256) {
669            return Ok($key.assume::<AesKey<A128CbcHs256>>());
670        }
671        #[cfg(feature = "aes")]
672        if $alg == KeyAlg::Aes(AesTypes::A256CbcHs512) {
673            return Ok($key.assume::<AesKey<A256CbcHs512>>());
674        }
675        #[cfg(feature = "aes")]
676        if $alg == KeyAlg::Aes(AesTypes::A128Kw) {
677            return Ok($key.assume::<AesKey<A128Kw>>());
678        }
679        #[cfg(feature = "aes")]
680        if $alg == KeyAlg::Aes(AesTypes::A256Kw) {
681            return Ok($key.assume::<AesKey<A256Kw>>());
682        }
683        match_key_alg!(@ $($rest)*; $key, $alg)
684    }};
685    (@ Bls $($rest:ident)*; $key:ident, $alg:ident) => {{
686        #[cfg(feature = "bls")]
687        if $alg == KeyAlg::Bls12_381(BlsCurves::G1) {
688            return Ok($key.assume::<BlsKeyPair<G1>>());
689        }
690        #[cfg(feature = "bls")]
691        if $alg == KeyAlg::Bls12_381(BlsCurves::G2) {
692            return Ok($key.assume::<BlsKeyPair<G2>>());
693        }
694        #[cfg(feature = "bls")]
695        if $alg == KeyAlg::Bls12_381(BlsCurves::G1G2) {
696            return Ok($key.assume::<BlsKeyPair<G1G2>>());
697        }
698        match_key_alg!(@ $($rest)*; $key, $alg)
699    }};
700    (@ Chacha $($rest:ident)*; $key:ident, $alg:ident) => {{
701        #[cfg(feature = "chacha")]
702        if $alg == KeyAlg::Chacha20(Chacha20Types::C20P) {
703            return Ok($key.assume::<Chacha20Key<C20P>>());
704        }
705        #[cfg(feature = "chacha")]
706        if $alg == KeyAlg::Chacha20(Chacha20Types::XC20P) {
707            return Ok($key.assume::<Chacha20Key<XC20P>>());
708        }
709        match_key_alg!(@ $($rest)*; $key, $alg)
710    }};
711    (@ Ed25519 $($rest:ident)*; $key:ident, $alg:ident) => {{
712        #[cfg(feature = "ed25519")]
713        if $alg == KeyAlg::Ed25519 {
714            return Ok($key.assume::<Ed25519KeyPair>())
715        }
716        match_key_alg!(@ $($rest)*; $key, $alg)
717    }};
718    (@ X25519 $($rest:ident)*; $key:ident, $alg:ident) => {{
719        #[cfg(feature = "ed25519")]
720        if $alg == KeyAlg::X25519 {
721            return Ok($key.assume::<X25519KeyPair>())
722        }
723        match_key_alg!(@ $($rest)*; $key, $alg)
724    }};
725    (@ K256 $($rest:ident)*; $key:ident, $alg:ident) => {{
726        #[cfg(feature = "k256")]
727        if $alg == KeyAlg::EcCurve(EcCurves::Secp256k1) {
728            return Ok($key.assume::<K256KeyPair>())
729        }
730        match_key_alg!(@ $($rest)*; $key, $alg)
731    }};
732    (@ P256 $($rest:ident)*; $key:ident, $alg:ident) => {{
733        #[cfg(feature = "p256")]
734        if $alg == KeyAlg::EcCurve(EcCurves::Secp256r1) && $key.backend() == KeyBackend::Software {
735            return Ok($key.assume::<P256KeyPair>())
736        }
737        match_key_alg!(@ $($rest)*; $key, $alg)
738    }};
739    (@ P256Hardware $($rest:ident)*; $key:ident, $alg:ident) => {{
740        #[cfg(feature = "p256_hardware")]
741        if $alg == KeyAlg::EcCurve(EcCurves::Secp256r1) && $key.backend() == KeyBackend::SecureElement {
742            return Ok($key.assume::<P256HardwareKeyPair>())
743        }
744        match_key_alg!(@ $($rest)*; $key, $alg)
745    }};
746    (@ P384 $($rest:ident)*; $key:ident, $alg:ident) => {{
747        #[cfg(feature = "p384")]
748        if $alg == KeyAlg::EcCurve(EcCurves::Secp384r1) {
749            return Ok($key.assume::<P384KeyPair>())
750        }
751        match_key_alg!(@ $($rest)*; $key, $alg)
752    }};
753}
754
755impl AnyKey {
756    fn key_as_aead(&self) -> Result<&dyn KeyAeadInPlace, Error> {
757        match_key_alg! {
758            self,
759            &dyn KeyAeadInPlace,
760            Aes,
761            Chacha,
762            "AEAD is not supported for this key type"
763        }
764    }
765
766    fn key_to_secret(&self) -> Result<&dyn ToSecretBytes, Error> {
767        match_key_alg! {
768            self,
769            &dyn ToSecretBytes,
770            Aes,
771            Bls,
772            Chacha,
773            Ed25519,
774            K256,
775            P256,
776            P384,
777            X25519,
778            "Secret key export is not supported for this key type"
779        }
780    }
781
782    fn key_to_public(&self) -> Result<&dyn ToPublicBytes, Error> {
783        match_key_alg! {
784            self,
785            &dyn ToPublicBytes,
786            Bls,
787            Ed25519,
788            K256,
789            P256,
790            P256Hardware,
791            P384,
792            X25519,
793            "Public key export is not supported for this key type"
794        }
795    }
796}
797
798impl ToPublicBytes for AnyKey {
799    fn public_bytes_length(&self) -> Result<usize, Error> {
800        self.key_to_public()?.public_bytes_length()
801    }
802
803    fn write_public_bytes(&self, out: &mut dyn WriteBuffer) -> Result<(), Error> {
804        self.key_to_public()?.write_public_bytes(out)
805    }
806}
807
808impl ToSecretBytes for AnyKey {
809    fn secret_bytes_length(&self) -> Result<usize, Error> {
810        self.key_to_secret()?.secret_bytes_length()
811    }
812
813    fn write_secret_bytes(&self, out: &mut dyn WriteBuffer) -> Result<(), Error> {
814        self.key_to_secret()?.write_secret_bytes(out)
815    }
816}
817
818impl KeyExchange for AnyKey {
819    fn write_key_exchange(&self, other: &AnyKey, out: &mut dyn WriteBuffer) -> Result<(), Error> {
820        if self.key_type_id() != other.key_type_id() {
821            return Err(err_msg!(Unsupported, "Unsupported key exchange"));
822        }
823        match self.algorithm() {
824            #[cfg(feature = "ed25519")]
825            KeyAlg::X25519 => Ok(self
826                .assume::<X25519KeyPair>()
827                .write_key_exchange(other.assume::<X25519KeyPair>(), out)?),
828            #[cfg(feature = "k256")]
829            KeyAlg::EcCurve(EcCurves::Secp256k1) => Ok(self
830                .assume::<K256KeyPair>()
831                .write_key_exchange(other.assume::<K256KeyPair>(), out)?),
832            #[cfg(feature = "p256")]
833            KeyAlg::EcCurve(EcCurves::Secp256r1) => Ok(self
834                .assume::<P256KeyPair>()
835                .write_key_exchange(other.assume::<P256KeyPair>(), out)?),
836            #[cfg(feature = "p384")]
837            KeyAlg::EcCurve(EcCurves::Secp384r1) => Ok(self
838                .assume::<P384KeyPair>()
839                .write_key_exchange(other.assume::<P384KeyPair>(), out)?),
840            #[allow(unreachable_patterns)]
841            _ => {
842                let _ = out;
843                Err(err_msg!(Unsupported, "Unsupported key exchange"))
844            }
845        }
846    }
847}
848
849impl KeyAeadInPlace for AnyKey {
850    fn encrypt_in_place(
851        &self,
852        buffer: &mut dyn ResizeBuffer,
853        nonce: &[u8],
854        aad: &[u8],
855    ) -> Result<usize, Error> {
856        self.key_as_aead()?.encrypt_in_place(buffer, nonce, aad)
857    }
858
859    fn decrypt_in_place(
860        &self,
861        buffer: &mut dyn ResizeBuffer,
862        nonce: &[u8],
863        aad: &[u8],
864    ) -> Result<(), Error> {
865        self.key_as_aead()?.decrypt_in_place(buffer, nonce, aad)
866    }
867
868    fn aead_params(&self) -> KeyAeadParams {
869        if let Ok(key) = self.key_as_aead() {
870            key.aead_params()
871        } else {
872            KeyAeadParams::default()
873        }
874    }
875
876    fn aead_padding(&self, msg_len: usize) -> usize {
877        if let Ok(key) = self.key_as_aead() {
878            key.aead_padding(msg_len)
879        } else {
880            0
881        }
882    }
883}
884
885impl ToJwk for AnyKey {
886    fn encode_jwk(&self, enc: &mut dyn JwkEncoder) -> Result<(), Error> {
887        let key = match_key_alg! {
888            self,
889            &dyn ToJwk,
890            Aes,
891            Bls,
892            Chacha,
893            Ed25519,
894            K256,
895            P256,
896            P256Hardware,
897            P384,
898            X25519,
899            "JWK export is not supported for this key type"
900        }?;
901        key.encode_jwk(enc)
902    }
903}
904
905impl KeySign for AnyKey {
906    fn write_signature(
907        &self,
908        message: &[u8],
909        sig_type: Option<SignatureType>,
910        out: &mut dyn WriteBuffer,
911    ) -> Result<(), Error> {
912        let key = match_key_alg! {
913            self,
914            &dyn KeySign,
915            Ed25519,
916            K256,
917            P256,
918            P256Hardware,
919            P384,
920            "Signing is not supported for this key type"
921        }?;
922        key.write_signature(message, sig_type, out)
923    }
924}
925
926impl KeySigVerify for AnyKey {
927    fn verify_signature(
928        &self,
929        message: &[u8],
930        signature: &[u8],
931        sig_type: Option<SignatureType>,
932    ) -> Result<bool, Error> {
933        let key = match_key_alg! {
934            self,
935            &dyn KeySigVerify,
936            Ed25519,
937            K256,
938            P256,
939            P256Hardware,
940            P384,
941            "Signature verification is not supported for this key type"
942        }?;
943        key.verify_signature(message, signature, sig_type)
944    }
945}
946
947// may want to implement in-place initialization to avoid copies
948trait AllocKey {
949    fn alloc_key<K: AnyKeyAlg + Send + Sync + RefUnwindSafe + UnwindSafe>(key: K) -> Self;
950}
951
952impl AllocKey for Arc<AnyKey> {
953    #[inline(always)]
954    fn alloc_key<K: AnyKeyAlg + Send + Sync + RefUnwindSafe + UnwindSafe>(key: K) -> Self {
955        Self::from_key(key)
956    }
957}
958
959impl AllocKey for Box<AnyKey> {
960    #[inline(always)]
961    fn alloc_key<K: AnyKeyAlg + Send + Sync + RefUnwindSafe + UnwindSafe>(key: K) -> Self {
962        Self::from_key(key)
963    }
964}
965
966pub trait AnyKeyAlg: HasKeyAlg + HasKeyBackend + 'static {
967    fn as_any(&self) -> &dyn Any;
968}
969
970// implement for all concrete key types
971impl<K: HasKeyAlg + HasKeyBackend + Sized + 'static> AnyKeyAlg for K {
972    fn as_any(&self) -> &dyn Any {
973        self
974    }
975}
976
977#[cfg(test)]
978mod tests {
979    #[allow(unused_imports)]
980    use super::*;
981
982    // FIXME - add a custom key type for testing, to allow feature independence
983
984    #[cfg(feature = "ed25519")]
985    #[test]
986    fn ed25519_as_any() {
987        let key = Box::<AnyKey>::random(KeyAlg::Ed25519).unwrap();
988        assert_eq!(key.algorithm(), KeyAlg::Ed25519);
989        assert_eq!(key.key_type_id(), TypeId::of::<Ed25519KeyPair>());
990        let _ = key.to_jwk_public(None).unwrap();
991    }
992
993    #[cfg(feature = "aes")]
994    #[test]
995    fn key_exchange_any() {
996        let alice = Box::<AnyKey>::random(KeyAlg::X25519).unwrap();
997        let bob = Box::<AnyKey>::random(KeyAlg::X25519).unwrap();
998        let exch_a = alice.key_exchange_bytes(&bob).unwrap();
999        let exch_b = bob.key_exchange_bytes(&alice).unwrap();
1000        assert_eq!(exch_a, exch_b);
1001
1002        let _aes_key =
1003            Box::<AnyKey>::from_key_exchange(KeyAlg::Aes(AesTypes::A256Gcm), &*alice, &*bob)
1004                .unwrap();
1005    }
1006
1007    #[cfg(feature = "chacha")]
1008    #[test]
1009    fn key_encrypt_any() {
1010        use crate::buffer::SecretBytes;
1011        let message = b"test message";
1012        let mut data = SecretBytes::from(&message[..]);
1013
1014        let key = Box::<AnyKey>::random(KeyAlg::Chacha20(Chacha20Types::XC20P)).unwrap();
1015        let nonce = [0u8; 24]; // size varies by algorithm
1016        key.encrypt_in_place(&mut data, &nonce, &[]).unwrap();
1017        assert_ne!(data, &message[..]);
1018        key.decrypt_in_place(&mut data, &nonce, &[]).unwrap();
1019        assert_eq!(data, &message[..]);
1020    }
1021}