askar_crypto/alg/
mod.rs

1//! Supported key algorithms
2
3use core::{
4    fmt::{self, Debug, Display, Formatter},
5    str::FromStr,
6};
7
8#[cfg(feature = "arbitrary")]
9use arbitrary::Arbitrary;
10use zeroize::Zeroize;
11
12use crate::{
13    backend::KeyBackend,
14    buffer::{WriteBuffer, Writer},
15    error::Error,
16};
17
18#[cfg(feature = "any_key")]
19mod any;
20#[cfg(feature = "any_key")]
21#[cfg_attr(docsrs, doc(cfg(feature = "any_key")))]
22pub use any::{AnyKey, AnyKeyCreate};
23
24#[cfg(feature = "aes")]
25#[cfg_attr(docsrs, doc(cfg(feature = "aes")))]
26pub mod aes;
27
28#[cfg(feature = "bls")]
29#[cfg_attr(docsrs, doc(cfg(feature = "bls")))]
30pub mod bls;
31
32#[cfg(feature = "chacha")]
33#[cfg_attr(docsrs, doc(cfg(feature = "chacha")))]
34pub mod chacha20;
35
36#[cfg(feature = "ed25519")]
37#[cfg_attr(docsrs, doc(cfg(feature = "ed25519")))]
38pub mod ed25519;
39
40#[cfg(feature = "ed25519")]
41#[cfg_attr(docsrs, doc(cfg(feature = "ed25519")))]
42pub mod x25519;
43
44#[cfg(feature = "ec_curves")]
45mod ec_common;
46
47#[cfg(feature = "k256")]
48#[cfg_attr(docsrs, doc(cfg(feature = "k256")))]
49pub mod k256;
50
51#[cfg(any(feature = "p256", feature = "p256_hardware"))]
52#[cfg_attr(docsrs, doc(cfg(any(feature = "p256", feature = "p256_hardware"))))]
53pub mod p256;
54
55#[cfg(feature = "p384")]
56#[cfg_attr(docsrs, doc(cfg(feature = "p384")))]
57pub mod p384;
58
59#[cfg(feature = "p256_hardware")]
60#[cfg_attr(docsrs, doc(cfg(feature = "p256_hardware")))]
61pub mod p256_hardware;
62
63/// Supported key algorithms
64#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Zeroize)]
65#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
66pub enum KeyAlg {
67    /// AES
68    Aes(AesTypes),
69    /// BLS12-381
70    Bls12_381(BlsCurves),
71    /// (X)ChaCha20-Poly1305
72    Chacha20(Chacha20Types),
73    /// Ed25519 signing key
74    Ed25519,
75    /// Curve25519 elliptic curve key exchange key
76    X25519,
77    /// Elliptic Curve key for signing or key exchange
78    EcCurve(EcCurves),
79}
80
81impl KeyAlg {
82    /// Get a reference to a string representing the `KeyAlg`
83    pub fn as_str(&self) -> &'static str {
84        match self {
85            Self::Aes(AesTypes::A128Gcm) => "a128gcm",
86            Self::Aes(AesTypes::A256Gcm) => "a256gcm",
87            Self::Aes(AesTypes::A128CbcHs256) => "a128cbchs256",
88            Self::Aes(AesTypes::A256CbcHs512) => "a256cbchs512",
89            Self::Aes(AesTypes::A128Kw) => "a128kw",
90            Self::Aes(AesTypes::A256Kw) => "a256kw",
91            Self::Bls12_381(BlsCurves::G1) => "bls12381g1",
92            Self::Bls12_381(BlsCurves::G2) => "bls12381g2",
93            Self::Chacha20(Chacha20Types::C20P) => "c20p",
94            Self::Chacha20(Chacha20Types::XC20P) => "xc20p",
95            Self::Ed25519 => "ed25519",
96            Self::X25519 => "x25519",
97            Self::EcCurve(EcCurves::Secp256k1) => "k256",
98            Self::EcCurve(EcCurves::Secp256r1) => "p256",
99            Self::EcCurve(EcCurves::Secp384r1) => "p384",
100        }
101    }
102}
103
104impl AsRef<str> for KeyAlg {
105    fn as_ref(&self) -> &str {
106        self.as_str()
107    }
108}
109
110impl FromStr for KeyAlg {
111    type Err = Error;
112
113    fn from_str(s: &str) -> Result<Self, Self::Err> {
114        match normalize_alg(s)? {
115            a if a == "a128gcm" || a == "aes128gcm" => Ok(Self::Aes(AesTypes::A128Gcm)),
116            a if a == "a256gcm" || a == "aes256gcm" => Ok(Self::Aes(AesTypes::A256Gcm)),
117            a if a == "a128cbchs256" || a == "aes128cbchs256" => {
118                Ok(Self::Aes(AesTypes::A128CbcHs256))
119            }
120            a if a == "a256cbchs512" || a == "aes256cbchs512" => {
121                Ok(Self::Aes(AesTypes::A256CbcHs512))
122            }
123            a if a == "a128kw" || a == "aes128kw" => Ok(Self::Aes(AesTypes::A128Kw)),
124            a if a == "a256kw" || a == "aes256kw" => Ok(Self::Aes(AesTypes::A256Kw)),
125            a if a == "bls12381g1" => Ok(Self::Bls12_381(BlsCurves::G1)),
126            a if a == "bls12381g2" => Ok(Self::Bls12_381(BlsCurves::G2)),
127            a if a == "c20p" || a == "chacha20poly1305" => Ok(Self::Chacha20(Chacha20Types::C20P)),
128            a if a == "xc20p" || a == "xchacha20poly1305" => {
129                Ok(Self::Chacha20(Chacha20Types::XC20P))
130            }
131            a if a == "ed25519" => Ok(Self::Ed25519),
132            a if a == "x25519" => Ok(Self::X25519),
133            a if a == "k256" || a == "secp256k1" => Ok(Self::EcCurve(EcCurves::Secp256k1)),
134            a if a == "p256" || a == "secp256r1" => Ok(Self::EcCurve(EcCurves::Secp256r1)),
135            a if a == "p384" || a == "secp384r1" => Ok(Self::EcCurve(EcCurves::Secp384r1)),
136            _ => Err(err_msg!(Unsupported, "Unknown key algorithm")),
137        }
138    }
139}
140
141#[inline(always)]
142pub(crate) fn normalize_alg(alg: &str) -> Result<NormalizedAlg, Error> {
143    NormalizedAlg::new(alg)
144}
145
146// Going through some hoops to avoid allocating.
147// This struct stores up to 64 bytes of a normalized
148// algorithm name in order to speed up comparisons
149// when matching.
150pub(crate) struct NormalizedAlg {
151    len: usize,
152    buf: [u8; 64],
153}
154
155impl NormalizedAlg {
156    fn new(val: &str) -> Result<Self, Error> {
157        let mut slf = Self {
158            len: 0,
159            buf: [0; 64],
160        };
161        let mut cu = [0u8; 4];
162        let mut writer = Writer::from_slice(slf.buf.as_mut());
163        for c in NormalizedIter::new(val) {
164            let s = c.encode_utf8(&mut cu);
165            writer.buffer_write(s.as_bytes())?;
166        }
167        slf.len = writer.position();
168        Ok(slf)
169    }
170}
171
172impl AsRef<[u8]> for NormalizedAlg {
173    fn as_ref(&self) -> &[u8] {
174        &self.buf[..self.len]
175    }
176}
177
178impl<T: AsRef<[u8]>> PartialEq<T> for NormalizedAlg {
179    fn eq(&self, other: &T) -> bool {
180        self.as_ref() == other.as_ref()
181    }
182}
183
184struct NormalizedIter<'a> {
185    chars: core::str::Chars<'a>,
186}
187
188impl<'a> NormalizedIter<'a> {
189    pub fn new(val: &'a str) -> Self {
190        Self { chars: val.chars() }
191    }
192}
193
194impl Iterator for NormalizedIter<'_> {
195    type Item = char;
196    fn next(&mut self) -> Option<Self::Item> {
197        #[allow(clippy::while_let_on_iterator)]
198        while let Some(c) = self.chars.next() {
199            if c != '-' && c != '_' && c != ' ' {
200                return Some(c.to_ascii_lowercase());
201            }
202        }
203        None
204    }
205}
206
207impl Display for KeyAlg {
208    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
209        f.write_str(self.as_str())
210    }
211}
212
213/// Supported algorithms for AES
214#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Zeroize)]
215#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
216pub enum AesTypes {
217    /// 128-bit AES-GCM
218    A128Gcm,
219    /// 256-bit AES-GCM
220    A256Gcm,
221    /// 128-bit AES-CBC with HMAC-256
222    A128CbcHs256,
223    /// 256-bit AES-CBC with HMAC-512
224    A256CbcHs512,
225    /// 128-bit AES Key Wrap
226    A128Kw,
227    /// 256-bit AES Key Wrap
228    A256Kw,
229}
230
231/// Supported public key types for Bls12_381
232#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Zeroize)]
233#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
234pub enum BlsCurves {
235    /// G1 curve
236    G1,
237    /// G2 curve
238    G2,
239}
240
241/// Supported algorithms for (X)ChaCha20-Poly1305
242#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Zeroize)]
243#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
244pub enum Chacha20Types {
245    /// ChaCha20-Poly1305
246    C20P,
247    /// XChaCha20-Poly1305
248    XC20P,
249}
250
251/// Supported curves for ECC operations
252#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Zeroize)]
253#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
254pub enum EcCurves {
255    /// NIST P-256 curve
256    Secp256r1,
257    /// Koblitz 256 curve
258    Secp256k1,
259    /// NIST P-384 curve
260    Secp384r1,
261}
262
263/// A trait for accessing the algorithm of a key, used when
264/// converting to generic `AnyKey` instances.
265pub trait HasKeyAlg: Debug {
266    /// Get the corresponding key algorithm.
267    fn algorithm(&self) -> KeyAlg;
268}
269
270/// A trait for accessing the backend of a key, used when
271/// converting to generic `AnyKey` instances.
272pub trait HasKeyBackend: Debug {
273    /// Get the corresponding key backend.
274    fn key_backend(&self) -> KeyBackend {
275        KeyBackend::default()
276    }
277}
278
279#[cfg(test)]
280mod tests {
281    use super::*;
282
283    #[test]
284    fn cmp_normalize() {
285        assert!(normalize_alg("Test").unwrap() == "test");
286        assert!(normalize_alg("t-e-s-t").unwrap() == "test");
287        assert!(normalize_alg("--TE__ST--").unwrap() == "test");
288        assert!(normalize_alg("t-e-s-t").unwrap() != "tes");
289        assert!(normalize_alg("t-e-s-t").unwrap() != "testt");
290    }
291}