1use std::collections::HashMap;
12
13use rpdfium_core::{Name, PdfSource};
14
15use crate::crypto::{self, CryptoError};
16use crate::object::{Object, ObjectId};
17use crate::store::ObjectStore;
18
19const PASSWORD_PADDING: [u8; 32] = [
21 0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08,
22 0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, 0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A,
23];
24
25#[derive(Debug, thiserror::Error)]
27pub enum SecurityError {
28 #[error("invalid password")]
30 InvalidPassword,
31 #[error("unsupported encryption version: V={0}, R={1}")]
33 UnsupportedVersion(u32, u32),
34 #[error("missing encryption dictionary key: {0}")]
36 MissingKey(String),
37 #[error("crypto error: {0}")]
39 Crypto(#[from] CryptoError),
40}
41
42#[derive(Debug, Clone, Copy, PartialEq, Eq)]
44pub enum CryptFilterMethod {
45 None,
47 V2,
49 Aesv2,
51 Aesv3,
53}
54
55#[derive(Debug, Clone, Copy, PartialEq, Eq)]
61pub struct Permissions(i32);
62
63impl Permissions {
64 pub fn from_bits(bits: i32) -> Self {
66 Self(bits)
67 }
68
69 pub fn bits(self) -> i32 {
71 self.0
72 }
73
74 pub fn modify_content(self) -> bool {
76 self.0 & (1 << 3) != 0
77 }
78
79 pub fn modify_annotation(self) -> bool {
81 self.0 & (1 << 5) != 0
82 }
83
84 pub fn fill_form(self) -> bool {
86 self.0 & (1 << 8) != 0
87 }
88
89 pub fn extract_for_accessibility(self) -> bool {
91 self.0 & (1 << 9) != 0
92 }
93}
94
95pub struct SecurityHandler {
98 revision: u32,
99 key_length_bytes: usize,
100 encryption_key: Vec<u8>,
101 permissions: Permissions,
102 encrypt_metadata: bool,
103 stream_cf: CryptFilterMethod,
104 string_cf: CryptFilterMethod,
105 o_value: Vec<u8>,
107 u_value: Vec<u8>,
109}
110
111impl SecurityHandler {
112 pub fn from_encrypt_dict<S: PdfSource>(
118 encrypt_dict: &HashMap<Name, Object>,
119 store: &ObjectStore<S>,
120 password: &str,
121 file_id: &[u8],
122 ) -> Result<Self, SecurityError> {
123 let v = get_int(encrypt_dict, store, &Name::v())? as u32;
125 let r = get_int(encrypt_dict, store, &Name::r())? as u32;
126 let p = get_int(encrypt_dict, store, &Name::p())?;
127
128 let o_bytes = get_string_bytes(encrypt_dict, store, &Name::o())?;
129 let u_bytes = get_string_bytes(encrypt_dict, store, &Name::u())?;
130
131 let key_length_bits =
133 get_optional_int(encrypt_dict, store, &Name::length()).unwrap_or(40) as usize;
134 let key_length_bytes = key_length_bits / 8;
135
136 if r <= 4 && !(5..=16).contains(&key_length_bytes) {
139 return Err(SecurityError::UnsupportedVersion(v, r));
140 }
141
142 let encrypt_metadata =
144 get_optional_bool(encrypt_dict, store, &Name::encrypt_metadata()).unwrap_or(true);
145
146 let (stream_cf, string_cf) = if v >= 4 {
148 let stm = parse_single_crypt_filter(encrypt_dict, store, &Name::stm_f());
149 let str_ = parse_single_crypt_filter(encrypt_dict, store, &Name::str_f());
150 (stm, str_)
151 } else if v == 1 || v == 2 || v == 3 {
152 (CryptFilterMethod::V2, CryptFilterMethod::V2)
153 } else {
154 (CryptFilterMethod::None, CryptFilterMethod::None)
155 };
156
157 match (v, r) {
158 (1, 2) | (2, 3) | (3, 3) | (4, 4) => {
159 let pwd_bytes = encode_password_latin1(password);
161 let key = derive_key_r2_r4(
162 &pwd_bytes,
163 &o_bytes,
164 p as i32,
165 file_id,
166 r,
167 key_length_bytes,
168 encrypt_metadata,
169 );
170
171 if verify_user_password_r2_r4(&key, &u_bytes, r, file_id) {
173 return Ok(Self {
174 revision: r,
175 key_length_bytes,
176 encryption_key: key,
177 permissions: Permissions::from_bits(p as i32),
178 encrypt_metadata,
179 stream_cf,
180 string_cf,
181 o_value: o_bytes.clone(),
182 u_value: u_bytes.clone(),
183 });
184 }
185
186 let user_password =
188 recover_user_password_from_owner(&pwd_bytes, &o_bytes, r, key_length_bytes);
189 let key = derive_key_r2_r4(
190 &user_password,
191 &o_bytes,
192 p as i32,
193 file_id,
194 r,
195 key_length_bytes,
196 encrypt_metadata,
197 );
198
199 if verify_user_password_r2_r4(&key, &u_bytes, r, file_id) {
200 Ok(Self {
201 revision: r,
202 key_length_bytes,
203 encryption_key: key,
204 permissions: Permissions::from_bits(p as i32),
205 encrypt_metadata,
206 stream_cf,
207 string_cf,
208 o_value: o_bytes,
209 u_value: u_bytes,
210 })
211 } else {
212 Err(SecurityError::InvalidPassword)
213 }
214 }
215 (5, 5) | (5, 6) => {
216 let oe_bytes = get_string_bytes(encrypt_dict, store, &Name::oe())?;
218 let ue_bytes = get_string_bytes(encrypt_dict, store, &Name::ue())?;
219
220 let key = if r == 5 {
221 derive_key_r5(password, &u_bytes, &ue_bytes, &o_bytes, &oe_bytes)?
222 } else {
223 derive_key_r6(password, &u_bytes, &ue_bytes, &o_bytes, &oe_bytes)?
224 };
225
226 match key {
227 Some(k) => {
228 let perms_bytes = get_string_bytes(encrypt_dict, store, &Name::perms())?;
240 if perms_bytes.len() < 16 {
241 return Err(SecurityError::MissingKey(
242 "Perms (too short, need ≥16 bytes)".into(),
243 ));
244 }
245 let decrypted = crypto::aes256_ecb_decrypt_block(&k, &perms_bytes[..16])?;
246 if &decrypted[9..12] != b"adb" {
250 return Err(SecurityError::InvalidPassword);
251 }
252 let perms_p = i32::from_le_bytes([
254 decrypted[0],
255 decrypted[1],
256 decrypted[2],
257 decrypted[3],
258 ]);
259 if perms_p != p as i32 {
260 return Err(SecurityError::InvalidPassword);
261 }
262
263 Ok(Self {
264 revision: r,
265 key_length_bytes: 32,
266 encryption_key: k,
267 permissions: Permissions::from_bits(p as i32),
268 encrypt_metadata,
269 stream_cf: CryptFilterMethod::Aesv3,
270 string_cf: CryptFilterMethod::Aesv3,
271 o_value: o_bytes,
272 u_value: u_bytes,
273 })
274 }
275 None => Err(SecurityError::InvalidPassword),
276 }
277 }
278 _ => Err(SecurityError::UnsupportedVersion(v, r)),
279 }
280 }
281
282 pub fn permissions(&self) -> Permissions {
284 self.permissions
285 }
286
287 pub fn decrypt_string(&self, data: &[u8], obj_id: ObjectId) -> Vec<u8> {
289 if self.string_cf == CryptFilterMethod::None {
290 return data.to_vec();
291 }
292
293 if self.revision >= 5 {
294 crypto::aes256_cbc_decrypt(&self.encryption_key, data).unwrap_or_else(|_| data.to_vec())
296 } else {
297 let object_key = self.compute_object_key(obj_id, self.string_cf);
298 match self.string_cf {
299 CryptFilterMethod::V2 => crypto::rc4_crypt(&object_key, data),
300 CryptFilterMethod::Aesv2 => {
301 crypto::aes128_cbc_decrypt(&object_key, data).unwrap_or_else(|_| data.to_vec())
302 }
303 CryptFilterMethod::Aesv3 => crypto::aes256_cbc_decrypt(&self.encryption_key, data)
304 .unwrap_or_else(|_| data.to_vec()),
305 CryptFilterMethod::None => data.to_vec(),
306 }
307 }
308 }
309
310 pub fn decrypt_stream(&self, data: &[u8], obj_id: ObjectId) -> Vec<u8> {
312 if self.stream_cf == CryptFilterMethod::None {
313 return data.to_vec();
314 }
315
316 if self.revision >= 5 {
317 crypto::aes256_cbc_decrypt(&self.encryption_key, data).unwrap_or_else(|_| data.to_vec())
318 } else {
319 let object_key = self.compute_object_key(obj_id, self.stream_cf);
320 match self.stream_cf {
321 CryptFilterMethod::V2 => crypto::rc4_crypt(&object_key, data),
322 CryptFilterMethod::Aesv2 => {
323 crypto::aes128_cbc_decrypt(&object_key, data).unwrap_or_else(|_| data.to_vec())
324 }
325 CryptFilterMethod::Aesv3 => crypto::aes256_cbc_decrypt(&self.encryption_key, data)
326 .unwrap_or_else(|_| data.to_vec()),
327 CryptFilterMethod::None => data.to_vec(),
328 }
329 }
330 }
331
332 pub fn encrypt_metadata(&self) -> bool {
334 self.encrypt_metadata
335 }
336
337 pub fn revision(&self) -> u32 {
339 self.revision
340 }
341
342 pub fn crypt_filter_method(&self) -> CryptFilterMethod {
344 self.stream_cf
345 }
346
347 pub fn key_length_bytes(&self) -> usize {
349 self.key_length_bytes
350 }
351
352 pub fn encryption_key(&self) -> &[u8] {
354 &self.encryption_key
355 }
356
357 pub fn stream_crypt_filter(&self) -> CryptFilterMethod {
359 self.stream_cf
360 }
361
362 pub fn string_crypt_filter(&self) -> CryptFilterMethod {
364 self.string_cf
365 }
366
367 pub fn o_value(&self) -> &[u8] {
369 &self.o_value
370 }
371
372 pub fn u_value(&self) -> &[u8] {
374 &self.u_value
375 }
376
377 pub fn version(&self) -> u32 {
381 match self.revision {
382 2 => 1,
383 3 | 4 => {
384 if self.stream_cf == CryptFilterMethod::V2
385 && self.string_cf == CryptFilterMethod::V2
386 {
387 if self.key_length_bytes == 5 { 1 } else { 2 }
388 } else {
389 4
390 }
391 }
392 5 | 6 => 5,
393 _ => 0,
394 }
395 }
396
397 pub fn encrypt_string(&self, data: &[u8], obj_id: ObjectId) -> Vec<u8> {
403 if self.string_cf == CryptFilterMethod::None {
404 return data.to_vec();
405 }
406 self.encrypt_with_method(data, obj_id, self.string_cf)
407 }
408
409 pub fn encrypt_stream(&self, data: &[u8], obj_id: ObjectId) -> Vec<u8> {
411 if self.stream_cf == CryptFilterMethod::None {
412 return data.to_vec();
413 }
414 self.encrypt_with_method(data, obj_id, self.stream_cf)
415 }
416
417 fn encrypt_with_method(&self, data: &[u8], obj_id: ObjectId, cf: CryptFilterMethod) -> Vec<u8> {
435 let iv = Self::generate_iv();
436
437 if self.revision >= 5 {
438 let encrypted = crypto::aes256_cbc_encrypt(&self.encryption_key, &iv, data)
439 .expect("AES-256 encryption failed: key size validated at construction");
440 let mut result = iv.to_vec();
441 result.extend_from_slice(&encrypted);
442 result
443 } else {
444 let object_key = self.compute_object_key(obj_id, cf);
445 match cf {
446 CryptFilterMethod::V2 => crypto::rc4_crypt(&object_key, data),
447 CryptFilterMethod::Aesv2 => {
448 let encrypted = crypto::aes128_cbc_encrypt(&object_key, &iv, data)
449 .expect("AES-128 encryption failed: key size validated at construction");
450 let mut result = iv.to_vec();
451 result.extend_from_slice(&encrypted);
452 result
453 }
454 CryptFilterMethod::Aesv3 => {
455 let encrypted = crypto::aes256_cbc_encrypt(&self.encryption_key, &iv, data)
456 .expect("AES-256 encryption failed: key size validated at construction");
457 let mut result = iv.to_vec();
458 result.extend_from_slice(&encrypted);
459 result
460 }
461 CryptFilterMethod::None => data.to_vec(),
462 }
463 }
464 }
465
466 fn generate_iv() -> [u8; 16] {
477 let mut iv = [0u8; 16];
478 getrandom::fill(&mut iv).expect("OS RNG unavailable");
479 iv
480 }
481
482 fn compute_object_key(&self, obj_id: ObjectId, cf: CryptFilterMethod) -> Vec<u8> {
490 let obj_num = obj_id.number;
491 let gen_num = obj_id.generation;
492
493 let mut buf = Vec::with_capacity(self.encryption_key.len() + 9);
494 buf.extend_from_slice(&self.encryption_key);
495 buf.push((obj_num & 0xFF) as u8);
497 buf.push(((obj_num >> 8) & 0xFF) as u8);
498 buf.push(((obj_num >> 16) & 0xFF) as u8);
499 buf.push((gen_num & 0xFF) as u8);
501 buf.push(((gen_num >> 8) & 0xFF) as u8);
502
503 if cf == CryptFilterMethod::Aesv2 {
504 buf.extend_from_slice(&[0x73, 0x41, 0x6C, 0x54]);
506 }
507
508 let hash = crypto::md5(&buf);
509 let n = std::cmp::min(self.key_length_bytes + 5, 16);
510 hash[..n].to_vec()
511 }
512}
513
514fn encode_password_latin1(password: &str) -> Vec<u8> {
521 password
522 .chars()
523 .map(|c| {
524 let code = c as u32;
525 if code <= 255 {
526 code as u8
527 } else {
528 0x3F }
530 })
531 .collect()
532}
533
534fn pad_password(password: &[u8]) -> [u8; 32] {
536 let mut padded = [0u8; 32];
537 let copy_len = std::cmp::min(password.len(), 32);
538 padded[..copy_len].copy_from_slice(&password[..copy_len]);
539 if copy_len < 32 {
540 padded[copy_len..].copy_from_slice(&PASSWORD_PADDING[..(32 - copy_len)]);
541 }
542 padded
543}
544
545fn derive_key_r2_r4(
547 password: &[u8],
548 o_value: &[u8],
549 permissions: i32,
550 file_id: &[u8],
551 revision: u32,
552 key_length_bytes: usize,
553 encrypt_metadata: bool,
554) -> Vec<u8> {
555 let padded = pad_password(password);
556
557 let mut buf = Vec::with_capacity(32 + o_value.len() + 4 + file_id.len() + 4);
558 buf.extend_from_slice(&padded);
559 buf.extend_from_slice(o_value);
560 buf.extend_from_slice(&(permissions as u32).to_le_bytes());
561 buf.extend_from_slice(file_id);
562
563 if revision >= 4 && !encrypt_metadata {
564 buf.extend_from_slice(&[0xFF, 0xFF, 0xFF, 0xFF]);
565 }
566
567 let mut hash = crypto::md5(&buf);
568
569 if revision >= 3 {
570 for _ in 0..50 {
571 hash = crypto::md5(&hash[..key_length_bytes]);
572 }
573 }
574
575 hash[..key_length_bytes].to_vec()
576}
577
578fn verify_user_password_r2(key: &[u8], u_value: &[u8]) -> bool {
584 let decrypted = crypto::rc4_crypt(key, u_value);
585 let expected = crypto::md5(&PASSWORD_PADDING);
586 decrypted[..] == expected[..]
587}
588
589fn verify_user_password_r3_r4(key: &[u8], u_value: &[u8], file_id: &[u8]) -> bool {
595 let mut buf = Vec::with_capacity(32 + file_id.len());
597 buf.extend_from_slice(&PASSWORD_PADDING);
598 buf.extend_from_slice(file_id);
599 let hash = crypto::md5(&buf);
600
601 let mut result = crypto::rc4_crypt(key, &hash);
603
604 for i in 1..=19u8 {
606 let modified_key: Vec<u8> = key.iter().map(|b| b ^ i).collect();
607 result = crypto::rc4_crypt(&modified_key, &result);
608 }
609
610 u_value.len() >= 16 && result.len() >= 16 && result[..16] == u_value[..16]
612}
613
614fn verify_user_password_r2_r4(key: &[u8], u_value: &[u8], revision: u32, file_id: &[u8]) -> bool {
616 if revision == 2 {
617 verify_user_password_r2(key, u_value)
618 } else {
619 verify_user_password_r3_r4(key, u_value, file_id)
620 }
621}
622
623fn recover_user_password_from_owner(
629 owner_password: &[u8],
630 o_value: &[u8],
631 revision: u32,
632 key_length_bytes: usize,
633) -> Vec<u8> {
634 let padded = pad_password(owner_password);
635 let mut hash = crypto::md5(&padded);
636
637 if revision >= 3 {
638 for _ in 0..50 {
639 hash = crypto::md5(&hash[..key_length_bytes]);
640 }
641 }
642
643 let key = &hash[..key_length_bytes];
644
645 if revision == 2 {
646 crypto::rc4_crypt(key, o_value)
647 } else {
648 let mut result = o_value.to_vec();
649 for i in (0..=19u8).rev() {
650 let modified_key: Vec<u8> = key.iter().map(|b| b ^ i).collect();
651 result = crypto::rc4_crypt(&modified_key, &result);
652 }
653 result
654 }
655}
656
657fn derive_key_r5(
665 password: &str,
666 u_value: &[u8],
667 ue_value: &[u8],
668 o_value: &[u8],
669 oe_value: &[u8],
670) -> Result<Option<Vec<u8>>, CryptoError> {
671 let pwd = truncate_utf8_password(password);
672
673 if u_value.len() >= 48 && ue_value.len() >= 32 {
675 let validation_salt = &u_value[32..40];
676 let hash = compute_r5_hash(&pwd, validation_salt);
677 if hash[..] == u_value[..32] {
678 let key_salt = &u_value[40..48];
680 let key_hash = compute_r5_hash(&pwd, key_salt);
681 let file_key = crypto::aes256_cbc_decrypt(&key_hash, &prepend_zero_iv(ue_value))?;
682 return Ok(Some(file_key));
683 }
684 }
685
686 if o_value.len() >= 48 && oe_value.len() >= 32 && u_value.len() >= 48 {
688 let validation_salt = &o_value[32..40];
689 let mut input = Vec::with_capacity(pwd.len() + 8 + 48);
690 input.extend_from_slice(&pwd);
691 input.extend_from_slice(validation_salt);
692 input.extend_from_slice(&u_value[..48]);
693 let hash = crypto::sha256(&input);
694 if hash[..] == o_value[..32] {
695 let key_salt = &o_value[40..48];
696 let mut key_input = Vec::with_capacity(pwd.len() + 8 + 48);
697 key_input.extend_from_slice(&pwd);
698 key_input.extend_from_slice(key_salt);
699 key_input.extend_from_slice(&u_value[..48]);
700 let key_hash = crypto::sha256(&key_input);
701 let file_key = crypto::aes256_cbc_decrypt(&key_hash, &prepend_zero_iv(oe_value))?;
702 return Ok(Some(file_key));
703 }
704 }
705
706 Ok(None)
707}
708
709fn derive_key_r6(
713 password: &str,
714 u_value: &[u8],
715 ue_value: &[u8],
716 o_value: &[u8],
717 oe_value: &[u8],
718) -> Result<Option<Vec<u8>>, CryptoError> {
719 let pwd = truncate_utf8_password(password);
720
721 if u_value.len() >= 48 && ue_value.len() >= 32 {
723 let validation_salt = &u_value[32..40];
724 let hash = compute_r6_hash(&pwd, validation_salt, &[]);
725 if hash[..] == u_value[..32] {
726 let key_salt = &u_value[40..48];
728 let key_hash = compute_r6_hash(&pwd, key_salt, &[]);
729 let file_key = crypto::aes256_cbc_decrypt(&key_hash, &prepend_zero_iv(ue_value))?;
730 return Ok(Some(file_key));
731 }
732 }
733
734 if o_value.len() >= 48 && oe_value.len() >= 32 && u_value.len() >= 48 {
736 let validation_salt = &o_value[32..40];
737 let hash = compute_r6_hash(&pwd, validation_salt, &u_value[..48]);
738 if hash[..] == o_value[..32] {
739 let key_salt = &o_value[40..48];
740 let key_hash = compute_r6_hash(&pwd, key_salt, &u_value[..48]);
741 let file_key = crypto::aes256_cbc_decrypt(&key_hash, &prepend_zero_iv(oe_value))?;
742 return Ok(Some(file_key));
743 }
744 }
745
746 Ok(None)
747}
748
749fn big_endian_mod3(bytes: &[u8]) -> u32 {
751 bytes
752 .iter()
753 .take(16)
754 .fold(0u32, |acc, &b| (acc * 256 + b as u32) % 3)
755}
756
757fn compute_r6_hash(password: &[u8], salt: &[u8], u_value: &[u8]) -> [u8; 32] {
762 let mut input = Vec::with_capacity(password.len() + salt.len() + u_value.len());
764 input.extend_from_slice(password);
765 input.extend_from_slice(salt);
766 input.extend_from_slice(u_value);
767 let mut k = crypto::sha256(&input);
768
769 let mut round: u32 = 0;
770 loop {
771 let sequence_len = password.len() + k.len() + u_value.len();
773 let mut k1 = Vec::with_capacity(sequence_len * 64);
774 for _ in 0..64 {
775 k1.extend_from_slice(password);
776 k1.extend_from_slice(&k);
777 k1.extend_from_slice(u_value);
778 }
779
780 let aes_key = &k[..16];
782 let aes_iv = &k[16..32];
783 let e = crypto::aes128_cbc_encrypt(aes_key, aes_iv, &k1)
785 .expect("AES-128-CBC key/IV from SHA-256 are always valid");
786
787 let hash_select = big_endian_mod3(&e);
789
790 match hash_select {
792 0 => {
793 let h = crypto::sha256(&e);
794 k = h;
795 }
796 1 => {
797 let h = crypto::sha384(&e);
798 k.copy_from_slice(&h[..32]);
799 }
800 _ => {
801 let h = crypto::sha512(&e);
802 k.copy_from_slice(&h[..32]);
803 }
804 }
805
806 if round >= 64 {
808 let last_byte = *e.last().unwrap_or(&0);
809 if last_byte <= (round - 32) as u8 {
810 break;
811 }
812 }
813
814 round += 1;
815
816 if round >= 1000 {
818 break;
819 }
820 }
821
822 k
823}
824
825fn compute_r5_hash(password: &[u8], salt: &[u8]) -> [u8; 32] {
827 let mut input = Vec::with_capacity(password.len() + salt.len());
828 input.extend_from_slice(password);
829 input.extend_from_slice(salt);
830 crypto::sha256(&input)
831}
832
833fn truncate_utf8_password(password: &str) -> Vec<u8> {
835 let bytes = password.as_bytes();
836 if bytes.len() <= 127 {
837 bytes.to_vec()
838 } else {
839 bytes[..127].to_vec()
840 }
841}
842
843fn prepend_zero_iv(data: &[u8]) -> Vec<u8> {
845 let mut result = vec![0u8; 16];
846 result.extend_from_slice(data);
847 result
848}
849
850fn parse_single_crypt_filter<S: PdfSource>(
857 encrypt_dict: &HashMap<Name, Object>,
858 store: &ObjectStore<S>,
859 filter_key: &Name,
860) -> CryptFilterMethod {
861 let filter_name = encrypt_dict
862 .get(filter_key)
863 .and_then(|obj| store.deep_resolve(obj).ok())
864 .and_then(|obj| obj.as_name())
865 .cloned()
866 .unwrap_or_else(|| Name::from("StdCF"));
867
868 if filter_name == Name::from("Identity") {
869 return CryptFilterMethod::None;
870 }
871
872 let cf_dict = encrypt_dict
874 .get(&Name::cf())
875 .and_then(|obj| store.deep_resolve(obj).ok())
876 .and_then(|obj| obj.as_dict());
877
878 if let Some(cf) = cf_dict {
879 if let Some(filter_obj) = cf.get(&filter_name) {
880 if let Ok(filter_resolved) = store.deep_resolve(filter_obj) {
881 if let Some(filter_dict) = filter_resolved.as_dict() {
882 let method = filter_dict
883 .get(&Name::cfm())
884 .and_then(|obj| store.deep_resolve(obj).ok())
885 .and_then(|obj| obj.as_name())
886 .cloned();
887
888 if let Some(m) = method {
889 if m == Name::aesv2() {
890 return CryptFilterMethod::Aesv2;
891 } else if m == Name::aesv3() {
892 return CryptFilterMethod::Aesv3;
893 } else if m == Name::v2() {
894 return CryptFilterMethod::V2;
895 } else if m == Name::none() {
896 return CryptFilterMethod::None;
897 }
898 }
899 }
900 }
901 }
902 }
903
904 CryptFilterMethod::V2
906}
907
908fn get_int<S: PdfSource>(
913 dict: &HashMap<Name, Object>,
914 store: &ObjectStore<S>,
915 key: &Name,
916) -> Result<i64, SecurityError> {
917 dict.get(key)
918 .and_then(|obj| store.deep_resolve(obj).ok())
919 .and_then(|obj| obj.as_i64())
920 .ok_or_else(|| SecurityError::MissingKey(key.to_string()))
921}
922
923fn get_optional_int<S: PdfSource>(
924 dict: &HashMap<Name, Object>,
925 store: &ObjectStore<S>,
926 key: &Name,
927) -> Option<i64> {
928 dict.get(key)
929 .and_then(|obj| store.deep_resolve(obj).ok())
930 .and_then(|obj| obj.as_i64())
931}
932
933fn get_optional_bool<S: PdfSource>(
934 dict: &HashMap<Name, Object>,
935 store: &ObjectStore<S>,
936 key: &Name,
937) -> Option<bool> {
938 dict.get(key)
939 .and_then(|obj| store.deep_resolve(obj).ok())
940 .and_then(|obj| obj.as_bool())
941}
942
943fn get_string_bytes<S: PdfSource>(
944 dict: &HashMap<Name, Object>,
945 store: &ObjectStore<S>,
946 key: &Name,
947) -> Result<Vec<u8>, SecurityError> {
948 dict.get(key)
949 .and_then(|obj| store.deep_resolve(obj).ok())
950 .and_then(|obj| obj.as_string())
951 .map(|s| s.as_bytes().to_vec())
952 .ok_or_else(|| SecurityError::MissingKey(key.to_string()))
953}
954
955#[cfg(test)]
956mod tests {
957 use super::*;
958
959 #[test]
960 fn password_padding_empty() {
961 let padded = pad_password(b"");
962 assert_eq!(padded, PASSWORD_PADDING);
963 }
964
965 #[test]
966 fn password_padding_short() {
967 let padded = pad_password(b"test");
968 assert_eq!(&padded[..4], b"test");
969 assert_eq!(&padded[4..], &PASSWORD_PADDING[..28]);
970 }
971
972 #[test]
973 fn password_padding_exact_32() {
974 let pwd = b"abcdefghijklmnopqrstuvwxyz012345"; let padded = pad_password(pwd);
976 assert_eq!(&padded[..], &pwd[..]);
977 }
978
979 #[test]
980 fn password_padding_longer_than_32() {
981 let pwd = b"abcdefghijklmnopqrstuvwxyz0123456789"; let padded = pad_password(pwd);
983 assert_eq!(&padded[..], &pwd[..32]);
984 }
985
986 #[test]
987 fn key_derivation_r2_known() {
988 let o_value = [0u8; 32];
990 let file_id = b"test_file_id_123";
991 let key = derive_key_r2_r4(b"", &o_value, -44, file_id, 2, 5, true);
992 assert_eq!(key.len(), 5);
993 let key2 = derive_key_r2_r4(b"", &o_value, -44, file_id, 2, 5, true);
995 assert_eq!(key, key2);
996 }
997
998 #[test]
999 fn key_derivation_r3_known() {
1000 let o_value = [0u8; 32];
1001 let file_id = b"test_file_id_123";
1002 let key = derive_key_r2_r4(b"", &o_value, -44, file_id, 3, 16, true);
1003 assert_eq!(key.len(), 16);
1004 let key_r2 = derive_key_r2_r4(b"", &o_value, -44, file_id, 2, 5, true);
1006 assert_ne!(key[..5], key_r2[..]);
1007 }
1008
1009 #[test]
1010 fn user_password_verification_r2_round_trip() {
1011 let o_value = [0x42u8; 32];
1013 let file_id = b"abcdef0123456789";
1014 let key = derive_key_r2_r4(b"password", &o_value, -4, file_id, 2, 5, true);
1015
1016 let expected_u = crypto::rc4_crypt(&key, &crypto::md5(&PASSWORD_PADDING));
1018 assert!(verify_user_password_r2(&key, &expected_u));
1019 }
1020
1021 #[test]
1022 fn user_password_verification_r2_wrong_password() {
1023 let o_value = [0x42u8; 32];
1024 let file_id = b"abcdef0123456789";
1025 let key = derive_key_r2_r4(b"password", &o_value, -4, file_id, 2, 5, true);
1026 let expected_u = crypto::rc4_crypt(&key, &crypto::md5(&PASSWORD_PADDING));
1027
1028 let wrong_key = derive_key_r2_r4(b"wrong", &o_value, -4, file_id, 2, 5, true);
1030 assert!(!verify_user_password_r2(&wrong_key, &expected_u));
1031 }
1032
1033 #[test]
1034 fn user_password_verification_r3_round_trip() {
1035 let o_value = [0x42u8; 32];
1036 let file_id = b"abcdef0123456789";
1037 let key = derive_key_r2_r4(b"pass", &o_value, -4, file_id, 3, 16, true);
1038
1039 let mut buf = Vec::new();
1041 buf.extend_from_slice(&PASSWORD_PADDING);
1042 buf.extend_from_slice(file_id);
1043 let hash = crypto::md5(&buf);
1044
1045 let mut result = crypto::rc4_crypt(&key, &hash);
1046 for i in 1..=19u8 {
1047 let modified_key: Vec<u8> = key.iter().map(|b| b ^ i).collect();
1048 result = crypto::rc4_crypt(&modified_key, &result);
1049 }
1050 let mut u_value = result;
1052 u_value.resize(32, 0);
1053
1054 assert!(verify_user_password_r3_r4(&key, &u_value, file_id));
1055 }
1056
1057 #[test]
1058 fn object_key_computation() {
1059 let handler = SecurityHandler {
1060 revision: 3,
1061 key_length_bytes: 5,
1062 encryption_key: vec![0x01, 0x02, 0x03, 0x04, 0x05],
1063 permissions: Permissions::from_bits(-4),
1064 encrypt_metadata: true,
1065 stream_cf: CryptFilterMethod::V2,
1066 string_cf: CryptFilterMethod::V2,
1067 o_value: Vec::new(),
1068 u_value: Vec::new(),
1069 };
1070
1071 let obj_id = ObjectId::new(10, 0);
1072 let key = handler.compute_object_key(obj_id, CryptFilterMethod::V2);
1073
1074 assert_eq!(key.len(), 10);
1076
1077 let key2 = handler.compute_object_key(obj_id, CryptFilterMethod::V2);
1079 assert_eq!(key, key2);
1080
1081 let key3 = handler.compute_object_key(ObjectId::new(11, 0), CryptFilterMethod::V2);
1083 assert_ne!(key, key3);
1084 }
1085
1086 #[test]
1087 fn object_key_aesv2_includes_salt() {
1088 let handler = SecurityHandler {
1089 revision: 4,
1090 key_length_bytes: 16,
1091 encryption_key: vec![0xAA; 16],
1092 permissions: Permissions::from_bits(-4),
1093 encrypt_metadata: true,
1094 stream_cf: CryptFilterMethod::Aesv2,
1095 string_cf: CryptFilterMethod::V2,
1096 o_value: Vec::new(),
1097 u_value: Vec::new(),
1098 };
1099
1100 let obj_id = ObjectId::new(1, 0);
1101 let key_rc4 = handler.compute_object_key(obj_id, CryptFilterMethod::V2);
1102 let key_aes = handler.compute_object_key(obj_id, CryptFilterMethod::Aesv2);
1103
1104 assert_ne!(key_rc4, key_aes);
1106 }
1107
1108 #[test]
1109 fn decrypt_string_rc4_round_trip() {
1110 let handler = SecurityHandler {
1111 revision: 3,
1112 key_length_bytes: 5,
1113 encryption_key: vec![0x01, 0x02, 0x03, 0x04, 0x05],
1114 permissions: Permissions::from_bits(-4),
1115 encrypt_metadata: true,
1116 stream_cf: CryptFilterMethod::V2,
1117 string_cf: CryptFilterMethod::V2,
1118 o_value: Vec::new(),
1119 u_value: Vec::new(),
1120 };
1121
1122 let obj_id = ObjectId::new(1, 0);
1123 let plaintext = b"Hello, encrypted world!";
1124
1125 let object_key = handler.compute_object_key(obj_id, handler.string_cf);
1127 let encrypted = crypto::rc4_crypt(&object_key, plaintext);
1128
1129 let decrypted = handler.decrypt_string(&encrypted, obj_id);
1131 assert_eq!(decrypted, plaintext);
1132 }
1133
1134 #[test]
1135 fn crypt_filter_method_none_passthrough() {
1136 let handler = SecurityHandler {
1137 revision: 4,
1138 key_length_bytes: 16,
1139 encryption_key: vec![0; 16],
1140 permissions: Permissions::from_bits(-4),
1141 encrypt_metadata: true,
1142 stream_cf: CryptFilterMethod::None,
1143 string_cf: CryptFilterMethod::None,
1144 o_value: Vec::new(),
1145 u_value: Vec::new(),
1146 };
1147
1148 let data = b"unencrypted data";
1149 let obj_id = ObjectId::new(1, 0);
1150 assert_eq!(handler.decrypt_string(data, obj_id), data);
1151 assert_eq!(handler.decrypt_stream(data, obj_id), data);
1152 }
1153
1154 #[test]
1155 fn truncate_utf8_password_short() {
1156 let pwd = truncate_utf8_password("hello");
1157 assert_eq!(pwd, b"hello");
1158 }
1159
1160 #[test]
1161 fn truncate_utf8_password_long() {
1162 let long_pwd = "a".repeat(200);
1163 let pwd = truncate_utf8_password(&long_pwd);
1164 assert_eq!(pwd.len(), 127);
1165 }
1166
1167 #[test]
1168 fn compute_r6_hash_basic() {
1169 let hash = compute_r6_hash(b"password", &[0u8; 8], &[]);
1171 assert_eq!(hash.len(), 32);
1172 let hash2 = compute_r6_hash(b"password", &[0u8; 8], &[]);
1174 assert_eq!(hash, hash2);
1175 }
1176
1177 #[test]
1178 fn compute_r6_hash_differs_from_simple_sha256() {
1179 let salt = [0x01u8; 8];
1181 let r6_hash = compute_r6_hash(b"test", &salt, &[]);
1182 let simple_hash = crypto::sha256(&{
1183 let mut v = b"test".to_vec();
1184 v.extend_from_slice(&salt);
1185 v
1186 });
1187 assert_ne!(r6_hash, simple_hash);
1190 }
1191
1192 #[test]
1193 fn compute_r6_hash_with_u_value() {
1194 let salt = [0x42u8; 8];
1196 let hash_no_u = compute_r6_hash(b"pwd", &salt, &[]);
1197 let hash_with_u = compute_r6_hash(b"pwd", &salt, &[0xAAu8; 48]);
1198 assert_ne!(hash_no_u, hash_with_u);
1199 }
1200
1201 #[test]
1202 fn r6_user_password_round_trip() {
1203 let password = b"test123";
1205 let validation_salt = [0x11u8; 8];
1206 let key_salt = [0x22u8; 8];
1207 let file_key = [0x42u8; 32]; let u_hash = compute_r6_hash(password, &validation_salt, &[]);
1211 let mut u_value = Vec::with_capacity(48);
1212 u_value.extend_from_slice(&u_hash);
1213 u_value.extend_from_slice(&validation_salt);
1214 u_value.extend_from_slice(&key_salt);
1215
1216 let key_hash = compute_r6_hash(password, &key_salt, &[]);
1218 let iv = [0u8; 16];
1219 let ue_value = crypto::aes256_cbc_encrypt(&key_hash, &iv, &file_key).unwrap();
1220
1221 let result = derive_key_r6(
1223 "test123", &u_value, &ue_value, &[0u8; 48], &[0u8; 32], )
1226 .unwrap();
1227
1228 assert!(result.is_some());
1229 assert_eq!(result.unwrap(), file_key);
1230 }
1231
1232 #[test]
1233 fn r6_wrong_password_returns_none() {
1234 let password = b"correct";
1235 let validation_salt = [0x33u8; 8];
1236 let key_salt = [0x44u8; 8];
1237
1238 let u_hash = compute_r6_hash(password, &validation_salt, &[]);
1239 let mut u_value = Vec::with_capacity(48);
1240 u_value.extend_from_slice(&u_hash);
1241 u_value.extend_from_slice(&validation_salt);
1242 u_value.extend_from_slice(&key_salt);
1243
1244 let key_hash = compute_r6_hash(password, &key_salt, &[]);
1245 let ue_value = crypto::aes256_cbc_encrypt(&key_hash, &[0u8; 16], &[0u8; 32]).unwrap();
1246
1247 let result = derive_key_r6("wrong", &u_value, &ue_value, &[0u8; 48], &[0u8; 32]).unwrap();
1249
1250 assert!(result.is_none());
1251 }
1252
1253 #[test]
1254 fn owner_password_recovery_r2() {
1255 let user_pwd = b"user";
1257 let owner_pwd = b"owner";
1258 let key_len = 5;
1259
1260 let padded_owner = pad_password(owner_pwd);
1262 let hash = crypto::md5(&padded_owner);
1263 let owner_key = &hash[..key_len];
1264 let padded_user = pad_password(user_pwd);
1265 let o_value = crypto::rc4_crypt(owner_key, &padded_user);
1266
1267 let recovered = recover_user_password_from_owner(owner_pwd, &o_value, 2, key_len);
1269 assert_eq!(&recovered[..], &padded_user[..]);
1270 }
1271
1272 #[test]
1277 fn password_padding_matches_pdf_spec() {
1278 let spec_padding: [u8; 32] = [
1280 0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA,
1281 0x01, 0x08, 0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, 0x2F, 0x0C, 0xA9, 0xFE,
1282 0x64, 0x53, 0x69, 0x7A,
1283 ];
1284 assert_eq!(PASSWORD_PADDING, spec_padding);
1285 }
1286
1287 #[test]
1292 fn big_endian_mod3_basic() {
1293 assert_eq!(big_endian_mod3(&[0u8; 16]), 0);
1295 assert_eq!(big_endian_mod3(&[0xFF; 16]), big_endian_mod3(&[0xFF; 16]));
1297 }
1298
1299 #[test]
1300 fn big_endian_mod3_differs_from_sum_mod3() {
1301 let bytes = [0u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1];
1326 assert_eq!(big_endian_mod3(&bytes), 1);
1327 let bytes = [0u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2];
1328 assert_eq!(big_endian_mod3(&bytes), 2);
1329 let bytes = [0u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3];
1330 assert_eq!(big_endian_mod3(&bytes), 0);
1331 }
1332
1333 #[test]
1338 fn separate_strf_stmf_decrypt() {
1339 let handler = SecurityHandler {
1341 revision: 4,
1342 key_length_bytes: 16,
1343 encryption_key: vec![0xBB; 16],
1344 permissions: Permissions::from_bits(-4),
1345 encrypt_metadata: true,
1346 stream_cf: CryptFilterMethod::Aesv2,
1347 string_cf: CryptFilterMethod::V2,
1348 o_value: Vec::new(),
1349 u_value: Vec::new(),
1350 };
1351
1352 assert_eq!(handler.crypt_filter_method(), CryptFilterMethod::Aesv2);
1354
1355 let obj_id = ObjectId::new(1, 0);
1356
1357 let plaintext = b"hello";
1359 let obj_key_str = handler.compute_object_key(obj_id, CryptFilterMethod::V2);
1360 let encrypted_str = crypto::rc4_crypt(&obj_key_str, plaintext);
1361 let decrypted = handler.decrypt_string(&encrypted_str, obj_id);
1362 assert_eq!(decrypted, plaintext);
1363
1364 let obj_key_stm = handler.compute_object_key(obj_id, CryptFilterMethod::Aesv2);
1366 assert_ne!(obj_key_str, obj_key_stm); }
1368
1369 #[test]
1374 fn encode_password_latin1_ascii() {
1375 let encoded = encode_password_latin1("hello");
1376 assert_eq!(encoded, b"hello");
1377 }
1378
1379 #[test]
1380 fn encode_password_latin1_latin_chars() {
1381 let encoded = encode_password_latin1("\u{00E9}");
1383 assert_eq!(encoded, vec![0xE9]);
1384 }
1385
1386 #[test]
1387 fn encode_password_latin1_non_latin() {
1388 let encoded = encode_password_latin1("\u{4E2D}");
1390 assert_eq!(encoded, vec![0x3F]);
1391 }
1392
1393 #[test]
1394 fn encode_password_latin1_mixed() {
1395 let encoded = encode_password_latin1("a\u{00FC}\u{4E2D}b");
1397 assert_eq!(encoded, vec![b'a', 0xFC, 0x3F, b'b']);
1398 }
1399
1400 #[test]
1405 fn encode_password_latin1_empty() {
1406 let encoded = encode_password_latin1("");
1407 assert!(encoded.is_empty());
1408 }
1409
1410 #[test]
1411 fn encode_password_latin1_ascii_alphanumeric() {
1412 let encoded = encode_password_latin1("ABC123");
1413 assert_eq!(encoded, b"ABC123");
1414 }
1415
1416 #[test]
1417 fn encode_password_latin1_0xff() {
1418 let encoded = encode_password_latin1("\u{00FF}");
1420 assert_eq!(encoded, vec![0xFF]);
1421 }
1422
1423 #[test]
1424 fn encode_password_latin1_over_range() {
1425 let encoded = encode_password_latin1("\u{0100}");
1427 assert_eq!(encoded, vec![0x3F]); }
1429
1430 #[test]
1431 fn truncate_utf8_password_empty() {
1432 let pwd = truncate_utf8_password("");
1433 assert!(pwd.is_empty());
1434 }
1435
1436 #[test]
1437 fn truncate_utf8_password_exact_127() {
1438 let input = "a".repeat(127);
1439 let pwd = truncate_utf8_password(&input);
1440 assert_eq!(pwd.len(), 127);
1441 assert_eq!(pwd, input.as_bytes());
1442 }
1443
1444 #[test]
1445 fn truncate_utf8_password_over_127() {
1446 let input = "a".repeat(128);
1447 let pwd = truncate_utf8_password(&input);
1448 assert_eq!(pwd.len(), 127);
1449 }
1450
1451 #[test]
1452 fn perms_validation_construct_and_verify() {
1453 let permissions: i32 = -4;
1458 let mut perms_plain = [0u8; 16];
1459 perms_plain[0..4].copy_from_slice(&permissions.to_le_bytes());
1460 perms_plain[8] = b'T'; perms_plain[9] = b'a';
1463 perms_plain[10] = b'd';
1464 perms_plain[11] = b'b';
1465
1466 let file_key = [0x42u8; 32];
1468 use aes::cipher::{BlockEncrypt, KeyInit};
1471 let cipher = aes::Aes256::new_from_slice(&file_key).unwrap();
1472 let mut block = aes::cipher::generic_array::GenericArray::clone_from_slice(&perms_plain);
1473 cipher.encrypt_block(&mut block);
1474 let encrypted_perms: [u8; 16] = block.into();
1475
1476 let decrypted = crypto::aes256_ecb_decrypt_block(&file_key, &encrypted_perms).unwrap();
1478
1479 assert_eq!(decrypted[8], b'T');
1481 assert_eq!(&decrypted[9..12], b"adb");
1482 let recovered_p =
1483 i32::from_le_bytes([decrypted[0], decrypted[1], decrypted[2], decrypted[3]]);
1484 assert_eq!(recovered_p, permissions);
1485 }
1486}