1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// uncomment to run doctests
// cargo test --doc lib
//#![doc = include_str!("../README.md")]
//! 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
// High-level API — this is what 99% of users import.
pub use PasswordString;
pub use decrypt;
pub use encrypt;
pub use 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 Pbkdf2Builder;
pub use derive_ackdf_key;
pub use derive_pbkdf2_key;
// Header-only inspection.
pub use read_version;