use std::fmt::Display;
use base64::{Engine as _, engine::general_purpose};
use clap::ValueEnum;
use cosmian_kmip::kmip_2_1::kmip_types::{CryptographicAlgorithm, RecommendedCurve};
use strum::EnumString;
use crate::error::UtilsError;
#[derive(Debug, Clone, Copy, EnumString, ValueEnum)]
#[strum(serialize_all = "kebab-case")]
pub enum Curve {
#[cfg(not(feature = "fips"))]
NistP192,
NistP224,
NistP256,
NistP384,
NistP521,
#[cfg(not(feature = "fips"))]
X25519,
#[cfg(not(feature = "fips"))]
Ed25519,
#[cfg(not(feature = "fips"))]
X448,
#[cfg(not(feature = "fips"))]
Ed448,
}
impl From<Curve> for RecommendedCurve {
fn from(curve: Curve) -> Self {
match curve {
#[cfg(not(feature = "fips"))]
Curve::NistP192 => Self::P192,
Curve::NistP224 => Self::P224,
Curve::NistP256 => Self::P256,
Curve::NistP384 => Self::P384,
Curve::NistP521 => Self::P521,
#[cfg(not(feature = "fips"))]
Curve::X25519 => Self::CURVE25519,
#[cfg(not(feature = "fips"))]
Curve::Ed25519 => Self::CURVEED25519,
#[cfg(not(feature = "fips"))]
Curve::X448 => Self::CURVE448,
#[cfg(not(feature = "fips"))]
Curve::Ed448 => Self::CURVEED448,
}
}
}
#[derive(Debug, Clone, Copy, Default, EnumString, ValueEnum)]
pub enum SymmetricAlgorithm {
#[cfg(not(feature = "fips"))]
Chacha20,
#[default]
Aes,
Sha3,
Shake,
}
impl Display for SymmetricAlgorithm {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
#[cfg(not(feature = "fips"))]
Self::Chacha20 => write!(f, "chacha20"),
Self::Aes => write!(f, "aes"),
Self::Sha3 => write!(f, "sha3"),
Self::Shake => write!(f, "shake"),
}
}
}
pub fn prepare_sym_key_elements(
number_of_bits: Option<usize>,
wrap_key_b64: &Option<String>,
algorithm: SymmetricAlgorithm,
) -> Result<(usize, Option<Vec<u8>>, CryptographicAlgorithm), UtilsError> {
let mut key_bytes = None;
let number_of_bits = if let Some(key_b64) = &wrap_key_b64 {
let bytes = general_purpose::STANDARD.decode(key_b64)?;
let number_of_bits = bytes.len() * 8;
key_bytes = Some(bytes);
number_of_bits
} else {
number_of_bits.unwrap_or(256)
};
let algorithm = match algorithm {
SymmetricAlgorithm::Aes => CryptographicAlgorithm::AES,
#[cfg(not(feature = "fips"))]
SymmetricAlgorithm::Chacha20 => CryptographicAlgorithm::ChaCha20,
SymmetricAlgorithm::Sha3 => match number_of_bits {
224 => CryptographicAlgorithm::SHA3224,
256 => CryptographicAlgorithm::SHA3256,
384 => CryptographicAlgorithm::SHA3384,
512 => CryptographicAlgorithm::SHA3512,
_ => {
return Err(UtilsError::Default(format!(
"invalid number of bits for sha3 {number_of_bits}"
)))
}
},
SymmetricAlgorithm::Shake => match number_of_bits {
128 => CryptographicAlgorithm::SHAKE128,
256 => CryptographicAlgorithm::SHAKE256,
_ => {
return Err(UtilsError::Default(format!(
"invalid number of bits for shake {number_of_bits}"
)))
}
},
};
Ok((number_of_bits, key_bytes, algorithm))
}