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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
// src/encryption/encrypt.rs
//! High-level [`encrypt`] entry point: streams plaintext to an AES Crypt v3 file.
use cratePasswordString;
use crate;
use crateAESCRYPT_LATEST_VERSION;
use crate;
use cratederive_setup_key;
use crateencrypt_session_block;
use crateencrypt_stream;
use crate;
use crateAescryptError;
use KeyInit;
use Aes256Enc;
use Mac;
use RevealSecret;
use ;
/// Encrypts the bytes read from `input` into a complete AES Crypt v3 file
/// written to `output`.
///
/// `encrypt` consumes `input` until EOF and writes a self-contained `.aes`
/// file: header, extensions terminator, iteration count, public IV, encrypted
/// session block, session HMAC, ciphertext stream, and payload HMAC. The
/// session key, session IV, and public IV are freshly generated from the
/// [`secure-gate`] CSPRNG on every call; the same `(password, plaintext,
/// iterations)` tuple therefore produces a different ciphertext every time.
///
/// # Format
///
/// Always v3. To produce v0/v1/v2 files, use the official `aescrypt` reference
/// tooling — this crate intentionally does not support legacy formats on
/// write (see the [crate-level Security Model](crate#security-model)).
///
/// # Errors
///
/// - [`AescryptError::Header`] — `password` is empty, or `kdf_iterations` is
/// outside [`PBKDF2_MIN_ITER`](crate::constants::PBKDF2_MIN_ITER) `..=`
/// [`PBKDF2_MAX_ITER`](crate::constants::PBKDF2_MAX_ITER).
/// - [`AescryptError::Crypto`] — PBKDF2 setup-key derivation failed (forwarded
/// from [`crate::derive_pbkdf2_key`]).
/// - [`AescryptError::Io`] — `input.read` or `output.write_all` returned an
/// error at any stage of header serialization or payload streaming.
///
/// # Panics
///
/// Never panics on valid input; the internal `expect` on `setup_key` is a
/// 32-byte invariant that is structurally guaranteed by
/// [`Aes256Key32`](crate::aliases::Aes256Key32).
///
/// # Security
///
/// - All secrets ([`PasswordString`], session key, session IV, setup key) live
/// in [`secure-gate`] wrappers and zeroize on drop. Plaintext blocks
/// transit the stack inside [`Block16`](crate::aliases::Block16) for the
/// same reason.
/// - The public IV doubles as the PBKDF2 salt; it is generated with
/// `Iv16::from_random` per call and is therefore unique with overwhelming
/// probability.
/// - HMAC-SHA256 is computed over the encrypted session block (with the v3
/// version byte appended) and over the ciphertext stream. Decryption verifies
/// both with constant-time equality.
/// - PKCS#7 padding is always applied to the final plaintext block.
/// - `kdf_iterations` controls password-cracking cost. Use
/// [`DEFAULT_PBKDF2_ITERATIONS`](crate::constants::DEFAULT_PBKDF2_ITERATIONS)
/// unless you have measured your platform.
///
/// # Compatibility
///
/// - Output is byte-compatible with the official AES Crypt reference
/// implementation for v3 files.
/// - Files produced by this function are accepted by [`crate::decrypt()`] and
/// by `aescrypt`'s C/.NET/Java tooling.
///
/// # Thread Safety
///
/// `encrypt` is `Send` whenever its `R`/`W` are. There is no shared mutable
/// state, so multiple threads may call `encrypt` concurrently on independent
/// inputs/outputs. Cancellation is the caller's responsibility — spawn in a
/// thread and abandon the join handle, or wire up an interruptible reader/writer.
///
/// # Examples
///
/// ```no_run
/// use aescrypt_rs::{encrypt, PasswordString, constants::DEFAULT_PBKDF2_ITERATIONS};
/// use std::io::Cursor;
///
/// let password = PasswordString::new("correct horse battery staple".to_string());
/// let plaintext = b"top secret";
///
/// let mut ciphertext = Vec::new();
/// encrypt(Cursor::new(plaintext), &mut ciphertext, &password, DEFAULT_PBKDF2_ITERATIONS)?;
/// # Ok::<(), aescrypt_rs::AescryptError>(())
/// ```
///
/// Threaded usage:
///
/// ```no_run
/// use aescrypt_rs::{encrypt, PasswordString};
/// use std::io::Cursor;
/// use std::thread;
///
/// let password = PasswordString::new("secret".to_string());
/// let data = b"large file data...";
///
/// let handle = thread::spawn(move || {
/// let mut encrypted = Vec::new();
/// encrypt(Cursor::new(data), &mut encrypted, &password, 300_000)
/// });
///
/// let _result = handle.join().unwrap();
/// ```
///
/// # See also
///
/// - [`crate::decrypt()`] — inverse operation.
/// - [`crate::Pbkdf2Builder`] — convenient way to derive a PBKDF2 key for
/// custom flows.
///
/// [`secure-gate`]: https://github.com/Slurp9187/secure-gate