use thiserror::Error;
pub type CrabResult<T> = Result<T, CrabError>;
#[derive(Error, Debug)]
pub enum CrabError {
#[error("Invalid input: {0}")]
InvalidInput(String),
#[error("Cryptographic operation failed: {0}")]
CryptoError(String),
#[error("Key operation failed: {0}")]
KeyError(String),
#[error("Authentication failed: invalid tag or corrupted data")]
AuthenticationFailed,
#[error("Signature verification failed")]
SignatureVerificationFailed,
#[error("Invalid nonce/IV: {0}")]
InvalidNonce(String),
#[error("Invalid ciphertext format: {0}")]
InvalidCiphertext(String),
#[error("Encoding error: {0}")]
EncodingError(String),
#[error("Random number generation failed: {0}")]
RandomError(String),
#[error("Serialization error: {0}")]
SerializationError(String),
#[error("Feature not enabled: {0}")]
FeatureNotEnabled(String),
#[error("Internal error: {0}")]
Internal(String),
}
impl CrabError {
pub fn invalid_input(msg: impl Into<String>) -> Self {
Self::InvalidInput(msg.into())
}
pub fn crypto_error(msg: impl Into<String>) -> Self {
Self::CryptoError(msg.into())
}
pub fn key_error(msg: impl Into<String>) -> Self {
Self::KeyError(msg.into())
}
pub fn encoding_error(msg: impl Into<String>) -> Self {
Self::EncodingError(msg.into())
}
pub fn random_error(msg: impl Into<String>) -> Self {
Self::RandomError(msg.into())
}
}
impl From<aes_gcm::Error> for CrabError {
fn from(_e: aes_gcm::Error) -> Self {
CrabError::AuthenticationFailed
}
}
impl From<argon2::Error> for CrabError {
fn from(e: argon2::Error) -> Self {
CrabError::KeyError(format!("Argon2 error: {}", e))
}
}
impl From<pbkdf2::password_hash::Error> for CrabError {
fn from(e: pbkdf2::password_hash::Error) -> Self {
CrabError::KeyError(format!("PBKDF2 error: {}", e))
}
}
impl From<ed25519_dalek::SignatureError> for CrabError {
fn from(_: ed25519_dalek::SignatureError) -> Self {
CrabError::SignatureVerificationFailed
}
}
impl From<getrandom::Error> for CrabError {
fn from(e: getrandom::Error) -> Self {
CrabError::RandomError(format!("getrandom error: {}", e))
}
}
impl From<base64::DecodeError> for CrabError {
fn from(e: base64::DecodeError) -> Self {
CrabError::EncodingError(format!("Base64 decode error: {}", e))
}
}
impl From<hex::FromHexError> for CrabError {
fn from(e: hex::FromHexError) -> Self {
CrabError::EncodingError(format!("Hex decode error: {}", e))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_display() {
let err = CrabError::invalid_input("Key too short");
assert_eq!(err.to_string(), "Invalid input: Key too short");
let auth_err = CrabError::AuthenticationFailed;
assert_eq!(auth_err.to_string(), "Authentication failed: invalid tag or corrupted data");
}
#[test]
fn test_error_construction() {
let err = CrabError::crypto_error("test error");
assert!(matches!(err, CrabError::CryptoError(_)));
}
}