use std::{
error::Error,
fmt::{self, Display, Formatter},
io,
sync::Arc,
};
pub use zeroize::Zeroize;
#[derive(Debug)]
pub enum CryptError {
IOError(Arc<io::Error>),
WriteError,
FileNotFound,
PathError,
UniqueFilenameFailed,
MessageExtractionError,
InvalidMessageFormat,
Utf8Error,
HexError(hex::FromHexError),
HexDecodingError(String),
EncapsulationError,
DecapsulationError,
InvalidKemPublicKey,
InvalidKemSecretKey,
InvalidKemCiphertext,
HmacVerificationError,
HmacShortData,
HmacKeyErr,
MissingSecretKey,
MissingPublicKey,
MissingCiphertext,
MissingSharedSecret,
MissingData,
InvalidParameters,
InvalidKeyType,
InvalidDataLength,
EncryptionFailed,
DecryptionFailed,
InvalidNonce,
AuthenticationFailed,
InvalidEnvelope,
UnsupportedEnvelopeVersion,
UnsupportedAlgorithm,
UnsupportedOperation,
SigningFailed,
SignatureVerificationFailed,
InvalidSignatureLength,
InvalidSignature,
Signing(Arc<SigningErr>),
CustomError(String),
}
impl fmt::Display for CryptError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
CryptError::IOError(e) => write!(f, "I/O error: {}", e),
CryptError::WriteError => write!(f, "write operation failed"),
CryptError::FileNotFound => write!(f, "file not found"),
CryptError::PathError => write!(f, "provided path does not exist"),
CryptError::UniqueFilenameFailed => write!(f, "failed to generate a unique filename"),
CryptError::MessageExtractionError => write!(f, "failed to extract message from data"),
CryptError::InvalidMessageFormat => write!(f, "invalid message format"),
CryptError::Utf8Error => write!(f, "UTF-8 conversion error"),
CryptError::HexError(e) => write!(f, "hex error: {}", e),
CryptError::HexDecodingError(msg) => write!(f, "hex decoding error: {}", msg),
CryptError::EncapsulationError => write!(f, "KEM encapsulation failed"),
CryptError::DecapsulationError => write!(f, "KEM decapsulation failed"),
CryptError::InvalidKemPublicKey => {
write!(f, "KEM public key is malformed or has wrong length")
}
CryptError::InvalidKemSecretKey => {
write!(f, "KEM secret key is malformed or has wrong length")
}
CryptError::InvalidKemCiphertext => {
write!(f, "KEM ciphertext is malformed or has wrong length")
}
CryptError::HmacVerificationError => write!(f, "HMAC verification failed"),
CryptError::HmacShortData => write!(f, "data is too short to contain a valid HMAC tag"),
CryptError::HmacKeyErr => write!(f, "HMAC key initialisation failed"),
CryptError::MissingSecretKey => write!(f, "required secret key not provided"),
CryptError::MissingPublicKey => write!(f, "required public key not provided"),
CryptError::MissingCiphertext => write!(f, "required ciphertext not provided"),
CryptError::MissingSharedSecret => write!(f, "required shared secret not provided"),
CryptError::MissingData => write!(f, "required data not provided"),
CryptError::InvalidParameters => write!(f, "invalid parameters provided"),
CryptError::InvalidKeyType => write!(f, "invalid or unsupported key type"),
CryptError::InvalidDataLength => write!(f, "data length is invalid for this operation"),
CryptError::EncryptionFailed => write!(f, "encryption failed"),
CryptError::DecryptionFailed => write!(f, "decryption failed"),
CryptError::InvalidNonce => write!(f, "nonce is invalid or missing"),
CryptError::AuthenticationFailed => write!(f, "authentication tag verification failed"),
CryptError::InvalidEnvelope => write!(f, "envelope is malformed or cannot be parsed"),
CryptError::UnsupportedEnvelopeVersion => write!(f, "unsupported envelope version"),
CryptError::UnsupportedAlgorithm => write!(f, "algorithm is not supported"),
CryptError::UnsupportedOperation => write!(f, "operation is not supported"),
CryptError::SigningFailed => write!(f, "digital signing operation failed"),
CryptError::SignatureVerificationFailed => write!(f, "signature verification failed"),
CryptError::InvalidSignatureLength => write!(f, "signature has invalid length"),
CryptError::InvalidSignature => write!(f, "signature is structurally invalid"),
CryptError::Signing(e) => write!(f, "signing error: {}", e),
CryptError::CustomError(msg) => write!(f, "{}", msg),
}
}
}
impl Clone for CryptError {
fn clone(&self) -> Self {
match self {
CryptError::IOError(e) => CryptError::IOError(Arc::clone(e)),
CryptError::WriteError => CryptError::WriteError,
CryptError::FileNotFound => CryptError::FileNotFound,
CryptError::PathError => CryptError::PathError,
CryptError::UniqueFilenameFailed => CryptError::UniqueFilenameFailed,
CryptError::MessageExtractionError => CryptError::MessageExtractionError,
CryptError::InvalidMessageFormat => CryptError::InvalidMessageFormat,
CryptError::Utf8Error => CryptError::Utf8Error,
CryptError::HexError(e) => CryptError::HexError(*e),
CryptError::HexDecodingError(s) => CryptError::HexDecodingError(s.clone()),
CryptError::EncapsulationError => CryptError::EncapsulationError,
CryptError::DecapsulationError => CryptError::DecapsulationError,
CryptError::InvalidKemPublicKey => CryptError::InvalidKemPublicKey,
CryptError::InvalidKemSecretKey => CryptError::InvalidKemSecretKey,
CryptError::InvalidKemCiphertext => CryptError::InvalidKemCiphertext,
CryptError::HmacVerificationError => CryptError::HmacVerificationError,
CryptError::HmacShortData => CryptError::HmacShortData,
CryptError::HmacKeyErr => CryptError::HmacKeyErr,
CryptError::MissingSecretKey => CryptError::MissingSecretKey,
CryptError::MissingPublicKey => CryptError::MissingPublicKey,
CryptError::MissingCiphertext => CryptError::MissingCiphertext,
CryptError::MissingSharedSecret => CryptError::MissingSharedSecret,
CryptError::MissingData => CryptError::MissingData,
CryptError::InvalidParameters => CryptError::InvalidParameters,
CryptError::InvalidKeyType => CryptError::InvalidKeyType,
CryptError::InvalidDataLength => CryptError::InvalidDataLength,
CryptError::EncryptionFailed => CryptError::EncryptionFailed,
CryptError::DecryptionFailed => CryptError::DecryptionFailed,
CryptError::InvalidNonce => CryptError::InvalidNonce,
CryptError::AuthenticationFailed => CryptError::AuthenticationFailed,
CryptError::InvalidEnvelope => CryptError::InvalidEnvelope,
CryptError::UnsupportedEnvelopeVersion => CryptError::UnsupportedEnvelopeVersion,
CryptError::UnsupportedAlgorithm => CryptError::UnsupportedAlgorithm,
CryptError::UnsupportedOperation => CryptError::UnsupportedOperation,
CryptError::SigningFailed => CryptError::SigningFailed,
CryptError::SignatureVerificationFailed => CryptError::SignatureVerificationFailed,
CryptError::InvalidSignatureLength => CryptError::InvalidSignatureLength,
CryptError::InvalidSignature => CryptError::InvalidSignature,
CryptError::Signing(e) => CryptError::Signing(Arc::clone(e)),
CryptError::CustomError(s) => CryptError::CustomError(s.clone()),
}
}
}
impl CryptError {
pub fn new(msg: &str) -> Self {
CryptError::CustomError(msg.to_owned())
}
}
impl Error for CryptError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
CryptError::IOError(e) => Some(e.as_ref()),
CryptError::HexError(e) => Some(e),
CryptError::Signing(e) => Some(e.as_ref()),
_ => None,
}
}
}
impl From<io::Error> for CryptError {
fn from(error: io::Error) -> Self {
CryptError::IOError(Arc::new(error))
}
}
impl From<hex::FromHexError> for CryptError {
fn from(error: hex::FromHexError) -> Self {
CryptError::HexError(error)
}
}
impl From<SigningErr> for CryptError {
fn from(err: SigningErr) -> Self {
CryptError::Signing(Arc::new(err))
}
}
#[derive(Debug)]
pub enum SigningErr {
SecretKeyMissing,
PublicKeyMissing,
SignatureVerificationFailed,
SigningMessageFailed,
SignatureMissing,
FileCreationFailed,
FileWriteFailed,
UnsupportedFileType(String),
CustomError(String),
IOError(Arc<io::Error>),
}
impl SigningErr {
pub fn new(msg: &str) -> Self {
SigningErr::CustomError(msg.to_owned())
}
}
impl Display for SigningErr {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
SigningErr::SecretKeyMissing => write!(f, "secret key is missing"),
SigningErr::PublicKeyMissing => write!(f, "public key is missing"),
SigningErr::SignatureVerificationFailed => write!(f, "signature verification failed"),
SigningErr::SigningMessageFailed => write!(f, "failed to sign message"),
SigningErr::SignatureMissing => write!(f, "signature is missing"),
SigningErr::FileCreationFailed => write!(f, "failed to create output file"),
SigningErr::FileWriteFailed => write!(f, "failed to write to file"),
SigningErr::UnsupportedFileType(ext) => {
write!(f, "unsupported file extension: .{}", ext)
}
SigningErr::CustomError(message) => write!(f, "{}", message),
SigningErr::IOError(err) => write!(f, "I/O error: {}", err),
}
}
}
impl Clone for SigningErr {
fn clone(&self) -> Self {
match self {
SigningErr::SecretKeyMissing => SigningErr::SecretKeyMissing,
SigningErr::PublicKeyMissing => SigningErr::PublicKeyMissing,
SigningErr::SignatureVerificationFailed => SigningErr::SignatureVerificationFailed,
SigningErr::SigningMessageFailed => SigningErr::SigningMessageFailed,
SigningErr::SignatureMissing => SigningErr::SignatureMissing,
SigningErr::FileCreationFailed => SigningErr::FileCreationFailed,
SigningErr::FileWriteFailed => SigningErr::FileWriteFailed,
SigningErr::UnsupportedFileType(s) => SigningErr::UnsupportedFileType(s.clone()),
SigningErr::CustomError(s) => SigningErr::CustomError(s.clone()),
SigningErr::IOError(e) => SigningErr::IOError(Arc::clone(e)),
}
}
}
impl PartialEq for SigningErr {
fn eq(&self, other: &Self) -> bool {
use SigningErr::*;
matches!(
(self, other),
(SecretKeyMissing, SecretKeyMissing)
| (PublicKeyMissing, PublicKeyMissing)
| (SignatureVerificationFailed, SignatureVerificationFailed)
| (SigningMessageFailed, SigningMessageFailed)
| (SignatureMissing, SignatureMissing)
| (FileCreationFailed, FileCreationFailed)
| (FileWriteFailed, FileWriteFailed)
)
}
}
impl Error for SigningErr {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
SigningErr::IOError(e) => Some(e.as_ref()),
_ => None,
}
}
}
impl From<io::Error> for SigningErr {
fn from(err: io::Error) -> Self {
SigningErr::IOError(Arc::new(err))
}
}
#[cfg(feature = "legacy-pqclean")]
impl From<pqcrypto_traits::Error> for SigningErr {
fn from(_: pqcrypto_traits::Error) -> Self {
SigningErr::SignatureVerificationFailed
}
}