1use super::objects::PdfDictionary;
7use super::{ParseError, ParseResult};
8use crate::encryption::{
9 EncryptionKey, Permissions, Rc4, Rc4Key, StandardSecurityHandler, UserPassword,
10};
11use crate::objects::ObjectId;
12
13#[derive(Debug, Clone)]
15pub struct EncryptionInfo {
16 pub filter: String,
18 pub v: i32,
20 pub r: i32,
22 pub o: Vec<u8>,
24 pub u: Vec<u8>,
26 pub p: i32,
28 pub length: Option<i32>,
30}
31
32pub struct EncryptionHandler {
34 encryption_info: EncryptionInfo,
36 security_handler: StandardSecurityHandler,
38 encryption_key: Option<EncryptionKey>,
40 file_id: Option<Vec<u8>>,
42}
43
44impl EncryptionHandler {
45 pub fn new(encrypt_dict: &PdfDictionary, file_id: Option<Vec<u8>>) -> ParseResult<Self> {
47 let encryption_info = Self::parse_encryption_dict(encrypt_dict)?;
48
49 let security_handler = match encryption_info.r {
51 2 => StandardSecurityHandler::rc4_40bit(),
52 3 | 4 => StandardSecurityHandler::rc4_128bit(),
53 5 => StandardSecurityHandler::aes_256_r5(),
54 6 => StandardSecurityHandler::aes_256_r6(),
55 _ => {
56 return Err(ParseError::SyntaxError {
57 position: 0,
58 message: format!("Encryption revision {} not supported", encryption_info.r),
59 });
60 }
61 };
62
63 Ok(Self {
64 encryption_info,
65 security_handler,
66 encryption_key: None,
67 file_id,
68 })
69 }
70
71 fn parse_encryption_dict(dict: &PdfDictionary) -> ParseResult<EncryptionInfo> {
73 let filter = dict
75 .get("Filter")
76 .and_then(|obj| obj.as_name())
77 .map(|name| name.0.as_str())
78 .ok_or_else(|| ParseError::MissingKey("Filter".to_string()))?;
79
80 if filter != "Standard" {
81 return Err(ParseError::SyntaxError {
82 position: 0,
83 message: format!("Encryption filter '{filter}' not supported"),
84 });
85 }
86
87 let v = dict
89 .get("V")
90 .and_then(|obj| obj.as_integer())
91 .map(|i| i as i32)
92 .unwrap_or(0);
93
94 let r = dict
96 .get("R")
97 .and_then(|obj| obj.as_integer())
98 .map(|i| i as i32)
99 .ok_or_else(|| ParseError::MissingKey("R".to_string()))?;
100
101 let o = dict
103 .get("O")
104 .and_then(|obj| obj.as_string())
105 .ok_or_else(|| ParseError::MissingKey("O".to_string()))?
106 .as_bytes()
107 .to_vec();
108
109 let u = dict
111 .get("U")
112 .and_then(|obj| obj.as_string())
113 .ok_or_else(|| ParseError::MissingKey("U".to_string()))?
114 .as_bytes()
115 .to_vec();
116
117 let p = dict
119 .get("P")
120 .and_then(|obj| obj.as_integer())
121 .map(|i| i as i32)
122 .ok_or_else(|| ParseError::MissingKey("P".to_string()))?;
123
124 let length = dict
126 .get("Length")
127 .and_then(|obj| obj.as_integer())
128 .map(|i| i as i32);
129
130 Ok(EncryptionInfo {
131 filter: filter.to_string(),
132 v,
133 r,
134 o,
135 u,
136 p,
137 length,
138 })
139 }
140
141 pub fn detect_encryption(trailer: &PdfDictionary) -> bool {
143 trailer.contains_key("Encrypt")
144 }
145
146 pub fn unlock_with_user_password(&mut self, password: &str) -> ParseResult<bool> {
148 let user_password = UserPassword(password.to_string());
149
150 let permissions = Permissions::from_bits(self.encryption_info.p as u32);
152
153 #[cfg(debug_assertions)]
155 {
156 eprintln!("[DEBUG unlock] password len: {}", password.len());
157 eprintln!(
158 "[DEBUG unlock] O[0..8]: {:02x?}",
159 &self.encryption_info.o[..8.min(self.encryption_info.o.len())]
160 );
161 eprintln!(
162 "[DEBUG unlock] U[0..8]: {:02x?}",
163 &self.encryption_info.u[..8.min(self.encryption_info.u.len())]
164 );
165 eprintln!(
166 "[DEBUG unlock] P: {} (0x{:08X})",
167 self.encryption_info.p, self.encryption_info.p as u32
168 );
169 eprintln!("[DEBUG unlock] R: {}", self.encryption_info.r);
170 if let Some(ref fid) = self.file_id {
171 eprintln!(
172 "[DEBUG unlock] file_id len: {}, first bytes: {:02x?}",
173 fid.len(),
174 &fid[..8.min(fid.len())]
175 );
176 } else {
177 eprintln!("[DEBUG unlock] file_id: None");
178 }
179 }
180
181 let computed_u = self
182 .security_handler
183 .compute_user_hash(
184 &user_password,
185 &self.encryption_info.o,
186 permissions,
187 self.file_id.as_deref(),
188 )
189 .map_err(|e| ParseError::SyntaxError {
190 position: 0,
191 message: format!("Failed to compute user hash: {e}"),
192 })?;
193
194 let comparison_length = if self.encryption_info.r >= 3 { 16 } else { 32 };
196
197 #[cfg(debug_assertions)]
198 {
199 eprintln!("[DEBUG unlock] computed_u[0..8]: {:02x?}", &computed_u[..8]);
200 eprintln!(
201 "[DEBUG unlock] stored_u[0..8]: {:02x?}",
202 &self.encryption_info.u[..8.min(self.encryption_info.u.len())]
203 );
204 eprintln!("[DEBUG unlock] comparison_length: {}", comparison_length);
205 }
206
207 let matches =
208 computed_u[..comparison_length] == self.encryption_info.u[..comparison_length];
209
210 if matches {
211 let key = self
213 .security_handler
214 .compute_encryption_key(
215 &user_password,
216 &self.encryption_info.o,
217 permissions,
218 self.file_id.as_deref(),
219 )
220 .map_err(|e| ParseError::SyntaxError {
221 position: 0,
222 message: format!("Failed to compute encryption key: {e}"),
223 })?;
224 self.encryption_key = Some(key);
225 }
226
227 Ok(matches)
228 }
229
230 pub fn unlock_with_owner_password(&mut self, password: &str) -> ParseResult<bool> {
237 const PADDING: [u8; 32] = [
239 0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA,
240 0x01, 0x08, 0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, 0x2F, 0x0C, 0xA9, 0xFE,
241 0x64, 0x53, 0x69, 0x7A,
242 ];
243
244 let mut padded = [0u8; 32];
246 let password_bytes = password.as_bytes();
247 let len = password_bytes.len().min(32);
248 padded[..len].copy_from_slice(&password_bytes[..len]);
249 if len < 32 {
250 padded[len..].copy_from_slice(&PADDING[..32 - len]);
251 }
252
253 let mut hash = md5::compute(&padded).to_vec();
255
256 let key_length = self.security_handler.key_length;
258 if self.encryption_info.r >= 3 {
259 for _ in 0..50 {
260 hash = md5::compute(&hash).to_vec();
261 }
262 }
263
264 let mut decrypted = self.encryption_info.o[..32].to_vec();
266
267 if self.encryption_info.r >= 3 {
268 for i in (0..20).rev() {
270 let mut key_bytes = hash[..key_length].to_vec();
271 for byte in &mut key_bytes {
272 *byte ^= i as u8;
273 }
274 let rc4_key = Rc4Key::from_slice(&key_bytes);
275 let mut cipher = Rc4::new(&rc4_key);
276 decrypted = cipher.process(&decrypted);
277 }
278 } else {
279 let rc4_key = Rc4Key::from_slice(&hash[..key_length]);
281 let mut cipher = Rc4::new(&rc4_key);
282 decrypted = cipher.process(&decrypted);
283 }
284
285 let user_pwd_end = decrypted
288 .iter()
289 .position(|&b| {
290 b == PADDING[0] && decrypted.len() > 1
292 })
293 .unwrap_or(32);
294
295 let user_password = String::from_utf8_lossy(&decrypted[..user_pwd_end]).to_string();
296
297 #[cfg(debug_assertions)]
298 {
299 eprintln!(
300 "[DEBUG owner unlock] derived user password: {:?}",
301 &user_password
302 );
303 eprintln!(
304 "[DEBUG owner unlock] decrypted bytes: {:02x?}",
305 &decrypted[..8]
306 );
307 }
308
309 if self.unlock_with_user_password(&user_password)? {
311 return Ok(true);
312 }
313
314 let full_user_password = String::from_utf8_lossy(&decrypted).to_string();
317 self.unlock_with_user_password(&full_user_password)
318 }
319
320 pub fn try_empty_password(&mut self) -> ParseResult<bool> {
322 self.unlock_with_user_password("")
323 }
324
325 pub fn is_unlocked(&self) -> bool {
327 self.encryption_key.is_some()
328 }
329
330 pub fn encryption_key(&self) -> Option<&EncryptionKey> {
332 self.encryption_key.as_ref()
333 }
334
335 pub fn decrypt_string(&self, data: &[u8], obj_id: &ObjectId) -> ParseResult<Vec<u8>> {
337 match &self.encryption_key {
338 Some(key) => Ok(self.security_handler.decrypt_string(data, key, obj_id)),
339 None => Err(ParseError::EncryptionNotSupported),
340 }
341 }
342
343 pub fn decrypt_stream(&self, data: &[u8], obj_id: &ObjectId) -> ParseResult<Vec<u8>> {
345 match &self.encryption_key {
346 Some(key) => Ok(self.security_handler.decrypt_stream(data, key, obj_id)),
347 None => Err(ParseError::EncryptionNotSupported),
348 }
349 }
350
351 pub fn algorithm_info(&self) -> String {
353 match (
354 self.encryption_info.r,
355 self.encryption_info.length.unwrap_or(40),
356 ) {
357 (2, _) => "RC4 40-bit".to_string(),
358 (3, len) => format!("RC4 {len}-bit"),
359 (4, len) => format!("RC4 {len}-bit with metadata control"),
360 (5, _) => "AES-256 (Revision 5)".to_string(),
361 (6, _) => "AES-256 (Revision 6, Unicode passwords)".to_string(),
362 (r, len) => format!("Unknown revision {r} with {len}-bit key"),
363 }
364 }
365
366 pub fn permissions(&self) -> Permissions {
368 Permissions::from_bits(self.encryption_info.p as u32)
369 }
370
371 pub fn has_file_id(&self) -> bool {
373 self.file_id.is_some()
374 }
375
376 pub fn revision(&self) -> i32 {
378 self.encryption_info.r
379 }
380
381 pub fn encrypt_strings(&self) -> bool {
383 true
385 }
386
387 pub fn encrypt_streams(&self) -> bool {
389 true
391 }
392
393 pub fn encrypt_metadata(&self) -> bool {
395 true
398 }
399}
400
401#[derive(Debug)]
403pub enum PasswordResult {
404 Success,
406 Rejected,
408 Cancelled,
410}
411
412pub trait PasswordProvider {
414 fn prompt_user_password(&self) -> ParseResult<Option<String>>;
416
417 fn prompt_owner_password(&self) -> ParseResult<Option<String>>;
419}
420
421pub struct ConsolePasswordProvider;
423
424impl PasswordProvider for ConsolePasswordProvider {
425 fn prompt_user_password(&self) -> ParseResult<Option<String>> {
426 tracing::debug!(
427 "PDF is encrypted. Enter user password (or press Enter for empty password):"
428 );
429
430 let mut input = String::new();
431 std::io::stdin()
432 .read_line(&mut input)
433 .map_err(|e| ParseError::SyntaxError {
434 position: 0,
435 message: format!("Failed to read password: {e}"),
436 })?;
437
438 input.truncate(input.trim_end().len());
440 Ok(Some(input))
441 }
442
443 fn prompt_owner_password(&self) -> ParseResult<Option<String>> {
444 tracing::debug!("User password failed. Enter owner password:");
445
446 let mut input = String::new();
447 std::io::stdin()
448 .read_line(&mut input)
449 .map_err(|e| ParseError::SyntaxError {
450 position: 0,
451 message: format!("Failed to read password: {e}"),
452 })?;
453
454 input.truncate(input.trim_end().len());
456 Ok(Some(input))
457 }
458}
459
460pub struct InteractiveDecryption<P: PasswordProvider> {
462 password_provider: P,
463}
464
465impl<P: PasswordProvider> InteractiveDecryption<P> {
466 pub fn new(password_provider: P) -> Self {
468 Self { password_provider }
469 }
470
471 pub fn unlock_pdf(&self, handler: &mut EncryptionHandler) -> ParseResult<PasswordResult> {
473 if handler.try_empty_password()? {
475 return Ok(PasswordResult::Success);
476 }
477
478 if let Some(password) = self.password_provider.prompt_user_password()? {
480 if handler.unlock_with_user_password(&password)? {
481 return Ok(PasswordResult::Success);
482 }
483 } else {
484 return Ok(PasswordResult::Cancelled);
485 }
486
487 if let Some(password) = self.password_provider.prompt_owner_password()? {
489 if handler.unlock_with_owner_password(&password)? {
490 return Ok(PasswordResult::Success);
491 }
492 } else {
493 return Ok(PasswordResult::Cancelled);
494 }
495
496 Ok(PasswordResult::Rejected)
497 }
498}
499
500#[cfg(test)]
501mod tests {
502 use super::*;
503 use crate::parser::objects::{PdfDictionary, PdfName, PdfObject, PdfString};
504
505 fn create_test_encryption_dict() -> PdfDictionary {
506 let mut dict = PdfDictionary::new();
507 dict.insert(
508 "Filter".to_string(),
509 PdfObject::Name(PdfName("Standard".to_string())),
510 );
511 dict.insert("V".to_string(), PdfObject::Integer(1));
512 dict.insert("R".to_string(), PdfObject::Integer(2));
513 dict.insert(
514 "O".to_string(),
515 PdfObject::String(PdfString::new(vec![0u8; 32])),
516 );
517 dict.insert(
518 "U".to_string(),
519 PdfObject::String(PdfString::new(vec![0u8; 32])),
520 );
521 dict.insert("P".to_string(), PdfObject::Integer(-4));
522 dict
523 }
524
525 #[test]
526 fn test_encryption_detection() {
527 let mut trailer = PdfDictionary::new();
528 assert!(!EncryptionHandler::detect_encryption(&trailer));
529
530 trailer.insert("Encrypt".to_string(), PdfObject::Reference(1, 0));
531 assert!(EncryptionHandler::detect_encryption(&trailer));
532 }
533
534 #[test]
535 fn test_encryption_info_parsing() {
536 let dict = create_test_encryption_dict();
537 let info = EncryptionHandler::parse_encryption_dict(&dict).unwrap();
538
539 assert_eq!(info.filter, "Standard");
540 assert_eq!(info.v, 1);
541 assert_eq!(info.r, 2);
542 assert_eq!(info.o.len(), 32);
543 assert_eq!(info.u.len(), 32);
544 assert_eq!(info.p, -4);
545 }
546
547 #[test]
548 fn test_encryption_handler_creation() {
549 let dict = create_test_encryption_dict();
550 let handler = EncryptionHandler::new(&dict, None).unwrap();
551
552 assert_eq!(handler.encryption_info.r, 2);
553 assert!(!handler.is_unlocked());
554 assert_eq!(handler.algorithm_info(), "RC4 40-bit");
555 }
556
557 #[test]
558 fn test_empty_password_attempt() {
559 let dict = create_test_encryption_dict();
560 let mut handler = EncryptionHandler::new(&dict, None).unwrap();
561
562 let result = handler.try_empty_password().unwrap();
564 assert!(!result);
565 assert!(!handler.is_unlocked());
566 }
567
568 #[test]
569 fn test_permissions() {
570 let dict = create_test_encryption_dict();
571 let handler = EncryptionHandler::new(&dict, None).unwrap();
572
573 let permissions = handler.permissions();
574 assert!(permissions.bits() != 0);
576 }
577
578 #[test]
579 fn test_encryption_flags() {
580 let dict = create_test_encryption_dict();
581 let handler = EncryptionHandler::new(&dict, None).unwrap();
582
583 assert!(handler.encrypt_strings());
584 assert!(handler.encrypt_streams());
585 assert!(handler.encrypt_metadata());
586 }
587
588 #[test]
589 fn test_decrypt_without_key() {
590 let dict = create_test_encryption_dict();
591 let handler = EncryptionHandler::new(&dict, None).unwrap();
592
593 let obj_id = ObjectId::new(1, 0);
594 let result = handler.decrypt_string(b"test", &obj_id);
595 assert!(result.is_err());
596 }
597
598 #[test]
599 fn test_unsupported_filter() {
600 let mut dict = PdfDictionary::new();
601 dict.insert(
602 "Filter".to_string(),
603 PdfObject::Name(PdfName("UnsupportedFilter".to_string())),
604 );
605 dict.insert("R".to_string(), PdfObject::Integer(2));
606 dict.insert(
607 "O".to_string(),
608 PdfObject::String(PdfString::new(vec![0u8; 32])),
609 );
610 dict.insert(
611 "U".to_string(),
612 PdfObject::String(PdfString::new(vec![0u8; 32])),
613 );
614 dict.insert("P".to_string(), PdfObject::Integer(-4));
615
616 let result = EncryptionHandler::new(&dict, None);
617 assert!(result.is_err());
618 }
619
620 #[test]
621 fn test_unsupported_revision() {
622 let mut dict = create_test_encryption_dict();
623 dict.insert("R".to_string(), PdfObject::Integer(99)); let result = EncryptionHandler::new(&dict, None);
626 assert!(result.is_err());
627 }
628
629 #[test]
630 fn test_missing_required_keys() {
631 let test_cases = vec![
632 ("Filter", PdfObject::Name(PdfName("Standard".to_string()))),
633 ("R", PdfObject::Integer(2)),
634 ("O", PdfObject::String(PdfString::new(vec![0u8; 32]))),
635 ("U", PdfObject::String(PdfString::new(vec![0u8; 32]))),
636 ("P", PdfObject::Integer(-4)),
637 ];
638
639 for (skip_key, _) in test_cases {
640 let mut dict = create_test_encryption_dict();
641 dict.0.remove(&PdfName(skip_key.to_string()));
642
643 let result = EncryptionHandler::parse_encryption_dict(&dict);
644 assert!(result.is_err(), "Should fail when {skip_key} is missing");
645 }
646 }
647
648 struct MockPasswordProvider {
650 user_password: Option<String>,
651 owner_password: Option<String>,
652 }
653
654 impl PasswordProvider for MockPasswordProvider {
655 fn prompt_user_password(&self) -> ParseResult<Option<String>> {
656 Ok(self.user_password.clone())
657 }
658
659 fn prompt_owner_password(&self) -> ParseResult<Option<String>> {
660 Ok(self.owner_password.clone())
661 }
662 }
663
664 #[test]
665 fn test_interactive_decryption_cancelled() {
666 let provider = MockPasswordProvider {
667 user_password: None,
668 owner_password: None,
669 };
670
671 let decryption = InteractiveDecryption::new(provider);
672 let dict = create_test_encryption_dict();
673 let mut handler = EncryptionHandler::new(&dict, None).unwrap();
674
675 let result = decryption.unlock_pdf(&mut handler).unwrap();
676 matches!(result, PasswordResult::Cancelled);
677 }
678
679 #[test]
680 fn test_interactive_decryption_rejected() {
681 let provider = MockPasswordProvider {
682 user_password: Some("wrong_password".to_string()),
683 owner_password: Some("also_wrong".to_string()),
684 };
685
686 let decryption = InteractiveDecryption::new(provider);
687 let dict = create_test_encryption_dict();
688 let mut handler = EncryptionHandler::new(&dict, None).unwrap();
689
690 let result = decryption.unlock_pdf(&mut handler).unwrap();
691 matches!(result, PasswordResult::Rejected);
692 }
693
694 #[test]
697 fn test_malformed_encryption_dictionary_invalid_types() {
698 let mut dict = PdfDictionary::new();
700 dict.insert("Filter".to_string(), PdfObject::Integer(123)); dict.insert("R".to_string(), PdfObject::Integer(2));
702 dict.insert(
703 "O".to_string(),
704 PdfObject::String(PdfString::new(vec![0u8; 32])),
705 );
706 dict.insert(
707 "U".to_string(),
708 PdfObject::String(PdfString::new(vec![0u8; 32])),
709 );
710 dict.insert("P".to_string(), PdfObject::Integer(-4));
711
712 let result = EncryptionHandler::parse_encryption_dict(&dict);
713 assert!(result.is_err());
714
715 let mut dict = create_test_encryption_dict();
717 dict.insert(
718 "R".to_string(),
719 PdfObject::Name(PdfName("not_a_number".to_string())),
720 );
721 let result = EncryptionHandler::parse_encryption_dict(&dict);
722 assert!(result.is_err());
723 }
724
725 #[test]
726 fn test_encryption_dictionary_edge_values() {
727 let mut dict = create_test_encryption_dict();
729 dict.insert("R".to_string(), PdfObject::Integer(0)); let result = EncryptionHandler::new(&dict, None);
731 assert!(result.is_err());
732
733 let mut dict = create_test_encryption_dict();
735 dict.insert("R".to_string(), PdfObject::Integer(-1));
736 let result = EncryptionHandler::new(&dict, None);
737 assert!(result.is_err());
738
739 let mut dict = create_test_encryption_dict();
741 dict.insert("R".to_string(), PdfObject::Integer(1000));
742 let result = EncryptionHandler::new(&dict, None);
743 assert!(result.is_err());
744 }
745
746 #[test]
747 fn test_encryption_dictionary_invalid_hash_lengths() {
748 let mut dict = create_test_encryption_dict();
750 dict.insert(
751 "O".to_string(),
752 PdfObject::String(PdfString::new(vec![0u8; 16])),
753 ); let result = EncryptionHandler::parse_encryption_dict(&dict);
755 assert!(result.is_ok());
757
758 let mut dict = create_test_encryption_dict();
760 dict.insert(
761 "U".to_string(),
762 PdfObject::String(PdfString::new(vec![0u8; 64])),
763 ); let result = EncryptionHandler::parse_encryption_dict(&dict);
765 assert!(result.is_ok());
766
767 let mut dict = create_test_encryption_dict();
769 dict.insert("O".to_string(), PdfObject::String(PdfString::new(vec![])));
770 dict.insert("U".to_string(), PdfObject::String(PdfString::new(vec![])));
771 let result = EncryptionHandler::parse_encryption_dict(&dict);
772 assert!(result.is_ok());
773 }
774
775 #[test]
776 fn test_encryption_with_different_key_lengths() {
777 let mut dict = create_test_encryption_dict();
779 dict.insert("R".to_string(), PdfObject::Integer(2));
780 let handler = EncryptionHandler::new(&dict, None).unwrap();
781 assert_eq!(handler.algorithm_info(), "RC4 40-bit");
782
783 let mut dict = create_test_encryption_dict();
785 dict.insert("R".to_string(), PdfObject::Integer(3));
786 dict.insert("Length".to_string(), PdfObject::Integer(128));
787 let handler = EncryptionHandler::new(&dict, None).unwrap();
788 assert_eq!(handler.algorithm_info(), "RC4 128-bit");
789
790 let mut dict = create_test_encryption_dict();
792 dict.insert("R".to_string(), PdfObject::Integer(4));
793 dict.insert("Length".to_string(), PdfObject::Integer(128));
794 let handler = EncryptionHandler::new(&dict, None).unwrap();
795 assert_eq!(
796 handler.algorithm_info(),
797 "RC4 128-bit with metadata control"
798 );
799
800 let mut dict = create_test_encryption_dict();
802 dict.insert("R".to_string(), PdfObject::Integer(5));
803 dict.insert("V".to_string(), PdfObject::Integer(5));
804 let handler = EncryptionHandler::new(&dict, None).unwrap();
805 assert_eq!(handler.algorithm_info(), "AES-256 (Revision 5)");
806
807 let mut dict = create_test_encryption_dict();
809 dict.insert("R".to_string(), PdfObject::Integer(6));
810 dict.insert("V".to_string(), PdfObject::Integer(5));
811 let handler = EncryptionHandler::new(&dict, None).unwrap();
812 assert_eq!(
813 handler.algorithm_info(),
814 "AES-256 (Revision 6, Unicode passwords)"
815 );
816 }
817
818 #[test]
819 fn test_file_id_handling() {
820 let dict = create_test_encryption_dict();
821
822 let file_id = Some(b"test_file_id_12345678".to_vec());
824 let handler = EncryptionHandler::new(&dict, file_id.clone()).unwrap();
825 assert_eq!(handler.file_id, file_id);
827
828 let handler = EncryptionHandler::new(&dict, None).unwrap();
830 assert_eq!(handler.file_id, None);
831
832 let empty_file_id = Some(vec![]);
834 let handler = EncryptionHandler::new(&dict, empty_file_id.clone()).unwrap();
835 assert_eq!(handler.file_id, empty_file_id);
836 }
837
838 #[test]
839 fn test_permissions_edge_cases() {
840 let permission_values = vec![0, -1, -4, -44, -100, i32::MAX, i32::MIN];
842
843 for p_value in permission_values {
844 let mut dict = create_test_encryption_dict();
845 dict.insert("P".to_string(), PdfObject::Integer(p_value as i64));
846 let handler = EncryptionHandler::new(&dict, None).unwrap();
847
848 let permissions = handler.permissions();
849 assert_eq!(permissions.bits(), p_value as u32);
850 }
851 }
852
853 #[test]
854 fn test_decrypt_with_different_object_ids() {
855 let dict = create_test_encryption_dict();
856 let handler = EncryptionHandler::new(&dict, None).unwrap();
857 let test_data = b"test data";
858
859 let object_ids = vec![
861 ObjectId::new(1, 0),
862 ObjectId::new(999, 0),
863 ObjectId::new(1, 999),
864 ObjectId::new(u32::MAX, u16::MAX),
865 ];
866
867 for obj_id in object_ids {
868 let result = handler.decrypt_string(test_data, &obj_id);
869 assert!(result.is_err());
870
871 let result = handler.decrypt_stream(test_data, &obj_id);
872 assert!(result.is_err());
873 }
874 }
875
876 #[test]
877 fn test_password_scenarios_comprehensive() {
878 let dict = create_test_encryption_dict();
879 let mut handler = EncryptionHandler::new(&dict, None).unwrap();
880
881 let test_passwords = vec![
883 "".to_string(), " ".to_string(), " ".to_string(), "password".to_string(), "Password123!@#".to_string(), "a".repeat(32), "a".repeat(50), "unicode_ñáéíóú".to_string(), "pass\nwith\nnewlines".to_string(), "pass\twith\ttabs".to_string(), "pass with spaces".to_string(), "🔐🗝️📄".to_string(), ];
896
897 for password in test_passwords {
898 let result = handler.unlock_with_user_password(&password);
900 assert!(result.is_ok());
901 assert!(!result.unwrap());
902
903 let result = handler.unlock_with_owner_password(&password);
904 assert!(result.is_ok());
905 assert!(!result.unwrap());
906 }
907 }
908
909 #[test]
910 fn test_encryption_handler_thread_safety_simulation() {
911 let dict = create_test_encryption_dict();
913 let handler = EncryptionHandler::new(&dict, None).unwrap();
914
915 for _ in 0..100 {
917 assert!(!handler.is_unlocked());
918 assert_eq!(handler.algorithm_info(), "RC4 40-bit");
919 assert!(handler.encrypt_strings());
920 assert!(handler.encrypt_streams());
921 assert!(handler.encrypt_metadata());
922 }
923 }
924
925 #[test]
926 fn test_encryption_state_transitions() {
927 let dict = create_test_encryption_dict();
928 let mut handler = EncryptionHandler::new(&dict, None).unwrap();
929
930 assert!(!handler.is_unlocked());
932
933 let result = handler.try_empty_password().unwrap();
935 assert!(!result);
936 assert!(!handler.is_unlocked());
937
938 let result = handler.unlock_with_user_password("test").unwrap();
940 assert!(!result);
941 assert!(!handler.is_unlocked());
942
943 let result = handler.unlock_with_owner_password("test").unwrap();
945 assert!(!result);
946 assert!(!handler.is_unlocked());
947
948 assert!(!handler.is_unlocked());
950 }
951
952 #[test]
953 fn test_interactive_decryption_edge_cases() {
954 let provider = MockPasswordProvider {
956 user_password: None,
957 owner_password: None,
958 };
959
960 let decryption = InteractiveDecryption::new(provider);
961 let dict = create_test_encryption_dict();
962 let mut handler = EncryptionHandler::new(&dict, None).unwrap();
963
964 let result = decryption.unlock_pdf(&mut handler).unwrap();
965 matches!(result, PasswordResult::Cancelled);
966
967 let provider = MockPasswordProvider {
969 user_password: Some("".to_string()),
970 owner_password: Some("".to_string()),
971 };
972
973 let decryption = InteractiveDecryption::new(provider);
974 let mut handler = EncryptionHandler::new(&dict, None).unwrap();
975
976 let result = decryption.unlock_pdf(&mut handler).unwrap();
977 matches!(result, PasswordResult::Rejected);
978 }
979
980 struct EdgeCasePasswordProvider {
982 call_count: std::cell::RefCell<usize>,
983 passwords: Vec<Option<String>>,
984 }
985
986 impl EdgeCasePasswordProvider {
987 fn new(passwords: Vec<Option<String>>) -> Self {
988 Self {
989 call_count: std::cell::RefCell::new(0),
990 passwords,
991 }
992 }
993 }
994
995 impl PasswordProvider for EdgeCasePasswordProvider {
996 fn prompt_user_password(&self) -> ParseResult<Option<String>> {
997 let mut count = self.call_count.borrow_mut();
998 if *count < self.passwords.len() {
999 let result = self.passwords[*count].clone();
1000 *count += 1;
1001 Ok(result)
1002 } else {
1003 Ok(None)
1004 }
1005 }
1006
1007 fn prompt_owner_password(&self) -> ParseResult<Option<String>> {
1008 self.prompt_user_password()
1009 }
1010 }
1011
1012 #[test]
1013 fn test_interactive_decryption_with_sequence() {
1014 let passwords = vec![
1015 Some("first_attempt".to_string()),
1016 Some("second_attempt".to_string()),
1017 None, ];
1019
1020 let provider = EdgeCasePasswordProvider::new(passwords);
1021 let decryption = InteractiveDecryption::new(provider);
1022 let dict = create_test_encryption_dict();
1023 let mut handler = EncryptionHandler::new(&dict, None).unwrap();
1024
1025 let result = decryption.unlock_pdf(&mut handler).unwrap();
1026 matches!(result, PasswordResult::Cancelled);
1027 }
1028}