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::Bls12_381(BlsCurves::G1G2) => "bls12381g1g2",
94            Self::Chacha20(Chacha20Types::C20P) => "c20p",
95            Self::Chacha20(Chacha20Types::XC20P) => "xc20p",
96            Self::Ed25519 => "ed25519",
97            Self::X25519 => "x25519",
98            Self::EcCurve(EcCurves::Secp256k1) => "k256",
99            Self::EcCurve(EcCurves::Secp256r1) => "p256",
100            Self::EcCurve(EcCurves::Secp384r1) => "p384",
101        }
102    }
103}
104
105impl AsRef<str> for KeyAlg {
106    fn as_ref(&self) -> &str {
107        self.as_str()
108    }
109}
110
111impl FromStr for KeyAlg {
112    type Err = Error;
113
114    fn from_str(s: &str) -> Result<Self, Self::Err> {
115        match normalize_alg(s)? {
116            a if a == "a128gcm" || a == "aes128gcm" => Ok(Self::Aes(AesTypes::A128Gcm)),
117            a if a == "a256gcm" || a == "aes256gcm" => Ok(Self::Aes(AesTypes::A256Gcm)),
118            a if a == "a128cbchs256" || a == "aes128cbchs256" => {
119                Ok(Self::Aes(AesTypes::A128CbcHs256))
120            }
121            a if a == "a256cbchs512" || a == "aes256cbchs512" => {
122                Ok(Self::Aes(AesTypes::A256CbcHs512))
123            }
124            a if a == "a128kw" || a == "aes128kw" => Ok(Self::Aes(AesTypes::A128Kw)),
125            a if a == "a256kw" || a == "aes256kw" => Ok(Self::Aes(AesTypes::A256Kw)),
126            a if a == "bls12381g1" => Ok(Self::Bls12_381(BlsCurves::G1)),
127            a if a == "bls12381g2" => Ok(Self::Bls12_381(BlsCurves::G2)),
128            a if a == "bls12381g1g2" => Ok(Self::Bls12_381(BlsCurves::G1G2)),
129            a if a == "c20p" || a == "chacha20poly1305" => Ok(Self::Chacha20(Chacha20Types::C20P)),
130            a if a == "xc20p" || a == "xchacha20poly1305" => {
131                Ok(Self::Chacha20(Chacha20Types::XC20P))
132            }
133            a if a == "ed25519" => Ok(Self::Ed25519),
134            a if a == "x25519" => Ok(Self::X25519),
135            a if a == "k256" || a == "secp256k1" => Ok(Self::EcCurve(EcCurves::Secp256k1)),
136            a if a == "p256" || a == "secp256r1" => Ok(Self::EcCurve(EcCurves::Secp256r1)),
137            a if a == "p384" || a == "secp384r1" => Ok(Self::EcCurve(EcCurves::Secp384r1)),
138            _ => Err(err_msg!(Unsupported, "Unknown key algorithm")),
139        }
140    }
141}
142
143#[inline(always)]
144pub(crate) fn normalize_alg(alg: &str) -> Result<NormalizedAlg, Error> {
145    NormalizedAlg::new(alg)
146}
147
148// Going through some hoops to avoid allocating.
149// This struct stores up to 64 bytes of a normalized
150// algorithm name in order to speed up comparisons
151// when matching.
152pub(crate) struct NormalizedAlg {
153    len: usize,
154    buf: [u8; 64],
155}
156
157impl NormalizedAlg {
158    fn new(val: &str) -> Result<Self, Error> {
159        let mut slf = Self {
160            len: 0,
161            buf: [0; 64],
162        };
163        let mut cu = [0u8; 4];
164        let mut writer = Writer::from_slice(slf.buf.as_mut());
165        for c in NormalizedIter::new(val) {
166            let s = c.encode_utf8(&mut cu);
167            writer.buffer_write(s.as_bytes())?;
168        }
169        slf.len = writer.position();
170        Ok(slf)
171    }
172}
173
174impl AsRef<[u8]> for NormalizedAlg {
175    fn as_ref(&self) -> &[u8] {
176        &self.buf[..self.len]
177    }
178}
179
180impl<T: AsRef<[u8]>> PartialEq<T> for NormalizedAlg {
181    fn eq(&self, other: &T) -> bool {
182        self.as_ref() == other.as_ref()
183    }
184}
185
186struct NormalizedIter<'a> {
187    chars: core::str::Chars<'a>,
188}
189
190impl<'a> NormalizedIter<'a> {
191    pub fn new(val: &'a str) -> Self {
192        Self { chars: val.chars() }
193    }
194}
195
196impl Iterator for NormalizedIter<'_> {
197    type Item = char;
198    fn next(&mut self) -> Option<Self::Item> {
199        #[allow(clippy::while_let_on_iterator)]
200        while let Some(c) = self.chars.next() {
201            if c != '-' && c != '_' && c != ' ' {
202                return Some(c.to_ascii_lowercase());
203            }
204        }
205        None
206    }
207}
208
209impl Display for KeyAlg {
210    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
211        f.write_str(self.as_str())
212    }
213}
214
215/// Supported algorithms for AES
216#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Zeroize)]
217#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
218pub enum AesTypes {
219    /// 128-bit AES-GCM
220    A128Gcm,
221    /// 256-bit AES-GCM
222    A256Gcm,
223    /// 128-bit AES-CBC with HMAC-256
224    A128CbcHs256,
225    /// 256-bit AES-CBC with HMAC-512
226    A256CbcHs512,
227    /// 128-bit AES Key Wrap
228    A128Kw,
229    /// 256-bit AES Key Wrap
230    A256Kw,
231}
232
233/// Supported public key types for Bls12_381
234#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Zeroize)]
235#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
236pub enum BlsCurves {
237    /// G1 curve
238    G1,
239    /// G2 curve
240    G2,
241    /// G1 + G2 curves
242    G1G2,
243}
244
245/// Supported algorithms for (X)ChaCha20-Poly1305
246#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Zeroize)]
247#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
248pub enum Chacha20Types {
249    /// ChaCha20-Poly1305
250    C20P,
251    /// XChaCha20-Poly1305
252    XC20P,
253}
254
255/// Supported curves for ECC operations
256#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Zeroize)]
257#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
258pub enum EcCurves {
259    /// NIST P-256 curve
260    Secp256r1,
261    /// Koblitz 256 curve
262    Secp256k1,
263    /// NIST P-384 curve
264    Secp384r1,
265}
266
267/// A trait for accessing the algorithm of a key, used when
268/// converting to generic `AnyKey` instances.
269pub trait HasKeyAlg: Debug {
270    /// Get the corresponding key algorithm.
271    fn algorithm(&self) -> KeyAlg;
272}
273
274/// A trait for accessing the backend of a key, used when
275/// converting to generic `AnyKey` instances.
276pub trait HasKeyBackend: Debug {
277    /// Get the corresponding key backend.
278    fn key_backend(&self) -> KeyBackend {
279        KeyBackend::default()
280    }
281}
282
283#[cfg(test)]
284mod tests {
285    use super::*;
286
287    #[test]
288    fn cmp_normalize() {
289        assert!(normalize_alg("Test").unwrap() == "test");
290        assert!(normalize_alg("t-e-s-t").unwrap() == "test");
291        assert!(normalize_alg("--TE__ST--").unwrap() == "test");
292        assert!(normalize_alg("t-e-s-t").unwrap() != "tes");
293        assert!(normalize_alg("t-e-s-t").unwrap() != "testt");
294    }
295}