use core::fmt;
use zeroize::Zeroize;
use crate::backends::ProviderRng;
use crate::{Error, Provider, Result};
pub struct Key {
bytes: [u8; Self::LEN],
provider: Option<Provider>,
}
impl Key {
pub const LEN: usize = 32;
pub fn generate() -> Result<Self> {
let provider = Provider::build_default().ok_or(Error::ProviderSelectionRequired)?;
Self::generate_with_provider(provider)
}
pub fn generate_with_provider(provider: Provider) -> Result<Self> {
let mut rng = ProviderRng::new(provider);
let mut key = [0u8; Self::LEN];
rng.fill(&mut key)?;
Ok(Self {
bytes: key,
provider: Some(provider),
})
}
#[must_use]
pub const fn from_bytes(bytes: [u8; Self::LEN]) -> Self {
Self {
bytes,
provider: None,
}
}
#[must_use]
pub const fn from_bytes_with_provider(bytes: [u8; Self::LEN], provider: Provider) -> Self {
Self {
bytes,
provider: Some(provider),
}
}
#[must_use]
pub const fn as_bytes(&self) -> &[u8; Self::LEN] {
&self.bytes
}
pub const fn provider(&self) -> Result<Provider> {
match self.provider {
Some(provider) => Ok(provider),
None => match Provider::build_default() {
Some(provider) => Ok(provider),
None => Err(Error::ProviderSelectionRequired),
},
}
}
}
impl Clone for Key {
fn clone(&self) -> Self {
Self {
bytes: self.bytes,
provider: self.provider,
}
}
}
impl Drop for Key {
fn drop(&mut self) {
self.bytes.zeroize();
}
}
impl fmt::Debug for Key {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Key").field(&"[REDACTED]").finish()
}
}
impl From<[u8; Key::LEN]> for Key {
fn from(bytes: [u8; Key::LEN]) -> Self {
Self::from_bytes(bytes)
}
}
impl TryFrom<&[u8]> for Key {
type Error = Error;
fn try_from(bytes: &[u8]) -> Result<Self> {
let actual = bytes.len();
let bytes = bytes
.try_into()
.map_err(|_| Error::InvalidKeyLength { actual })?;
Ok(Self::from_bytes(bytes))
}
}