use std::borrow::Cow;
use std::str::FromStr;
use super::enc::{Encrypted, ToDecrypt};
pub use crate::crypto::{
alg::KeyAlg,
backend::KeyBackend,
buffer::{SecretBytes, WriteBuffer},
encrypt::KeyAeadParams,
};
use crate::{
crypto::{
alg::{bls::BlsKeyGen, AnyKey, AnyKeyCreate},
encrypt::KeyAeadInPlace,
jwk::{FromJwk, ToJwk},
kdf::{KeyDerivation, KeyExchange},
random::{fill_random, RandomDet},
repr::{ToPublicBytes, ToSecretBytes},
sign::{KeySigVerify, KeySign, SignatureType},
Error as CryptoError,
},
error::Error,
};
#[cfg(feature = "mobile_secure_element")]
use crate::crypto::alg::p256_hardware::P256HardwareKeyPair;
#[derive(Debug)]
pub struct LocalKey {
pub(crate) inner: Box<AnyKey>,
pub(crate) ephemeral: bool,
}
impl LocalKey {
pub fn generate_with_rng(alg: KeyAlg, ephemeral: bool) -> Result<Self, Error> {
let inner = Box::<AnyKey>::random(alg)?;
Ok(Self { inner, ephemeral })
}
pub fn generate_for_hardware(alg: KeyAlg, ephemeral: bool) -> Result<Self, Error> {
let inner = Box::<AnyKey>::generate_for_hardware(alg)?;
Ok(Self { inner, ephemeral })
}
pub fn from_id(alg: KeyAlg, id: &str) -> Result<Self, Error> {
let inner = Box::<AnyKey>::get_with_id(alg, id)?;
Ok(Self {
inner,
ephemeral: false,
})
}
pub fn from_seed(alg: KeyAlg, seed: &[u8], method: Option<&str>) -> Result<Self, Error> {
let inner = match method {
Some("bls_keygen") => Box::<AnyKey>::generate_with_rng(alg, BlsKeyGen::new(seed)?)?,
None | Some("") => Box::<AnyKey>::generate_with_rng(alg, RandomDet::new(seed))?,
_ => {
return Err(err_msg!(
Unsupported,
"Unknown seed method for key generation"
))
}
};
Ok(Self {
inner,
ephemeral: false,
})
}
pub fn from_jwk_slice(jwk: &[u8]) -> Result<Self, Error> {
let inner = Box::<AnyKey>::from_jwk_slice(jwk)?;
Ok(Self {
inner,
ephemeral: false,
})
}
pub fn from_jwk(jwk: &str) -> Result<Self, Error> {
let inner = Box::<AnyKey>::from_jwk(jwk)?;
Ok(Self {
inner,
ephemeral: false,
})
}
pub fn from_public_bytes(alg: KeyAlg, public: &[u8]) -> Result<Self, Error> {
let inner = Box::<AnyKey>::from_public_bytes(alg, public)?;
Ok(Self {
inner,
ephemeral: false,
})
}
pub fn to_public_bytes(&self) -> Result<SecretBytes, Error> {
Ok(self.inner.to_public_bytes()?)
}
pub fn from_secret_bytes(alg: KeyAlg, secret: &[u8]) -> Result<Self, Error> {
let inner = Box::<AnyKey>::from_secret_bytes(alg, secret)?;
Ok(Self {
inner,
ephemeral: false,
})
}
pub fn to_secret_bytes(&self) -> Result<SecretBytes, Error> {
Ok(self.inner.to_secret_bytes()?)
}
pub fn to_key_exchange(&self, alg: KeyAlg, pk: &LocalKey) -> Result<Self, Error> {
let inner = Box::<AnyKey>::from_key_exchange(alg, &*self.inner, &*pk.inner)?;
Ok(Self {
inner,
ephemeral: self.ephemeral || pk.ephemeral,
})
}
pub(crate) fn from_key_derivation(
alg: KeyAlg,
derive: impl KeyDerivation,
) -> Result<Self, Error> {
let inner = Box::<AnyKey>::from_key_derivation(alg, derive)?;
Ok(Self {
inner,
ephemeral: false,
})
}
pub(crate) fn encode(&self) -> Result<SecretBytes, Error> {
Ok(self.inner.to_jwk_secret(None)?)
}
pub fn algorithm(&self) -> KeyAlg {
self.inner.algorithm()
}
pub fn to_jwk_public(&self, alg: Option<KeyAlg>) -> Result<String, Error> {
Ok(self.inner.to_jwk_public(alg)?)
}
pub fn to_jwk_secret(&self) -> Result<SecretBytes, Error> {
Ok(self.inner.to_jwk_secret(None)?)
}
pub fn to_jwk_thumbprint(&self, alg: Option<KeyAlg>) -> Result<String, Error> {
Ok(self.inner.to_jwk_thumbprint(alg)?)
}
pub fn to_jwk_thumbprints(&self) -> Result<Vec<String>, Error> {
Ok(vec![self.inner.to_jwk_thumbprint(None)?])
}
pub fn convert_key(&self, alg: KeyAlg) -> Result<Self, Error> {
let inner = self.inner.convert_key(alg)?;
Ok(Self {
inner,
ephemeral: self.ephemeral,
})
}
pub fn aead_params(&self) -> Result<KeyAeadParams, Error> {
let params = self.inner.aead_params();
if params.tag_length == 0 {
return Err(err_msg!(
Unsupported,
"AEAD is not supported for this key type"
));
}
Ok(params)
}
pub fn aead_padding(&self, msg_len: usize) -> usize {
self.inner.aead_padding(msg_len)
}
pub fn aead_random_nonce(&self) -> Result<Vec<u8>, Error> {
let nonce_len = self.inner.aead_params().nonce_length;
if nonce_len == 0 {
return Ok(Vec::new());
}
let mut buf = vec![0; nonce_len];
fill_random(&mut buf);
Ok(buf)
}
pub fn aead_encrypt(
&self,
message: &[u8],
nonce: &[u8],
aad: &[u8],
) -> Result<Encrypted, Error> {
let params = self.inner.aead_params();
let mut nonce = Cow::Borrowed(nonce);
if nonce.is_empty() && params.nonce_length > 0 {
nonce = Cow::Owned(self.aead_random_nonce()?);
}
let pad_len = self.inner.aead_padding(message.len());
let mut buf =
SecretBytes::from_slice_reserve(message, pad_len + params.tag_length + nonce.len());
let tag_pos = self.inner.encrypt_in_place(&mut buf, nonce.as_ref(), aad)?;
let nonce_pos = buf.len();
if !nonce.is_empty() {
buf.extend_from_slice(nonce.as_ref());
}
Ok(Encrypted::new(buf, tag_pos, nonce_pos))
}
pub fn aead_decrypt<'d>(
&'d self,
ciphertext: impl Into<ToDecrypt<'d>>,
nonce: &[u8],
aad: &[u8],
) -> Result<SecretBytes, Error> {
let mut buf = ciphertext.into().into_secret();
self.inner.decrypt_in_place(&mut buf, nonce, aad)?;
Ok(buf)
}
pub fn sign_message(&self, message: &[u8], sig_type: Option<&str>) -> Result<Vec<u8>, Error> {
let mut sig = Vec::new();
self.inner.write_signature(
message,
sig_type.map(SignatureType::from_str).transpose()?,
&mut sig,
)?;
Ok(sig)
}
pub fn verify_signature(
&self,
message: &[u8],
signature: &[u8],
sig_type: Option<&str>,
) -> Result<bool, Error> {
Ok(self.inner.verify_signature(
message,
signature,
sig_type.map(SignatureType::from_str).transpose()?,
)?)
}
pub fn wrap_key(&self, key: &LocalKey, nonce: &[u8]) -> Result<Encrypted, Error> {
let params = self.inner.aead_params();
let mut buf = SecretBytes::with_capacity(
key.inner.secret_bytes_length()? + params.tag_length + params.nonce_length,
);
key.inner.write_secret_bytes(&mut buf)?;
let tag_pos = self.inner.encrypt_in_place(&mut buf, nonce, &[])?;
let nonce_pos = buf.len();
buf.extend_from_slice(nonce);
Ok(Encrypted::new(buf, tag_pos, nonce_pos))
}
pub fn unwrap_key<'d>(
&'d self,
alg: KeyAlg,
ciphertext: impl Into<ToDecrypt<'d>>,
nonce: &[u8],
) -> Result<LocalKey, Error> {
let mut buf = ciphertext.into().into_secret();
self.inner.decrypt_in_place(&mut buf, nonce, &[])?;
Self::from_secret_bytes(alg, buf.as_ref())
}
pub fn is_hardware_backed(&self) -> bool {
#[cfg(feature = "mobile_secure_element")]
return self.inner.downcast_ref::<P256HardwareKeyPair>().is_some();
#[cfg(not(feature = "mobile_secure_element"))]
false
}
}
impl KeyExchange for LocalKey {
fn write_key_exchange(
&self,
other: &LocalKey,
out: &mut dyn WriteBuffer,
) -> Result<(), CryptoError> {
self.inner.write_key_exchange(&other.inner, out)
}
}