1use crate::object::{Dict, Name, Object};
22
23const PAD: [u8; 32] = [
25 0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08,
26 0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, 0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A,
27];
28
29#[derive(Clone, Copy, PartialEq)]
31enum Cipher {
32 Rc4,
34 Aesv2,
36 Aesv3,
38}
39
40#[derive(Clone)]
42pub struct Decryptor {
43 key: Vec<u8>,
45 cipher: Cipher,
46 encrypt_metadata: bool,
50}
51
52fn encrypt_metadata_flag(enc: &Dict) -> bool {
55 enc.get("EncryptMetadata")
56 .and_then(Object::as_bool)
57 .unwrap_or(true)
58}
59
60impl Decryptor {
61 pub fn from_standard(enc: &Dict, id0: &[u8]) -> Option<Decryptor> {
77 Decryptor::from_standard_with_password(enc, id0, b"")
78 }
79
80 pub fn from_standard_with_password_str(
85 enc: &Dict,
86 id0: &[u8],
87 password: &str,
88 ) -> Option<Decryptor> {
89 let dec = Decryptor::from_standard_with_password(enc, id0, password.as_bytes());
90 if dec.is_some() || password.is_ascii() || password.chars().any(|c| (c as u32) > 255) {
91 return dec;
92 }
93 let latin1: Vec<u8> = password.chars().map(|c| c as u8).collect();
94 Decryptor::from_standard_with_password(enc, id0, &latin1)
95 }
96
97 pub fn from_standard_with_password(
103 enc: &Dict,
104 id0: &[u8],
105 password: &[u8],
106 ) -> Option<Decryptor> {
107 if enc.get_name("Filter").map(|n| n.0.as_str()) != Some("Standard") {
108 return None;
109 }
110 let v = enc.get_int("V").unwrap_or(0);
111 let r = enc.get_int("R").unwrap_or(0);
112 let encrypt_metadata = encrypt_metadata_flag(enc);
113 match (v, r) {
114 (1 | 2, 2 | 3) => {
116 let n = if v == 1 {
117 5
118 } else {
119 (enc.get_int("Length").unwrap_or(40) / 8).clamp(5, 16) as usize
120 };
121 let key = rc4_family_key(enc, id0, r, n, password)?;
122 Some(Decryptor {
123 key,
124 cipher: Cipher::Rc4,
125 encrypt_metadata,
126 })
127 }
128 (4, 4) => {
130 let key = rc4_family_key(enc, id0, r, 16, password)?;
131 let cipher = match crypt_filter_method(enc)?.as_str() {
132 "AESV2" => Cipher::Aesv2,
133 "V2" => Cipher::Rc4,
134 _ => return None, };
136 Some(Decryptor {
137 key,
138 cipher,
139 encrypt_metadata,
140 })
141 }
142 (5, 5 | 6) => aesv3_key(enc, r, password).map(|key| Decryptor {
144 key,
145 cipher: Cipher::Aesv3,
146 encrypt_metadata,
147 }),
148 _ => None,
149 }
150 }
151
152 pub fn decrypt_object(&self, obj: &mut Object, num: u32, gen: u16) {
169 let key = match self.cipher {
170 Cipher::Aesv3 => self.key.clone(), Cipher::Rc4 | Cipher::Aesv2 => self.object_key(num, gen),
172 };
173 decrypt_in_place(obj, &key, self.cipher, self.encrypt_metadata);
174 }
175
176 fn object_key(&self, num: u32, gen: u16) -> Vec<u8> {
180 let mut input = Vec::with_capacity(self.key.len() + 9);
181 input.extend_from_slice(&self.key);
182 input.extend_from_slice(&num.to_le_bytes()[..3]);
183 input.extend_from_slice(&gen.to_le_bytes()[..2]);
184 if self.cipher == Cipher::Aesv2 {
185 input.extend_from_slice(b"sAlT");
186 }
187 let digest = md5(&input);
188 let n = (self.key.len() + 5).min(16);
189 digest[..n].to_vec()
190 }
191}
192
193fn decrypt_in_place(obj: &mut Object, key: &[u8], cipher: Cipher, encrypt_metadata: bool) {
199 match obj {
200 Object::String(bytes) => *bytes = decrypt_bytes(cipher, key, bytes),
201 Object::Array(items) => items
202 .iter_mut()
203 .for_each(|it| decrypt_in_place(it, key, cipher, encrypt_metadata)),
204 Object::Dict(dict) => dict
205 .values_mut()
206 .for_each(|v| decrypt_in_place(v, key, cipher, encrypt_metadata)),
207 Object::Stream(stream) => {
208 stream
209 .dict
210 .values_mut()
211 .for_each(|v| decrypt_in_place(v, key, cipher, encrypt_metadata));
212 if !encrypt_metadata && is_metadata_stream(&stream.dict) {
213 return;
214 }
215 stream.data = decrypt_bytes(cipher, key, &stream.data);
216 }
217 _ => {}
218 }
219}
220
221fn is_metadata_stream(dict: &Dict) -> bool {
223 dict.get_name("Type").map(|n| n.0.as_str()) == Some("Metadata")
224}
225
226fn decrypt_bytes(cipher: Cipher, key: &[u8], data: &[u8]) -> Vec<u8> {
228 match cipher {
229 Cipher::Rc4 => rc4(key, data),
230 Cipher::Aesv2 | Cipher::Aesv3 => aes_cbc_decrypt(key, data),
231 }
232}
233
234fn crypt_filter_method(enc: &Dict) -> Option<String> {
237 let stmf = enc
238 .get_name("StmF")
239 .map(|n| n.0.as_str())
240 .unwrap_or("StdCF");
241 let filter = enc.get_dict("CF")?.get_dict(stmf)?;
242 Some(filter.get_name("CFM")?.0.clone())
243}
244
245fn pad_password(password: &[u8]) -> [u8; 32] {
249 let mut out = [0u8; 32];
250 let n = password.len().min(32);
251 out[..n].copy_from_slice(&password[..n]);
252 out[n..].copy_from_slice(&PAD[..32 - n]);
253 out
254}
255
256fn rc4_family_key(enc: &Dict, id0: &[u8], r: i64, n: usize, password: &[u8]) -> Option<Vec<u8>> {
261 let u = enc.get("U").and_then(Object::as_str_bytes)?;
262 if let Some(key) = md5_file_key(enc, id0, r, n, &pad_password(password)) {
263 if verify_user_password(&key, r, id0, u) {
264 return Some(key);
265 }
266 }
267 let o = enc.get("O").and_then(Object::as_str_bytes)?;
271 if o.len() < 32 {
272 return None;
273 }
274 let mut d = md5(&pad_password(password));
275 if r >= 3 {
276 for _ in 0..50 {
277 d = md5(&d[..n]);
278 }
279 }
280 let okey = &d[..n];
281 let recovered = if r == 2 {
282 rc4(okey, &o[..32])
283 } else {
284 let mut x = o[..32].to_vec();
285 for i in (1u8..=19).rev() {
286 let keyed: Vec<u8> = okey.iter().map(|b| b ^ i).collect();
287 x = rc4(&keyed, &x);
288 }
289 rc4(okey, &x)
290 };
291 let padded: [u8; 32] = recovered.get(..32)?.try_into().ok()?;
292 let key = md5_file_key(enc, id0, r, n, &padded)?;
293 verify_user_password(&key, r, id0, u).then_some(key)
294}
295
296fn md5_file_key(enc: &Dict, id0: &[u8], r: i64, n: usize, padded: &[u8; 32]) -> Option<Vec<u8>> {
298 let o = enc.get("O").and_then(Object::as_str_bytes)?;
299 if o.len() < 32 {
300 return None;
301 }
302 let p = enc.get_int("P")?;
303 let mut input = Vec::with_capacity(32 + 32 + 4 + id0.len() + 4);
304 input.extend_from_slice(padded);
305 input.extend_from_slice(&o[..32]);
306 input.extend_from_slice(&(p as i32 as u32).to_le_bytes()); input.extend_from_slice(id0);
308 if r >= 4 && !encrypt_metadata_flag(enc) {
310 input.extend_from_slice(&[0xFF, 0xFF, 0xFF, 0xFF]);
311 }
312 let mut digest = md5(&input);
313 if r >= 3 {
314 for _ in 0..50 {
315 digest = md5(&digest[..n]);
316 }
317 }
318 Some(digest[..n].to_vec())
319}
320
321fn verify_user_password(key: &[u8], r: i64, id0: &[u8], u: &[u8]) -> bool {
323 if r == 2 {
324 let computed = rc4(key, &PAD);
326 u.len() >= 32 && computed == u[..32]
327 } else {
328 let mut input = Vec::with_capacity(32 + id0.len());
330 input.extend_from_slice(&PAD);
331 input.extend_from_slice(id0);
332 let mut x = md5(&input).to_vec();
333 x = rc4(key, &x);
334 for i in 1u8..=19 {
335 let keyed: Vec<u8> = key.iter().map(|b| b ^ i).collect();
336 x = rc4(&keyed, &x);
337 }
338 u.len() >= 16 && x[..16] == u[..16]
340 }
341}
342
343fn rc4(key: &[u8], data: &[u8]) -> Vec<u8> {
345 debug_assert!(!key.is_empty());
346 let mut s: [u8; 256] = core::array::from_fn(|i| i as u8);
347 let mut j = 0u8;
348 for i in 0..256 {
349 j = j.wrapping_add(s[i]).wrapping_add(key[i % key.len()]);
350 s.swap(i, j as usize);
351 }
352 let mut out = Vec::with_capacity(data.len());
353 let (mut i, mut j) = (0u8, 0u8);
354 for &byte in data {
355 i = i.wrapping_add(1);
356 j = j.wrapping_add(s[i as usize]);
357 s.swap(i as usize, j as usize);
358 let k = s[s[i as usize].wrapping_add(s[j as usize]) as usize];
359 out.push(byte ^ k);
360 }
361 out
362}
363
364#[rustfmt::skip]
368const AES_SBOX: [u8; 256] = [
369 0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,
370 0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,
371 0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,
372 0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,
373 0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,
374 0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,
375 0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,
376 0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,
377 0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,
378 0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,
379 0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,
380 0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,
381 0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,
382 0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,
383 0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,
384 0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16,
385];
386
387const AES_RCON: [u8; 11] = [
389 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36,
390];
391
392fn aes_inv_sbox() -> [u8; 256] {
394 let mut inv = [0u8; 256];
395 for (i, &s) in AES_SBOX.iter().enumerate() {
396 inv[s as usize] = i as u8;
397 }
398 inv
399}
400
401fn gmul(mut a: u8, mut b: u8) -> u8 {
403 let mut p = 0u8;
404 for _ in 0..8 {
405 if b & 1 != 0 {
406 p ^= a;
407 }
408 let hi = a & 0x80;
409 a <<= 1;
410 if hi != 0 {
411 a ^= 0x1b;
412 }
413 b >>= 1;
414 }
415 p
416}
417
418fn aes_expand_key(key: &[u8]) -> Vec<[u8; 16]> {
421 let nk = key.len() / 4; let nr = nk + 6;
423 let total = 4 * (nr + 1);
424 let mut w: Vec<[u8; 4]> = Vec::with_capacity(total);
425 for i in 0..nk {
426 w.push([key[4 * i], key[4 * i + 1], key[4 * i + 2], key[4 * i + 3]]);
427 }
428 for i in nk..total {
429 let mut t = w[i - 1];
430 if i.is_multiple_of(nk) {
431 t = [t[1], t[2], t[3], t[0]]; for b in &mut t {
433 *b = AES_SBOX[*b as usize]; }
435 t[0] ^= AES_RCON[i / nk];
436 } else if nk > 6 && i % nk == 4 {
437 for b in &mut t {
438 *b = AES_SBOX[*b as usize];
439 }
440 }
441 let prev = w[i - nk];
442 w.push([
443 prev[0] ^ t[0],
444 prev[1] ^ t[1],
445 prev[2] ^ t[2],
446 prev[3] ^ t[3],
447 ]);
448 }
449 (0..=nr)
450 .map(|round| {
451 let mut rk = [0u8; 16];
452 for c in 0..4 {
453 rk[4 * c..4 * c + 4].copy_from_slice(&w[4 * round + c]);
454 }
455 rk
456 })
457 .collect()
458}
459
460fn add_round_key(s: &mut [u8; 16], rk: &[u8; 16]) {
461 for (b, k) in s.iter_mut().zip(rk) {
462 *b ^= k;
463 }
464}
465
466fn shift_rows(s: &mut [u8; 16]) {
467 let o = *s;
468 for r in 1..4 {
469 for c in 0..4 {
470 s[r + 4 * c] = o[r + 4 * ((c + r) % 4)];
471 }
472 }
473}
474
475fn inv_shift_rows(s: &mut [u8; 16]) {
476 let o = *s;
477 for r in 1..4 {
478 for c in 0..4 {
479 s[r + 4 * c] = o[r + 4 * ((c + 4 - r) % 4)];
480 }
481 }
482}
483
484fn mix_columns(s: &mut [u8; 16]) {
485 for c in 0..4 {
486 let i = 4 * c;
487 let (a0, a1, a2, a3) = (s[i], s[i + 1], s[i + 2], s[i + 3]);
488 s[i] = gmul(a0, 2) ^ gmul(a1, 3) ^ a2 ^ a3;
489 s[i + 1] = a0 ^ gmul(a1, 2) ^ gmul(a2, 3) ^ a3;
490 s[i + 2] = a0 ^ a1 ^ gmul(a2, 2) ^ gmul(a3, 3);
491 s[i + 3] = gmul(a0, 3) ^ a1 ^ a2 ^ gmul(a3, 2);
492 }
493}
494
495fn inv_mix_columns(s: &mut [u8; 16]) {
496 for c in 0..4 {
497 let i = 4 * c;
498 let (a0, a1, a2, a3) = (s[i], s[i + 1], s[i + 2], s[i + 3]);
499 s[i] = gmul(a0, 14) ^ gmul(a1, 11) ^ gmul(a2, 13) ^ gmul(a3, 9);
500 s[i + 1] = gmul(a0, 9) ^ gmul(a1, 14) ^ gmul(a2, 11) ^ gmul(a3, 13);
501 s[i + 2] = gmul(a0, 13) ^ gmul(a1, 9) ^ gmul(a2, 14) ^ gmul(a3, 11);
502 s[i + 3] = gmul(a0, 11) ^ gmul(a1, 13) ^ gmul(a2, 9) ^ gmul(a3, 14);
503 }
504}
505
506fn aes_encrypt_block(s: &mut [u8; 16], rks: &[[u8; 16]]) {
507 #[cfg(target_arch = "aarch64")]
508 if std::arch::is_aarch64_feature_detected!("aes") {
509 unsafe { aes_hw::encrypt_block(s, rks) };
511 return;
512 }
513 #[cfg(target_arch = "x86_64")]
514 if std::arch::is_x86_feature_detected!("aes") {
515 unsafe { aes_hw::encrypt_block(s, rks) };
517 return;
518 }
519 aes_encrypt_block_soft(s, rks);
520}
521
522fn aes_encrypt_block_soft(s: &mut [u8; 16], rks: &[[u8; 16]]) {
524 let nr = rks.len() - 1;
525 add_round_key(s, &rks[0]);
526 for rk in &rks[1..nr] {
527 s.iter_mut().for_each(|b| *b = AES_SBOX[*b as usize]);
528 shift_rows(s);
529 mix_columns(s);
530 add_round_key(s, rk);
531 }
532 s.iter_mut().for_each(|b| *b = AES_SBOX[*b as usize]);
533 shift_rows(s);
534 add_round_key(s, &rks[nr]);
535}
536
537fn aes_decrypt_block(s: &mut [u8; 16], rks: &[[u8; 16]], inv_sbox: &[u8; 256]) {
538 #[cfg(target_arch = "aarch64")]
539 if std::arch::is_aarch64_feature_detected!("aes") {
540 unsafe { aes_hw::decrypt_block(s, rks) };
542 return;
543 }
544 #[cfg(target_arch = "x86_64")]
545 if std::arch::is_x86_feature_detected!("aes") {
546 unsafe { aes_hw::decrypt_block(s, rks) };
548 return;
549 }
550 aes_decrypt_block_soft(s, rks, inv_sbox);
551}
552
553fn aes_decrypt_block_soft(s: &mut [u8; 16], rks: &[[u8; 16]], inv_sbox: &[u8; 256]) {
555 let nr = rks.len() - 1;
556 add_round_key(s, &rks[nr]);
557 for rk in rks[1..nr].iter().rev() {
558 inv_shift_rows(s);
559 s.iter_mut().for_each(|b| *b = inv_sbox[*b as usize]);
560 add_round_key(s, rk);
561 inv_mix_columns(s);
562 }
563 inv_shift_rows(s);
564 s.iter_mut().for_each(|b| *b = inv_sbox[*b as usize]);
565 add_round_key(s, &rks[0]);
566}
567
568#[cfg(target_arch = "aarch64")]
576mod aes_hw {
577 use core::arch::aarch64::{
578 vaesdq_u8, vaeseq_u8, vaesimcq_u8, vaesmcq_u8, veorq_u8, vld1q_u8, vmovq_n_u8, vst1q_u8,
579 };
580
581 #[target_feature(enable = "aes")]
584 pub unsafe fn encrypt_block(s: &mut [u8; 16], rks: &[[u8; 16]]) {
585 let nr = rks.len() - 1;
586 let mut x = vld1q_u8(s.as_ptr());
590 for rk in &rks[..nr - 1] {
591 x = vaesmcq_u8(vaeseq_u8(x, vld1q_u8(rk.as_ptr())));
592 }
593 x = vaeseq_u8(x, vld1q_u8(rks[nr - 1].as_ptr()));
594 x = veorq_u8(x, vld1q_u8(rks[nr].as_ptr()));
595 vst1q_u8(s.as_mut_ptr(), x);
596 }
597
598 #[target_feature(enable = "aes")]
601 pub unsafe fn decrypt_block(s: &mut [u8; 16], rks: &[[u8; 16]]) {
602 let nr = rks.len() - 1;
603 let zero = vmovq_n_u8(0);
607 let mut x = vld1q_u8(s.as_ptr());
608 x = veorq_u8(x, vld1q_u8(rks[nr].as_ptr()));
609 for rk in rks[1..nr].iter().rev() {
610 x = vaesdq_u8(x, zero);
611 x = veorq_u8(x, vld1q_u8(rk.as_ptr()));
612 x = vaesimcq_u8(x);
613 }
614 x = vaesdq_u8(x, zero);
615 x = veorq_u8(x, vld1q_u8(rks[0].as_ptr()));
616 vst1q_u8(s.as_mut_ptr(), x);
617 }
618}
619
620#[cfg(target_arch = "x86_64")]
622mod aes_hw {
623 use core::arch::x86_64::{
624 __m128i, _mm_aesdec_si128, _mm_aesdeclast_si128, _mm_aesenc_si128, _mm_aesenclast_si128,
625 _mm_aesimc_si128, _mm_loadu_si128, _mm_storeu_si128, _mm_xor_si128,
626 };
627
628 #[target_feature(enable = "aes")]
631 pub unsafe fn encrypt_block(s: &mut [u8; 16], rks: &[[u8; 16]]) {
632 let nr = rks.len() - 1;
633 let mut x = _mm_loadu_si128(s.as_ptr().cast::<__m128i>());
634 x = _mm_xor_si128(x, _mm_loadu_si128(rks[0].as_ptr().cast::<__m128i>()));
635 for rk in &rks[1..nr] {
636 x = _mm_aesenc_si128(x, _mm_loadu_si128(rk.as_ptr().cast::<__m128i>()));
637 }
638 x = _mm_aesenclast_si128(x, _mm_loadu_si128(rks[nr].as_ptr().cast::<__m128i>()));
639 _mm_storeu_si128(s.as_mut_ptr().cast::<__m128i>(), x);
640 }
641
642 #[target_feature(enable = "aes")]
645 pub unsafe fn decrypt_block(s: &mut [u8; 16], rks: &[[u8; 16]]) {
646 let nr = rks.len() - 1;
647 let mut x = _mm_loadu_si128(s.as_ptr().cast::<__m128i>());
650 x = _mm_xor_si128(x, _mm_loadu_si128(rks[nr].as_ptr().cast::<__m128i>()));
651 for rk in rks[1..nr].iter().rev() {
652 let dk = _mm_aesimc_si128(_mm_loadu_si128(rk.as_ptr().cast::<__m128i>()));
653 x = _mm_aesdec_si128(x, dk);
654 }
655 x = _mm_aesdeclast_si128(x, _mm_loadu_si128(rks[0].as_ptr().cast::<__m128i>()));
656 _mm_storeu_si128(s.as_mut_ptr().cast::<__m128i>(), x);
657 }
658}
659
660fn aes_cbc_decrypt_blocks(key: &[u8], iv: &[u8], data: &[u8]) -> Vec<u8> {
663 if data.is_empty() || !data.len().is_multiple_of(16) || iv.len() < 16 {
664 return Vec::new();
665 }
666 let rks = aes_expand_key(key);
667 let inv_sbox = aes_inv_sbox();
668 let mut prev = [0u8; 16];
669 prev.copy_from_slice(&iv[..16]);
670 let mut out = Vec::with_capacity(data.len());
671 for chunk in data.as_chunks::<16>().0 {
672 let mut block = [0u8; 16];
673 block.copy_from_slice(chunk);
674 let cipher = block;
675 aes_decrypt_block(&mut block, &rks, &inv_sbox);
676 for (b, p) in block.iter_mut().zip(&prev) {
677 *b ^= p;
678 }
679 out.extend_from_slice(&block);
680 prev = cipher;
681 }
682 out
683}
684
685fn aes_cbc_encrypt_blocks(key: &[u8], iv: &[u8], data: &[u8]) -> Vec<u8> {
688 let rks = aes_expand_key(key);
689 let mut prev = [0u8; 16];
690 prev.copy_from_slice(&iv[..16]);
691 let mut out = Vec::with_capacity(data.len());
692 for chunk in data.as_chunks::<16>().0 {
693 let mut block = [0u8; 16];
694 for ((b, c), p) in block.iter_mut().zip(chunk).zip(&prev) {
695 *b = c ^ p;
696 }
697 aes_encrypt_block(&mut block, &rks);
698 out.extend_from_slice(&block);
699 prev = block;
700 }
701 out
702}
703
704fn aes_cbc_decrypt(key: &[u8], data: &[u8]) -> Vec<u8> {
708 if data.len() < 16 {
709 return Vec::new();
710 }
711 let (iv, ct) = data.split_at(16);
712 let mut out = aes_cbc_decrypt_blocks(key, iv, ct);
713 strip_pkcs7(&mut out);
714 out
715}
716
717fn strip_pkcs7(data: &mut Vec<u8>) {
719 let Some(&pad) = data.last() else {
720 return;
721 };
722 let pad = pad as usize;
723 if (1..=16).contains(&pad) && pad <= data.len() {
724 let start = data.len() - pad;
725 if data[start..].iter().all(|&b| b as usize == pad) {
726 data.truncate(start);
727 }
728 }
729}
730
731fn pkcs7_pad(data: &[u8]) -> Vec<u8> {
735 let pad = 16 - data.len() % 16;
736 let mut out = data.to_vec();
737 out.resize(data.len() + pad, pad as u8);
738 out
739}
740
741fn aes_cbc_encrypt(key: &[u8], rng: &mut dyn FnMut(&mut [u8]), data: &[u8]) -> Vec<u8> {
745 let mut iv = [0u8; 16];
746 rng(&mut iv);
747 let mut out = iv.to_vec();
748 out.extend_from_slice(&aes_cbc_encrypt_blocks(key, &iv, &pkcs7_pad(data)));
749 out
750}
751
752#[rustfmt::skip]
755const SHA256_K: [u32; 64] = [
756 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
757 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
758 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
759 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
760 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
761 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
762 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
763 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
764];
765
766#[derive(Debug, Clone)]
771pub struct Sha256 {
772 h: [u32; 8],
773 tail: [u8; 64],
774 tail_len: usize,
775 total: u64,
776}
777
778impl Default for Sha256 {
779 fn default() -> Sha256 {
780 Sha256::new()
781 }
782}
783
784impl Sha256 {
785 pub fn new() -> Sha256 {
787 Sha256 {
788 h: [
789 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab,
790 0x5be0cd19,
791 ],
792 tail: [0u8; 64],
793 tail_len: 0,
794 total: 0,
795 }
796 }
797
798 pub fn update(&mut self, input: &[u8]) {
803 self.total = self.total.wrapping_add(input.len() as u64);
804 let mut input = input;
805 if self.tail_len > 0 {
806 let take = input.len().min(64 - self.tail_len);
807 self.tail[self.tail_len..self.tail_len + take].copy_from_slice(&input[..take]);
808 self.tail_len += take;
809 input = &input[take..];
810 if self.tail_len < 64 {
811 return;
812 }
813 let block = self.tail;
814 sha256_compress(&mut self.h, &block);
815 self.tail_len = 0;
816 }
817 let (blocks, rest) = input.as_chunks::<64>();
818 for block in blocks {
819 sha256_compress(&mut self.h, block);
820 }
821 self.tail[..rest.len()].copy_from_slice(rest);
822 self.tail_len = rest.len();
823 }
824
825 pub fn finalize(mut self) -> [u8; 32] {
827 let mut pad = [0u8; 128];
830 pad[..self.tail_len].copy_from_slice(&self.tail[..self.tail_len]);
831 pad[self.tail_len] = 0x80;
832 let padded = if self.tail_len < 56 { 64 } else { 128 };
833 let bitlen = self.total.wrapping_mul(8);
834 pad[padded - 8..padded].copy_from_slice(&bitlen.to_be_bytes());
835 for block in pad[..padded].as_chunks::<64>().0 {
836 sha256_compress(&mut self.h, block);
837 }
838 let mut out = [0u8; 32];
839 for (i, word) in self.h.iter().enumerate() {
840 out[4 * i..4 * i + 4].copy_from_slice(&word.to_be_bytes());
841 }
842 out
843 }
844}
845
846pub fn sha256(input: &[u8]) -> [u8; 32] {
848 let mut hasher = Sha256::new();
849 hasher.update(input);
850 hasher.finalize()
851}
852
853fn sha256_compress(h: &mut [u32; 8], block: &[u8; 64]) {
854 #[cfg(target_arch = "aarch64")]
855 if std::arch::is_aarch64_feature_detected!("sha2") {
856 unsafe { sha_hw::compress256(h, block) };
858 return;
859 }
860 sha256_compress_soft(h, block);
861}
862
863fn sha256_compress_soft(h: &mut [u32; 8], block: &[u8; 64]) {
865 let mut w = [0u32; 64];
866 for (word, bytes) in w.iter_mut().zip(block.as_chunks::<4>().0) {
867 *word = u32::from_be_bytes(*bytes);
868 }
869 for i in 16..64 {
870 let s0 = w[i - 15].rotate_right(7) ^ w[i - 15].rotate_right(18) ^ (w[i - 15] >> 3);
871 let s1 = w[i - 2].rotate_right(17) ^ w[i - 2].rotate_right(19) ^ (w[i - 2] >> 10);
872 w[i] = w[i - 16]
873 .wrapping_add(s0)
874 .wrapping_add(w[i - 7])
875 .wrapping_add(s1);
876 }
877 let [mut a, mut b, mut c, mut d, mut e, mut f, mut g, mut hh] = *h;
878 for (k, wi) in SHA256_K.iter().zip(&w) {
879 let s1 = e.rotate_right(6) ^ e.rotate_right(11) ^ e.rotate_right(25);
880 let ch = (e & f) ^ ((!e) & g);
881 let t1 = hh
882 .wrapping_add(s1)
883 .wrapping_add(ch)
884 .wrapping_add(*k)
885 .wrapping_add(*wi);
886 let s0 = a.rotate_right(2) ^ a.rotate_right(13) ^ a.rotate_right(22);
887 let maj = (a & b) ^ (a & c) ^ (b & c);
888 let t2 = s0.wrapping_add(maj);
889 hh = g;
890 g = f;
891 f = e;
892 e = d.wrapping_add(t1);
893 d = c;
894 c = b;
895 b = a;
896 a = t1.wrapping_add(t2);
897 }
898 for (hv, v) in h.iter_mut().zip([a, b, c, d, e, f, g, hh]) {
899 *hv = hv.wrapping_add(v);
900 }
901}
902
903#[rustfmt::skip]
904const SHA512_K: [u64; 80] = [
905 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc,
906 0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118,
907 0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
908 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694,
909 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
910 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
911 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4,
912 0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70,
913 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
914 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
915 0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30,
916 0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
917 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8,
918 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3,
919 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
920 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b,
921 0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178,
922 0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
923 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c,
924 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817,
925];
926
927fn sha512_core(input: &[u8], mut h: [u64; 8]) -> [u64; 8] {
928 let (blocks, tail) = input.as_chunks::<128>();
929 for block in blocks {
930 sha512_compress(&mut h, block);
931 }
932 let mut pad = [0u8; 256];
936 pad[..tail.len()].copy_from_slice(tail);
937 pad[tail.len()] = 0x80;
938 let padded = if tail.len() < 112 { 128 } else { 256 };
939 let bitlen = (input.len() as u128).wrapping_mul(8);
940 pad[padded - 16..padded].copy_from_slice(&bitlen.to_be_bytes());
941 for block in pad[..padded].as_chunks::<128>().0 {
942 sha512_compress(&mut h, block);
943 }
944 h
945}
946
947fn sha512_compress(h: &mut [u64; 8], block: &[u8; 128]) {
948 #[cfg(target_arch = "aarch64")]
949 if std::arch::is_aarch64_feature_detected!("sha3") {
950 unsafe { sha_hw::compress512(h, block) };
953 return;
954 }
955 sha512_compress_soft(h, block);
956}
957
958fn sha512_compress_soft(h: &mut [u64; 8], block: &[u8; 128]) {
960 let mut w = [0u64; 80];
961 for (word, bytes) in w.iter_mut().zip(block.as_chunks::<8>().0) {
962 *word = u64::from_be_bytes(*bytes);
963 }
964 for i in 16..80 {
965 let s0 = w[i - 15].rotate_right(1) ^ w[i - 15].rotate_right(8) ^ (w[i - 15] >> 7);
966 let s1 = w[i - 2].rotate_right(19) ^ w[i - 2].rotate_right(61) ^ (w[i - 2] >> 6);
967 w[i] = w[i - 16]
968 .wrapping_add(s0)
969 .wrapping_add(w[i - 7])
970 .wrapping_add(s1);
971 }
972 let [mut a, mut b, mut c, mut d, mut e, mut f, mut g, mut hh] = *h;
973 for (k, wi) in SHA512_K.iter().zip(&w) {
974 let s1 = e.rotate_right(14) ^ e.rotate_right(18) ^ e.rotate_right(41);
975 let ch = (e & f) ^ ((!e) & g);
976 let t1 = hh
977 .wrapping_add(s1)
978 .wrapping_add(ch)
979 .wrapping_add(*k)
980 .wrapping_add(*wi);
981 let s0 = a.rotate_right(28) ^ a.rotate_right(34) ^ a.rotate_right(39);
982 let maj = (a & b) ^ (a & c) ^ (b & c);
983 let t2 = s0.wrapping_add(maj);
984 hh = g;
985 g = f;
986 f = e;
987 e = d.wrapping_add(t1);
988 d = c;
989 c = b;
990 b = a;
991 a = t1.wrapping_add(t2);
992 }
993 for (hv, v) in h.iter_mut().zip([a, b, c, d, e, f, g, hh]) {
994 *hv = hv.wrapping_add(v);
995 }
996}
997
998#[cfg(target_arch = "aarch64")]
1007mod sha_hw {
1008 use core::arch::aarch64::{
1009 uint32x4_t, uint64x2_t, vaddq_u32, vaddq_u64, vextq_u64, vld1q_u32, vld1q_u64, vld1q_u8,
1010 vreinterpretq_u32_u8, vreinterpretq_u64_u8, vrev32q_u8, vrev64q_u8, vsha256h2q_u32,
1011 vsha256hq_u32, vsha256su0q_u32, vsha256su1q_u32, vsha512h2q_u64, vsha512hq_u64,
1012 vsha512su0q_u64, vsha512su1q_u64, vst1q_u32,
1013 };
1014
1015 use super::{SHA256_K, SHA512_K};
1016
1017 #[target_feature(enable = "sha2")]
1020 pub unsafe fn compress256(h: &mut [u32; 8], block: &[u8; 64]) {
1021 let mut abcd = vld1q_u32(h.as_ptr());
1022 let mut efgh = vld1q_u32(h.as_ptr().add(4));
1023 let saved = (abcd, efgh);
1024 let mut w: [uint32x4_t; 4] = [
1025 vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(block.as_ptr()))),
1026 vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(block.as_ptr().add(16)))),
1027 vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(block.as_ptr().add(32)))),
1028 vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(block.as_ptr().add(48)))),
1029 ];
1030 for step in 0..16 {
1031 let wk = vaddq_u32(w[step % 4], vld1q_u32(SHA256_K.as_ptr().add(4 * step)));
1032 if step < 12 {
1034 w[step % 4] = vsha256su1q_u32(
1035 vsha256su0q_u32(w[step % 4], w[(step + 1) % 4]),
1036 w[(step + 2) % 4],
1037 w[(step + 3) % 4],
1038 );
1039 }
1040 let prev = abcd;
1041 abcd = vsha256hq_u32(abcd, efgh, wk);
1042 efgh = vsha256h2q_u32(efgh, prev, wk);
1043 }
1044 vst1q_u32(h.as_mut_ptr(), vaddq_u32(abcd, saved.0));
1045 vst1q_u32(h.as_mut_ptr().add(4), vaddq_u32(efgh, saved.1));
1046 }
1047
1048 #[target_feature(enable = "sha2,sha3")]
1051 pub unsafe fn compress512(h: &mut [u64; 8], block: &[u8; 128]) {
1052 let mut s: [uint64x2_t; 4] = [
1056 vld1q_u64(h.as_ptr()),
1057 vld1q_u64(h.as_ptr().add(2)),
1058 vld1q_u64(h.as_ptr().add(4)),
1059 vld1q_u64(h.as_ptr().add(6)),
1060 ];
1061 let saved = s;
1062 let mut w: [uint64x2_t; 8] = [core::mem::zeroed(); 8];
1063 for (pair, bytes) in w.iter_mut().zip(block.as_chunks::<16>().0) {
1064 *pair = vreinterpretq_u64_u8(vrev64q_u8(vld1q_u8(bytes.as_ptr())));
1065 }
1066 for step in 0..40 {
1067 let r = 3 - (step % 4);
1068 let wk = vaddq_u64(w[step % 8], vld1q_u64(SHA512_K.as_ptr().add(2 * step)));
1069 let sum = vaddq_u64(vextq_u64::<1>(wk, wk), s[r]);
1070 let im = vsha512hq_u64(
1071 sum,
1072 vextq_u64::<1>(s[(r + 3) % 4], s[r]),
1073 vextq_u64::<1>(s[(r + 2) % 4], s[(r + 3) % 4]),
1074 );
1075 let updated = vsha512h2q_u64(im, s[(r + 2) % 4], s[(r + 1) % 4]);
1076 s[(r + 2) % 4] = vaddq_u64(s[(r + 2) % 4], im);
1077 s[r] = updated;
1078 if step < 32 {
1080 let i = step % 8;
1081 w[i] = vsha512su1q_u64(
1082 vsha512su0q_u64(w[i], w[(i + 1) % 8]),
1083 w[(i + 7) % 8],
1084 vextq_u64::<1>(w[(i + 4) % 8], w[(i + 5) % 8]),
1085 );
1086 }
1087 }
1088 for (i, (out, kept)) in s.iter().zip(saved).enumerate() {
1089 let summed = vaddq_u64(*out, kept);
1090 core::arch::aarch64::vst1q_u64(h.as_mut_ptr().add(2 * i), summed);
1091 }
1092 }
1093}
1094
1095fn sha512(input: &[u8]) -> Vec<u8> {
1096 let h = sha512_core(
1097 input,
1098 [
1099 0x6a09e667f3bcc908,
1100 0xbb67ae8584caa73b,
1101 0x3c6ef372fe94f82b,
1102 0xa54ff53a5f1d36f1,
1103 0x510e527fade682d1,
1104 0x9b05688c2b3e6c1f,
1105 0x1f83d9abfb41bd6b,
1106 0x5be0cd19137e2179,
1107 ],
1108 );
1109 h.iter().flat_map(|w| w.to_be_bytes()).collect()
1110}
1111
1112fn sha384(input: &[u8]) -> Vec<u8> {
1113 let h = sha512_core(
1114 input,
1115 [
1116 0xcbbb9d5dc1059ed8,
1117 0x629a292a367cd507,
1118 0x9159015a3070dd17,
1119 0x152fecd8f70e5939,
1120 0x67332667ffc00b31,
1121 0x8eb44a8768581511,
1122 0xdb0c2e0d64f98fa7,
1123 0x47b5481dbefa4fa4,
1124 ],
1125 );
1126 h.iter().take(6).flat_map(|w| w.to_be_bytes()).collect()
1127}
1128
1129fn aesv3_key(enc: &Dict, r: i64, password: &[u8]) -> Option<Vec<u8>> {
1135 let pw = &password[..password.len().min(127)];
1136 let u = enc.get("U").and_then(Object::as_str_bytes)?;
1137 if u.len() < 48 {
1138 return None;
1139 }
1140 let perms = enc.get("Perms").and_then(Object::as_str_bytes);
1148 let o = enc.get("O").and_then(Object::as_str_bytes);
1149 if let Some(perms) = perms.filter(|p| p.len() >= 16) {
1150 if let Some(ue) = enc.get("UE").and_then(Object::as_str_bytes) {
1151 if ue.len() >= 32 {
1152 let intermediate = hash_2b(r, pw, &u[40..48], &[]);
1153 let file_key = aes_cbc_decrypt_blocks(&intermediate, &[0u8; 16], &ue[..32]);
1154 if file_key.len() == 32 && perms_marker_valid(&file_key, perms) {
1155 return Some(file_key);
1156 }
1157 }
1158 }
1159 if let (Some(o), Some(oe)) = (o, enc.get("OE").and_then(Object::as_str_bytes)) {
1160 if o.len() >= 48 && oe.len() >= 32 {
1161 let intermediate = hash_2b(r, pw, &o[40..48], &u[..48]);
1162 let file_key = aes_cbc_decrypt_blocks(&intermediate, &[0u8; 16], &oe[..32]);
1163 if file_key.len() == 32 && perms_marker_valid(&file_key, perms) {
1164 return Some(file_key);
1165 }
1166 }
1167 }
1168 }
1169 if let Some(ue) = enc.get("UE").and_then(Object::as_str_bytes) {
1170 if ue.len() >= 32 && hash_2b(r, pw, &u[32..40], &[])[..32] == u[..32] {
1171 let intermediate = hash_2b(r, pw, &u[40..48], &[]);
1172 let file_key = aes_cbc_decrypt_blocks(&intermediate, &[0u8; 16], &ue[..32]);
1173 if file_key.len() == 32 {
1174 return Some(file_key);
1175 }
1176 }
1177 }
1178 let o = o?;
1179 let oe = enc.get("OE").and_then(Object::as_str_bytes)?;
1180 if o.len() < 48 || oe.len() < 32 {
1181 return None;
1182 }
1183 if hash_2b(r, pw, &o[32..40], &u[..48])[..32] != o[..32] {
1184 return None;
1185 }
1186 let intermediate = hash_2b(r, pw, &o[40..48], &u[..48]);
1187 let file_key = aes_cbc_decrypt_blocks(&intermediate, &[0u8; 16], &oe[..32]);
1188 (file_key.len() == 32).then_some(file_key)
1189}
1190
1191fn perms_marker_valid(file_key: &[u8], perms: &[u8]) -> bool {
1194 let rks = aes_expand_key(file_key);
1195 let inv_sbox = aes_inv_sbox();
1196 let mut block = [0u8; 16];
1197 block.copy_from_slice(&perms[..16]);
1198 aes_decrypt_block(&mut block, &rks, &inv_sbox);
1199 &block[9..12] == b"adb"
1200}
1201
1202fn hash_2b(r: i64, password: &[u8], salt: &[u8], udata: &[u8]) -> Vec<u8> {
1205 let mut seed = Vec::with_capacity(password.len() + salt.len() + udata.len());
1206 seed.extend_from_slice(password);
1207 seed.extend_from_slice(salt);
1208 seed.extend_from_slice(udata);
1209 let mut k = sha256(&seed).to_vec();
1210 if r < 6 {
1211 return k; }
1213 let mut round = 0usize;
1214 let mut k1 = Vec::with_capacity(64 * (password.len() + 64 + udata.len()));
1215 loop {
1216 k1.clear();
1217 for _ in 0..64 {
1218 k1.extend_from_slice(password);
1219 k1.extend_from_slice(&k);
1220 k1.extend_from_slice(udata);
1221 }
1222 let e = aes_cbc_encrypt_blocks(&k[..16], &k[16..32], &k1);
1223 let modulus = e[..16].iter().map(|&b| u32::from(b)).sum::<u32>() % 3;
1224 k = match modulus {
1225 0 => sha256(&e).to_vec(),
1226 1 => sha384(&e),
1227 _ => sha512(&e),
1228 };
1229 round += 1;
1230 if round >= 64 && usize::from(*e.last().unwrap()) <= round - 32 {
1231 break;
1232 }
1233 }
1234 k.truncate(32);
1235 k
1236}
1237
1238pub(crate) struct KeyMaterial {
1242 file_key: [u8; 32],
1243 u: Vec<u8>,
1244 ue: Vec<u8>,
1245 o: Vec<u8>,
1246 oe: Vec<u8>,
1247 perms: Vec<u8>,
1248}
1249
1250pub(crate) fn r6_key_material(
1257 user_pw: &[u8],
1258 owner_pw: &[u8],
1259 p: i32,
1260 encrypt_metadata: bool,
1261 rng: &mut dyn FnMut(&mut [u8]),
1262) -> KeyMaterial {
1263 let user_pw = &user_pw[..user_pw.len().min(127)];
1264 let owner_pw = &owner_pw[..owner_pw.len().min(127)];
1265
1266 let mut file_key = [0u8; 32];
1267 rng(&mut file_key);
1268
1269 let mut user_salt = [0u8; 16];
1272 rng(&mut user_salt);
1273 let mut u = hash_2b(6, user_pw, &user_salt[..8], &[]);
1274 u.extend_from_slice(&user_salt);
1275 let user_intermediate = hash_2b(6, user_pw, &user_salt[8..], &[]);
1276 let ue = aes_cbc_encrypt_blocks(&user_intermediate, &[0u8; 16], &file_key);
1277
1278 let mut owner_salt = [0u8; 16];
1281 rng(&mut owner_salt);
1282 let mut o = hash_2b(6, owner_pw, &owner_salt[..8], &u[..48]);
1283 o.extend_from_slice(&owner_salt);
1284 let owner_intermediate = hash_2b(6, owner_pw, &owner_salt[8..], &u[..48]);
1285 let oe = aes_cbc_encrypt_blocks(&owner_intermediate, &[0u8; 16], &file_key);
1286
1287 let mut perms_block = [0u8; 16];
1290 perms_block[..4].copy_from_slice(&p.to_le_bytes());
1291 perms_block[4..8].copy_from_slice(&[0xff; 4]);
1292 perms_block[8] = if encrypt_metadata { b'T' } else { b'F' };
1293 perms_block[9..12].copy_from_slice(b"adb");
1294 rng(&mut perms_block[12..]);
1295 aes_encrypt_block(&mut perms_block, &aes_expand_key(&file_key));
1296
1297 KeyMaterial {
1298 file_key,
1299 u,
1300 ue,
1301 o,
1302 oe,
1303 perms: perms_block.to_vec(),
1304 }
1305}
1306
1307#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
1311pub(crate) fn fill_os_random(buf: &mut [u8]) {
1312 getrandom::fill(buf).expect("OS random number generator unavailable");
1313}
1314
1315#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1320pub struct Permissions {
1321 pub print: bool,
1324 pub modify: bool,
1327 pub copy: bool,
1329 pub annotate: bool,
1332 pub fill_forms: bool,
1335 pub accessibility: bool,
1337 pub assemble: bool,
1340 pub print_hires: bool,
1343}
1344
1345pub const PERMISSION_NAMES: [&str; 8] = [
1350 "print",
1351 "modify",
1352 "copy",
1353 "annotate",
1354 "fill-forms",
1355 "accessibility",
1356 "assemble",
1357 "print-hires",
1358];
1359
1360impl Permissions {
1361 pub fn all() -> Permissions {
1363 Permissions {
1364 print: true,
1365 modify: true,
1366 copy: true,
1367 annotate: true,
1368 fill_forms: true,
1369 accessibility: true,
1370 assemble: true,
1371 print_hires: true,
1372 }
1373 }
1374
1375 pub fn from_names<'a>(names: impl IntoIterator<Item = &'a str>) -> Result<Permissions, String> {
1380 let mut permissions = Permissions {
1381 print: false,
1382 modify: false,
1383 copy: false,
1384 annotate: false,
1385 fill_forms: false,
1386 accessibility: false,
1387 assemble: false,
1388 print_hires: false,
1389 };
1390 for name in names {
1391 match name {
1392 "print" => permissions.print = true,
1393 "modify" => permissions.modify = true,
1394 "copy" => permissions.copy = true,
1395 "annotate" => permissions.annotate = true,
1396 "fill-forms" => permissions.fill_forms = true,
1397 "accessibility" => permissions.accessibility = true,
1398 "assemble" => permissions.assemble = true,
1399 "print-hires" => permissions.print_hires = true,
1400 other => return Err(other.to_string()),
1401 }
1402 }
1403 Ok(permissions)
1404 }
1405
1406 pub(crate) fn p_value(&self) -> i32 {
1413 let flags: [(u32, bool); 8] = [
1414 (3, self.print),
1415 (4, self.modify),
1416 (5, self.copy),
1417 (6, self.annotate),
1418 (9, self.fill_forms),
1419 (10, self.accessibility),
1420 (11, self.assemble),
1421 (12, self.print_hires),
1422 ];
1423 let mut bits: u32 = !0b11; for (bit, granted) in flags {
1425 if !granted {
1426 bits &= !(1u32 << (bit - 1));
1427 }
1428 }
1429 bits as i32
1430 }
1431}
1432
1433impl Default for Permissions {
1434 fn default() -> Permissions {
1436 Permissions::all()
1437 }
1438}
1439
1440fn aes256_encrypt_dict(material: &KeyMaterial, p: i32) -> Dict {
1446 let mut std_cf = Dict::new();
1447 std_cf.insert(
1448 Name("CFM".to_string()),
1449 Object::Name(Name("AESV3".to_string())),
1450 );
1451 std_cf.insert(Name("Length".to_string()), Object::Int(32));
1452 let mut cf = Dict::new();
1453 cf.insert(Name("StdCF".to_string()), Object::Dict(std_cf));
1454
1455 let mut dict = Dict::new();
1456 dict.insert(
1457 Name("Filter".to_string()),
1458 Object::Name(Name("Standard".to_string())),
1459 );
1460 dict.insert(Name("V".to_string()), Object::Int(5));
1461 dict.insert(Name("R".to_string()), Object::Int(6));
1462 dict.insert(Name("Length".to_string()), Object::Int(256));
1463 dict.insert(Name("CF".to_string()), Object::Dict(cf));
1464 dict.insert(
1465 Name("StmF".to_string()),
1466 Object::Name(Name("StdCF".to_string())),
1467 );
1468 dict.insert(
1469 Name("StrF".to_string()),
1470 Object::Name(Name("StdCF".to_string())),
1471 );
1472 dict.insert(Name("P".to_string()), Object::Int(i64::from(p)));
1473 dict.insert(Name("U".to_string()), Object::String(material.u.clone()));
1474 dict.insert(Name("UE".to_string()), Object::String(material.ue.clone()));
1475 dict.insert(Name("O".to_string()), Object::String(material.o.clone()));
1476 dict.insert(Name("OE".to_string()), Object::String(material.oe.clone()));
1477 dict.insert(
1478 Name("Perms".to_string()),
1479 Object::String(material.perms.clone()),
1480 );
1481 dict
1482}
1483
1484#[allow(
1489 clippy::type_complexity,
1490 reason = "Box<dyn FnMut(&mut [u8]) + Send> names the one random-byte source the write path takes; a type alias would only rename it"
1491)]
1492pub struct Encryptor {
1493 file_key: [u8; 32],
1494 rng: Box<dyn FnMut(&mut [u8]) + Send>,
1495}
1496
1497impl Encryptor {
1498 #[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
1508 pub fn aes256(
1509 user_password: &str,
1510 owner_password: &str,
1511 permissions: Permissions,
1512 ) -> (Encryptor, Dict) {
1513 Encryptor::aes256_with_rng(
1514 user_password,
1515 owner_password,
1516 permissions,
1517 Box::new(fill_os_random),
1518 )
1519 }
1520
1521 #[allow(clippy::type_complexity, reason = "see Encryptor's rng field")]
1524 pub fn aes256_with_rng(
1525 user_password: &str,
1526 owner_password: &str,
1527 permissions: Permissions,
1528 rng: Box<dyn FnMut(&mut [u8]) + Send>,
1529 ) -> (Encryptor, Dict) {
1530 let mut rng = rng;
1531 let p = permissions.p_value();
1532 let material = r6_key_material(
1533 user_password.as_bytes(),
1534 owner_password.as_bytes(),
1535 p,
1536 true,
1537 &mut *rng,
1538 );
1539 let dict = aes256_encrypt_dict(&material, p);
1540 let encryptor = Encryptor {
1541 file_key: material.file_key,
1542 rng,
1543 };
1544 (encryptor, dict)
1545 }
1546
1547 pub fn encrypt_object(&mut self, obj: &mut Object, num: u32, gen: u16) {
1556 let _ = (num, gen);
1557 encrypt_in_place(obj, &self.file_key, &mut *self.rng);
1558 }
1559}
1560
1561fn encrypt_in_place(obj: &mut Object, key: &[u8], rng: &mut dyn FnMut(&mut [u8])) {
1566 match obj {
1567 Object::String(bytes) => *bytes = aes_cbc_encrypt(key, rng, bytes),
1568 Object::Array(items) => {
1569 for it in items {
1570 encrypt_in_place(it, key, &mut *rng);
1571 }
1572 }
1573 Object::Dict(dict) => {
1574 for v in dict.values_mut() {
1575 encrypt_in_place(v, key, &mut *rng);
1576 }
1577 }
1578 Object::Stream(stream) => {
1579 for v in stream.dict.values_mut() {
1580 encrypt_in_place(v, key, &mut *rng);
1581 }
1582 stream.data = aes_cbc_encrypt(key, rng, &stream.data);
1583 }
1584 _ => {}
1585 }
1586}
1587
1588#[rustfmt::skip]
1590const MD5_S: [u32; 64] = [
1591 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
1592 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
1593 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
1594 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21,
1595];
1596
1597#[rustfmt::skip]
1599const MD5_K: [u32; 64] = [
1600 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
1601 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
1602 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
1603 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
1604 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
1605 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
1606 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
1607 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391,
1608];
1609
1610fn md5(input: &[u8]) -> [u8; 16] {
1613 let (mut a0, mut b0, mut c0, mut d0) = (
1614 0x6745_2301u32,
1615 0xefcd_ab89u32,
1616 0x98ba_dcfeu32,
1617 0x1032_5476u32,
1618 );
1619
1620 let mut msg = input.to_vec();
1621 let bitlen = (input.len() as u64).wrapping_mul(8);
1622 msg.push(0x80);
1623 while msg.len() % 64 != 56 {
1624 msg.push(0);
1625 }
1626 msg.extend_from_slice(&bitlen.to_le_bytes());
1627
1628 for chunk in msg.as_chunks::<64>().0 {
1629 let mut m = [0u32; 16];
1630 for (word, bytes) in m.iter_mut().zip(chunk.as_chunks::<4>().0) {
1631 *word = u32::from_le_bytes(*bytes);
1632 }
1633 let (mut a, mut b, mut c, mut d) = (a0, b0, c0, d0);
1634 for i in 0..64 {
1635 let (f, g) = match i {
1636 0..=15 => ((b & c) | (!b & d), i),
1637 16..=31 => ((d & b) | (!d & c), (5 * i + 1) % 16),
1638 32..=47 => (b ^ c ^ d, (3 * i + 5) % 16),
1639 _ => (c ^ (b | !d), (7 * i) % 16),
1640 };
1641 let f = f.wrapping_add(a).wrapping_add(MD5_K[i]).wrapping_add(m[g]);
1642 a = d;
1643 d = c;
1644 c = b;
1645 b = b.wrapping_add(f.rotate_left(MD5_S[i]));
1646 }
1647 a0 = a0.wrapping_add(a);
1648 b0 = b0.wrapping_add(b);
1649 c0 = c0.wrapping_add(c);
1650 d0 = d0.wrapping_add(d);
1651 }
1652
1653 let mut out = [0u8; 16];
1654 out[0..4].copy_from_slice(&a0.to_le_bytes());
1655 out[4..8].copy_from_slice(&b0.to_le_bytes());
1656 out[8..12].copy_from_slice(&c0.to_le_bytes());
1657 out[12..16].copy_from_slice(&d0.to_le_bytes());
1658 out
1659}
1660
1661#[cfg(test)]
1662mod tests {
1663 use super::*;
1664 use crate::object::Name;
1665
1666 fn hex(bytes: &[u8]) -> String {
1667 bytes.iter().map(|b| format!("{b:02x}")).collect()
1668 }
1669
1670 #[test]
1671 fn md5_known_vectors() {
1672 assert_eq!(hex(&md5(b"")), "d41d8cd98f00b204e9800998ecf8427e");
1673 assert_eq!(hex(&md5(b"abc")), "900150983cd24fb0d6963f7d28e17f72");
1674 assert_eq!(
1675 hex(&md5(b"The quick brown fox jumps over the lazy dog")),
1676 "9e107d9d372bb6826bd81d3542a419d6"
1677 );
1678 }
1679
1680 #[test]
1681 fn md5_spans_block_boundary() {
1682 let input = [b'a'; 56];
1684 assert_eq!(hex(&md5(&input)), "3b0c8ac703f828b04c6c197006d17218");
1685 }
1686
1687 #[test]
1692 fn aes_block_known_vectors() {
1693 let plain: [u8; 16] = core::array::from_fn(|i| (i as u8) * 0x11);
1694 let key128: [u8; 16] = core::array::from_fn(|i| i as u8);
1695 let key256: [u8; 32] = core::array::from_fn(|i| i as u8);
1696
1697 type Encrypt = fn(&mut [u8; 16], &[[u8; 16]]);
1698 type Decrypt = fn(&mut [u8; 16], &[[u8; 16]], &[u8; 256]);
1699 let paths: [(Encrypt, Decrypt); 2] = [
1700 (aes_encrypt_block, aes_decrypt_block),
1701 (aes_encrypt_block_soft, aes_decrypt_block_soft),
1702 ];
1703 for (encrypt, decrypt) in paths {
1704 let mut s = plain;
1705 encrypt(&mut s, &aes_expand_key(&key128));
1706 assert_eq!(hex(&s), "69c4e0d86a7b0430d8cdb78070b4c55a");
1707 decrypt(&mut s, &aes_expand_key(&key128), &aes_inv_sbox());
1708 assert_eq!(s, plain);
1709
1710 let mut s = plain;
1711 encrypt(&mut s, &aes_expand_key(&key256));
1712 assert_eq!(hex(&s), "8ea2b7ca516745bfeafc49904b496089");
1713 decrypt(&mut s, &aes_expand_key(&key256), &aes_inv_sbox());
1714 assert_eq!(s, plain);
1715 }
1716 }
1717
1718 #[test]
1721 fn aes_cbc_round_trips_multiple_blocks() {
1722 let key: [u8; 16] = core::array::from_fn(|i| (i as u8).wrapping_mul(7));
1723 let iv: [u8; 16] = core::array::from_fn(|i| 0xa5 ^ (i as u8));
1724 let data: Vec<u8> = (0..64u8).collect();
1725 let ct = aes_cbc_encrypt_blocks(&key, &iv, &data);
1726 assert_eq!(ct.len(), data.len());
1727 assert_ne!(ct, data);
1728 assert_eq!(aes_cbc_decrypt_blocks(&key, &iv, &ct), data);
1729 }
1730
1731 #[test]
1735 fn sha2_known_vectors() {
1736 assert_eq!(
1737 hex(&sha256(b"")),
1738 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
1739 );
1740 assert_eq!(
1741 hex(&sha256(b"abc")),
1742 "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
1743 );
1744 assert_eq!(
1745 hex(&sha256(&[b'a'; 200])),
1746 "c2a908d98f5df987ade41b5fce213067efbcc21ef2240212a41e54b5e7c28ae5"
1747 );
1748 assert_eq!(
1749 hex(&sha384(b"abc")),
1750 "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed\
1751 8086072ba1e7cc2358baeca134c825a7"
1752 );
1753 assert_eq!(
1754 hex(&sha512(b"abc")),
1755 "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a\
1756 2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"
1757 );
1758 assert_eq!(
1759 hex(&sha512(&[b'a'; 300])),
1760 "a6a77010dd9696c23831e6549de51724df332c2075039b75fcfe6c2e6de42fbd\
1761 3c80ed4073267e00c8c320712c3cdd9d65a96f90a3fe4a58a6b70a103be08e83"
1762 );
1763 }
1764
1765 #[test]
1769 fn sha2_soft_compressions_match_the_dispatch() {
1770 let block64: [u8; 64] = core::array::from_fn(|i| (i as u8).wrapping_mul(31));
1771 let mut via_dispatch = [0x6a09e667u32; 8];
1772 let mut via_soft = via_dispatch;
1773 sha256_compress(&mut via_dispatch, &block64);
1774 sha256_compress_soft(&mut via_soft, &block64);
1775 assert_eq!(via_dispatch, via_soft);
1776
1777 let block128: [u8; 128] = core::array::from_fn(|i| (i as u8).wrapping_mul(29));
1778 let mut via_dispatch = [0x6a09e667f3bcc908u64; 8];
1779 let mut via_soft = via_dispatch;
1780 sha512_compress(&mut via_dispatch, &block128);
1781 sha512_compress_soft(&mut via_soft, &block128);
1782 assert_eq!(via_dispatch, via_soft);
1783 }
1784
1785 #[test]
1788 fn incremental_sha256_matches_the_one_shot() {
1789 let input: Vec<u8> = (0..300u16).map(|i| (i % 251) as u8).collect();
1790 for splits in [
1791 vec![0, 1, 3, 7, 60, 63, 64, 65, 37],
1792 vec![300],
1793 vec![128, 128, 44],
1794 vec![55, 9, 236],
1795 ] {
1796 let mut hasher = Sha256::new();
1797 let mut fed = 0usize;
1798 for len in splits {
1799 hasher.update(&input[fed..fed + len]);
1800 fed += len;
1801 }
1802 hasher.update(&input[fed..]);
1803 assert_eq!(hasher.finalize(), sha256(&input));
1804 }
1805 assert_eq!(Sha256::new().finalize(), sha256(b""));
1806 assert_eq!(Sha256::default().finalize(), sha256(b""));
1807 }
1808
1809 #[test]
1810 fn rc4_known_vector() {
1811 let ct = rc4(b"Key", b"Plaintext");
1813 assert_eq!(hex(&ct), "bbf316e8d940af0ad3");
1814 assert_eq!(rc4(b"Key", &ct), b"Plaintext");
1816 }
1817
1818 const N: usize = 16; const P: i32 = -44;
1825 const ID0: &[u8] = b"0123456789abcdef";
1826
1827 fn owner_entry(owner_pw: &[u8], user_pw: &[u8]) -> Vec<u8> {
1829 let mut d = md5(&pad_password(owner_pw));
1830 for _ in 0..50 {
1831 d = md5(&d[..N]);
1832 }
1833 let rc4key = d[..N].to_vec();
1834 let mut o = rc4(&rc4key, &pad_password(user_pw));
1835 for i in 1u8..=19 {
1836 let k: Vec<u8> = rc4key.iter().map(|b| b ^ i).collect();
1837 o = rc4(&k, &o);
1838 }
1839 o
1840 }
1841
1842 fn file_key(o: &[u8], user_pw: &[u8]) -> Vec<u8> {
1844 let mut input = Vec::new();
1845 input.extend_from_slice(&pad_password(user_pw));
1846 input.extend_from_slice(o);
1847 input.extend_from_slice(&(P as u32).to_le_bytes());
1848 input.extend_from_slice(ID0);
1849 let mut d = md5(&input);
1850 for _ in 0..50 {
1851 d = md5(&d[..N]);
1852 }
1853 d[..N].to_vec()
1854 }
1855
1856 fn user_entry(key: &[u8]) -> Vec<u8> {
1858 let mut input = Vec::new();
1859 input.extend_from_slice(&PAD);
1860 input.extend_from_slice(ID0);
1861 let mut x = md5(&input).to_vec();
1862 x = rc4(key, &x);
1863 for i in 1u8..=19 {
1864 let k: Vec<u8> = key.iter().map(|b| b ^ i).collect();
1865 x = rc4(&k, &x);
1866 }
1867 x.resize(32, 0); x
1869 }
1870
1871 fn obj_key(key: &[u8], num: u32, gen: u16) -> Vec<u8> {
1872 let mut input = key.to_vec();
1873 input.extend_from_slice(&num.to_le_bytes()[..3]);
1874 input.extend_from_slice(&gen.to_le_bytes()[..2]);
1875 md5(&input)[..(key.len() + 5).min(16)].to_vec()
1876 }
1877
1878 fn hexstr(b: &[u8]) -> String {
1879 let mut s = String::from("<");
1880 for x in b {
1881 s.push_str(&format!("{x:02x}"));
1882 }
1883 s.push('>');
1884 s
1885 }
1886
1887 fn encrypted_fixture(u_override: Option<Vec<u8>>) -> Vec<u8> {
1888 encrypted_fixture_with(b"", b"", u_override)
1889 }
1890
1891 fn encrypted_fixture_with(
1892 user_pw: &[u8],
1893 owner_pw: &[u8],
1894 u_override: Option<Vec<u8>>,
1895 ) -> Vec<u8> {
1896 use pdfboss_testkit::PdfBuilder;
1897 let o = owner_entry(owner_pw, user_pw);
1898 let key = file_key(&o, user_pw);
1899 let u = u_override.unwrap_or_else(|| user_entry(&key));
1900
1901 let msg = rc4(&obj_key(&key, 3, 0), b"Top secret message");
1902 let stream = rc4(&obj_key(&key, 4, 0), b"decrypted stream body");
1903
1904 let mut b = PdfBuilder::new().version(1, 4);
1905 b.object(1, "<< /Type /Catalog /Pages 2 0 R >>");
1906 b.object(2, "<< /Type /Pages /Kids [] /Count 0 >>");
1907 b.object(3, &format!("<< /Msg {} >>", hexstr(&msg)));
1908 b.stream(4, "", &stream);
1909 b.object(
1910 9,
1911 &format!(
1912 "<< /Filter /Standard /V 2 /R 3 /Length 128 /P {P} /O {} /U {} >>",
1913 hexstr(&o),
1914 hexstr(&u)
1915 ),
1916 );
1917 let trailer = format!("/Encrypt 9 0 R /ID [{}{}]", hexstr(ID0), hexstr(ID0));
1918 b.trailer_extra(&trailer).build(1)
1919 }
1920
1921 #[test]
1922 fn document_load_decrypts_standard_rc4() {
1923 use crate::object::ObjRef;
1924 use crate::Document;
1925
1926 let doc = Document::load(encrypted_fixture(None)).expect("empty password opens the file");
1927
1928 let obj3 = doc.get(ObjRef { num: 3, gen: 0 }).unwrap();
1929 let msg = obj3
1930 .as_dict()
1931 .unwrap()
1932 .get("Msg")
1933 .unwrap()
1934 .as_str_bytes()
1935 .unwrap();
1936 assert_eq!(msg, b"Top secret message", "string decrypted");
1937
1938 let obj4 = doc.get(ObjRef { num: 4, gen: 0 }).unwrap();
1939 let data = doc.stream_data(obj4.as_stream().unwrap()).unwrap();
1940 assert_eq!(data, b"decrypted stream body", "stream decrypted");
1941 }
1942
1943 #[test]
1944 fn document_load_rejects_when_password_does_not_verify() {
1945 use crate::error::Error;
1946 use crate::Document;
1947
1948 let bad_u = vec![0u8; 32];
1951 let err = Document::load(encrypted_fixture(Some(bad_u)));
1952 assert!(matches!(err, Err(Error::Encrypted)));
1953 }
1954
1955 #[test]
1956 fn real_user_password_opens_an_rc4_file() {
1957 use crate::error::Error;
1958 use crate::object::ObjRef;
1959 use crate::Document;
1960
1961 let bytes = encrypted_fixture_with(b"hunter2", b"owner-secret", None);
1962 assert!(
1963 matches!(Document::load(bytes.clone()), Err(Error::Encrypted)),
1964 "without the password the file stays closed"
1965 );
1966 let doc = Document::load_with_password(bytes, "hunter2").expect("user password opens");
1967 let obj3 = doc.get(ObjRef { num: 3, gen: 0 }).unwrap();
1968 let msg = obj3.as_dict().unwrap().get("Msg").unwrap();
1969 assert_eq!(msg.as_str_bytes().unwrap(), b"Top secret message");
1970 }
1971
1972 #[test]
1973 fn owner_password_opens_an_rc4_file() {
1974 use crate::object::ObjRef;
1975 use crate::Document;
1976
1977 let bytes = encrypted_fixture_with(b"hunter2", b"owner-secret", None);
1978 let doc =
1979 Document::load_with_password(bytes, "owner-secret").expect("owner password opens");
1980 let obj3 = doc.get(ObjRef { num: 3, gen: 0 }).unwrap();
1981 let msg = obj3.as_dict().unwrap().get("Msg").unwrap();
1982 assert_eq!(msg.as_str_bytes().unwrap(), b"Top secret message");
1983 }
1984
1985 #[test]
1986 fn wrong_password_stays_encrypted() {
1987 use crate::error::Error;
1988 use crate::Document;
1989
1990 let bytes = encrypted_fixture_with(b"hunter2", b"owner-secret", None);
1991 let err = Document::load_with_password(bytes, "letmein");
1992 assert!(matches!(err, Err(Error::Encrypted)));
1993 }
1994
1995 #[test]
1996 fn real_passwords_open_an_aes256_r6_file() {
1997 use crate::error::Error;
1998 use crate::object::ObjRef;
1999 use crate::Document;
2000
2001 let bytes = encrypted_fixture_aesv3_with(6, "pässword".as_bytes(), b"owner-secret");
2002 assert!(
2003 matches!(Document::load(bytes.clone()), Err(Error::Encrypted)),
2004 "without the password the file stays closed"
2005 );
2006 for pw in ["pässword", "owner-secret"] {
2007 let doc = Document::load_with_password(bytes.clone(), pw)
2008 .unwrap_or_else(|_| panic!("{pw:?} opens the file"));
2009 let obj3 = doc.get(ObjRef { num: 3, gen: 0 }).unwrap();
2010 let msg = obj3.as_dict().unwrap().get("Msg").unwrap();
2011 assert_eq!(msg.as_str_bytes().unwrap(), b"AES-256 secret");
2012 }
2013 assert!(matches!(
2014 Document::load_with_password(bytes, "letmein"),
2015 Err(Error::Encrypted)
2016 ));
2017 }
2018
2019 #[test]
2020 fn empty_password_files_still_open_through_the_password_api() {
2021 use crate::object::ObjRef;
2022 use crate::Document;
2023
2024 let doc = Document::load_with_password(encrypted_fixture(None), "")
2028 .expect("the empty password opens through the password API too");
2029 let obj3 = doc.get(ObjRef { num: 3, gen: 0 }).unwrap();
2030 let msg = obj3.as_dict().unwrap().get("Msg").unwrap();
2031 assert_eq!(msg.as_str_bytes().unwrap(), b"Top secret message");
2032 }
2033
2034 #[test]
2035 fn unsupported_handler_is_declined() {
2036 let mut enc = Dict::new();
2039 enc.insert(Name("Filter".into()), Object::Name(Name("Standard".into())));
2040 enc.insert(Name("V".into()), Object::Int(6));
2041 enc.insert(Name("R".into()), Object::Int(7));
2042 enc.insert(Name("O".into()), Object::String(vec![0; 48]));
2043 enc.insert(Name("U".into()), Object::String(vec![0; 48]));
2044 enc.insert(Name("P".into()), Object::Int(-4));
2045 assert!(Decryptor::from_standard(&enc, ID0).is_none());
2046 }
2047
2048 #[test]
2051 fn aes_fips197_block_vectors() {
2052 let pt: [u8; 16] = [
2054 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
2055 0xee, 0xff,
2056 ];
2057 let key128: Vec<u8> = (0u8..16).collect();
2058 let rks = aes_expand_key(&key128);
2059 let mut b = pt;
2060 aes_encrypt_block(&mut b, &rks);
2061 assert_eq!(hex(&b), "69c4e0d86a7b0430d8cdb78070b4c55a");
2062 aes_decrypt_block(&mut b, &rks, &aes_inv_sbox());
2063 assert_eq!(b, pt, "AES-128 decrypt inverts encrypt");
2064
2065 let key256: Vec<u8> = (0u8..32).collect();
2066 let rks = aes_expand_key(&key256);
2067 let mut b = pt;
2068 aes_encrypt_block(&mut b, &rks);
2069 assert_eq!(hex(&b), "8ea2b7ca516745bfeafc49904b496089");
2070 }
2071
2072 #[test]
2073 fn sha2_vectors() {
2074 assert_eq!(
2075 hex(&sha256(b"abc")),
2076 "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
2077 );
2078 assert_eq!(
2079 hex(&sha512(b"abc")),
2080 "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a\
2081 2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"
2082 );
2083 assert_eq!(
2084 hex(&sha384(b"abc")),
2085 "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed\
2086 8086072ba1e7cc2358baeca134c825a7"
2087 );
2088 }
2089
2090 #[test]
2091 fn aes_cbc_roundtrip() {
2092 let key: Vec<u8> = (0u8..16).collect();
2093 let iv = [0x24u8; 16];
2094 let pt = b"a message spanning several AES blocks exactly?!!";
2095 let ct = aes_cbc_encrypt_blocks(&key, &iv, &pkcs7_pad(pt));
2096 let mut val = iv.to_vec(); val.extend_from_slice(&ct);
2098 assert_eq!(aes_cbc_decrypt(&key, &val), pt);
2099 }
2100
2101 fn obj_key_aes(key: &[u8], num: u32, gen: u16) -> Vec<u8> {
2104 let mut input = key.to_vec();
2105 input.extend_from_slice(&num.to_le_bytes()[..3]);
2106 input.extend_from_slice(&gen.to_le_bytes()[..2]);
2107 input.extend_from_slice(b"sAlT");
2108 md5(&input)[..(key.len() + 5).min(16)].to_vec()
2109 }
2110
2111 fn aes_encrypt_pdf(key: &[u8], pt: &[u8], iv: &[u8; 16]) -> Vec<u8> {
2114 let mut out = iv.to_vec();
2115 out.extend_from_slice(&aes_cbc_encrypt_blocks(key, iv, &pkcs7_pad(pt)));
2116 out
2117 }
2118
2119 fn encrypted_fixture_aesv2() -> Vec<u8> {
2120 use pdfboss_testkit::PdfBuilder;
2121 let o = owner_entry(b"", b"");
2122 let key = file_key(&o, b""); let u = user_entry(&key);
2124 let iv = [0x11u8; 16];
2125 let msg = aes_encrypt_pdf(&obj_key_aes(&key, 3, 0), b"Top secret message", &iv);
2126 let stream = aes_encrypt_pdf(&obj_key_aes(&key, 4, 0), b"decrypted stream body", &iv);
2127
2128 let mut b = PdfBuilder::new().version(1, 5);
2129 b.object(1, "<< /Type /Catalog /Pages 2 0 R >>");
2130 b.object(2, "<< /Type /Pages /Kids [] /Count 0 >>");
2131 b.object(3, &format!("<< /Msg {} >>", hexstr(&msg)));
2132 b.stream(4, "", &stream);
2133 b.object(
2134 9,
2135 &format!(
2136 "<< /Filter /Standard /V 4 /R 4 /Length 128 /P {P} /O {} /U {} \
2137 /CF << /StdCF << /CFM /AESV2 /Length 16 >> >> /StmF /StdCF /StrF /StdCF >>",
2138 hexstr(&o),
2139 hexstr(&u)
2140 ),
2141 );
2142 let trailer = format!("/Encrypt 9 0 R /ID [{}{}]", hexstr(ID0), hexstr(ID0));
2143 b.trailer_extra(&trailer).build(1)
2144 }
2145
2146 #[test]
2147 fn document_load_decrypts_aesv2() {
2148 use crate::object::ObjRef;
2149 use crate::Document;
2150 let doc = Document::load(encrypted_fixture_aesv2()).expect("AESV2 empty password opens");
2151 let obj3 = doc.get(ObjRef { num: 3, gen: 0 }).unwrap();
2152 let msg = obj3
2153 .as_dict()
2154 .unwrap()
2155 .get("Msg")
2156 .unwrap()
2157 .as_str_bytes()
2158 .unwrap();
2159 assert_eq!(msg, b"Top secret message");
2160 let obj4 = doc.get(ObjRef { num: 4, gen: 0 }).unwrap();
2161 assert_eq!(
2162 doc.stream_data(obj4.as_stream().unwrap()).unwrap(),
2163 b"decrypted stream body"
2164 );
2165 }
2166
2167 fn encrypted_fixture_aesv3(r: i64) -> Vec<u8> {
2170 encrypted_fixture_aesv3_with(r, b"", b"")
2171 }
2172
2173 fn encrypted_fixture_aesv3_with(r: i64, user_pw: &[u8], owner_pw: &[u8]) -> Vec<u8> {
2174 encrypted_fixture_aesv3_with_metadata(r, user_pw, owner_pw, true, None)
2175 }
2176
2177 fn encrypted_fixture_aesv3_with_metadata(
2183 r: i64,
2184 user_pw: &[u8],
2185 owner_pw: &[u8],
2186 encrypt_metadata: bool,
2187 metadata: Option<&[u8]>,
2188 ) -> Vec<u8> {
2189 use pdfboss_testkit::PdfBuilder;
2190 let key: Vec<u8> = (0u8..32).map(|i| i ^ 0x5a).collect(); let vsalt: [u8; 8] = [1, 2, 3, 4, 5, 6, 7, 8];
2192 let ksalt: [u8; 8] = [9, 10, 11, 12, 13, 14, 15, 16];
2193 let mut u = hash_2b(r, user_pw, &vsalt, &[]); u.extend_from_slice(&vsalt);
2195 u.extend_from_slice(&ksalt);
2196 let intermediate = hash_2b(r, user_pw, &ksalt, &[]);
2197 let ue = aes_cbc_encrypt_blocks(&intermediate, &[0u8; 16], &key);
2198 let ovsalt: [u8; 8] = [21, 22, 23, 24, 25, 26, 27, 28];
2200 let oksalt: [u8; 8] = [31, 32, 33, 34, 35, 36, 37, 38];
2201 let mut o = hash_2b(r, owner_pw, &ovsalt, &u[..48]);
2202 o.extend_from_slice(&ovsalt);
2203 o.extend_from_slice(&oksalt);
2204 let ointermediate = hash_2b(r, owner_pw, &oksalt, &u[..48]);
2205 let oe = aes_cbc_encrypt_blocks(&ointermediate, &[0u8; 16], &key);
2206 let iv = [0x22u8; 16];
2207 let msg = aes_encrypt_pdf(&key, b"AES-256 secret", &iv);
2208 let stream = aes_encrypt_pdf(&key, b"AES-256 stream body", &iv);
2209
2210 let mut b = PdfBuilder::new().version(1, 7);
2211 let catalog = match metadata {
2212 Some(_) => "<< /Type /Catalog /Pages 2 0 R /Metadata 5 0 R >>",
2213 None => "<< /Type /Catalog /Pages 2 0 R >>",
2214 };
2215 b.object(1, catalog);
2216 b.object(2, "<< /Type /Pages /Kids [] /Count 0 >>");
2217 b.object(3, &format!("<< /Msg {} >>", hexstr(&msg)));
2218 b.stream(4, "", &stream);
2219 if let Some(metadata) = metadata {
2220 b.stream(5, "<< /Type /Metadata /Subtype /XML >>", metadata);
2221 }
2222 let encrypt_metadata_entry = if encrypt_metadata {
2223 ""
2224 } else {
2225 " /EncryptMetadata false"
2226 };
2227 b.object(
2228 9,
2229 &format!(
2230 "<< /Filter /Standard /V 5 /R {r} /Length 256 /P {P} /U {} /UE {} \
2231 /O {} /OE {}{encrypt_metadata_entry} \
2232 /CF << /StdCF << /CFM /AESV3 /Length 32 >> >> /StmF /StdCF /StrF /StdCF >>",
2233 hexstr(&u),
2234 hexstr(&ue),
2235 hexstr(&o),
2236 hexstr(&oe)
2237 ),
2238 );
2239 let trailer = format!("/Encrypt 9 0 R /ID [{}{}]", hexstr(ID0), hexstr(ID0));
2240 b.trailer_extra(&trailer).build(1)
2241 }
2242
2243 fn assert_aesv3_decrypts(r: i64) {
2244 use crate::object::ObjRef;
2245 use crate::Document;
2246 let doc = Document::load(encrypted_fixture_aesv3(r)).expect("AESV3 empty password opens");
2247 let obj3 = doc.get(ObjRef { num: 3, gen: 0 }).unwrap();
2248 let msg = obj3
2249 .as_dict()
2250 .unwrap()
2251 .get("Msg")
2252 .unwrap()
2253 .as_str_bytes()
2254 .unwrap();
2255 assert_eq!(msg, b"AES-256 secret", "R{r} string");
2256 let obj4 = doc.get(ObjRef { num: 4, gen: 0 }).unwrap();
2257 assert_eq!(
2258 doc.stream_data(obj4.as_stream().unwrap()).unwrap(),
2259 b"AES-256 stream body",
2260 "R{r} stream"
2261 );
2262 }
2263
2264 #[test]
2265 fn document_load_decrypts_aesv3_r5() {
2266 assert_aesv3_decrypts(5);
2267 }
2268
2269 #[test]
2270 fn document_load_decrypts_aesv3_r6() {
2271 assert_aesv3_decrypts(6); }
2273
2274 #[test]
2275 fn encrypt_metadata_false_leaves_the_metadata_stream_plaintext() {
2276 use crate::object::ObjRef;
2277 use crate::Document;
2278
2279 const XMP: &[u8] = b"<?xpacket begin='' id='W5M0MpCehiHzreSzNTczkc9d'?>\
2280 <x:xmpmeta xmlns:x='adobe:ns:meta/'><rdf:RDF \
2281 xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'><rdf:Description \
2282 xmlns:dc='http://purl.org/dc/elements/1.1/'><dc:title>XMP Secret \
2283 Title</dc:title></rdf:Description></rdf:RDF></x:xmpmeta><?xpacket end='w'?>";
2284
2285 let bytes =
2286 encrypted_fixture_aesv3_with_metadata(6, b"user-pw", b"owner-pw", false, Some(XMP));
2287 let doc = Document::load_with_password(bytes, "user-pw").expect("user password opens");
2288
2289 let obj3 = doc.get(ObjRef { num: 3, gen: 0 }).unwrap();
2290 let msg = obj3.as_dict().unwrap().get("Msg").unwrap();
2291 assert_eq!(
2292 msg.as_str_bytes().unwrap(),
2293 b"AES-256 secret",
2294 "an ordinary string still decrypts under EncryptMetadata false"
2295 );
2296
2297 let obj5 = doc.get(ObjRef { num: 5, gen: 0 }).unwrap();
2298 let metadata = doc.stream_data(obj5.as_stream().unwrap()).unwrap();
2299 assert_eq!(
2300 metadata, XMP,
2301 "the metadata stream was stored in plaintext and must not be decrypted"
2302 );
2303 }
2304
2305 #[test]
2315 fn r6_key_material_opens_under_aesv3_key() {
2316 let mut c = 0u8;
2317 let mut rng = |b: &mut [u8]| {
2318 for x in b {
2319 c = c.wrapping_add(1);
2320 *x = c;
2321 }
2322 };
2323 let material = r6_key_material(b"user-pw", b"owner-pw", P, true, &mut rng);
2324 let dict = aes256_encrypt_dict(&material, P);
2325
2326 let user_key = aesv3_key(&dict, 6, b"user-pw").expect("user password opens");
2327 assert_eq!(user_key, material.file_key.to_vec());
2328
2329 let owner_key = aesv3_key(&dict, 6, b"owner-pw").expect("owner password opens");
2330 assert_eq!(owner_key, material.file_key.to_vec());
2331
2332 assert!(aesv3_key(&dict, 6, b"wrong-pw").is_none());
2333
2334 assert!(perms_marker_valid(&material.file_key, &material.perms));
2335
2336 let mut without_perms = dict.clone();
2341 without_perms.remove("Perms");
2342 assert_eq!(
2343 aesv3_key(&without_perms, 6, b"user-pw"),
2344 Some(material.file_key.to_vec())
2345 );
2346 assert_eq!(
2347 aesv3_key(&without_perms, 6, b"owner-pw"),
2348 Some(material.file_key.to_vec())
2349 );
2350 }
2351
2352 #[test]
2355 fn permissions_all_grants_every_bit() {
2356 assert_eq!(Permissions::all().p_value(), -4);
2358 assert_eq!(Permissions::default().p_value(), -4);
2359 }
2360
2361 #[test]
2362 fn permissions_p_value_clears_exactly_its_own_bit() {
2363 let base = Permissions::all().p_value();
2364 assert_eq!(
2365 Permissions {
2366 print: false,
2367 ..Permissions::all()
2368 }
2369 .p_value(),
2370 base & !(1 << 2), );
2372 assert_eq!(
2373 Permissions {
2374 modify: false,
2375 ..Permissions::all()
2376 }
2377 .p_value(),
2378 base & !(1 << 3), );
2380 assert_eq!(
2381 Permissions {
2382 copy: false,
2383 ..Permissions::all()
2384 }
2385 .p_value(),
2386 base & !(1 << 4), );
2388 assert_eq!(
2389 Permissions {
2390 annotate: false,
2391 ..Permissions::all()
2392 }
2393 .p_value(),
2394 base & !(1 << 5), );
2396 assert_eq!(
2397 Permissions {
2398 fill_forms: false,
2399 ..Permissions::all()
2400 }
2401 .p_value(),
2402 base & !(1 << 8), );
2404 assert_eq!(
2405 Permissions {
2406 accessibility: false,
2407 ..Permissions::all()
2408 }
2409 .p_value(),
2410 base & !(1 << 9), );
2412 assert_eq!(
2413 Permissions {
2414 assemble: false,
2415 ..Permissions::all()
2416 }
2417 .p_value(),
2418 base & !(1 << 10), );
2420 assert_eq!(
2421 Permissions {
2422 print_hires: false,
2423 ..Permissions::all()
2424 }
2425 .p_value(),
2426 base & !(1 << 11), );
2428 }
2429
2430 #[allow(clippy::type_complexity, reason = "see Encryptor's rng field")]
2436 fn counter_rng() -> Box<dyn FnMut(&mut [u8]) + Send> {
2437 let mut c = 0u8;
2438 Box::new(move |buf: &mut [u8]| {
2439 for b in buf {
2440 c = c.wrapping_add(1);
2441 *b = c;
2442 }
2443 })
2444 }
2445
2446 fn decryptor_for(dict: &Dict, password: &[u8]) -> Decryptor {
2451 let key = aesv3_key(dict, 6, password).expect("password opens the produced dict");
2452 Decryptor {
2453 key,
2454 cipher: Cipher::Aesv3,
2455 encrypt_metadata: true,
2456 }
2457 }
2458
2459 #[test]
2460 fn encrypt_object_round_trips_dict_array_and_leaves_other_types_untouched() {
2461 use crate::object::ObjRef;
2462
2463 let (mut enc, dict) =
2464 Encryptor::aes256_with_rng("user-pw", "owner-pw", Permissions::all(), counter_rng());
2465
2466 let mut d = Dict::new();
2467 d.insert(
2468 Name("Msg".to_string()),
2469 Object::String(b"Top secret message".to_vec()),
2470 );
2471 d.insert(
2472 Name("List".to_string()),
2473 Object::Array(vec![
2474 Object::String(b"first".to_vec()),
2475 Object::String(b"second".to_vec()),
2476 ]),
2477 );
2478 d.insert(
2479 Name("Ref".to_string()),
2480 Object::Ref(ObjRef { num: 7, gen: 0 }),
2481 );
2482 d.insert(
2483 Name("Kind".to_string()),
2484 Object::Name(Name("Example".to_string())),
2485 );
2486 d.insert(Name("Count".to_string()), Object::Int(42));
2487 d.insert(Name("Scale".to_string()), Object::Real(1.5));
2488 d.insert(Name("On".to_string()), Object::Bool(true));
2489 d.insert(Name("Missing".to_string()), Object::Null);
2490 let original = Object::Dict(d);
2491
2492 let mut obj = original.clone();
2493 enc.encrypt_object(&mut obj, 3, 0);
2494 assert_ne!(obj, original, "encryption must change the strings");
2495
2496 let (enc_dict, orig_dict) = (obj.as_dict().unwrap(), original.as_dict().unwrap());
2499 for key in ["Ref", "Kind", "Count", "Scale", "On", "Missing"] {
2500 assert_eq!(
2501 enc_dict.get(key),
2502 orig_dict.get(key),
2503 "{key} passes through untouched"
2504 );
2505 }
2506
2507 let decryptor = decryptor_for(&dict, b"user-pw");
2508 let mut roundtripped = obj.clone();
2509 decryptor.decrypt_object(&mut roundtripped, 3, 0);
2510 assert_eq!(roundtripped, original);
2511
2512 let owner_decryptor = decryptor_for(&dict, b"owner-pw");
2514 let mut via_owner = obj;
2515 owner_decryptor.decrypt_object(&mut via_owner, 3, 0);
2516 assert_eq!(via_owner, original);
2517 }
2518
2519 #[test]
2520 fn encrypt_object_round_trips_a_stream_and_its_dict() {
2521 use crate::object::Stream;
2522
2523 let (mut enc, dict) =
2524 Encryptor::aes256_with_rng("", "owner-pw", Permissions::all(), counter_rng());
2525
2526 let mut stream_dict = Dict::new();
2527 stream_dict.insert(
2528 Name("Producer".to_string()),
2529 Object::String(b"pdfboss".to_vec()),
2530 );
2531 let original = Object::Stream(Stream {
2532 dict: stream_dict,
2533 data: b"decrypted stream body".to_vec(),
2534 });
2535 let mut obj = original.clone();
2536 enc.encrypt_object(&mut obj, 4, 0);
2537 let encrypted = obj.as_stream().unwrap();
2538 assert_ne!(encrypted.data, original.as_stream().unwrap().data);
2539 assert_ne!(
2540 encrypted.dict.get("Producer"),
2541 original.as_stream().unwrap().dict.get("Producer"),
2542 "the stream dict's own strings are encrypted too"
2543 );
2544
2545 let decryptor = decryptor_for(&dict, b"");
2546 let mut roundtripped = obj;
2547 decryptor.decrypt_object(&mut roundtripped, 4, 0);
2548 assert_eq!(roundtripped, original);
2549 }
2550
2551 #[test]
2552 fn encrypt_object_round_trips_padding_edge_lengths() {
2553 let (mut enc, dict) =
2554 Encryptor::aes256_with_rng("pw", "owner", Permissions::all(), counter_rng());
2555 let decryptor = decryptor_for(&dict, b"pw");
2556
2557 for plaintext in [Vec::new(), vec![0x41], vec![0x42; 16]] {
2558 let original = Object::String(plaintext.clone());
2559 let mut obj = original.clone();
2560 enc.encrypt_object(&mut obj, 1, 0);
2561 let mut roundtripped = obj;
2562 decryptor.decrypt_object(&mut roundtripped, 1, 0);
2563 assert_eq!(roundtripped, original, "{} bytes", plaintext.len());
2564 }
2565 }
2566}