use core::fmt;
use std::io;
#[derive(Debug)]
#[non_exhaustive]
pub enum Error {
InvalidKeyLength(usize),
InvalidIvLength(usize),
InvalidCiphertextLength(usize),
InvalidPadding,
AuthenticationFailed,
InvalidIterations(u32),
EmptyPassword,
InvalidPassword,
AlteredMessage,
NotAesCrypt,
UnsupportedVersion(u8),
InvalidStream(StreamError),
InvalidExtension(ExtensionError),
LimitExceeded(Limit),
InvalidPath,
BackendUnavailable,
Random(io::Error),
Io(io::Error),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::InvalidKeyLength(n) => write!(f, "invalid key length: {} octets", n),
Error::InvalidIvLength(n) => write!(f, "invalid IV length: {} octets (expected 16)", n),
Error::InvalidCiphertextLength(n) => {
write!(f, "invalid data length: {} octets is not a multiple of 16", n)
}
Error::InvalidPadding => f.write_str("invalid padding"),
Error::AuthenticationFailed => f.write_str("authentication failed"),
Error::InvalidIterations(n) => write!(f, "invalid iteration count: {}", n),
Error::EmptyPassword => f.write_str("the password is empty"),
Error::InvalidPassword => f.write_str("the password is incorrect or the stream was altered"),
Error::AlteredMessage => f.write_str("the encrypted message was altered or truncated"),
Error::NotAesCrypt => f.write_str("not an AES Crypt stream"),
Error::UnsupportedVersion(v) => write!(f, "unsupported AES Crypt stream version {}", v),
Error::InvalidStream(why) => write!(f, "invalid AES Crypt stream: {}", why),
Error::InvalidExtension(why) => write!(f, "invalid extension: {}", why),
Error::LimitExceeded(limit) => write!(f, "limit exceeded: {}", limit),
Error::InvalidPath => f.write_str("the path has no file name"),
Error::BackendUnavailable => f.write_str("the AES backend is not supported by this CPU"),
Error::Random(e) => write!(f, "random number generator failed: {}", e),
Error::Io(e) => write!(f, "I/O error: {}", e),
}
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Error::Io(e) | Error::Random(e) => Some(e),
_ => None,
}
}
}
impl From<io::Error> for Error {
fn from(e: io::Error) -> Self {
Error::Io(e)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum StreamError {
TruncatedHeader,
TruncatedExtensions,
TruncatedKeyBlock,
Truncated,
UnalignedCiphertext,
MissingFinalBlock,
InvalidPadding,
ZeroIterations,
}
impl fmt::Display for StreamError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match self {
StreamError::TruncatedHeader => "truncated header",
StreamError::TruncatedExtensions => "truncated extensions",
StreamError::TruncatedKeyBlock => "truncated key block",
StreamError::Truncated => "truncated stream",
StreamError::UnalignedCiphertext => "ciphertext length is not a multiple of 16",
StreamError::MissingFinalBlock => "missing final block",
StreamError::InvalidPadding => "invalid padding",
StreamError::ZeroIterations => "zero PBKDF2 iterations",
})
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum ExtensionError {
EmptyIdentifier,
NulInIdentifier,
InvalidLength,
UnsupportedVersion,
}
impl fmt::Display for ExtensionError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match self {
ExtensionError::EmptyIdentifier => "the identifier is empty",
ExtensionError::NulInIdentifier => "the identifier contains a NUL octet",
ExtensionError::InvalidLength => "extension length must be 1 to 65535 octets",
ExtensionError::UnsupportedVersion => "versions 0 and 1 do not support extensions",
})
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum Limit {
Iterations {
found: u32,
max: u32,
},
HeaderLength {
max: usize,
},
Extensions {
max: usize,
},
}
impl fmt::Display for Limit {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Limit::Iterations { found, max } => write!(f, "{} PBKDF2 iterations (at most {} allowed)", found, max),
Limit::HeaderLength { max } => write!(f, "header longer than {} octets", max),
Limit::Extensions { max } => write!(f, "more than {} header extensions", max),
}
}
}