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::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
146pub(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#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Zeroize)]
215#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
216pub enum AesTypes {
217 A128Gcm,
219 A256Gcm,
221 A128CbcHs256,
223 A256CbcHs512,
225 A128Kw,
227 A256Kw,
229}
230
231#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Zeroize)]
233#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
234pub enum BlsCurves {
235 G1,
237 G2,
239}
240
241#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Zeroize)]
243#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
244pub enum Chacha20Types {
245 C20P,
247 XC20P,
249}
250
251#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Zeroize)]
253#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
254pub enum EcCurves {
255 Secp256r1,
257 Secp256k1,
259 Secp384r1,
261}
262
263pub trait HasKeyAlg: Debug {
266 fn algorithm(&self) -> KeyAlg;
268}
269
270pub trait HasKeyBackend: Debug {
273 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}