aescrypt-rs 0.2.0-rc.9

AES Crypt (v0-v3) Rust encryption/decryption library
Documentation
// uncomment to run doctests
// cargo test --doc lib
//#![doc = include_str!("../README.md")]

#![forbid(unsafe_code)]

//! Fast, safe, streaming AES Crypt (v0–v3) encryption and decryption.
//!
//! `aescrypt-rs` reads every published AES Crypt file format version (v0–v3) and writes
//! the modern v3 format only. The public surface is intentionally small — most users
//! only need [`encrypt()`], [`decrypt()`], and [`read_version()`] — but the lower-level
//! KDF, header, session, and streaming primitives are exposed for custom flows.
//!
//! # Quick Start
//!
//! Encrypt and decrypt data using AES Crypt format v3:
//!
//! ```rust,no_run
//! use aescrypt_rs::{encrypt, decrypt, PasswordString, constants::DEFAULT_PBKDF2_ITERATIONS};
//! use std::io::Cursor;
//!
//! let password = PasswordString::new("correct horse battery staple".to_string());
//! let data = b"top secret";
//!
//! // Encrypt
//! let mut ciphertext = Vec::new();
//! encrypt(Cursor::new(data), &mut ciphertext, &password, DEFAULT_PBKDF2_ITERATIONS)?;
//!
//! // Decrypt
//! let mut plaintext = Vec::new();
//! decrypt(Cursor::new(&ciphertext), &mut plaintext, &password)?;
//!
//! assert_eq!(data, &plaintext[..]);
//! # Ok::<(), aescrypt_rs::AescryptError>(())
//! ```
//!
//! Detect file format version without decrypting:
//!
//! ```rust
//! use aescrypt_rs::read_version;
//! use std::io::Cursor;
//!
//! let header = b"AES\x03\x00";
//! let version = read_version(Cursor::new(header))?;
//! assert_eq!(version, 3);
//! # Ok::<(), aescrypt_rs::AescryptError>(())
//! ```
//!
//! # Supported Formats
//!
//! | Operation        | v0  | v1  | v2  | v3  |
//! | ---------------- | :-: | :-: | :-: | :-: |
//! | [`decrypt()`]    |  Y  |  Y  |  Y  |  Y  |
//! | [`encrypt()`]    |  –  |  –  |  –  |  Y  |
//! | [`read_version()`] |  Y  |  Y  |  Y  |  Y  |
//!
//! v3 is the only format produced on write. v0–v2 are read-only for compatibility with
//! files generated by older AES Crypt tools.
//!
//! # Feature Flags
//!
//! This crate defines **no Cargo features**. The following dependency feature flags
//! are always enabled and cannot be disabled by downstream crates:
//!
//! - `aes/zeroize` — automatic zeroization of AES round keys on drop.
//! - `secure-gate/rand` — CSPRNG-backed random IV/key/salt generation.
//! - `secure-gate/ct-eq` — constant-time HMAC and PKCS#7 padding comparisons.
//!
//! Building with `--no-default-features` is a no-op; the security posture is fixed.
//!
//! # MSRV
//!
//! Minimum Supported Rust Version is **1.70** (edition 2021). CI verifies the crate
//! against `cargo +1.70 test --all-features`. See `CHANGELOG.md` for the dependency
//! pin matrix that keeps the resolver honest on 1.70.
//!
//! # Security Model
//!
//! - **No `unsafe` in this crate** — enforced by `#![forbid(unsafe_code)]`. Cryptographic
//!   backends and `secure-gate` may use `unsafe` internally; this crate does not.
//! - **Key derivation**: PBKDF2-HMAC-SHA512 for v3 (caller-controlled iterations,
//!   default [`DEFAULT_PBKDF2_ITERATIONS`](constants::DEFAULT_PBKDF2_ITERATIONS) = 300 000),
//!   and the AES Crypt v0–v2 ACKDF (8192 SHA-256 iterations, UTF-16-LE password) for legacy reads.
//! - **Bulk encryption**: AES-256-CBC with PKCS#7 padding (v3) or legacy modulo padding
//!   (v0/v1/v2 read-only).
//! - **Authentication**: HMAC-SHA256 over the encrypted session block and ciphertext
//!   stream. Session and payload tags are compared with constant-time equality.
//! - **Memory hygiene**: keys, IVs, salts, passwords, and intermediate buffers are
//!   wrapped in [`secure-gate`] types ([`PasswordString`], [`Aes256Key32`](aliases::Aes256Key32),
//!   [`Iv16`](aliases::Iv16), [`Salt16`](aliases::Salt16), …) that zeroize on drop.
//! - **Decrypt-then-verify**: as defined by the AES Crypt format, the v3 payload HMAC
//!   is verified **after** the ciphertext stream is decrypted. [`decrypt()`] therefore
//!   may write partial unauthenticated plaintext to its `output` before returning an
//!   error — see [`decrypt()`] for the mandatory caller contract.
//! - **PBKDF2 iteration bounds**: enforced by the encryption path to
//!   `[`PBKDF2_MIN_ITER`](constants::PBKDF2_MIN_ITER) ..= [`PBKDF2_MAX_ITER`](constants::PBKDF2_MAX_ITER)`.
//!   Lowering iterations weakens password resistance; do not go below
//!   [`DEFAULT_PBKDF2_ITERATIONS`](constants::DEFAULT_PBKDF2_ITERATIONS).
//!
//! # Errors
//!
//! Every fallible operation in this crate returns
//! [`Result<T, AescryptError>`](AescryptError). The error variants are documented on
//! [`AescryptError`] together with the public APIs that produce each variant.
//!
//! [`secure-gate`]: https://github.com/Slurp9187/secure-gate

pub mod aliases;
pub mod constants;
pub mod decryption;
pub mod encryption;
pub mod error;
pub mod header;
pub mod kdf;
pub mod pbkdf2_builder;
pub mod utilities;

// High-level API — this is what 99% of users import.
pub use aliases::PasswordString;
pub use decryption::decrypt;
pub use encryption::encrypt;
pub use error::AescryptError;

// Low-level KDFs — intentionally public at the root because:
// • They are needed for custom decryption flows (e.g. reading v0–v2 files without the high-level API).
// • They are the only non-wrapper crypto functions users ever need directly.
// • Keeping them at the root is the established pattern in the ecosystem (see `ring`, `password-hash`, etc.).
pub use pbkdf2_builder::Pbkdf2Builder;

pub use kdf::ackdf::derive_ackdf_key;
pub use kdf::pbkdf2::derive_pbkdf2_key;

// Header-only inspection.
pub use header::read_version;