Skip to main content

aescrypt_rs/
error.rs

1//! Error types for AES Crypt operations.
2//!
3//! Every fallible function in this crate returns
4//! [`Result<T, AescryptError>`](AescryptError). [`AescryptError`] discriminates between
5//! I/O failures, cryptographic failures, header / extension parsing failures, and
6//! unsupported file format versions.
7//!
8//! # Variant → API table
9//!
10//! | Variant                                | Typical producer                                                                                                                                                                                                                                                                                |
11//! | -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
12//! | [`AescryptError::Io`]                  | [`encrypt`], [`decrypt`], [`read_version`], every reader/writer helper in [`crate::encryption`] / [`crate::decryption`]                                                                                                                                                                        |
13//! | [`AescryptError::Crypto`]              | [`derive_ackdf_key`], [`derive_pbkdf2_key`], [`Pbkdf2Builder::derive_secure`], [`utf8_to_utf16le`]                                                                                                                                                                                              |
14//! | [`AescryptError::Header`]              | [`encrypt`], [`decrypt`], [`read_version`], [`derive_setup_key`], [`write_header`] / [`write_extensions`] / [`write_iterations`], [`read_file_version`], [`read_kdf_iterations`], [`consume_all_extensions`], [`extract_session_data`], [`decrypt_ciphertext_stream`] |
15//! | [`AescryptError::UnsupportedVersion`]  | [`write_header`], [`write_extensions`], [`write_iterations`], [`read_file_version`]                                                                                                                                                                                                            |
16//!
17//! [`encrypt`]: crate::encrypt()
18//! [`decrypt`]: crate::decrypt()
19//! [`read_version`]: crate::read_version
20//! [`derive_ackdf_key`]: crate::derive_ackdf_key
21//! [`derive_pbkdf2_key`]: crate::derive_pbkdf2_key
22//! [`Pbkdf2Builder::derive_secure`]: crate::Pbkdf2Builder::derive_secure
23//! [`utf8_to_utf16le`]: crate::utilities::utf8_to_utf16le
24//! [`derive_setup_key`]: crate::encryption::derive_setup_key
25//! [`write_header`]: crate::encryption::write_header
26//! [`write_extensions`]: crate::encryption::write_extensions
27//! [`write_iterations`]: crate::encryption::write_iterations
28//! [`read_file_version`]: crate::decryption::read_file_version
29//! [`read_kdf_iterations`]: crate::decryption::read_kdf_iterations
30//! [`consume_all_extensions`]: crate::decryption::consume_all_extensions
31//! [`extract_session_data`]: crate::decryption::extract_session_data
32//! [`decrypt_ciphertext_stream`]: crate::decryption::decrypt_ciphertext_stream
33
34use thiserror::Error;
35
36/// The error type returned by every fallible AES Crypt operation in this crate.
37///
38/// `AescryptError` is non-exhaustive in spirit: it discriminates four classes of
39/// failure (I/O, cryptographic, header/format, unsupported version) but the
40/// human-readable message inside [`Crypto`](Self::Crypto) and
41/// [`Header`](Self::Header) is part of the error display, not the structured API,
42/// and may be refined in patch releases.
43///
44/// # Errors
45///
46/// All four variants are constructed by code inside this crate; downstream callers
47/// generally pattern-match on the variant and surface a friendly message based on
48/// the [`Display`](std::fmt::Display) impl provided by [`thiserror`].
49///
50/// See the [variant → API table](self) at the module level for which public APIs
51/// produce each variant.
52///
53/// # Security
54///
55/// Error messages are written for human diagnostics. They never embed the
56/// password, derived keys, IVs, salts, or plaintext. Untrusted callers may safely
57/// log the [`Display`](std::fmt::Display) form. Wrap-and-`?` is the recommended
58/// pattern; do not attempt to recover from [`Header`](Self::Header) by retrying
59/// with different inputs.
60#[derive(Error, Debug)]
61pub enum AescryptError {
62    /// An I/O operation on the underlying reader or writer failed.
63    ///
64    /// This variant wraps [`std::io::Error`] verbatim and is produced by every
65    /// public function that performs streaming reads or writes — including
66    /// [`crate::encrypt()`], [`crate::decrypt()`], [`crate::read_version`], and
67    /// the lower-level helpers in [`crate::encryption`] / [`crate::decryption`].
68    /// Common causes: file not found, permission denied, broken pipe, premature
69    /// EOF inside the header / session block / payload.
70    #[error("I/O error: {0}")]
71    Io(#[from] std::io::Error),
72
73    /// A cryptographic primitive returned an error.
74    ///
75    /// Produced by:
76    ///
77    /// - [`crate::derive_pbkdf2_key`] / [`crate::Pbkdf2Builder::derive_secure`]
78    ///   when the underlying `pbkdf2` crate rejects its parameters.
79    /// - [`crate::derive_ackdf_key`] when the password is not valid UTF-8
80    ///   (forwarded from [`crate::utilities::utf8_to_utf16le`]).
81    /// - [`crate::utilities::utf8_to_utf16le`] for non-UTF-8 password bytes.
82    ///
83    /// The wrapped `String` is a short human-readable description and is part of
84    /// the [`Display`](std::fmt::Display) output only — it is not a stable
85    /// machine-readable code.
86    #[error("Crypto error: {0}")]
87    Crypto(String),
88
89    /// A header, extension, or trailer in the AES Crypt file failed validation.
90    ///
91    /// Triggered by, for example:
92    ///
93    /// - Invalid magic bytes (header is not `b"AES"`).
94    /// - Reserved byte after the version is not `0x00` for v1–v3.
95    /// - More than 256 extension blocks in a v2/v3 header (DoS guard).
96    /// - PBKDF2 iteration count outside
97    ///   [`PBKDF2_MIN_ITER`](crate::constants::PBKDF2_MIN_ITER)
98    ///   `..=` [`PBKDF2_MAX_ITER`](crate::constants::PBKDF2_MAX_ITER).
99    /// - Empty password supplied to [`crate::encrypt()`].
100    /// - Session-block HMAC mismatch ("session data corrupted or tampered").
101    /// - Payload HMAC mismatch ("HMAC verification failed").
102    /// - v3 PKCS#7 padding malformed ("v3: invalid PKCS#7 padding").
103    /// - v0/v1/v2/v3 trailer length wrong ("expected … trailer").
104    ///
105    /// **Security note**: an HMAC failure is reported as `Header(...)` for
106    /// historical reasons; treat it as authenticated-decryption failure and
107    /// discard any plaintext already written to the output.
108    #[error("Header error: {0}")]
109    Header(String),
110
111    /// The file declares an AES Crypt format version this crate cannot handle.
112    ///
113    /// Returned by [`crate::decryption::read_file_version`] when the version
114    /// byte is `> 3`, and by the encryption-side [`crate::encryption::write_header`]
115    /// / [`write_extensions`](crate::encryption::write_extensions) /
116    /// [`write_iterations`](crate::encryption::write_iterations) when callers
117    /// request a version `< 3` (this crate writes v3 only). The contained `u8`
118    /// is the rejected version number.
119    #[error("Unsupported version: {0}")]
120    UnsupportedVersion(u8),
121}
122
123impl From<&'static str> for AescryptError {
124    fn from(msg: &'static str) -> Self {
125        AescryptError::Crypto(msg.to_string())
126    }
127}