1use crate::object::{Dict, Object};
17
18const PAD: [u8; 32] = [
20 0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08,
21 0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, 0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A,
22];
23
24#[derive(Clone, Copy, PartialEq)]
26enum Cipher {
27 Rc4,
29 Aesv2,
31 Aesv3,
33}
34
35#[derive(Clone)]
38pub struct Decryptor {
39 key: Vec<u8>,
41 cipher: Cipher,
42}
43
44impl Decryptor {
45 pub fn from_standard(enc: &Dict, id0: &[u8]) -> Option<Decryptor> {
61 if enc.get_name("Filter").map(|n| n.0.as_str()) != Some("Standard") {
62 return None;
63 }
64 let v = enc.get_int("V").unwrap_or(0);
65 let r = enc.get_int("R").unwrap_or(0);
66 match (v, r) {
67 (1 | 2, 2 | 3) => {
69 let n = if v == 1 {
70 5
71 } else {
72 (enc.get_int("Length").unwrap_or(40) / 8).clamp(5, 16) as usize
73 };
74 let key = md5_file_key(enc, id0, r, n)?;
75 let u = enc.get("U").and_then(Object::as_str_bytes)?;
76 verify_user_password(&key, r, id0, u).then_some(Decryptor {
77 key,
78 cipher: Cipher::Rc4,
79 })
80 }
81 (4, 4) => {
83 let key = md5_file_key(enc, id0, r, 16)?;
84 let u = enc.get("U").and_then(Object::as_str_bytes)?;
85 if !verify_user_password(&key, r, id0, u) {
86 return None;
87 }
88 let cipher = match crypt_filter_method(enc)?.as_str() {
89 "AESV2" => Cipher::Aesv2,
90 "V2" => Cipher::Rc4,
91 _ => return None, };
93 Some(Decryptor { key, cipher })
94 }
95 (5, 5 | 6) => aesv3_key(enc, r).map(|key| Decryptor {
97 key,
98 cipher: Cipher::Aesv3,
99 }),
100 _ => None,
101 }
102 }
103
104 pub fn decrypt_object(&self, obj: &mut Object, num: u32, gen: u16) {
121 let key = match self.cipher {
122 Cipher::Aesv3 => self.key.clone(), Cipher::Rc4 | Cipher::Aesv2 => self.object_key(num, gen),
124 };
125 decrypt_in_place(obj, &key, self.cipher);
126 }
127
128 fn object_key(&self, num: u32, gen: u16) -> Vec<u8> {
132 let mut input = Vec::with_capacity(self.key.len() + 9);
133 input.extend_from_slice(&self.key);
134 input.extend_from_slice(&num.to_le_bytes()[..3]);
135 input.extend_from_slice(&gen.to_le_bytes()[..2]);
136 if self.cipher == Cipher::Aesv2 {
137 input.extend_from_slice(b"sAlT");
138 }
139 let digest = md5(&input);
140 let n = (self.key.len() + 5).min(16);
141 digest[..n].to_vec()
142 }
143}
144
145fn decrypt_in_place(obj: &mut Object, key: &[u8], cipher: Cipher) {
148 match obj {
149 Object::String(bytes) => *bytes = decrypt_bytes(cipher, key, bytes),
150 Object::Array(items) => items
151 .iter_mut()
152 .for_each(|it| decrypt_in_place(it, key, cipher)),
153 Object::Dict(dict) => dict
154 .values_mut()
155 .for_each(|v| decrypt_in_place(v, key, cipher)),
156 Object::Stream(stream) => {
157 stream
158 .dict
159 .values_mut()
160 .for_each(|v| decrypt_in_place(v, key, cipher));
161 stream.data = decrypt_bytes(cipher, key, &stream.data);
162 }
163 _ => {}
164 }
165}
166
167fn decrypt_bytes(cipher: Cipher, key: &[u8], data: &[u8]) -> Vec<u8> {
169 match cipher {
170 Cipher::Rc4 => rc4(key, data),
171 Cipher::Aesv2 | Cipher::Aesv3 => aes_cbc_decrypt(key, data),
172 }
173}
174
175fn crypt_filter_method(enc: &Dict) -> Option<String> {
178 let stmf = enc
179 .get_name("StmF")
180 .map(|n| n.0.as_str())
181 .unwrap_or("StdCF");
182 let filter = enc.get_dict("CF")?.get_dict(stmf)?;
183 Some(filter.get_name("CFM")?.0.clone())
184}
185
186fn md5_file_key(enc: &Dict, id0: &[u8], r: i64, n: usize) -> Option<Vec<u8>> {
188 let o = enc.get("O").and_then(Object::as_str_bytes)?;
189 if o.len() < 32 {
190 return None;
191 }
192 let p = enc.get_int("P")?;
193 let mut input = Vec::with_capacity(32 + 32 + 4 + id0.len() + 4);
194 input.extend_from_slice(&PAD); input.extend_from_slice(&o[..32]);
196 input.extend_from_slice(&(p as i32 as u32).to_le_bytes()); input.extend_from_slice(id0);
198 if r >= 4 && enc.get("EncryptMetadata").and_then(Object::as_bool) == Some(false) {
200 input.extend_from_slice(&[0xFF, 0xFF, 0xFF, 0xFF]);
201 }
202 let mut digest = md5(&input);
203 if r >= 3 {
204 for _ in 0..50 {
205 digest = md5(&digest[..n]);
206 }
207 }
208 Some(digest[..n].to_vec())
209}
210
211fn verify_user_password(key: &[u8], r: i64, id0: &[u8], u: &[u8]) -> bool {
213 if r == 2 {
214 let computed = rc4(key, &PAD);
216 u.len() >= 32 && computed == u[..32]
217 } else {
218 let mut input = Vec::with_capacity(32 + id0.len());
220 input.extend_from_slice(&PAD);
221 input.extend_from_slice(id0);
222 let mut x = md5(&input).to_vec();
223 x = rc4(key, &x);
224 for i in 1u8..=19 {
225 let keyed: Vec<u8> = key.iter().map(|b| b ^ i).collect();
226 x = rc4(&keyed, &x);
227 }
228 u.len() >= 16 && x[..16] == u[..16]
230 }
231}
232
233fn rc4(key: &[u8], data: &[u8]) -> Vec<u8> {
235 debug_assert!(!key.is_empty());
236 let mut s: [u8; 256] = core::array::from_fn(|i| i as u8);
237 let mut j = 0u8;
238 for i in 0..256 {
239 j = j.wrapping_add(s[i]).wrapping_add(key[i % key.len()]);
240 s.swap(i, j as usize);
241 }
242 let mut out = Vec::with_capacity(data.len());
243 let (mut i, mut j) = (0u8, 0u8);
244 for &byte in data {
245 i = i.wrapping_add(1);
246 j = j.wrapping_add(s[i as usize]);
247 s.swap(i as usize, j as usize);
248 let k = s[s[i as usize].wrapping_add(s[j as usize]) as usize];
249 out.push(byte ^ k);
250 }
251 out
252}
253
254#[rustfmt::skip]
258const AES_SBOX: [u8; 256] = [
259 0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,
260 0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,
261 0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,
262 0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,
263 0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,
264 0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,
265 0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,
266 0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,
267 0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,
268 0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,
269 0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,
270 0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,
271 0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,
272 0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,
273 0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,
274 0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16,
275];
276
277const AES_RCON: [u8; 11] = [
279 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36,
280];
281
282fn aes_inv_sbox() -> [u8; 256] {
284 let mut inv = [0u8; 256];
285 for (i, &s) in AES_SBOX.iter().enumerate() {
286 inv[s as usize] = i as u8;
287 }
288 inv
289}
290
291fn gmul(mut a: u8, mut b: u8) -> u8 {
293 let mut p = 0u8;
294 for _ in 0..8 {
295 if b & 1 != 0 {
296 p ^= a;
297 }
298 let hi = a & 0x80;
299 a <<= 1;
300 if hi != 0 {
301 a ^= 0x1b;
302 }
303 b >>= 1;
304 }
305 p
306}
307
308fn aes_expand_key(key: &[u8]) -> Vec<[u8; 16]> {
311 let nk = key.len() / 4; let nr = nk + 6;
313 let total = 4 * (nr + 1);
314 let mut w: Vec<[u8; 4]> = Vec::with_capacity(total);
315 for i in 0..nk {
316 w.push([key[4 * i], key[4 * i + 1], key[4 * i + 2], key[4 * i + 3]]);
317 }
318 for i in nk..total {
319 let mut t = w[i - 1];
320 if i.is_multiple_of(nk) {
321 t = [t[1], t[2], t[3], t[0]]; for b in &mut t {
323 *b = AES_SBOX[*b as usize]; }
325 t[0] ^= AES_RCON[i / nk];
326 } else if nk > 6 && i % nk == 4 {
327 for b in &mut t {
328 *b = AES_SBOX[*b as usize];
329 }
330 }
331 let prev = w[i - nk];
332 w.push([
333 prev[0] ^ t[0],
334 prev[1] ^ t[1],
335 prev[2] ^ t[2],
336 prev[3] ^ t[3],
337 ]);
338 }
339 (0..=nr)
340 .map(|round| {
341 let mut rk = [0u8; 16];
342 for c in 0..4 {
343 rk[4 * c..4 * c + 4].copy_from_slice(&w[4 * round + c]);
344 }
345 rk
346 })
347 .collect()
348}
349
350fn add_round_key(s: &mut [u8; 16], rk: &[u8; 16]) {
351 for (b, k) in s.iter_mut().zip(rk) {
352 *b ^= k;
353 }
354}
355
356fn shift_rows(s: &mut [u8; 16]) {
357 let o = *s;
358 for r in 1..4 {
359 for c in 0..4 {
360 s[r + 4 * c] = o[r + 4 * ((c + r) % 4)];
361 }
362 }
363}
364
365fn inv_shift_rows(s: &mut [u8; 16]) {
366 let o = *s;
367 for r in 1..4 {
368 for c in 0..4 {
369 s[r + 4 * c] = o[r + 4 * ((c + 4 - r) % 4)];
370 }
371 }
372}
373
374fn mix_columns(s: &mut [u8; 16]) {
375 for c in 0..4 {
376 let i = 4 * c;
377 let (a0, a1, a2, a3) = (s[i], s[i + 1], s[i + 2], s[i + 3]);
378 s[i] = gmul(a0, 2) ^ gmul(a1, 3) ^ a2 ^ a3;
379 s[i + 1] = a0 ^ gmul(a1, 2) ^ gmul(a2, 3) ^ a3;
380 s[i + 2] = a0 ^ a1 ^ gmul(a2, 2) ^ gmul(a3, 3);
381 s[i + 3] = gmul(a0, 3) ^ a1 ^ a2 ^ gmul(a3, 2);
382 }
383}
384
385fn inv_mix_columns(s: &mut [u8; 16]) {
386 for c in 0..4 {
387 let i = 4 * c;
388 let (a0, a1, a2, a3) = (s[i], s[i + 1], s[i + 2], s[i + 3]);
389 s[i] = gmul(a0, 14) ^ gmul(a1, 11) ^ gmul(a2, 13) ^ gmul(a3, 9);
390 s[i + 1] = gmul(a0, 9) ^ gmul(a1, 14) ^ gmul(a2, 11) ^ gmul(a3, 13);
391 s[i + 2] = gmul(a0, 13) ^ gmul(a1, 9) ^ gmul(a2, 14) ^ gmul(a3, 11);
392 s[i + 3] = gmul(a0, 11) ^ gmul(a1, 13) ^ gmul(a2, 9) ^ gmul(a3, 14);
393 }
394}
395
396fn aes_encrypt_block(s: &mut [u8; 16], rks: &[[u8; 16]]) {
397 let nr = rks.len() - 1;
398 add_round_key(s, &rks[0]);
399 for rk in &rks[1..nr] {
400 s.iter_mut().for_each(|b| *b = AES_SBOX[*b as usize]);
401 shift_rows(s);
402 mix_columns(s);
403 add_round_key(s, rk);
404 }
405 s.iter_mut().for_each(|b| *b = AES_SBOX[*b as usize]);
406 shift_rows(s);
407 add_round_key(s, &rks[nr]);
408}
409
410fn aes_decrypt_block(s: &mut [u8; 16], rks: &[[u8; 16]], inv_sbox: &[u8; 256]) {
411 let nr = rks.len() - 1;
412 add_round_key(s, &rks[nr]);
413 for rk in rks[1..nr].iter().rev() {
414 inv_shift_rows(s);
415 s.iter_mut().for_each(|b| *b = inv_sbox[*b as usize]);
416 add_round_key(s, rk);
417 inv_mix_columns(s);
418 }
419 inv_shift_rows(s);
420 s.iter_mut().for_each(|b| *b = inv_sbox[*b as usize]);
421 add_round_key(s, &rks[0]);
422}
423
424fn aes_cbc_decrypt_blocks(key: &[u8], iv: &[u8], data: &[u8]) -> Vec<u8> {
427 if data.is_empty() || !data.len().is_multiple_of(16) || iv.len() < 16 {
428 return Vec::new();
429 }
430 let rks = aes_expand_key(key);
431 let inv_sbox = aes_inv_sbox();
432 let mut prev = [0u8; 16];
433 prev.copy_from_slice(&iv[..16]);
434 let mut out = Vec::with_capacity(data.len());
435 for chunk in data.chunks_exact(16) {
436 let mut block = [0u8; 16];
437 block.copy_from_slice(chunk);
438 let cipher = block;
439 aes_decrypt_block(&mut block, &rks, &inv_sbox);
440 for (b, p) in block.iter_mut().zip(&prev) {
441 *b ^= p;
442 }
443 out.extend_from_slice(&block);
444 prev = cipher;
445 }
446 out
447}
448
449fn aes_cbc_encrypt_blocks(key: &[u8], iv: &[u8], data: &[u8]) -> Vec<u8> {
452 let rks = aes_expand_key(key);
453 let mut prev = [0u8; 16];
454 prev.copy_from_slice(&iv[..16]);
455 let mut out = Vec::with_capacity(data.len());
456 for chunk in data.chunks_exact(16) {
457 let mut block = [0u8; 16];
458 for ((b, c), p) in block.iter_mut().zip(chunk).zip(&prev) {
459 *b = c ^ p;
460 }
461 aes_encrypt_block(&mut block, &rks);
462 out.extend_from_slice(&block);
463 prev = block;
464 }
465 out
466}
467
468fn aes_cbc_decrypt(key: &[u8], data: &[u8]) -> Vec<u8> {
472 if data.len() < 16 {
473 return Vec::new();
474 }
475 let (iv, ct) = data.split_at(16);
476 let mut out = aes_cbc_decrypt_blocks(key, iv, ct);
477 strip_pkcs7(&mut out);
478 out
479}
480
481fn strip_pkcs7(data: &mut Vec<u8>) {
483 let Some(&pad) = data.last() else {
484 return;
485 };
486 let pad = pad as usize;
487 if (1..=16).contains(&pad) && pad <= data.len() {
488 let start = data.len() - pad;
489 if data[start..].iter().all(|&b| b as usize == pad) {
490 data.truncate(start);
491 }
492 }
493}
494
495#[rustfmt::skip]
498const SHA256_K: [u32; 64] = [
499 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
500 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
501 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
502 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
503 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
504 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
505 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
506 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
507];
508
509fn sha256(input: &[u8]) -> [u8; 32] {
510 let mut h: [u32; 8] = [
511 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab,
512 0x5be0cd19,
513 ];
514 let mut msg = input.to_vec();
515 let bitlen = (input.len() as u64).wrapping_mul(8);
516 msg.push(0x80);
517 while msg.len() % 64 != 56 {
518 msg.push(0);
519 }
520 msg.extend_from_slice(&bitlen.to_be_bytes());
521
522 for chunk in msg.chunks_exact(64) {
523 let mut w = [0u32; 64];
524 for (word, bytes) in w.iter_mut().zip(chunk.chunks_exact(4)) {
525 *word = u32::from_be_bytes(bytes.try_into().unwrap());
526 }
527 for i in 16..64 {
528 let s0 = w[i - 15].rotate_right(7) ^ w[i - 15].rotate_right(18) ^ (w[i - 15] >> 3);
529 let s1 = w[i - 2].rotate_right(17) ^ w[i - 2].rotate_right(19) ^ (w[i - 2] >> 10);
530 w[i] = w[i - 16]
531 .wrapping_add(s0)
532 .wrapping_add(w[i - 7])
533 .wrapping_add(s1);
534 }
535 let [mut a, mut b, mut c, mut d, mut e, mut f, mut g, mut hh] = h;
536 for (k, wi) in SHA256_K.iter().zip(&w) {
537 let s1 = e.rotate_right(6) ^ e.rotate_right(11) ^ e.rotate_right(25);
538 let ch = (e & f) ^ ((!e) & g);
539 let t1 = hh
540 .wrapping_add(s1)
541 .wrapping_add(ch)
542 .wrapping_add(*k)
543 .wrapping_add(*wi);
544 let s0 = a.rotate_right(2) ^ a.rotate_right(13) ^ a.rotate_right(22);
545 let maj = (a & b) ^ (a & c) ^ (b & c);
546 let t2 = s0.wrapping_add(maj);
547 hh = g;
548 g = f;
549 f = e;
550 e = d.wrapping_add(t1);
551 d = c;
552 c = b;
553 b = a;
554 a = t1.wrapping_add(t2);
555 }
556 for (hv, v) in h.iter_mut().zip([a, b, c, d, e, f, g, hh]) {
557 *hv = hv.wrapping_add(v);
558 }
559 }
560
561 let mut out = [0u8; 32];
562 for (i, word) in h.iter().enumerate() {
563 out[4 * i..4 * i + 4].copy_from_slice(&word.to_be_bytes());
564 }
565 out
566}
567
568#[rustfmt::skip]
569const SHA512_K: [u64; 80] = [
570 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc,
571 0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118,
572 0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
573 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694,
574 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
575 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
576 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4,
577 0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70,
578 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
579 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
580 0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30,
581 0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
582 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8,
583 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3,
584 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
585 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b,
586 0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178,
587 0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
588 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c,
589 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817,
590];
591
592fn sha512_core(input: &[u8], mut h: [u64; 8]) -> [u64; 8] {
593 let mut msg = input.to_vec();
594 let bitlen = (input.len() as u128).wrapping_mul(8);
595 msg.push(0x80);
596 while msg.len() % 128 != 112 {
597 msg.push(0);
598 }
599 msg.extend_from_slice(&bitlen.to_be_bytes());
600
601 for chunk in msg.chunks_exact(128) {
602 let mut w = [0u64; 80];
603 for (word, bytes) in w.iter_mut().zip(chunk.chunks_exact(8)) {
604 *word = u64::from_be_bytes(bytes.try_into().unwrap());
605 }
606 for i in 16..80 {
607 let s0 = w[i - 15].rotate_right(1) ^ w[i - 15].rotate_right(8) ^ (w[i - 15] >> 7);
608 let s1 = w[i - 2].rotate_right(19) ^ w[i - 2].rotate_right(61) ^ (w[i - 2] >> 6);
609 w[i] = w[i - 16]
610 .wrapping_add(s0)
611 .wrapping_add(w[i - 7])
612 .wrapping_add(s1);
613 }
614 let [mut a, mut b, mut c, mut d, mut e, mut f, mut g, mut hh] = h;
615 for (k, wi) in SHA512_K.iter().zip(&w) {
616 let s1 = e.rotate_right(14) ^ e.rotate_right(18) ^ e.rotate_right(41);
617 let ch = (e & f) ^ ((!e) & g);
618 let t1 = hh
619 .wrapping_add(s1)
620 .wrapping_add(ch)
621 .wrapping_add(*k)
622 .wrapping_add(*wi);
623 let s0 = a.rotate_right(28) ^ a.rotate_right(34) ^ a.rotate_right(39);
624 let maj = (a & b) ^ (a & c) ^ (b & c);
625 let t2 = s0.wrapping_add(maj);
626 hh = g;
627 g = f;
628 f = e;
629 e = d.wrapping_add(t1);
630 d = c;
631 c = b;
632 b = a;
633 a = t1.wrapping_add(t2);
634 }
635 for (hv, v) in h.iter_mut().zip([a, b, c, d, e, f, g, hh]) {
636 *hv = hv.wrapping_add(v);
637 }
638 }
639 h
640}
641
642fn sha512(input: &[u8]) -> Vec<u8> {
643 let h = sha512_core(
644 input,
645 [
646 0x6a09e667f3bcc908,
647 0xbb67ae8584caa73b,
648 0x3c6ef372fe94f82b,
649 0xa54ff53a5f1d36f1,
650 0x510e527fade682d1,
651 0x9b05688c2b3e6c1f,
652 0x1f83d9abfb41bd6b,
653 0x5be0cd19137e2179,
654 ],
655 );
656 h.iter().flat_map(|w| w.to_be_bytes()).collect()
657}
658
659fn sha384(input: &[u8]) -> Vec<u8> {
660 let h = sha512_core(
661 input,
662 [
663 0xcbbb9d5dc1059ed8,
664 0x629a292a367cd507,
665 0x9159015a3070dd17,
666 0x152fecd8f70e5939,
667 0x67332667ffc00b31,
668 0x8eb44a8768581511,
669 0xdb0c2e0d64f98fa7,
670 0x47b5481dbefa4fa4,
671 ],
672 );
673 h.iter().take(6).flat_map(|w| w.to_be_bytes()).collect()
674}
675
676fn aesv3_key(enc: &Dict, r: i64) -> Option<Vec<u8>> {
679 let u = enc.get("U").and_then(Object::as_str_bytes)?;
680 let ue = enc.get("UE").and_then(Object::as_str_bytes)?;
681 if u.len() < 48 || ue.len() < 32 {
682 return None;
683 }
684 let validation_salt = &u[32..40];
685 let key_salt = &u[40..48];
686 let pw: &[u8] = b""; if hash_2b(r, pw, validation_salt, &[])[..32] != u[..32] {
688 return None; }
690 let intermediate = hash_2b(r, pw, key_salt, &[]);
691 let file_key = aes_cbc_decrypt_blocks(&intermediate, &[0u8; 16], &ue[..32]);
692 (file_key.len() == 32).then_some(file_key)
693}
694
695fn hash_2b(r: i64, password: &[u8], salt: &[u8], udata: &[u8]) -> Vec<u8> {
698 let mut seed = Vec::with_capacity(password.len() + salt.len() + udata.len());
699 seed.extend_from_slice(password);
700 seed.extend_from_slice(salt);
701 seed.extend_from_slice(udata);
702 let mut k = sha256(&seed).to_vec();
703 if r < 6 {
704 return k; }
706 let mut round = 0usize;
707 loop {
708 let mut k1 = Vec::with_capacity(64 * (password.len() + k.len() + udata.len()));
709 for _ in 0..64 {
710 k1.extend_from_slice(password);
711 k1.extend_from_slice(&k);
712 k1.extend_from_slice(udata);
713 }
714 let e = aes_cbc_encrypt_blocks(&k[..16], &k[16..32], &k1);
715 let modulus = e[..16].iter().map(|&b| u32::from(b)).sum::<u32>() % 3;
716 k = match modulus {
717 0 => sha256(&e).to_vec(),
718 1 => sha384(&e),
719 _ => sha512(&e),
720 };
721 round += 1;
722 if round >= 64 && usize::from(*e.last().unwrap()) <= round - 32 {
723 break;
724 }
725 }
726 k.truncate(32);
727 k
728}
729
730#[rustfmt::skip]
732const MD5_S: [u32; 64] = [
733 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
734 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
735 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
736 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21,
737];
738
739#[rustfmt::skip]
741const MD5_K: [u32; 64] = [
742 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
743 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
744 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
745 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
746 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
747 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
748 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
749 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391,
750];
751
752fn md5(input: &[u8]) -> [u8; 16] {
755 let (mut a0, mut b0, mut c0, mut d0) = (
756 0x6745_2301u32,
757 0xefcd_ab89u32,
758 0x98ba_dcfeu32,
759 0x1032_5476u32,
760 );
761
762 let mut msg = input.to_vec();
763 let bitlen = (input.len() as u64).wrapping_mul(8);
764 msg.push(0x80);
765 while msg.len() % 64 != 56 {
766 msg.push(0);
767 }
768 msg.extend_from_slice(&bitlen.to_le_bytes());
769
770 for chunk in msg.chunks_exact(64) {
771 let mut m = [0u32; 16];
772 for (word, bytes) in m.iter_mut().zip(chunk.chunks_exact(4)) {
773 *word = u32::from_le_bytes(bytes.try_into().unwrap());
774 }
775 let (mut a, mut b, mut c, mut d) = (a0, b0, c0, d0);
776 for i in 0..64 {
777 let (f, g) = match i {
778 0..=15 => ((b & c) | (!b & d), i),
779 16..=31 => ((d & b) | (!d & c), (5 * i + 1) % 16),
780 32..=47 => (b ^ c ^ d, (3 * i + 5) % 16),
781 _ => (c ^ (b | !d), (7 * i) % 16),
782 };
783 let f = f.wrapping_add(a).wrapping_add(MD5_K[i]).wrapping_add(m[g]);
784 a = d;
785 d = c;
786 c = b;
787 b = b.wrapping_add(f.rotate_left(MD5_S[i]));
788 }
789 a0 = a0.wrapping_add(a);
790 b0 = b0.wrapping_add(b);
791 c0 = c0.wrapping_add(c);
792 d0 = d0.wrapping_add(d);
793 }
794
795 let mut out = [0u8; 16];
796 out[0..4].copy_from_slice(&a0.to_le_bytes());
797 out[4..8].copy_from_slice(&b0.to_le_bytes());
798 out[8..12].copy_from_slice(&c0.to_le_bytes());
799 out[12..16].copy_from_slice(&d0.to_le_bytes());
800 out
801}
802
803#[cfg(test)]
804mod tests {
805 use super::*;
806 use crate::object::Name;
807
808 fn hex(bytes: &[u8]) -> String {
809 bytes.iter().map(|b| format!("{b:02x}")).collect()
810 }
811
812 #[test]
813 fn md5_known_vectors() {
814 assert_eq!(hex(&md5(b"")), "d41d8cd98f00b204e9800998ecf8427e");
815 assert_eq!(hex(&md5(b"abc")), "900150983cd24fb0d6963f7d28e17f72");
816 assert_eq!(
817 hex(&md5(b"The quick brown fox jumps over the lazy dog")),
818 "9e107d9d372bb6826bd81d3542a419d6"
819 );
820 }
821
822 #[test]
823 fn md5_spans_block_boundary() {
824 let input = [b'a'; 56];
826 assert_eq!(hex(&md5(&input)), "3b0c8ac703f828b04c6c197006d17218");
827 }
828
829 #[test]
830 fn rc4_known_vector() {
831 let ct = rc4(b"Key", b"Plaintext");
833 assert_eq!(hex(&ct), "bbf316e8d940af0ad3");
834 assert_eq!(rc4(b"Key", &ct), b"Plaintext");
836 }
837
838 const N: usize = 16; const P: i32 = -44;
843 const ID0: &[u8] = b"0123456789abcdef";
844
845 fn owner_entry() -> Vec<u8> {
847 let mut d = md5(&PAD);
848 for _ in 0..50 {
849 d = md5(&d[..N]);
850 }
851 let rc4key = d[..N].to_vec();
852 let mut o = rc4(&rc4key, &PAD);
853 for i in 1u8..=19 {
854 let k: Vec<u8> = rc4key.iter().map(|b| b ^ i).collect();
855 o = rc4(&k, &o);
856 }
857 o
858 }
859
860 fn file_key(o: &[u8]) -> Vec<u8> {
862 let mut input = Vec::new();
863 input.extend_from_slice(&PAD);
864 input.extend_from_slice(o);
865 input.extend_from_slice(&(P as u32).to_le_bytes());
866 input.extend_from_slice(ID0);
867 let mut d = md5(&input);
868 for _ in 0..50 {
869 d = md5(&d[..N]);
870 }
871 d[..N].to_vec()
872 }
873
874 fn user_entry(key: &[u8]) -> Vec<u8> {
876 let mut input = Vec::new();
877 input.extend_from_slice(&PAD);
878 input.extend_from_slice(ID0);
879 let mut x = md5(&input).to_vec();
880 x = rc4(key, &x);
881 for i in 1u8..=19 {
882 let k: Vec<u8> = key.iter().map(|b| b ^ i).collect();
883 x = rc4(&k, &x);
884 }
885 x.resize(32, 0); x
887 }
888
889 fn obj_key(key: &[u8], num: u32, gen: u16) -> Vec<u8> {
890 let mut input = key.to_vec();
891 input.extend_from_slice(&num.to_le_bytes()[..3]);
892 input.extend_from_slice(&gen.to_le_bytes()[..2]);
893 md5(&input)[..(key.len() + 5).min(16)].to_vec()
894 }
895
896 fn hexstr(b: &[u8]) -> String {
897 let mut s = String::from("<");
898 for x in b {
899 s.push_str(&format!("{x:02x}"));
900 }
901 s.push('>');
902 s
903 }
904
905 fn encrypted_fixture(u_override: Option<Vec<u8>>) -> Vec<u8> {
906 use pdfboss_testkit::PdfBuilder;
907 let o = owner_entry();
908 let key = file_key(&o);
909 let u = u_override.unwrap_or_else(|| user_entry(&key));
910
911 let msg = rc4(&obj_key(&key, 3, 0), b"Top secret message");
912 let stream = rc4(&obj_key(&key, 4, 0), b"decrypted stream body");
913
914 let mut b = PdfBuilder::new().version(1, 4);
915 b.object(1, "<< /Type /Catalog /Pages 2 0 R >>");
916 b.object(2, "<< /Type /Pages /Kids [] /Count 0 >>");
917 b.object(3, &format!("<< /Msg {} >>", hexstr(&msg)));
918 b.stream(4, "", &stream);
919 b.object(
920 9,
921 &format!(
922 "<< /Filter /Standard /V 2 /R 3 /Length 128 /P {P} /O {} /U {} >>",
923 hexstr(&o),
924 hexstr(&u)
925 ),
926 );
927 let trailer = format!("/Encrypt 9 0 R /ID [{}{}]", hexstr(ID0), hexstr(ID0));
928 b.trailer_extra(&trailer).build(1)
929 }
930
931 #[test]
932 fn document_load_decrypts_standard_rc4() {
933 use crate::object::ObjRef;
934 use crate::Document;
935
936 let doc = Document::load(encrypted_fixture(None)).expect("empty password opens the file");
937
938 let obj3 = doc.get(ObjRef { num: 3, gen: 0 }).unwrap();
939 let msg = obj3
940 .as_dict()
941 .unwrap()
942 .get("Msg")
943 .unwrap()
944 .as_str_bytes()
945 .unwrap();
946 assert_eq!(msg, b"Top secret message", "string decrypted");
947
948 let obj4 = doc.get(ObjRef { num: 4, gen: 0 }).unwrap();
949 let data = doc.stream_data(obj4.as_stream().unwrap()).unwrap();
950 assert_eq!(data, b"decrypted stream body", "stream decrypted");
951 }
952
953 #[test]
954 fn document_load_rejects_when_password_does_not_verify() {
955 use crate::error::Error;
956 use crate::Document;
957
958 let bad_u = vec![0u8; 32];
961 let err = Document::load(encrypted_fixture(Some(bad_u)));
962 assert!(matches!(err, Err(Error::Encrypted)));
963 }
964
965 #[test]
966 fn unsupported_handler_is_declined() {
967 let mut enc = Dict::new();
970 enc.insert(Name("Filter".into()), Object::Name(Name("Standard".into())));
971 enc.insert(Name("V".into()), Object::Int(6));
972 enc.insert(Name("R".into()), Object::Int(7));
973 enc.insert(Name("O".into()), Object::String(vec![0; 48]));
974 enc.insert(Name("U".into()), Object::String(vec![0; 48]));
975 enc.insert(Name("P".into()), Object::Int(-4));
976 assert!(Decryptor::from_standard(&enc, ID0).is_none());
977 }
978
979 #[test]
982 fn aes_fips197_block_vectors() {
983 let pt: [u8; 16] = [
985 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
986 0xee, 0xff,
987 ];
988 let key128: Vec<u8> = (0u8..16).collect();
989 let rks = aes_expand_key(&key128);
990 let mut b = pt;
991 aes_encrypt_block(&mut b, &rks);
992 assert_eq!(hex(&b), "69c4e0d86a7b0430d8cdb78070b4c55a");
993 aes_decrypt_block(&mut b, &rks, &aes_inv_sbox());
994 assert_eq!(b, pt, "AES-128 decrypt inverts encrypt");
995
996 let key256: Vec<u8> = (0u8..32).collect();
997 let rks = aes_expand_key(&key256);
998 let mut b = pt;
999 aes_encrypt_block(&mut b, &rks);
1000 assert_eq!(hex(&b), "8ea2b7ca516745bfeafc49904b496089");
1001 }
1002
1003 #[test]
1004 fn sha2_vectors() {
1005 assert_eq!(
1006 hex(&sha256(b"abc")),
1007 "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
1008 );
1009 assert_eq!(
1010 hex(&sha512(b"abc")),
1011 "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a\
1012 2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"
1013 );
1014 assert_eq!(
1015 hex(&sha384(b"abc")),
1016 "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed\
1017 8086072ba1e7cc2358baeca134c825a7"
1018 );
1019 }
1020
1021 fn pkcs7_pad(data: &[u8]) -> Vec<u8> {
1022 let pad = 16 - (data.len() % 16); let mut v = data.to_vec();
1024 v.resize(data.len() + pad, pad as u8);
1025 v
1026 }
1027
1028 #[test]
1029 fn aes_cbc_roundtrip() {
1030 let key: Vec<u8> = (0u8..16).collect();
1031 let iv = [0x24u8; 16];
1032 let pt = b"a message spanning several AES blocks exactly?!!";
1033 let ct = aes_cbc_encrypt_blocks(&key, &iv, &pkcs7_pad(pt));
1034 let mut val = iv.to_vec(); val.extend_from_slice(&ct);
1036 assert_eq!(aes_cbc_decrypt(&key, &val), pt);
1037 }
1038
1039 fn obj_key_aes(key: &[u8], num: u32, gen: u16) -> Vec<u8> {
1042 let mut input = key.to_vec();
1043 input.extend_from_slice(&num.to_le_bytes()[..3]);
1044 input.extend_from_slice(&gen.to_le_bytes()[..2]);
1045 input.extend_from_slice(b"sAlT");
1046 md5(&input)[..(key.len() + 5).min(16)].to_vec()
1047 }
1048
1049 fn aes_encrypt_pdf(key: &[u8], pt: &[u8], iv: &[u8; 16]) -> Vec<u8> {
1052 let mut out = iv.to_vec();
1053 out.extend_from_slice(&aes_cbc_encrypt_blocks(key, iv, &pkcs7_pad(pt)));
1054 out
1055 }
1056
1057 fn encrypted_fixture_aesv2() -> Vec<u8> {
1058 use pdfboss_testkit::PdfBuilder;
1059 let o = owner_entry();
1060 let key = file_key(&o); let u = user_entry(&key);
1062 let iv = [0x11u8; 16];
1063 let msg = aes_encrypt_pdf(&obj_key_aes(&key, 3, 0), b"Top secret message", &iv);
1064 let stream = aes_encrypt_pdf(&obj_key_aes(&key, 4, 0), b"decrypted stream body", &iv);
1065
1066 let mut b = PdfBuilder::new().version(1, 5);
1067 b.object(1, "<< /Type /Catalog /Pages 2 0 R >>");
1068 b.object(2, "<< /Type /Pages /Kids [] /Count 0 >>");
1069 b.object(3, &format!("<< /Msg {} >>", hexstr(&msg)));
1070 b.stream(4, "", &stream);
1071 b.object(
1072 9,
1073 &format!(
1074 "<< /Filter /Standard /V 4 /R 4 /Length 128 /P {P} /O {} /U {} \
1075 /CF << /StdCF << /CFM /AESV2 /Length 16 >> >> /StmF /StdCF /StrF /StdCF >>",
1076 hexstr(&o),
1077 hexstr(&u)
1078 ),
1079 );
1080 let trailer = format!("/Encrypt 9 0 R /ID [{}{}]", hexstr(ID0), hexstr(ID0));
1081 b.trailer_extra(&trailer).build(1)
1082 }
1083
1084 #[test]
1085 fn document_load_decrypts_aesv2() {
1086 use crate::object::ObjRef;
1087 use crate::Document;
1088 let doc = Document::load(encrypted_fixture_aesv2()).expect("AESV2 empty password opens");
1089 let obj3 = doc.get(ObjRef { num: 3, gen: 0 }).unwrap();
1090 let msg = obj3
1091 .as_dict()
1092 .unwrap()
1093 .get("Msg")
1094 .unwrap()
1095 .as_str_bytes()
1096 .unwrap();
1097 assert_eq!(msg, b"Top secret message");
1098 let obj4 = doc.get(ObjRef { num: 4, gen: 0 }).unwrap();
1099 assert_eq!(
1100 doc.stream_data(obj4.as_stream().unwrap()).unwrap(),
1101 b"decrypted stream body"
1102 );
1103 }
1104
1105 fn encrypted_fixture_aesv3(r: i64) -> Vec<u8> {
1108 use pdfboss_testkit::PdfBuilder;
1109 let key: Vec<u8> = (0u8..32).map(|i| i ^ 0x5a).collect(); let vsalt: [u8; 8] = [1, 2, 3, 4, 5, 6, 7, 8];
1111 let ksalt: [u8; 8] = [9, 10, 11, 12, 13, 14, 15, 16];
1112 let mut u = hash_2b(r, b"", &vsalt, &[]); u.extend_from_slice(&vsalt);
1114 u.extend_from_slice(&ksalt);
1115 let intermediate = hash_2b(r, b"", &ksalt, &[]);
1116 let ue = aes_cbc_encrypt_blocks(&intermediate, &[0u8; 16], &key);
1117 let iv = [0x22u8; 16];
1118 let msg = aes_encrypt_pdf(&key, b"AES-256 secret", &iv);
1119 let stream = aes_encrypt_pdf(&key, b"AES-256 stream body", &iv);
1120
1121 let mut b = PdfBuilder::new().version(1, 7);
1122 b.object(1, "<< /Type /Catalog /Pages 2 0 R >>");
1123 b.object(2, "<< /Type /Pages /Kids [] /Count 0 >>");
1124 b.object(3, &format!("<< /Msg {} >>", hexstr(&msg)));
1125 b.stream(4, "", &stream);
1126 b.object(
1127 9,
1128 &format!(
1129 "<< /Filter /Standard /V 5 /R {r} /Length 256 /P {P} /U {} /UE {} \
1130 /O {} /OE {} \
1131 /CF << /StdCF << /CFM /AESV3 /Length 32 >> >> /StmF /StdCF /StrF /StdCF >>",
1132 hexstr(&u),
1133 hexstr(&ue),
1134 hexstr(&[0u8; 48]),
1135 hexstr(&[0u8; 32])
1136 ),
1137 );
1138 let trailer = format!("/Encrypt 9 0 R /ID [{}{}]", hexstr(ID0), hexstr(ID0));
1139 b.trailer_extra(&trailer).build(1)
1140 }
1141
1142 fn assert_aesv3_decrypts(r: i64) {
1143 use crate::object::ObjRef;
1144 use crate::Document;
1145 let doc = Document::load(encrypted_fixture_aesv3(r)).expect("AESV3 empty password opens");
1146 let obj3 = doc.get(ObjRef { num: 3, gen: 0 }).unwrap();
1147 let msg = obj3
1148 .as_dict()
1149 .unwrap()
1150 .get("Msg")
1151 .unwrap()
1152 .as_str_bytes()
1153 .unwrap();
1154 assert_eq!(msg, b"AES-256 secret", "R{r} string");
1155 let obj4 = doc.get(ObjRef { num: 4, gen: 0 }).unwrap();
1156 assert_eq!(
1157 doc.stream_data(obj4.as_stream().unwrap()).unwrap(),
1158 b"AES-256 stream body",
1159 "R{r} stream"
1160 );
1161 }
1162
1163 #[test]
1164 fn document_load_decrypts_aesv3_r5() {
1165 assert_aesv3_decrypts(5);
1166 }
1167
1168 #[test]
1169 fn document_load_decrypts_aesv3_r6() {
1170 assert_aesv3_decrypts(6); }
1172}