1use aes::cipher::{BlockDecryptMut, BlockEncryptMut, KeyIvInit, block_padding::NoPadding};
8use md5::{Digest, Md5};
9use rc4::{KeyInit, Rc4, StreamCipher, consts};
10use sha2::{Sha256, Sha384, Sha512};
11
12use crate::error::{Error, Result};
13use crate::object::{Dict, Name, ObjId, Object, PdfString};
14
15const PAD: [u8; 32] = [
17 0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41, 0x64, 0x00, 0x4e, 0x56, 0xff, 0xfa, 0x01, 0x08,
18 0x2e, 0x2e, 0x00, 0xb6, 0xd0, 0x68, 0x3e, 0x80, 0x2f, 0x0c, 0xa9, 0xfe, 0x64, 0x53, 0x69, 0x7a,
19];
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
23pub enum CryptMethod {
24 Identity,
26 Rc4,
28 AesV2,
30 AesV3,
32}
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
36pub enum Authentication {
37 None,
41 User,
43 Owner,
45}
46
47#[derive(Debug, Clone)]
49pub struct SecurityHandler {
50 revision: i64,
51 key: Vec<u8>,
52 strings: CryptMethod,
53 streams: CryptMethod,
54 embedded_files: CryptMethod,
55 encrypt_metadata: bool,
56 permissions: u32,
57 authentication: Authentication,
58}
59
60impl SecurityHandler {
61 pub fn new(encrypt: &Dict, id0: &[u8], password: &[u8]) -> Result<Self> {
65 let filter = encrypt.get_name(b"Filter").unwrap_or(b"Standard");
66 if filter != b"Standard" {
67 return Err(Error::UnsupportedEncryption(format!(
68 "security handler /{}",
69 String::from_utf8_lossy(filter)
70 )));
71 }
72 let v = encrypt.get_int(b"V").unwrap_or(0);
73 let r = encrypt.get_int(b"R").unwrap_or(0);
74 if !(2..=6).contains(&r) {
75 return Err(Error::UnsupportedEncryption(format!("revision {r}")));
76 }
77 let o = encrypt
78 .get(b"O")
79 .and_then(Object::as_string)
80 .unwrap_or_default();
81 let u = encrypt
82 .get(b"U")
83 .and_then(Object::as_string)
84 .unwrap_or_default();
85 let p = encrypt.get_int(b"P").unwrap_or(0) as i32;
87 let encrypt_metadata = encrypt
88 .get(b"EncryptMetadata")
89 .and_then(Object::as_bool)
90 .unwrap_or(true);
91
92 let (strings, streams, embedded_files) = crypt_methods(encrypt, v)?;
93 let mut handler = Self {
94 revision: r,
95 key: Vec::new(),
96 strings,
97 streams,
98 embedded_files,
99 encrypt_metadata,
100 permissions: p as u32,
101 authentication: Authentication::User,
102 };
103
104 if let Some((key, auth)) =
105 authenticate(encrypt, id0, password, v, r, o, u, p, encrypt_metadata)
106 {
107 handler.key = key;
108 handler.authentication = auth;
109 return Ok(handler);
110 }
111 if strings == CryptMethod::Identity && streams == CryptMethod::Identity {
114 handler.authentication = Authentication::None;
115 return Ok(handler);
116 }
117 Err(Error::InvalidPassword)
118 }
119
120 pub fn permissions(&self) -> u32 {
122 self.permissions
123 }
124
125 pub fn is_authenticated(&self) -> bool {
127 self.authentication != Authentication::None
128 }
129
130 pub fn authentication(&self) -> Authentication {
132 self.authentication
133 }
134
135 pub fn revision(&self) -> i64 {
137 self.revision
138 }
139
140 pub fn encrypt_metadata(&self) -> bool {
142 self.encrypt_metadata
143 }
144
145 pub fn string_method(&self) -> CryptMethod {
147 self.strings
148 }
149
150 pub fn stream_method(&self) -> CryptMethod {
152 self.streams
153 }
154
155 pub fn embedded_file_method(&self) -> CryptMethod {
157 self.embedded_files
158 }
159
160 pub fn decrypt(&self, id: ObjId, method: CryptMethod, data: &[u8]) -> Vec<u8> {
162 if !self.is_authenticated() {
163 return data.to_vec();
164 }
165 match method {
166 CryptMethod::Identity => data.to_vec(),
167 CryptMethod::Rc4 => {
168 let mut out = data.to_vec();
169 rc4(&self.object_key(id, false), &mut out);
170 out
171 }
172 CryptMethod::AesV2 => aes_cbc_decrypt(&self.object_key(id, true), data),
173 CryptMethod::AesV3 => aes_cbc_decrypt(&self.key, data),
174 }
175 }
176
177 pub fn decrypt_strings(&self, id: ObjId, object: &mut Object) {
180 match object {
181 Object::String(s) => s.bytes = self.decrypt(id, self.strings, &s.bytes),
182 Object::Array(items) => {
183 for item in items {
184 self.decrypt_strings(id, item);
185 }
186 }
187 Object::Dict(d) => self.decrypt_dict_strings(id, d),
188 Object::Stream(s) => self.decrypt_dict_strings(id, &mut s.dict),
189 _ => {}
190 }
191 }
192
193 fn decrypt_dict_strings(&self, id: ObjId, dict: &mut Dict) {
194 let is_signature = dict.is_type(b"Sig")
196 || dict.is_type(b"DocTimeStamp")
197 || dict.contains_key(b"ByteRange");
198 let keys: Vec<_> = dict.iter().map(|(k, _)| k.clone()).collect();
199 for key in keys {
200 if is_signature && key.as_bytes() == b"Contents" {
201 continue;
202 }
203 if let Some(mut value) = dict.remove(key.as_bytes()) {
204 self.decrypt_strings(id, &mut value);
205 dict.insert(key, value);
206 }
207 }
208 }
209
210 fn object_key(&self, id: ObjId, aes: bool) -> Vec<u8> {
212 let mut h = Md5::new();
213 h.update(&self.key);
214 h.update(&id.num.to_le_bytes()[..3]);
215 h.update(id.generation.to_le_bytes());
216 if aes {
217 h.update(b"sAlT");
218 }
219 let digest = h.finalize();
220 let n = (self.key.len() + 5).min(16);
221 digest.get(..n).unwrap_or_default().to_vec()
222 }
223}
224
225#[allow(clippy::too_many_arguments)]
227fn authenticate(
228 encrypt: &Dict,
229 id0: &[u8],
230 password: &[u8],
231 v: i64,
232 r: i64,
233 o: &[u8],
234 u: &[u8],
235 p: i32,
236 encrypt_metadata: bool,
237) -> Option<(Vec<u8>, Authentication)> {
238 let candidates = password_candidates(password, r);
239 if r >= 5 {
240 let oe = encrypt
241 .get(b"OE")
242 .and_then(Object::as_string)
243 .unwrap_or_default();
244 let ue = encrypt
245 .get(b"UE")
246 .and_then(Object::as_string)
247 .unwrap_or_default();
248 return candidates.iter().find_map(|pw| {
249 let pw = pw.get(..pw.len().min(127)).unwrap_or_default();
250 aes256_key(r, pw, o, u, oe, ue)
251 });
252 }
253 let length_bits = if v == 1 {
254 40
255 } else {
256 encrypt.get_int(b"Length").unwrap_or(40)
257 };
258 let length_bits = if length_bits <= 16 {
260 length_bits * 8
261 } else {
262 length_bits
263 };
264 let n = if r == 2 {
265 5
266 } else {
267 (length_bits / 8).clamp(5, 16) as usize
268 };
269 let user_key = |pw: &[u8]| compute_key(pw, o, p, id0, r, n, encrypt_metadata);
270 candidates.iter().find_map(|pw| {
271 let key = user_key(pw);
272 if check_user_key(&key, u, id0, r) {
273 return Some((key, Authentication::User));
274 }
275 let key = user_key(&owner_to_user_password(pw, o, r, n));
277 check_user_key(&key, u, id0, r).then_some((key, Authentication::Owner))
278 })
279}
280
281fn password_candidates(password: &[u8], r: i64) -> Vec<Vec<u8>> {
289 let mut out = vec![password.to_vec()];
290 let Ok(text) = std::str::from_utf8(password) else {
291 return out;
292 };
293 let variant: Option<Vec<u8>> = if r <= 4 {
294 text.chars()
295 .map(|c| u8::try_from(u32::from(c)).ok())
296 .collect::<Option<Vec<u8>>>()
297 } else {
298 let prepped: String = text
299 .chars()
300 .filter(|c| !is_mapped_to_nothing(*c))
301 .map(|c| {
302 if c != ' ' && c.is_whitespace() {
303 ' '
304 } else {
305 c
306 }
307 })
308 .collect();
309 Some(prepped.into_bytes())
310 };
311 if let Some(v) = variant
312 && v != password
313 {
314 out.push(v);
315 }
316 out
317}
318
319fn is_mapped_to_nothing(c: char) -> bool {
321 matches!(
322 c,
323 '\u{ad}'
324 | '\u{34f}'
325 | '\u{1806}'
326 | '\u{180b}'..='\u{180d}'
327 | '\u{200b}'..='\u{200d}'
328 | '\u{2060}'
329 | '\u{fe00}'..='\u{fe0f}'
330 | '\u{feff}'
331 )
332}
333
334fn crypt_methods(encrypt: &Dict, v: i64) -> Result<(CryptMethod, CryptMethod, CryptMethod)> {
337 match v {
338 1..=3 => Ok((CryptMethod::Rc4, CryptMethod::Rc4, CryptMethod::Rc4)),
339 4 | 5 => {
340 let cf = encrypt.get_dict(b"CF");
341 let method = |key: &[u8]| -> Result<CryptMethod> {
342 let name = encrypt.get_name(key).unwrap_or(b"Identity");
343 if name == b"Identity" {
344 return Ok(CryptMethod::Identity);
345 }
346 let filter = cf.and_then(|cf| cf.get_dict(name));
347 match filter.and_then(|f| f.get_name(b"CFM")) {
348 Some(b"V2") => Ok(CryptMethod::Rc4),
349 Some(b"AESV2") => Ok(CryptMethod::AesV2),
350 Some(b"AESV3") => Ok(CryptMethod::AesV3),
351 Some(b"None") => Ok(CryptMethod::Identity),
352 None if v == 5 => Ok(CryptMethod::AesV3),
355 None => Ok(CryptMethod::AesV2),
356 Some(other) => Err(Error::UnsupportedEncryption(format!(
357 "crypt filter method /{}",
358 String::from_utf8_lossy(other)
359 ))),
360 }
361 };
362 let strings = method(b"StrF")?;
363 let streams = method(b"StmF")?;
364 let embedded = if encrypt.contains_key(b"EFF") {
365 method(b"EFF")?
366 } else {
367 streams
368 };
369 Ok((strings, streams, embedded))
370 }
371 other => Err(Error::UnsupportedEncryption(format!("algorithm V {other}"))),
372 }
373}
374
375fn padded(password: &[u8]) -> [u8; 32] {
376 let mut out = PAD;
377 let n = password.len().min(32);
378 if let (Some(dst), Some(src)) = (out.get_mut(..n), password.get(..n)) {
379 dst.copy_from_slice(src);
380 }
381 if let (Some(dst), Some(src)) = (out.get_mut(n..), PAD.get(..32 - n)) {
382 dst.copy_from_slice(src);
383 }
384 out
385}
386
387fn compute_key(
389 password: &[u8],
390 o: &[u8],
391 p: i32,
392 id0: &[u8],
393 r: i64,
394 n: usize,
395 encrypt_metadata: bool,
396) -> Vec<u8> {
397 let mut h = Md5::new();
398 h.update(padded(password));
399 h.update(o.get(..32).unwrap_or(o));
400 h.update(p.to_le_bytes());
401 h.update(id0);
402 if r >= 4 && !encrypt_metadata {
403 h.update([0xff; 4]);
404 }
405 let mut digest = h.finalize().to_vec();
406 if r >= 3 {
407 for _ in 0..50 {
408 digest = Md5::digest(digest.get(..n).unwrap_or_default()).to_vec();
409 }
410 }
411 digest.truncate(n);
412 digest
413}
414
415fn check_user_key(key: &[u8], u: &[u8], id0: &[u8], r: i64) -> bool {
417 if r == 2 {
418 let mut out = PAD.to_vec();
419 rc4(key, &mut out);
420 return u.get(..32) == Some(&out[..]);
421 }
422 let mut h = Md5::new();
423 h.update(PAD);
424 h.update(id0);
425 let mut out = h.finalize().to_vec();
426 for i in 0..20u8 {
427 let k: Vec<u8> = key.iter().map(|b| b ^ i).collect();
428 rc4(&k, &mut out);
429 }
430 u.get(..16) == out.get(..16)
431}
432
433fn owner_to_user_password(owner: &[u8], o: &[u8], r: i64, n: usize) -> Vec<u8> {
435 let mut digest = Md5::digest(padded(owner)).to_vec();
436 if r >= 3 {
437 for _ in 0..50 {
438 digest = Md5::digest(&digest).to_vec();
439 }
440 }
441 digest.truncate(n);
442 let mut out = o.get(..32).unwrap_or(o).to_vec();
443 if r == 2 {
444 rc4(&digest, &mut out);
445 } else {
446 for i in (0..20u8).rev() {
447 let k: Vec<u8> = digest.iter().map(|b| b ^ i).collect();
448 rc4(&k, &mut out);
449 }
450 }
451 out
452}
453
454fn aes256_key(
457 r: i64,
458 pw: &[u8],
459 o: &[u8],
460 u: &[u8],
461 oe: &[u8],
462 ue: &[u8],
463) -> Option<(Vec<u8>, Authentication)> {
464 let (o, u) = (o.get(..48)?, u.get(..48)?);
465 let hash = |input: &[u8], salt: &[u8], udata: &[u8]| -> Vec<u8> {
466 if r == 5 {
467 let mut h = Sha256::new();
468 h.update(input);
469 h.update(salt);
470 h.update(udata);
471 h.finalize().to_vec()
472 } else {
473 hash_2b(input, salt, udata)
474 }
475 };
476 let unwrap = |intermediate: &[u8], wrapped: &[u8]| -> Option<Vec<u8>> {
477 let mut buf = wrapped.get(..32)?.to_vec();
478 cbc::Decryptor::<aes::Aes256>::new_from_slices(intermediate, &[0u8; 16])
479 .ok()?
480 .decrypt_padded_mut::<NoPadding>(&mut buf)
481 .ok()?;
482 Some(buf)
483 };
484 if hash(pw, u.get(32..40)?, &[]) == u.get(..32)? {
485 let k = hash(pw, u.get(40..48)?, &[]);
486 return Some((unwrap(&k, ue)?, Authentication::User));
487 }
488 if hash(pw, o.get(32..40)?, u) == o.get(..32)? {
489 let k = hash(pw, o.get(40..48)?, u);
490 return Some((unwrap(&k, oe)?, Authentication::Owner));
491 }
492 None
493}
494
495fn hash_2b(password: &[u8], salt: &[u8], udata: &[u8]) -> Vec<u8> {
497 let mut h = Sha256::new();
498 h.update(password);
499 h.update(salt);
500 h.update(udata);
501 let mut k = h.finalize().to_vec();
502 let mut round = 0u32;
503 loop {
504 let mut k1 = Vec::with_capacity(64 * (password.len() + k.len() + udata.len()));
505 for _ in 0..64 {
506 k1.extend_from_slice(password);
507 k1.extend_from_slice(&k);
508 k1.extend_from_slice(udata);
509 }
510 let (Some(key), Some(iv)) = (k.get(..16), k.get(16..32)) else {
511 return k;
512 };
513 let len = k1.len();
514 let Ok(enc) = cbc::Encryptor::<aes::Aes128>::new_from_slices(key, iv) else {
515 return k;
516 };
517 let Ok(e) = enc.encrypt_padded_mut::<NoPadding>(&mut k1, len) else {
519 return k;
520 };
521 let e = e.to_vec();
522 let sum: u32 = e.iter().take(16).map(|&b| u32::from(b)).sum();
523 k = match sum % 3 {
524 0 => Sha256::digest(&e).to_vec(),
525 1 => Sha384::digest(&e).to_vec(),
526 _ => Sha512::digest(&e).to_vec(),
527 };
528 let last = u32::from(e.last().copied().unwrap_or(0));
529 round += 1;
530 if round >= 64 && last <= round - 32 {
531 break;
532 }
533 }
534 k.truncate(32);
535 k
536}
537
538fn rc4(key: &[u8], data: &mut [u8]) {
541 macro_rules! apply {
542 ($($n:literal => $size:ty),*) => {
543 match key.len() {
544 $($n => {
545 if let Ok(mut c) = Rc4::<$size>::new_from_slice(key) {
546 c.apply_keystream(data);
547 }
548 })*
549 _ => {}
550 }
551 };
552 }
553 apply!(5 => consts::U5, 6 => consts::U6, 7 => consts::U7, 8 => consts::U8,
554 9 => consts::U9, 10 => consts::U10, 11 => consts::U11, 12 => consts::U12,
555 13 => consts::U13, 14 => consts::U14, 15 => consts::U15, 16 => consts::U16);
556}
557
558fn aes_cbc_decrypt(key: &[u8], data: &[u8]) -> Vec<u8> {
561 let (Some(iv), Some(body)) = (data.get(..16), data.get(16..)) else {
562 return Vec::new();
563 };
564 let mut buf = body
565 .get(..body.len() / 16 * 16)
566 .unwrap_or_default()
567 .to_vec();
568 let ok = match key.len() {
569 16 => cbc::Decryptor::<aes::Aes128>::new_from_slices(key, iv)
570 .ok()
571 .and_then(|d| d.decrypt_padded_mut::<NoPadding>(&mut buf).ok().map(|_| ())),
572 32 => cbc::Decryptor::<aes::Aes256>::new_from_slices(key, iv)
573 .ok()
574 .and_then(|d| d.decrypt_padded_mut::<NoPadding>(&mut buf).ok().map(|_| ())),
575 _ => None,
576 };
577 if ok.is_none() {
578 return Vec::new();
579 }
580 if let Some(&pad) = buf.last() {
581 let n = usize::from(pad);
582 if (1..=16).contains(&n) && n <= buf.len() && buf.iter().rev().take(n).all(|&b| b == pad) {
583 buf.truncate(buf.len() - n);
584 }
585 }
586 buf
587}
588
589pub trait Entropy: Send + Sync {
593 fn fill(&self, buf: &mut [u8]);
595}
596
597#[derive(Debug, Clone, Copy, PartialEq, Eq)]
600pub struct Permissions {
601 pub print: bool,
603 pub modify: bool,
605 pub copy: bool,
607 pub annotate: bool,
609 pub fill_forms: bool,
611 pub accessibility: bool,
613 pub assemble: bool,
615 pub print_high_quality: bool,
617}
618
619impl Permissions {
620 pub const ALL: Permissions = Permissions {
622 print: true,
623 modify: true,
624 copy: true,
625 annotate: true,
626 fill_forms: true,
627 accessibility: true,
628 assemble: true,
629 print_high_quality: true,
630 };
631
632 pub fn bits(&self) -> u32 {
634 let mut p: u32 = 0xffff_f0c0;
635 for (on, bit) in [
636 (self.print, 3),
637 (self.modify, 4),
638 (self.copy, 5),
639 (self.annotate, 6),
640 (self.fill_forms, 9),
641 (self.accessibility, 10),
642 (self.assemble, 11),
643 (self.print_high_quality, 12),
644 ] {
645 if on {
646 p |= 1 << (bit - 1);
647 }
648 }
649 p
650 }
651
652 pub fn from_bits(p: u32) -> Self {
654 let bit = |n: u32| p & (1 << (n - 1)) != 0;
655 Self {
656 print: bit(3),
657 modify: bit(4),
658 copy: bit(5),
659 annotate: bit(6),
660 fill_forms: bit(9),
661 accessibility: bit(10),
662 assemble: bit(11),
663 print_high_quality: bit(12),
664 }
665 }
666}
667
668impl Default for Permissions {
669 fn default() -> Self {
670 Self::ALL
671 }
672}
673
674impl SecurityHandler {
675 pub fn new_aes256(
678 user_password: &[u8],
679 owner_password: &[u8],
680 permissions: Permissions,
681 encrypt_metadata: bool,
682 entropy: &dyn Entropy,
683 ) -> (Self, Dict) {
684 let truncate = |pw: &[u8]| pw.get(..pw.len().min(127)).unwrap_or_default().to_vec();
685 let (user, owner) = (truncate(user_password), truncate(owner_password));
686 let mut key = [0u8; 32];
687 entropy.fill(&mut key);
688 let mut salts = [0u8; 32];
689 entropy.fill(&mut salts);
690 let (uvs, rest) = salts.split_at(8);
691 let (uks, rest) = rest.split_at(8);
692 let (ovs, oks) = rest.split_at(8);
693
694 let wrap = |intermediate: &[u8]| -> Vec<u8> {
695 let mut buf = key.to_vec();
696 if let Ok(enc) =
697 cbc::Encryptor::<aes::Aes256>::new_from_slices(intermediate, &[0u8; 16])
698 {
699 let _ = enc.encrypt_padded_mut::<NoPadding>(&mut buf, 32);
700 }
701 buf
702 };
703 let mut u = hash_2b(&user, uvs, &[]);
704 u.extend_from_slice(uvs);
705 u.extend_from_slice(uks);
706 let ue = wrap(&hash_2b(&user, uks, &[]));
707 let mut o = hash_2b(&owner, ovs, &u);
708 o.extend_from_slice(ovs);
709 o.extend_from_slice(oks);
710 let oe = wrap(&hash_2b(&owner, oks, &u));
711
712 let p = permissions.bits();
713 let mut perms = [0u8; 16];
714 perms[..4].copy_from_slice(&p.to_le_bytes());
715 perms[4..8].copy_from_slice(&[0xff; 4]);
716 perms[8] = if encrypt_metadata { b'T' } else { b'F' };
717 perms[9..12].copy_from_slice(b"adb");
718 entropy.fill(&mut perms[12..]);
719 if let Ok(enc) = cbc::Encryptor::<aes::Aes256>::new_from_slices(&key, &[0u8; 16]) {
720 let _ = enc.encrypt_padded_mut::<NoPadding>(&mut perms, 16);
722 }
723
724 let mut std_cf = Dict::new();
725 std_cf.insert("AuthEvent", Name::from("DocOpen"));
726 std_cf.insert("CFM", Name::from("AESV3"));
727 std_cf.insert("Length", 32i64);
728 let mut cf = Dict::new();
729 cf.insert("StdCF", std_cf);
730 let mut dict = Dict::new();
731 dict.insert("Filter", Name::from("Standard"));
732 dict.insert("V", 5i64);
733 dict.insert("R", 6i64);
734 dict.insert("Length", 256i64);
735 dict.insert("CF", cf);
736 dict.insert("StmF", Name::from("StdCF"));
737 dict.insert("StrF", Name::from("StdCF"));
738 dict.insert("O", PdfString::hex(o));
739 dict.insert("U", PdfString::hex(u));
740 dict.insert("OE", PdfString::hex(oe));
741 dict.insert("UE", PdfString::hex(ue));
742 dict.insert("Perms", PdfString::hex(perms.to_vec()));
743 dict.insert("P", i64::from(p as i32));
744 if !encrypt_metadata {
745 dict.insert("EncryptMetadata", false);
746 }
747 let handler = Self {
748 revision: 6,
749 key: key.to_vec(),
750 strings: CryptMethod::AesV3,
751 streams: CryptMethod::AesV3,
752 embedded_files: CryptMethod::AesV3,
753 encrypt_metadata,
754 permissions: p,
755 authentication: Authentication::Owner,
756 };
757 (handler, dict)
758 }
759
760 pub fn can_encrypt(&self) -> bool {
764 self.is_authenticated()
765 && [self.strings, self.streams]
766 .iter()
767 .all(|m| matches!(m, CryptMethod::AesV3 | CryptMethod::Identity))
768 }
769
770 pub fn encrypt(
772 &self,
773 method: CryptMethod,
774 data: &[u8],
775 entropy: &dyn Entropy,
776 ) -> Result<Vec<u8>> {
777 match method {
778 CryptMethod::Identity => Ok(data.to_vec()),
779 CryptMethod::AesV3 => {
780 let mut iv = [0u8; 16];
781 entropy.fill(&mut iv);
782 let pad = 16 - data.len() % 16;
783 let mut buf = data.to_vec();
784 buf.resize(data.len() + pad, pad as u8);
785 let len = buf.len();
786 cbc::Encryptor::<aes::Aes256>::new_from_slices(&self.key, &iv)
787 .map_err(|_| Error::UnsupportedEncryption("bad AES-256 key".into()))?
788 .encrypt_padded_mut::<NoPadding>(&mut buf, len)
789 .map_err(|_| Error::UnsupportedEncryption("AES padding".into()))?;
790 let mut out = iv.to_vec();
791 out.extend_from_slice(&buf);
792 Ok(out)
793 }
794 _ => Err(Error::UnsupportedEncryption(
795 "only AES-256 is written; save in full to re-encrypt".into(),
796 )),
797 }
798 }
799
800 pub fn encrypt_strings(&self, object: &mut Object, entropy: &dyn Entropy) -> Result<()> {
803 match object {
804 Object::String(s) => {
805 s.bytes = self.encrypt(self.strings, &s.bytes, entropy)?;
806 Ok(())
807 }
808 Object::Array(items) => items
809 .iter_mut()
810 .try_for_each(|i| self.encrypt_strings(i, entropy)),
811 Object::Dict(d) => self.encrypt_dict_strings(d, entropy),
812 Object::Stream(st) => self.encrypt_dict_strings(&mut st.dict, entropy),
813 _ => Ok(()),
814 }
815 }
816
817 fn encrypt_dict_strings(&self, dict: &mut Dict, entropy: &dyn Entropy) -> Result<()> {
818 let is_signature = dict.is_type(b"Sig")
819 || dict.is_type(b"DocTimeStamp")
820 || dict.contains_key(b"ByteRange");
821 let keys: Vec<_> = dict.iter().map(|(k, _)| k.clone()).collect();
822 for key in keys {
823 if is_signature && key.as_bytes() == b"Contents" {
824 continue;
825 }
826 if let Some(mut value) = dict.remove(key.as_bytes()) {
827 self.encrypt_strings(&mut value, entropy)?;
828 dict.insert(key, value);
829 }
830 }
831 Ok(())
832 }
833}
834
835#[cfg(test)]
836mod tests {
837 use super::*;
838
839 #[test]
840 fn rc4_known_vector() {
841 let mut data = b"Plaintext".to_vec();
843 rc4(b"Key\0\0", &mut data);
844 let mut back = data.clone();
845 rc4(b"Key\0\0", &mut back);
846 assert_eq!(back, b"Plaintext");
847 let mut untouched = b"x".to_vec();
848 rc4(b"abc", &mut untouched);
849 assert_eq!(untouched, b"x");
850 }
851
852 #[test]
853 fn padding() {
854 assert_eq!(padded(b""), PAD);
855 let p = padded(b"ab");
856 assert_eq!(&p[..2], b"ab");
857 assert_eq!(&p[2..], &PAD[..30]);
858 assert_eq!(padded(&[7; 40]), [7; 32]);
859 }
860
861 #[test]
862 fn aes_lenient_decrypt() {
863 assert!(aes_cbc_decrypt(&[0; 16], b"short").is_empty());
864 assert!(aes_cbc_decrypt(&[0; 3], &[0; 32]).is_empty());
865 let key = [1u8; 16];
867 let iv = [2u8; 16];
868 let mut block = *b"hello\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b";
869 cbc::Encryptor::<aes::Aes128>::new_from_slices(&key, &iv)
870 .unwrap()
871 .encrypt_padded_mut::<NoPadding>(&mut block, 16)
872 .unwrap();
873 let mut data = iv.to_vec();
874 data.extend_from_slice(&block);
875 assert_eq!(aes_cbc_decrypt(&key, &data), b"hello");
876 }
877
878 #[test]
879 fn unsupported_handlers() {
880 let mut d = Dict::new();
881 d.insert("Filter", crate::object::Name::from("Adobe.PubSec"));
882 assert!(matches!(
883 SecurityHandler::new(&d, b"", b""),
884 Err(Error::UnsupportedEncryption(_))
885 ));
886 let mut d = Dict::new();
887 d.insert("Filter", crate::object::Name::from("Standard"));
888 d.insert("R", 7i64);
889 assert!(matches!(
890 SecurityHandler::new(&d, b"", b""),
891 Err(Error::UnsupportedEncryption(_))
892 ));
893 }
894
895 #[test]
896 fn password_variants() {
897 assert_eq!(password_candidates(b"abc", 4), vec![b"abc".to_vec()]);
898 assert_eq!(
899 password_candidates("æøå".as_bytes(), 4),
900 vec!["æøå".as_bytes().to_vec(), vec![0xe6, 0xf8, 0xe5]]
901 );
902 assert_eq!(password_candidates("€".as_bytes(), 3).len(), 1);
904 assert_eq!(
905 password_candidates("a\u{ad}b\u{a0}c".as_bytes(), 6)[1],
906 b"ab c".to_vec()
907 );
908 assert_eq!(password_candidates(&[0xff], 6), vec![vec![0xff]]);
909 }
910
911 #[test]
912 fn identity_only_opens_without_password() {
913 let mut cf = Dict::new();
914 let mut std_cf = Dict::new();
915 std_cf.insert("CFM", crate::object::Name::from("AESV3"));
916 cf.insert("StdCF", std_cf);
917 let mut d = Dict::new();
918 d.insert("Filter", crate::object::Name::from("Standard"));
919 d.insert("V", 5i64);
920 d.insert("R", 6i64);
921 d.insert("CF", cf);
922 d.insert("StmF", crate::object::Name::from("Identity"));
923 d.insert("StrF", crate::object::Name::from("Identity"));
924 d.insert("EFF", crate::object::Name::from("StdCF"));
925 let h = SecurityHandler::new(&d, b"", b"").unwrap();
926 assert_eq!(h.authentication(), Authentication::None);
927 assert!(!h.is_authenticated());
928 assert_eq!(h.embedded_file_method(), CryptMethod::AesV3);
929 assert_eq!(
930 h.decrypt(ObjId::new(1, 0), CryptMethod::AesV3, b"raw"),
931 b"raw"
932 );
933 d.insert("StmF", crate::object::Name::from("StdCF"));
935 assert_eq!(
936 SecurityHandler::new(&d, b"", b"").err(),
937 Some(Error::InvalidPassword)
938 );
939 }
940
941 struct Counter(std::sync::atomic::AtomicU8);
943
944 impl Entropy for Counter {
945 fn fill(&self, buf: &mut [u8]) {
946 for b in buf {
947 *b = self.0.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
948 }
949 }
950 }
951
952 #[test]
953 fn permissions_bits() {
954 assert_eq!(
955 Permissions::ALL.bits(),
956 0xffff_ffc0 | 0b1111 << 2 | 0xf << 8
957 );
958 let none = Permissions::from_bits(0xffff_f0c0);
959 assert!(!none.print && !none.copy && !none.assemble);
960 assert_eq!(
961 Permissions::from_bits(Permissions::ALL.bits()),
962 Permissions::ALL
963 );
964 let print_only = Permissions {
965 print: true,
966 ..Permissions::from_bits(0)
967 };
968 assert_eq!(print_only.bits(), 0xffff_f0c4);
969 }
970
971 #[test]
972 fn aes256_write_then_read() {
973 let entropy = Counter(Default::default());
974 let perms = Permissions {
975 copy: false,
976 ..Permissions::ALL
977 };
978 let (writer, dict) = SecurityHandler::new_aes256(b"user", b"owner", perms, true, &entropy);
979 assert!(writer.can_encrypt());
980 let id = ObjId::new(7, 0);
981 let secret = b"attack at dawn".to_vec();
982 let encrypted = writer
983 .encrypt(CryptMethod::AesV3, &secret, &entropy)
984 .unwrap();
985 assert_eq!(encrypted.len(), 16 + 16);
986
987 for (pw, auth) in [
988 (&b"user"[..], Authentication::User),
989 (b"owner", Authentication::Owner),
990 ] {
991 let reader = SecurityHandler::new(&dict, b"", pw).unwrap();
992 assert_eq!(reader.authentication(), auth);
993 assert_eq!(reader.revision(), 6);
994 assert_eq!(Permissions::from_bits(reader.permissions()), perms);
995 assert_eq!(reader.decrypt(id, CryptMethod::AesV3, &encrypted), secret);
996 }
997 assert_eq!(
998 SecurityHandler::new(&dict, b"", b"nope").err(),
999 Some(Error::InvalidPassword)
1000 );
1001
1002 let mut obj = Object::Array(vec![Object::String(PdfString::literal("hi"))]);
1003 writer.encrypt_strings(&mut obj, &entropy).unwrap();
1004 let reader = SecurityHandler::new(&dict, b"", b"user").unwrap();
1005 reader.decrypt_strings(id, &mut obj);
1006 assert_eq!(obj.as_array().unwrap()[0].as_string(), Some(&b"hi"[..]));
1007 }
1008
1009 #[test]
1010 fn same_entropy_same_output() {
1011 let a = SecurityHandler::new_aes256(
1012 b"u",
1013 b"o",
1014 Permissions::ALL,
1015 false,
1016 &Counter(Default::default()),
1017 )
1018 .1;
1019 let b = SecurityHandler::new_aes256(
1020 b"u",
1021 b"o",
1022 Permissions::ALL,
1023 false,
1024 &Counter(Default::default()),
1025 )
1026 .1;
1027 assert_eq!(a, b);
1028 assert_eq!(a.get(b"EncryptMetadata"), Some(&Object::Bool(false)));
1029 }
1030
1031 #[test]
1032 fn legacy_methods_are_never_written() {
1033 let entropy = Counter(Default::default());
1034 let (h, _) = SecurityHandler::new_aes256(b"", b"", Permissions::ALL, true, &entropy);
1035 assert!(h.encrypt(CryptMethod::Rc4, b"x", &entropy).is_err());
1036 assert!(h.encrypt(CryptMethod::AesV2, b"x", &entropy).is_err());
1037 assert_eq!(
1038 h.encrypt(CryptMethod::Identity, b"x", &entropy).unwrap(),
1039 b"x"
1040 );
1041 }
1042
1043 #[test]
1044 fn crypt_filter_methods() {
1045 let mut std_cf = Dict::new();
1046 std_cf.insert("CFM", crate::object::Name::from("AESV2"));
1047 let mut cf = Dict::new();
1048 cf.insert("StdCF", std_cf);
1049 let mut d = Dict::new();
1050 d.insert("CF", cf);
1051 d.insert("StmF", crate::object::Name::from("StdCF"));
1052 d.insert("StrF", crate::object::Name::from("Identity"));
1053 assert_eq!(
1054 crypt_methods(&d, 4).unwrap(),
1055 (
1056 CryptMethod::Identity,
1057 CryptMethod::AesV2,
1058 CryptMethod::AesV2
1059 )
1060 );
1061 assert_eq!(
1062 crypt_methods(&Dict::new(), 2).unwrap(),
1063 (CryptMethod::Rc4, CryptMethod::Rc4, CryptMethod::Rc4)
1064 );
1065 assert!(crypt_methods(&Dict::new(), 9).is_err());
1066 }
1067}