1use std::borrow::Cow;
2use std::str::FromStr;
3
4use super::enc::{Encrypted, ToDecrypt};
5pub use crate::crypto::{
6 alg::KeyAlg,
7 backend::KeyBackend,
8 buffer::{SecretBytes, WriteBuffer},
9 encrypt::KeyAeadParams,
10};
11use crate::{
12 crypto::{
13 alg::{bls::BlsKeyGen, AnyKey, AnyKeyCreate},
14 encrypt::KeyAeadInPlace,
15 jwk::{FromJwk, ToJwk},
16 kdf::{KeyDerivation, KeyExchange},
17 random::{fill_random, RandomDet},
18 repr::{ToPublicBytes, ToSecretBytes},
19 sign::{KeySigVerify, KeySign, SignatureType},
20 Error as CryptoError,
21 },
22 error::Error,
23};
24
25#[cfg(feature = "mobile_secure_element")]
26use crate::crypto::alg::p256_hardware::P256HardwareKeyPair;
27
28#[derive(Debug)]
30pub struct LocalKey {
31 pub(crate) inner: Box<AnyKey>,
32 pub(crate) ephemeral: bool,
33}
34
35impl LocalKey {
36 pub fn generate_with_rng(alg: KeyAlg, ephemeral: bool) -> Result<Self, Error> {
38 let inner = Box::<AnyKey>::random(alg)?;
39 Ok(Self { inner, ephemeral })
40 }
41
42 pub fn generate_for_hardware(alg: KeyAlg, ephemeral: bool) -> Result<Self, Error> {
44 let inner = Box::<AnyKey>::generate_for_hardware(alg)?;
45 Ok(Self { inner, ephemeral })
46 }
47
48 pub fn from_id(alg: KeyAlg, id: &str) -> Result<Self, Error> {
50 let inner = Box::<AnyKey>::get_with_id(alg, id)?;
51 Ok(Self {
52 inner,
53 ephemeral: false,
54 })
55 }
56
57 pub fn from_seed(alg: KeyAlg, seed: &[u8], method: Option<&str>) -> Result<Self, Error> {
59 let inner = match method {
60 Some("bls_keygen") => Box::<AnyKey>::generate_with_rng(alg, BlsKeyGen::new(seed)?)?,
61 None | Some("") => Box::<AnyKey>::generate_with_rng(alg, RandomDet::new(seed))?,
62 _ => {
63 return Err(err_msg!(
64 Unsupported,
65 "Unknown seed method for key generation"
66 ))
67 }
68 };
69 Ok(Self {
70 inner,
71 ephemeral: false,
72 })
73 }
74
75 pub fn from_jwk_slice(jwk: &[u8]) -> Result<Self, Error> {
77 let inner = Box::<AnyKey>::from_jwk_slice(jwk)?;
78 Ok(Self {
79 inner,
80 ephemeral: false,
81 })
82 }
83
84 pub fn from_jwk(jwk: &str) -> Result<Self, Error> {
86 let inner = Box::<AnyKey>::from_jwk(jwk)?;
87 Ok(Self {
88 inner,
89 ephemeral: false,
90 })
91 }
92
93 pub fn from_public_bytes(alg: KeyAlg, public: &[u8]) -> Result<Self, Error> {
95 let inner = Box::<AnyKey>::from_public_bytes(alg, public)?;
96 Ok(Self {
97 inner,
98 ephemeral: false,
99 })
100 }
101
102 pub fn to_public_bytes(&self) -> Result<SecretBytes, Error> {
104 Ok(self.inner.to_public_bytes()?)
105 }
106
107 pub fn from_secret_bytes(alg: KeyAlg, secret: &[u8]) -> Result<Self, Error> {
109 let inner = Box::<AnyKey>::from_secret_bytes(alg, secret)?;
110 Ok(Self {
111 inner,
112 ephemeral: false,
113 })
114 }
115
116 pub fn to_secret_bytes(&self) -> Result<SecretBytes, Error> {
118 Ok(self.inner.to_secret_bytes()?)
119 }
120
121 pub fn to_key_exchange(&self, alg: KeyAlg, pk: &LocalKey) -> Result<Self, Error> {
123 let inner = Box::<AnyKey>::from_key_exchange(alg, &*self.inner, &*pk.inner)?;
124 Ok(Self {
125 inner,
126 ephemeral: self.ephemeral || pk.ephemeral,
127 })
128 }
129
130 pub(crate) fn from_key_derivation(
131 alg: KeyAlg,
132 derive: impl KeyDerivation,
133 ) -> Result<Self, Error> {
134 let inner = Box::<AnyKey>::from_key_derivation(alg, derive)?;
135 Ok(Self {
136 inner,
137 ephemeral: false,
138 })
139 }
140
141 pub(crate) fn encode(&self) -> Result<SecretBytes, Error> {
142 Ok(self.inner.to_jwk_secret(None)?)
143 }
144
145 pub fn algorithm(&self) -> KeyAlg {
147 self.inner.algorithm()
148 }
149
150 pub fn to_jwk_public(&self, alg: Option<KeyAlg>) -> Result<String, Error> {
152 Ok(self.inner.to_jwk_public(alg)?)
153 }
154
155 pub fn to_jwk_secret(&self) -> Result<SecretBytes, Error> {
157 Ok(self.inner.to_jwk_secret(None)?)
158 }
159
160 pub fn to_jwk_thumbprint(&self, alg: Option<KeyAlg>) -> Result<String, Error> {
162 Ok(self.inner.to_jwk_thumbprint(alg)?)
163 }
164
165 pub fn to_jwk_thumbprints(&self) -> Result<Vec<String>, Error> {
167 Ok(vec![self.inner.to_jwk_thumbprint(None)?])
168 }
169
170 pub fn convert_key(&self, alg: KeyAlg) -> Result<Self, Error> {
172 let inner = self.inner.convert_key(alg)?;
173 Ok(Self {
174 inner,
175 ephemeral: self.ephemeral,
176 })
177 }
178
179 pub fn aead_params(&self) -> Result<KeyAeadParams, Error> {
181 let params = self.inner.aead_params();
182 if params.tag_length == 0 {
183 return Err(err_msg!(
184 Unsupported,
185 "AEAD is not supported for this key type"
186 ));
187 }
188 Ok(params)
189 }
190
191 pub fn aead_padding(&self, msg_len: usize) -> usize {
193 self.inner.aead_padding(msg_len)
194 }
195
196 pub fn aead_random_nonce(&self) -> Result<Vec<u8>, Error> {
198 let nonce_len = self.inner.aead_params().nonce_length;
199 if nonce_len == 0 {
200 return Ok(Vec::new());
201 }
202 let mut buf = vec![0; nonce_len];
203 fill_random(&mut buf);
204 Ok(buf)
205 }
206
207 pub fn aead_encrypt(
209 &self,
210 message: &[u8],
211 nonce: &[u8],
212 aad: &[u8],
213 ) -> Result<Encrypted, Error> {
214 let params = self.inner.aead_params();
215 let mut nonce = Cow::Borrowed(nonce);
216 if nonce.is_empty() && params.nonce_length > 0 {
217 nonce = Cow::Owned(self.aead_random_nonce()?);
218 }
219 let pad_len = self.inner.aead_padding(message.len());
220 let mut buf =
221 SecretBytes::from_slice_reserve(message, pad_len + params.tag_length + nonce.len());
222 let tag_pos = self.inner.encrypt_in_place(&mut buf, nonce.as_ref(), aad)?;
223 let nonce_pos = buf.len();
224 if !nonce.is_empty() {
225 buf.extend_from_slice(nonce.as_ref());
226 }
227 Ok(Encrypted::new(buf, tag_pos, nonce_pos))
228 }
229
230 pub fn aead_decrypt<'d>(
232 &'d self,
233 ciphertext: impl Into<ToDecrypt<'d>>,
234 nonce: &[u8],
235 aad: &[u8],
236 ) -> Result<SecretBytes, Error> {
237 let mut buf = ciphertext.into().into_secret();
238 self.inner.decrypt_in_place(&mut buf, nonce, aad)?;
239 Ok(buf)
240 }
241
242 pub fn sign_message(&self, message: &[u8], sig_type: Option<&str>) -> Result<Vec<u8>, Error> {
244 let mut sig = Vec::new();
245 self.inner.write_signature(
246 message,
247 sig_type.map(SignatureType::from_str).transpose()?,
248 &mut sig,
249 )?;
250 Ok(sig)
251 }
252
253 pub fn verify_signature(
255 &self,
256 message: &[u8],
257 signature: &[u8],
258 sig_type: Option<&str>,
259 ) -> Result<bool, Error> {
260 Ok(self.inner.verify_signature(
261 message,
262 signature,
263 sig_type.map(SignatureType::from_str).transpose()?,
264 )?)
265 }
266
267 pub fn wrap_key(&self, key: &LocalKey, nonce: &[u8]) -> Result<Encrypted, Error> {
269 let params = self.inner.aead_params();
270 let mut buf = SecretBytes::with_capacity(
271 key.inner.secret_bytes_length()? + params.tag_length + params.nonce_length,
272 );
273 key.inner.write_secret_bytes(&mut buf)?;
274 let tag_pos = self.inner.encrypt_in_place(&mut buf, nonce, &[])?;
275 let nonce_pos = buf.len();
276 buf.extend_from_slice(nonce);
277 Ok(Encrypted::new(buf, tag_pos, nonce_pos))
278 }
279
280 pub fn unwrap_key<'d>(
282 &'d self,
283 alg: KeyAlg,
284 ciphertext: impl Into<ToDecrypt<'d>>,
285 nonce: &[u8],
286 ) -> Result<LocalKey, Error> {
287 let mut buf = ciphertext.into().into_secret();
288 self.inner.decrypt_in_place(&mut buf, nonce, &[])?;
289 Self::from_secret_bytes(alg, buf.as_ref())
290 }
291
292 pub fn is_hardware_backed(&self) -> bool {
295 #[cfg(feature = "mobile_secure_element")]
296 return self.inner.downcast_ref::<P256HardwareKeyPair>().is_some();
297
298 #[cfg(not(feature = "mobile_secure_element"))]
299 false
300 }
301}
302
303impl KeyExchange for LocalKey {
304 fn write_key_exchange(
305 &self,
306 other: &LocalKey,
307 out: &mut dyn WriteBuffer,
308 ) -> Result<(), CryptoError> {
309 self.inner.write_key_exchange(&other.inner, out)
310 }
311}