1use 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#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Zeroize)]
65#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
66pub enum KeyAlg {
67 Aes(AesTypes),
69 Bls12_381(BlsCurves),
71 Chacha20(Chacha20Types),
73 Ed25519,
75 X25519,
77 EcCurve(EcCurves),
79}
80
81impl KeyAlg {
82 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
148pub(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#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Zeroize)]
217#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
218pub enum AesTypes {
219 A128Gcm,
221 A256Gcm,
223 A128CbcHs256,
225 A256CbcHs512,
227 A128Kw,
229 A256Kw,
231}
232
233#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Zeroize)]
235#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
236pub enum BlsCurves {
237 G1,
239 G2,
241 G1G2,
243}
244
245#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Zeroize)]
247#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
248pub enum Chacha20Types {
249 C20P,
251 XC20P,
253}
254
255#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Zeroize)]
257#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
258pub enum EcCurves {
259 Secp256r1,
261 Secp256k1,
263 Secp384r1,
265}
266
267pub trait HasKeyAlg: Debug {
270 fn algorithm(&self) -> KeyAlg;
272}
273
274pub trait HasKeyBackend: Debug {
277 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}