use async_trait::async_trait;
use cosmian_kmip::{
kmip_0::kmip_types::{BlockCipherMode, HashingAlgorithm, PaddingMethod},
kmip_2_1::kmip_types::{
CryptographicAlgorithm, CryptographicParameters, DigitalSignatureAlgorithm,
},
};
use zeroize::Zeroizing;
use crate::{InterfaceError, KeyType, error::InterfaceResult};
#[derive(Debug)]
pub struct KeyMetadata {
pub key_type: KeyType,
pub key_length_in_bits: usize,
pub sensitive: bool,
pub id: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CryptoAlgorithm {
AesCbc,
AesGcm,
RsaPkcsV15,
RsaOaepSha256,
RsaOaepSha1,
}
impl CryptoAlgorithm {
pub fn from_kmip(value: &CryptographicParameters) -> Result<Option<Self>, InterfaceError> {
value
.cryptographic_algorithm
.map_or(Ok(None), |algorithm| match algorithm {
cosmian_kmip::kmip_2_1::kmip_types::CryptographicAlgorithm::AES => value
.block_cipher_mode
.map_or(
Ok(Some(Self::AesGcm)),
|block_cipher_mode| match block_cipher_mode {
BlockCipherMode::CBC => Ok(Some(Self::AesCbc)),
BlockCipherMode::GCM => Ok(Some(Self::AesGcm)),
bcm => Err(InterfaceError::Default(format!(
"Block cipher mode: {bcm:?} not supported for AES",
))),
},
),
cosmian_kmip::kmip_2_1::kmip_types::CryptographicAlgorithm::RSA => value
.padding_method
.map_or(Ok(Some(Self::RsaOaepSha256)), |padding_method| {
match padding_method {
PaddingMethod::OAEP => match value.hashing_algorithm {
Some(HashingAlgorithm::SHA1) => Ok(Some(Self::RsaOaepSha1)),
_ => Ok(Some(Self::RsaOaepSha256)), },
PaddingMethod::PKCS1v15 => Ok(Some(Self::RsaPkcsV15)),
pm => Err(InterfaceError::Default(format!(
"Padding method: {pm:?} not supported for RSA",
))),
}
}),
x => Err(InterfaceError::Default(format!(
"Cryptographic algorithm: {x:?} not supported",
))),
})
}
pub fn get_aes_algorithm(supported_algorithms: &[Self]) -> InterfaceResult<Self> {
if supported_algorithms.contains(&Self::AesGcm) {
return Ok(Self::AesGcm);
} else if supported_algorithms.contains(&Self::AesCbc) {
return Ok(Self::AesCbc);
}
Err(InterfaceError::InvalidRequest(
"AES not supported".to_owned(),
))
}
pub fn get_rsa_algorithm(supported_algorithms: &[Self]) -> InterfaceResult<Self> {
if supported_algorithms.contains(&Self::RsaOaepSha256) {
return Ok(Self::RsaOaepSha256);
} else if supported_algorithms.contains(&Self::RsaOaepSha1) {
return Ok(Self::RsaOaepSha1);
} else if supported_algorithms.contains(&Self::RsaPkcsV15) {
return Ok(Self::RsaPkcsV15);
}
Err(InterfaceError::InvalidRequest(
"RSA not supported".to_owned(),
))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SigningAlgorithm {
RsaPkcsV15,
Sha1WithRsa,
Sha256WithRsa,
Sha384WithRsa,
Sha512WithRsa,
}
impl SigningAlgorithm {
pub fn from_kmip(params: Option<&CryptographicParameters>) -> Result<Self, InterfaceError> {
let Some(params) = params else {
return Ok(Self::Sha256WithRsa);
};
if let Some(dsa) = ¶ms.digital_signature_algorithm {
return match dsa {
DigitalSignatureAlgorithm::SHA1WithRSAEncryption => Ok(Self::Sha1WithRsa),
DigitalSignatureAlgorithm::SHA224WithRSAEncryption
| DigitalSignatureAlgorithm::SHA256WithRSAEncryption => Ok(Self::Sha256WithRsa),
DigitalSignatureAlgorithm::SHA384WithRSAEncryption => Ok(Self::Sha384WithRsa),
DigitalSignatureAlgorithm::SHA512WithRSAEncryption => Ok(Self::Sha512WithRsa),
other => Err(InterfaceError::InvalidRequest(format!(
"Unsupported digital signature algorithm for HSM signing: {other:?}"
))),
};
}
if params.cryptographic_algorithm == Some(CryptographicAlgorithm::RSA) {
return match params.hashing_algorithm {
Some(HashingAlgorithm::SHA1) => Ok(Self::Sha1WithRsa),
Some(HashingAlgorithm::SHA256) | None => Ok(Self::Sha256WithRsa),
Some(HashingAlgorithm::SHA384) => Ok(Self::Sha384WithRsa),
Some(HashingAlgorithm::SHA512) => Ok(Self::Sha512WithRsa),
Some(other) => Err(InterfaceError::InvalidRequest(format!(
"Unsupported hashing algorithm for RSA signing: {other:?}"
))),
};
}
Ok(Self::Sha256WithRsa)
}
}
#[derive(Debug, Default)]
pub struct EncryptedContent {
pub ciphertext: Vec<u8>,
pub iv: Option<Vec<u8>>,
pub tag: Option<Vec<u8>>,
}
#[async_trait]
pub trait CryptoOracle: Send + Sync {
async fn encrypt(
&self,
uid: &str,
data: &[u8],
cryptographic_algorithm: Option<CryptoAlgorithm>,
authenticated_encryption_additional_data: Option<&[u8]>,
) -> InterfaceResult<EncryptedContent>;
async fn decrypt(
&self,
uid: &str,
data: &[u8],
cryptographic_algorithm: Option<CryptoAlgorithm>,
authenticated_encryption_additional_data: Option<&[u8]>,
) -> InterfaceResult<Zeroizing<Vec<u8>>>;
async fn get_key_type(&self, uid: &str) -> InterfaceResult<Option<KeyType>>;
async fn get_key_metadata(&self, uid: &str) -> InterfaceResult<Option<KeyMetadata>>;
async fn sign(
&self,
uid: &str,
data: &[u8],
cryptographic_parameters: Option<&CryptographicParameters>,
) -> InterfaceResult<Vec<u8>>;
}