use std::fmt;
use crate::error::DataError;
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum CryptoAlgorithm {
#[default]
Aes256Gcm,
XChaCha20Poly1305,
}
impl CryptoAlgorithm {
#[must_use]
pub fn as_str(self) -> &'static str {
match self {
Self::Aes256Gcm => "AES-256-GCM",
Self::XChaCha20Poly1305 => "XChaCha20-Poly1305",
}
}
pub fn from_envelope_str(s: &str) -> Result<Self, DataError> {
match s {
"AES-256-GCM" => Ok(Self::Aes256Gcm),
"XChaCha20-Poly1305" => Ok(Self::XChaCha20Poly1305),
other => Err(DataError::UnsupportedAlgorithm {
algorithm: other.to_string(),
}),
}
}
#[must_use]
pub fn nonce_len(self) -> usize {
match self {
Self::Aes256Gcm => 12,
Self::XChaCha20Poly1305 => 24,
}
}
fn rank(self) -> u8 {
match self {
Self::Aes256Gcm => 1,
Self::XChaCha20Poly1305 => 2,
}
}
}
impl fmt::Display for CryptoAlgorithm {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Debug, Clone, Default)]
pub struct AlgorithmPolicy {
preferred: CryptoAlgorithm,
min_algorithm: Option<CryptoAlgorithm>,
}
impl AlgorithmPolicy {
#[must_use]
pub fn new(preferred: CryptoAlgorithm, min_algorithm: Option<CryptoAlgorithm>) -> Self {
Self {
preferred,
min_algorithm,
}
}
#[must_use]
pub fn prefer(algorithm: CryptoAlgorithm) -> Self {
Self {
preferred: algorithm,
min_algorithm: None,
}
}
#[must_use]
pub fn preferred(&self) -> CryptoAlgorithm {
self.preferred
}
pub fn validate(&self) -> Result<(), DataError> {
if let Some(min) = self.min_algorithm {
if self.preferred.rank() < min.rank() {
return Err(DataError::AlgorithmBelowPolicyMinimum {
requested: self.preferred.as_str().to_string(),
minimum: min.as_str().to_string(),
});
}
}
Ok(())
}
}