use alloc::string::String;
#[cfg(all(not(feature = "std"), feature = "encryption"))]
use alloc::string::ToString;
use keetanetwork_utils::impl_variant_error_from;
use snafu::Snafu;
#[cfg(feature = "encryption")]
pub use aead::Error as AeadError;
#[derive(Debug, Snafu, Clone, PartialEq)]
#[snafu(visibility(pub))]
pub enum CryptoError {
#[snafu(display("Invalid key material"))]
InvalidKeyMaterial,
#[snafu(display("Key derivation failed"))]
KeyDerivationFailed,
#[snafu(display("Invalid public key format"))]
InvalidPublicKey,
#[snafu(display("Invalid private key format"))]
InvalidPrivateKey,
#[snafu(display("Signature verification failed"))]
SignatureVerificationFailed,
#[snafu(display("Signature error"))]
SignatureError,
#[snafu(display("Unsupported algorithm: {algorithm}"))]
UnsupportedAlgorithm { algorithm: String },
#[snafu(display("Internal cryptographic error: {message}"))]
InternalError { message: String },
#[snafu(display("Invalid length specified: {message}"))]
InvalidLength { message: String },
#[snafu(display("Invalid input provided"))]
InvalidInput,
#[snafu(display("Encryption failed"))]
EncryptionFailed,
#[snafu(display("Decryption failed"))]
DecryptionFailed,
#[snafu(display("Invalid operation for this key type"))]
InvalidOperation,
#[snafu(display("Invalid key size provided"))]
InvalidKeySize,
#[snafu(display("Invalid IV size provided"))]
InvalidIvSize,
#[snafu(display("Encryption not supported for this algorithm"))]
EncryptionNotSupported,
}
pub(crate) trait OrCryptoError<T> {
#[cfg(feature = "encryption")]
fn or_encryption_failed(self) -> Result<T, CryptoError>;
#[cfg(feature = "encryption")]
fn or_decryption_failed(self) -> Result<T, CryptoError>;
fn or_invalid_public_key(self) -> Result<T, CryptoError>;
}
impl<T, E> OrCryptoError<T> for Result<T, E> {
#[cfg(feature = "encryption")]
fn or_encryption_failed(self) -> Result<T, CryptoError> {
self.map_err(|_| CryptoError::EncryptionFailed)
}
#[cfg(feature = "encryption")]
fn or_decryption_failed(self) -> Result<T, CryptoError> {
self.map_err(|_| CryptoError::DecryptionFailed)
}
fn or_invalid_public_key(self) -> Result<T, CryptoError> {
self.map_err(|_| CryptoError::InvalidPublicKey)
}
}
impl_variant_error_from!(CryptoError, {
hkdf::InvalidLength => KeyDerivationFailed,
hkdf::InvalidPrkLength => KeyDerivationFailed,
core::array::TryFromSliceError => InvalidKeySize,
hex::FromHexError => InvalidInput,
});
#[cfg(feature = "encryption")]
impl From<rand_core::OsError> for CryptoError {
fn from(error: rand_core::OsError) -> Self {
CryptoError::InternalError { message: error.to_string() }
}
}
#[cfg(feature = "encryption")]
impl_variant_error_from!(CryptoError, {
cbc::cipher::InvalidLength => InvalidKeySize,
cbc::cipher::inout::PadError => DecryptionFailed,
cbc::cipher::inout::NotEqualError => DecryptionFailed,
cbc::cipher::block_padding::UnpadError => DecryptionFailed,
});
#[cfg(feature = "encryption")]
keetanetwork_utils::impl_error_from_with_fields!(CryptoError, {
AeadError => InternalError { message: |error: AeadError| error.to_string() }
});
#[cfg(feature = "signature")]
impl_variant_error_from!(CryptoError, {
crate::operations::SignatureError => SignatureError,
});
#[cfg(feature = "signature")]
impl From<CryptoError> for crate::operations::SignatureError {
fn from(_: CryptoError) -> Self {
crate::operations::SignatureError::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use keetanetwork_utils::{test_error_from_conversions, test_error_variants};
#[cfg(feature = "encryption")]
use crate::algorithms::aes_cbc::Aes256Cbc;
#[cfg(feature = "encryption")]
use crate::operations::encryption::SymmetricEncryption;
#[cfg(feature = "encryption")]
use aes::Aes256;
#[cfg(feature = "encryption")]
use cbc::cipher::KeyIvInit;
#[cfg(feature = "encryption")]
use cbc::Encryptor;
test_error_variants! {
test_all_error_variants, [
CryptoError::InvalidKeyMaterial,
CryptoError::KeyDerivationFailed,
CryptoError::InvalidPublicKey,
CryptoError::InvalidPrivateKey,
CryptoError::SignatureVerificationFailed,
CryptoError::SignatureError,
CryptoError::UnsupportedAlgorithm { algorithm: "test".to_string() },
CryptoError::InternalError { message: "test".to_string() },
CryptoError::InvalidLength { message: "test".to_string() },
CryptoError::InvalidInput,
CryptoError::EncryptionFailed,
CryptoError::DecryptionFailed,
CryptoError::InvalidOperation,
CryptoError::InvalidKeySize,
CryptoError::InvalidIvSize,
CryptoError::EncryptionNotSupported,
]
}
test_error_from_conversions! {
test_hkdf_error_conversions, CryptoError, [
hkdf::InvalidLength,
hkdf::InvalidPrkLength,
]
}
test_error_from_conversions! {
test_try_from_slice_error_conversion, CryptoError, [
<[u8; 32]>::try_from([1u8, 2, 3].as_slice()).unwrap_err(),
]
}
#[cfg(feature = "encryption")]
test_error_from_conversions! {
test_cbc_error_conversions, CryptoError, [
cbc::cipher::inout::PadError,
cbc::cipher::inout::NotEqualError,
cbc::cipher::block_padding::UnpadError,
]
}
#[cfg(feature = "encryption")]
test_error_from_conversions! {
test_aead_error_conversions, CryptoError, [
AeadError,
]
}
#[cfg(feature = "signature")]
test_error_from_conversions! {
test_signature_error_conversions, CryptoError, [
crate::operations::SignatureError::new(),
]
}
#[cfg(feature = "signature")]
test_error_from_conversions! {
test_crypto_error_to_signature_error, crate::operations::SignatureError, [
CryptoError::SignatureError,
]
}
#[cfg(feature = "encryption")]
#[test]
fn test_cbc_cipher_invalid_length_conversion() {
let wrong_key = [0u8; 16]; let iv = [0u8; 16];
let result = Encryptor::<Aes256>::new_from_slices(&wrong_key, &iv);
assert!(result.is_err());
let cbc_error = result.unwrap_err();
let crypto_error: CryptoError = cbc_error.into();
assert_eq!(crypto_error, CryptoError::InvalidKeySize);
}
#[cfg(feature = "encryption")]
#[test]
fn test_padding_errors_conversion() {
let cipher = Aes256Cbc;
let key = [0u8; 32]; let invalid_ciphertext = [0u8; 15];
let result = cipher.decrypt(key, invalid_ciphertext);
assert!(result.is_err());
assert_eq!(result.unwrap_err(), CryptoError::DecryptionFailed);
}
}