1use aes::cipher::KeyInit;
5use aes::Aes256;
6use serpent::Serpent;
7use twofish::Twofish;
8use xts_mode::Xts128;
9
10use crate::error::{Result, VeraError};
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum Prf {
15 Sha512,
17 Sha256,
19 Whirlpool,
21 Streebog,
23 Ripemd160,
25}
26
27impl Prf {
28 #[must_use]
30 pub fn all() -> [Prf; 5] {
31 [
32 Prf::Sha512,
33 Prf::Sha256,
34 Prf::Whirlpool,
35 Prf::Streebog,
36 Prf::Ripemd160,
37 ]
38 }
39
40 #[must_use]
42 pub fn name(self) -> &'static str {
43 match self {
44 Prf::Sha512 => "sha512",
45 Prf::Sha256 => "sha256",
46 Prf::Whirlpool => "whirlpool",
47 Prf::Streebog => "streebog",
48 Prf::Ripemd160 => "ripemd160",
49 }
50 }
51
52 #[must_use]
54 pub fn iterations(self) -> u32 {
55 match self {
56 Prf::Ripemd160 => 655_331,
57 _ => 500_000,
58 }
59 }
60
61 #[must_use]
65 pub fn iterations_pim(self, pim: u32) -> u32 {
66 if pim == 0 {
67 return self.iterations();
68 }
69 match self {
70 Prf::Ripemd160 => pim.saturating_mul(2048),
71 _ => 15_000u32.saturating_add(pim.saturating_mul(1000)),
72 }
73 }
74
75 pub fn derive(self, password: &[u8], salt: &[u8], iterations: u32, out_len: usize) -> Vec<u8> {
77 let mut out = vec![0u8; out_len];
78 let it = iterations.max(1);
79 match self {
80 Prf::Sha512 => pbkdf2::pbkdf2_hmac::<sha2::Sha512>(password, salt, it, &mut out),
81 Prf::Sha256 => pbkdf2::pbkdf2_hmac::<sha2::Sha256>(password, salt, it, &mut out),
82 Prf::Whirlpool => {
83 pbkdf2::pbkdf2_hmac::<whirlpool::Whirlpool>(password, salt, it, &mut out);
84 }
85 Prf::Streebog => {
86 pbkdf2::pbkdf2_hmac::<streebog::Streebog512>(password, salt, it, &mut out);
87 }
88 Prf::Ripemd160 => {
89 pbkdf2::pbkdf2_hmac::<ripemd::Ripemd160>(password, salt, it, &mut out);
90 }
91 }
92 out
93 }
94}
95
96#[derive(Debug, Clone, Copy, PartialEq, Eq)]
99pub enum Cipher {
100 Aes,
102 Serpent,
104 Twofish,
106}
107
108impl Cipher {
109 #[must_use]
111 pub fn all() -> [Cipher; 3] {
112 [Cipher::Aes, Cipher::Serpent, Cipher::Twofish]
113 }
114
115 #[must_use]
117 pub fn name(self) -> &'static str {
118 match self {
119 Cipher::Aes => "aes",
120 Cipher::Serpent => "serpent",
121 Cipher::Twofish => "twofish",
122 }
123 }
124
125 #[must_use]
127 pub fn key_len(self) -> usize {
128 64
129 }
130}
131
132#[must_use]
135pub fn cipher_chains() -> Vec<Vec<Cipher>> {
136 use Cipher::{Aes, Serpent, Twofish};
137 vec![
138 vec![Aes],
139 vec![Serpent],
140 vec![Twofish],
141 vec![Twofish, Aes], vec![Serpent, Twofish, Aes], vec![Aes, Serpent], vec![Aes, Twofish, Serpent], vec![Serpent, Twofish], ]
147}
148
149pub const MAX_CHAIN_KEY_LEN: usize = 3 * 64;
151
152pub fn xts_decrypt_chain(
161 ciphers: &[Cipher],
162 key: &[u8],
163 buffer: &mut [u8],
164 unit_size: usize,
165 base_unit: u128,
166) -> Result<()> {
167 let n = ciphers.len();
168 if n == 0 || key.len() < 64 * n {
169 return Err(VeraError::Crypto {
170 what: "cascade key too short",
171 });
172 }
173 let mut subkey = [0u8; 64];
174 for j in (0..n).rev() {
175 subkey[..32].copy_from_slice(&key[32 * j..32 * j + 32]);
176 subkey[32..].copy_from_slice(&key[32 * (n + j)..32 * (n + j) + 32]);
177 xts_decrypt(ciphers[j], &subkey, buffer, unit_size, base_unit)?;
178 }
179 Ok(())
180}
181
182pub fn xts_decrypt(
188 cipher: Cipher,
189 key: &[u8],
190 buffer: &mut [u8],
191 unit_size: usize,
192 base_unit: u128,
193) -> Result<()> {
194 if key.len() != 64 {
195 return Err(VeraError::Crypto {
196 what: "xts key must be 64 bytes",
197 });
198 }
199 let (k1, k2) = key.split_at(32);
200 match cipher {
201 Cipher::Aes => decrypt_units(
202 &Xts128::new(Aes256::new(k1.into()), Aes256::new(k2.into())),
203 buffer,
204 unit_size,
205 base_unit,
206 ),
207 Cipher::Serpent => {
208 let c1 = Serpent::new_from_slice(k1).map_err(|_| VeraError::Crypto {
213 what: "serpent 256-bit key",
214 })?; let c2 = Serpent::new_from_slice(k2).map_err(|_| VeraError::Crypto {
216 what: "serpent 256-bit key",
217 })?; decrypt_units(&Xts128::new(c1, c2), buffer, unit_size, base_unit);
219 }
220 Cipher::Twofish => decrypt_units(
221 &Xts128::new(Twofish::new(k1.into()), Twofish::new(k2.into())),
222 buffer,
223 unit_size,
224 base_unit,
225 ),
226 }
227 Ok(())
228}
229
230fn decrypt_units<C>(xts: &Xts128<C>, buffer: &mut [u8], unit_size: usize, base: u128)
231where
232 C: aes::cipher::BlockCipher + aes::cipher::BlockEncrypt + aes::cipher::BlockDecrypt,
233{
234 for (u, chunk) in buffer.chunks_mut(unit_size).enumerate() {
235 if chunk.len() < 16 {
236 continue; }
238 let tweak = (base + u as u128).to_le_bytes();
239 xts.decrypt_sector(chunk, tweak);
240 }
241}
242
243#[cfg(test)]
244mod tests {
245 use super::*;
246
247 #[test]
248 fn prf_iterations_and_names() {
249 assert_eq!(Prf::Sha512.iterations(), 500_000);
250 assert_eq!(Prf::Ripemd160.iterations(), 655_331);
251 assert_eq!(Prf::Sha512.iterations_pim(0), 500_000);
252 assert_eq!(Prf::Sha512.iterations_pim(10), 25_000);
253 assert_eq!(Prf::Ripemd160.iterations_pim(10), 20_480);
254 assert_eq!(Prf::all().len(), 5);
255 assert_eq!(
256 Cipher::all().map(Cipher::name),
257 ["aes", "serpent", "twofish"]
258 );
259 }
260
261 #[test]
262 fn every_prf_has_a_name_and_derives() {
263 assert_eq!(Prf::Sha256.name(), "sha256");
265 assert_eq!(Prf::Whirlpool.name(), "whirlpool");
266 assert_eq!(Prf::Streebog.name(), "streebog");
267 assert_eq!(Prf::Ripemd160.name(), "ripemd160");
268 for prf in Prf::all() {
270 let k = prf.derive(b"password", b"salt", 1, 64);
271 assert_eq!(k.len(), 64, "prf {} derive length", prf.name());
272 }
273 }
274
275 #[test]
276 fn cipher_key_len_is_two_256bit_subkeys() {
277 assert_eq!(Cipher::Aes.key_len(), 64);
278 assert_eq!(Cipher::Twofish.key_len(), 64);
279 }
280
281 #[test]
282 fn pbkdf2_sha512_matches_python() {
283 let k = Prf::Sha512.derive(b"password", b"salt", 1, 32);
285 assert_eq!(
286 hex(&k),
287 "867f70cf1ade02cff3752599a3a53dc4af34c7a669815ae5d513554e1c8cf252"
288 );
289 }
290
291 #[test]
292 fn xts_roundtrips_for_each_cipher() {
293 for cipher in Cipher::all() {
294 let key = [0x24u8; 64];
295 let mut buf = vec![0u8; 512];
296 for (i, b) in buf.iter_mut().enumerate() {
297 *b = (i as u8) ^ 0x3c;
298 }
299 let plain = buf.clone();
300 let (k1, k2) = key.split_at(32);
302 match cipher {
303 Cipher::Aes => encrypt_one(
304 &Xts128::new(Aes256::new(k1.into()), Aes256::new(k2.into())),
305 &mut buf,
306 256,
307 ),
308 Cipher::Serpent => encrypt_one(
309 &Xts128::new(
310 Serpent::new_from_slice(k1).unwrap(),
311 Serpent::new_from_slice(k2).unwrap(),
312 ),
313 &mut buf,
314 256,
315 ),
316 Cipher::Twofish => encrypt_one(
317 &Xts128::new(Twofish::new(k1.into()), Twofish::new(k2.into())),
318 &mut buf,
319 256,
320 ),
321 }
322 xts_decrypt(cipher, &key, &mut buf, 512, 256).unwrap();
323 assert_eq!(buf, plain, "cipher {}", cipher.name());
324 }
325 }
326
327 #[test]
328 fn xts_rejects_bad_key_len() {
329 let mut b = [0u8; 512];
330 assert!(matches!(
331 xts_decrypt(Cipher::Aes, &[0u8; 48], &mut b, 512, 0),
332 Err(VeraError::Crypto { .. })
333 ));
334 }
335
336 #[test]
337 fn cipher_chains_are_the_eight_veracrypt_chains() {
338 let chains = cipher_chains();
339 assert_eq!(chains.len(), 8);
340 assert_eq!(chains[0], vec![Cipher::Aes]);
342 assert_eq!(chains[3], vec![Cipher::Twofish, Cipher::Aes]);
343 assert_eq!(
344 chains[6],
345 vec![Cipher::Aes, Cipher::Twofish, Cipher::Serpent]
346 );
347 assert!(chains.iter().all(|c| c.len() <= 3));
348 }
349
350 #[test]
351 fn xts_decrypt_chain_rejects_empty_and_short_key() {
352 let mut b = [0u8; 512];
353 assert!(matches!(
355 xts_decrypt_chain(&[], &[0u8; 64], &mut b, 512, 0),
356 Err(VeraError::Crypto { .. })
357 ));
358 assert!(matches!(
360 xts_decrypt_chain(&[Cipher::Aes, Cipher::Twofish], &[0u8; 100], &mut b, 512, 0),
361 Err(VeraError::Crypto { .. })
362 ));
363 }
364
365 #[test]
366 fn xts_decrypt_chain_roundtrips_a_three_cipher_cascade() {
367 let ciphers = [Cipher::Aes, Cipher::Twofish, Cipher::Serpent];
371 let n = ciphers.len();
372 let mut key = [0u8; 192];
373 for (i, b) in key.iter_mut().enumerate() {
374 *b = (i as u8).wrapping_mul(7) ^ 0x5a;
375 }
376 let mut buf = vec![0u8; 512];
377 for (i, b) in buf.iter_mut().enumerate() {
378 *b = (i as u8) ^ 0x91;
379 }
380 let plain = buf.clone();
381 for j in 0..n {
383 let mut k1 = [0u8; 32];
384 let mut k2 = [0u8; 32];
385 k1.copy_from_slice(&key[32 * j..32 * j + 32]);
386 k2.copy_from_slice(&key[32 * (n + j)..32 * (n + j) + 32]);
387 match ciphers[j] {
388 Cipher::Aes => encrypt_one(
389 &Xts128::new(Aes256::new((&k1).into()), Aes256::new((&k2).into())),
390 &mut buf,
391 256,
392 ),
393 Cipher::Twofish => encrypt_one(
394 &Xts128::new(Twofish::new((&k1).into()), Twofish::new((&k2).into())),
395 &mut buf,
396 256,
397 ),
398 Cipher::Serpent => encrypt_one(
399 &Xts128::new(
400 Serpent::new_from_slice(&k1).unwrap(),
401 Serpent::new_from_slice(&k2).unwrap(),
402 ),
403 &mut buf,
404 256,
405 ),
406 }
407 }
408 assert_ne!(buf, plain, "cascade must actually encrypt");
409 xts_decrypt_chain(&ciphers, &key, &mut buf, 512, 256).unwrap();
410 assert_eq!(buf, plain, "two-cipher cascade round-trip");
411 }
412
413 fn encrypt_one<C>(xts: &Xts128<C>, buf: &mut [u8], unit: u128)
414 where
415 C: aes::cipher::BlockCipher + aes::cipher::BlockEncrypt + aes::cipher::BlockDecrypt,
416 {
417 xts.encrypt_sector(buf, unit.to_le_bytes());
418 }
419
420 fn hex(b: &[u8]) -> String {
421 use std::fmt::Write;
422 b.iter().fold(String::new(), |mut s, x| {
423 let _ = write!(s, "{x:02x}");
424 s
425 })
426 }
427}