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 pub ue: Option<Vec<u8>>,
32 pub oe: Option<Vec<u8>>,
34}
35
36pub struct EncryptionHandler {
38 encryption_info: EncryptionInfo,
40 security_handler: StandardSecurityHandler,
42 encryption_key: Option<EncryptionKey>,
44 file_id: Option<Vec<u8>>,
46}
47
48impl EncryptionHandler {
49 pub fn new(encrypt_dict: &PdfDictionary, file_id: Option<Vec<u8>>) -> ParseResult<Self> {
51 let encryption_info = Self::parse_encryption_dict(encrypt_dict)?;
52
53 let security_handler = match encryption_info.r {
55 2 => StandardSecurityHandler::rc4_40bit(),
56 3 | 4 => StandardSecurityHandler::rc4_128bit(),
57 5 => StandardSecurityHandler::aes_256_r5(),
58 6 => StandardSecurityHandler::aes_256_r6(),
59 _ => {
60 return Err(ParseError::SyntaxError {
61 position: 0,
62 message: format!("Encryption revision {} not supported", encryption_info.r),
63 });
64 }
65 };
66
67 Ok(Self {
68 encryption_info,
69 security_handler,
70 encryption_key: None,
71 file_id,
72 })
73 }
74
75 fn parse_encryption_dict(dict: &PdfDictionary) -> ParseResult<EncryptionInfo> {
77 let filter = dict
79 .get("Filter")
80 .and_then(|obj| obj.as_name())
81 .map(|name| name.0.as_str())
82 .ok_or_else(|| ParseError::MissingKey("Filter".to_string()))?;
83
84 if filter != "Standard" {
85 return Err(ParseError::SyntaxError {
86 position: 0,
87 message: format!("Encryption filter '{filter}' not supported"),
88 });
89 }
90
91 let v = dict
93 .get("V")
94 .and_then(|obj| obj.as_integer())
95 .map(|i| i as i32)
96 .unwrap_or(0);
97
98 let r = dict
100 .get("R")
101 .and_then(|obj| obj.as_integer())
102 .map(|i| i as i32)
103 .ok_or_else(|| ParseError::MissingKey("R".to_string()))?;
104
105 let o = dict
107 .get("O")
108 .and_then(|obj| obj.as_string())
109 .ok_or_else(|| ParseError::MissingKey("O".to_string()))?
110 .as_bytes()
111 .to_vec();
112
113 let u = dict
115 .get("U")
116 .and_then(|obj| obj.as_string())
117 .ok_or_else(|| ParseError::MissingKey("U".to_string()))?
118 .as_bytes()
119 .to_vec();
120
121 let p = dict
123 .get("P")
124 .and_then(|obj| obj.as_integer())
125 .map(|i| i as i32)
126 .ok_or_else(|| ParseError::MissingKey("P".to_string()))?;
127
128 let length = dict
130 .get("Length")
131 .and_then(|obj| obj.as_integer())
132 .map(|i| i as i32);
133
134 let ue = dict
136 .get("UE")
137 .and_then(|obj| obj.as_string())
138 .map(|s| s.as_bytes().to_vec());
139
140 let oe = dict
142 .get("OE")
143 .and_then(|obj| obj.as_string())
144 .map(|s| s.as_bytes().to_vec());
145
146 Ok(EncryptionInfo {
147 filter: filter.to_string(),
148 v,
149 r,
150 o,
151 u,
152 p,
153 length,
154 ue,
155 oe,
156 })
157 }
158
159 pub fn detect_encryption(trailer: &PdfDictionary) -> bool {
161 trailer.contains_key("Encrypt")
162 }
163
164 pub fn unlock_with_user_password(&mut self, password: &str) -> ParseResult<bool> {
166 let user_password = UserPassword(password.to_string());
167
168 match self.encryption_info.r {
169 5 | 6 => self.unlock_user_r5_r6(&user_password),
170 _ => self.unlock_user_r2_r4(&user_password),
171 }
172 }
173
174 fn unlock_user_r2_r4(&mut self, user_password: &UserPassword) -> ParseResult<bool> {
176 let permissions = Permissions::from_bits(self.encryption_info.p as u32);
177
178 let computed_u = self
179 .security_handler
180 .compute_user_hash(
181 user_password,
182 &self.encryption_info.o,
183 permissions,
184 self.file_id.as_deref(),
185 )
186 .map_err(|e| ParseError::SyntaxError {
187 position: 0,
188 message: format!("Failed to compute user hash: {e}"),
189 })?;
190
191 let comparison_length = if self.encryption_info.r >= 3 { 16 } else { 32 };
193
194 if computed_u.len() < comparison_length || self.encryption_info.u.len() < comparison_length
195 {
196 return Ok(false);
197 }
198
199 let matches =
200 computed_u[..comparison_length] == self.encryption_info.u[..comparison_length];
201
202 if matches {
203 let key = self
204 .security_handler
205 .compute_encryption_key(
206 user_password,
207 &self.encryption_info.o,
208 permissions,
209 self.file_id.as_deref(),
210 )
211 .map_err(|e| ParseError::SyntaxError {
212 position: 0,
213 message: format!("Failed to compute encryption key: {e}"),
214 })?;
215 self.encryption_key = Some(key);
216 }
217
218 Ok(matches)
219 }
220
221 fn unlock_user_r5_r6(&mut self, user_password: &UserPassword) -> ParseResult<bool> {
223 let u_entry = &self.encryption_info.u;
224
225 let is_valid = if self.encryption_info.r == 5 {
227 self.security_handler
228 .validate_r5_user_password(user_password, u_entry)
229 } else {
230 self.security_handler
231 .validate_r6_user_password(user_password, u_entry)
232 }
233 .map_err(|e| ParseError::SyntaxError {
234 position: 0,
235 message: format!(
236 "Failed to validate R{} user password: {e}",
237 self.encryption_info.r
238 ),
239 })?;
240
241 if is_valid {
242 let ue_entry =
244 self.encryption_info
245 .ue
246 .as_deref()
247 .ok_or_else(|| ParseError::SyntaxError {
248 position: 0,
249 message: format!(
250 "R{} encryption requires UE entry but it is missing",
251 self.encryption_info.r
252 ),
253 })?;
254
255 let key = if self.encryption_info.r == 5 {
256 self.security_handler
257 .recover_r5_encryption_key(user_password, u_entry, ue_entry)
258 } else {
259 self.security_handler
260 .recover_r6_encryption_key(user_password, u_entry, ue_entry)
261 }
262 .map_err(|e| ParseError::SyntaxError {
263 position: 0,
264 message: format!(
265 "Failed to recover R{} encryption key: {e}",
266 self.encryption_info.r
267 ),
268 })?;
269
270 self.encryption_key = Some(key);
271 }
272
273 Ok(is_valid)
274 }
275
276 pub fn unlock_with_owner_password(&mut self, password: &str) -> ParseResult<bool> {
283 const PADDING: [u8; 32] = [
285 0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA,
286 0x01, 0x08, 0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, 0x2F, 0x0C, 0xA9, 0xFE,
287 0x64, 0x53, 0x69, 0x7A,
288 ];
289
290 let mut padded = [0u8; 32];
292 let password_bytes = password.as_bytes();
293 let len = password_bytes.len().min(32);
294 padded[..len].copy_from_slice(&password_bytes[..len]);
295 if len < 32 {
296 padded[len..].copy_from_slice(&PADDING[..32 - len]);
297 }
298
299 let mut hash = md5::compute(&padded).to_vec();
301
302 let key_length = self.security_handler.key_length;
304 if self.encryption_info.r >= 3 {
305 for _ in 0..50 {
306 hash = md5::compute(&hash).to_vec();
307 }
308 }
309
310 let mut decrypted = self.encryption_info.o[..32].to_vec();
312
313 if self.encryption_info.r >= 3 {
314 for i in (0..20).rev() {
316 let mut key_bytes = hash[..key_length].to_vec();
317 for byte in &mut key_bytes {
318 *byte ^= i as u8;
319 }
320 let rc4_key = Rc4Key::from_slice(&key_bytes);
321 let mut cipher = Rc4::new(&rc4_key);
322 decrypted = cipher.process(&decrypted);
323 }
324 } else {
325 let rc4_key = Rc4Key::from_slice(&hash[..key_length]);
327 let mut cipher = Rc4::new(&rc4_key);
328 decrypted = cipher.process(&decrypted);
329 }
330
331 let user_pwd_end = decrypted
334 .iter()
335 .position(|&b| {
336 b == PADDING[0] && decrypted.len() > 1
338 })
339 .unwrap_or(32);
340
341 let user_password = String::from_utf8_lossy(&decrypted[..user_pwd_end]).to_string();
342
343 #[cfg(debug_assertions)]
344 {
345 eprintln!(
346 "[DEBUG owner unlock] derived user password: {:?}",
347 &user_password
348 );
349 eprintln!(
350 "[DEBUG owner unlock] decrypted bytes: {:02x?}",
351 &decrypted[..8]
352 );
353 }
354
355 if self.unlock_with_user_password(&user_password)? {
357 return Ok(true);
358 }
359
360 let full_user_password = String::from_utf8_lossy(&decrypted).to_string();
363 self.unlock_with_user_password(&full_user_password)
364 }
365
366 pub fn try_empty_password(&mut self) -> ParseResult<bool> {
368 self.unlock_with_user_password("")
369 }
370
371 pub fn is_unlocked(&self) -> bool {
373 self.encryption_key.is_some()
374 }
375
376 pub fn encryption_key(&self) -> Option<&EncryptionKey> {
378 self.encryption_key.as_ref()
379 }
380
381 pub fn decrypt_string(&self, data: &[u8], obj_id: &ObjectId) -> ParseResult<Vec<u8>> {
383 match &self.encryption_key {
384 Some(key) => Ok(self.security_handler.decrypt_string(data, key, obj_id)),
385 None => Err(ParseError::EncryptionNotSupported),
386 }
387 }
388
389 pub fn decrypt_stream(&self, data: &[u8], obj_id: &ObjectId) -> ParseResult<Vec<u8>> {
391 match &self.encryption_key {
392 Some(key) => Ok(self.security_handler.decrypt_stream(data, key, obj_id)),
393 None => Err(ParseError::EncryptionNotSupported),
394 }
395 }
396
397 pub fn algorithm_info(&self) -> String {
399 match (
400 self.encryption_info.r,
401 self.encryption_info.length.unwrap_or(40),
402 ) {
403 (2, _) => "RC4 40-bit".to_string(),
404 (3, len) => format!("RC4 {len}-bit"),
405 (4, len) => format!("RC4 {len}-bit with metadata control"),
406 (5, _) => "AES-256 (Revision 5)".to_string(),
407 (6, _) => "AES-256 (Revision 6, Unicode passwords)".to_string(),
408 (r, len) => format!("Unknown revision {r} with {len}-bit key"),
409 }
410 }
411
412 pub fn permissions(&self) -> Permissions {
414 Permissions::from_bits(self.encryption_info.p as u32)
415 }
416
417 pub fn has_file_id(&self) -> bool {
419 self.file_id.is_some()
420 }
421
422 pub fn revision(&self) -> i32 {
424 self.encryption_info.r
425 }
426
427 pub fn encrypt_strings(&self) -> bool {
429 true
431 }
432
433 pub fn encrypt_streams(&self) -> bool {
435 true
437 }
438
439 pub fn encrypt_metadata(&self) -> bool {
441 true
444 }
445}
446
447#[derive(Debug)]
449pub enum PasswordResult {
450 Success,
452 Rejected,
454 Cancelled,
456}
457
458pub trait PasswordProvider {
460 fn prompt_user_password(&self) -> ParseResult<Option<String>>;
462
463 fn prompt_owner_password(&self) -> ParseResult<Option<String>>;
465}
466
467pub struct ConsolePasswordProvider;
469
470impl PasswordProvider for ConsolePasswordProvider {
471 fn prompt_user_password(&self) -> ParseResult<Option<String>> {
472 tracing::debug!(
473 "PDF is encrypted. Enter user password (or press Enter for empty password):"
474 );
475
476 let mut input = String::new();
477 std::io::stdin()
478 .read_line(&mut input)
479 .map_err(|e| ParseError::SyntaxError {
480 position: 0,
481 message: format!("Failed to read password: {e}"),
482 })?;
483
484 input.truncate(input.trim_end().len());
486 Ok(Some(input))
487 }
488
489 fn prompt_owner_password(&self) -> ParseResult<Option<String>> {
490 tracing::debug!("User password failed. Enter owner password:");
491
492 let mut input = String::new();
493 std::io::stdin()
494 .read_line(&mut input)
495 .map_err(|e| ParseError::SyntaxError {
496 position: 0,
497 message: format!("Failed to read password: {e}"),
498 })?;
499
500 input.truncate(input.trim_end().len());
502 Ok(Some(input))
503 }
504}
505
506pub struct InteractiveDecryption<P: PasswordProvider> {
508 password_provider: P,
509}
510
511impl<P: PasswordProvider> InteractiveDecryption<P> {
512 pub fn new(password_provider: P) -> Self {
514 Self { password_provider }
515 }
516
517 pub fn unlock_pdf(&self, handler: &mut EncryptionHandler) -> ParseResult<PasswordResult> {
519 if handler.try_empty_password()? {
521 return Ok(PasswordResult::Success);
522 }
523
524 if let Some(password) = self.password_provider.prompt_user_password()? {
526 if handler.unlock_with_user_password(&password)? {
527 return Ok(PasswordResult::Success);
528 }
529 } else {
530 return Ok(PasswordResult::Cancelled);
531 }
532
533 if let Some(password) = self.password_provider.prompt_owner_password()? {
535 if handler.unlock_with_owner_password(&password)? {
536 return Ok(PasswordResult::Success);
537 }
538 } else {
539 return Ok(PasswordResult::Cancelled);
540 }
541
542 Ok(PasswordResult::Rejected)
543 }
544}
545
546#[cfg(test)]
547mod tests {
548 use super::*;
549 use crate::parser::objects::{PdfDictionary, PdfName, PdfObject, PdfString};
550
551 fn create_test_encryption_dict() -> PdfDictionary {
552 let mut dict = PdfDictionary::new();
553 dict.insert(
554 "Filter".to_string(),
555 PdfObject::Name(PdfName("Standard".to_string())),
556 );
557 dict.insert("V".to_string(), PdfObject::Integer(1));
558 dict.insert("R".to_string(), PdfObject::Integer(2));
559 dict.insert(
560 "O".to_string(),
561 PdfObject::String(PdfString::new(vec![0u8; 32])),
562 );
563 dict.insert(
564 "U".to_string(),
565 PdfObject::String(PdfString::new(vec![0u8; 32])),
566 );
567 dict.insert("P".to_string(), PdfObject::Integer(-4));
568 dict
569 }
570
571 #[test]
572 fn test_encryption_detection() {
573 let mut trailer = PdfDictionary::new();
574 assert!(!EncryptionHandler::detect_encryption(&trailer));
575
576 trailer.insert("Encrypt".to_string(), PdfObject::Reference(1, 0));
577 assert!(EncryptionHandler::detect_encryption(&trailer));
578 }
579
580 #[test]
581 fn test_encryption_info_parsing() {
582 let dict = create_test_encryption_dict();
583 let info = EncryptionHandler::parse_encryption_dict(&dict).unwrap();
584
585 assert_eq!(info.filter, "Standard");
586 assert_eq!(info.v, 1);
587 assert_eq!(info.r, 2);
588 assert_eq!(info.o.len(), 32);
589 assert_eq!(info.u.len(), 32);
590 assert_eq!(info.p, -4);
591 }
592
593 #[test]
594 fn test_encryption_handler_creation() {
595 let dict = create_test_encryption_dict();
596 let handler = EncryptionHandler::new(&dict, None).unwrap();
597
598 assert_eq!(handler.encryption_info.r, 2);
599 assert!(!handler.is_unlocked());
600 assert_eq!(handler.algorithm_info(), "RC4 40-bit");
601 }
602
603 #[test]
604 fn test_empty_password_attempt() {
605 let dict = create_test_encryption_dict();
606 let mut handler = EncryptionHandler::new(&dict, None).unwrap();
607
608 let result = handler.try_empty_password().unwrap();
610 assert!(!result);
611 assert!(!handler.is_unlocked());
612 }
613
614 #[test]
615 fn test_permissions() {
616 let dict = create_test_encryption_dict();
617 let handler = EncryptionHandler::new(&dict, None).unwrap();
618
619 let permissions = handler.permissions();
620 assert!(permissions.bits() != 0);
622 }
623
624 #[test]
625 fn test_encryption_flags() {
626 let dict = create_test_encryption_dict();
627 let handler = EncryptionHandler::new(&dict, None).unwrap();
628
629 assert!(handler.encrypt_strings());
630 assert!(handler.encrypt_streams());
631 assert!(handler.encrypt_metadata());
632 }
633
634 #[test]
635 fn test_decrypt_without_key() {
636 let dict = create_test_encryption_dict();
637 let handler = EncryptionHandler::new(&dict, None).unwrap();
638
639 let obj_id = ObjectId::new(1, 0);
640 let result = handler.decrypt_string(b"test", &obj_id);
641 assert!(result.is_err());
642 }
643
644 #[test]
645 fn test_unsupported_filter() {
646 let mut dict = PdfDictionary::new();
647 dict.insert(
648 "Filter".to_string(),
649 PdfObject::Name(PdfName("UnsupportedFilter".to_string())),
650 );
651 dict.insert("R".to_string(), PdfObject::Integer(2));
652 dict.insert(
653 "O".to_string(),
654 PdfObject::String(PdfString::new(vec![0u8; 32])),
655 );
656 dict.insert(
657 "U".to_string(),
658 PdfObject::String(PdfString::new(vec![0u8; 32])),
659 );
660 dict.insert("P".to_string(), PdfObject::Integer(-4));
661
662 let result = EncryptionHandler::new(&dict, None);
663 assert!(result.is_err());
664 }
665
666 #[test]
667 fn test_unsupported_revision() {
668 let mut dict = create_test_encryption_dict();
669 dict.insert("R".to_string(), PdfObject::Integer(99)); let result = EncryptionHandler::new(&dict, None);
672 assert!(result.is_err());
673 }
674
675 #[test]
676 fn test_missing_required_keys() {
677 let test_cases = vec![
678 ("Filter", PdfObject::Name(PdfName("Standard".to_string()))),
679 ("R", PdfObject::Integer(2)),
680 ("O", PdfObject::String(PdfString::new(vec![0u8; 32]))),
681 ("U", PdfObject::String(PdfString::new(vec![0u8; 32]))),
682 ("P", PdfObject::Integer(-4)),
683 ];
684
685 for (skip_key, _) in test_cases {
686 let mut dict = create_test_encryption_dict();
687 dict.0.remove(&PdfName(skip_key.to_string()));
688
689 let result = EncryptionHandler::parse_encryption_dict(&dict);
690 assert!(result.is_err(), "Should fail when {skip_key} is missing");
691 }
692 }
693
694 struct MockPasswordProvider {
696 user_password: Option<String>,
697 owner_password: Option<String>,
698 }
699
700 impl PasswordProvider for MockPasswordProvider {
701 fn prompt_user_password(&self) -> ParseResult<Option<String>> {
702 Ok(self.user_password.clone())
703 }
704
705 fn prompt_owner_password(&self) -> ParseResult<Option<String>> {
706 Ok(self.owner_password.clone())
707 }
708 }
709
710 #[test]
711 fn test_interactive_decryption_cancelled() {
712 let provider = MockPasswordProvider {
713 user_password: None,
714 owner_password: None,
715 };
716
717 let decryption = InteractiveDecryption::new(provider);
718 let dict = create_test_encryption_dict();
719 let mut handler = EncryptionHandler::new(&dict, None).unwrap();
720
721 let result = decryption.unlock_pdf(&mut handler).unwrap();
722 matches!(result, PasswordResult::Cancelled);
723 }
724
725 #[test]
726 fn test_interactive_decryption_rejected() {
727 let provider = MockPasswordProvider {
728 user_password: Some("wrong_password".to_string()),
729 owner_password: Some("also_wrong".to_string()),
730 };
731
732 let decryption = InteractiveDecryption::new(provider);
733 let dict = create_test_encryption_dict();
734 let mut handler = EncryptionHandler::new(&dict, None).unwrap();
735
736 let result = decryption.unlock_pdf(&mut handler).unwrap();
737 matches!(result, PasswordResult::Rejected);
738 }
739
740 #[test]
743 fn test_malformed_encryption_dictionary_invalid_types() {
744 let mut dict = PdfDictionary::new();
746 dict.insert("Filter".to_string(), PdfObject::Integer(123)); dict.insert("R".to_string(), PdfObject::Integer(2));
748 dict.insert(
749 "O".to_string(),
750 PdfObject::String(PdfString::new(vec![0u8; 32])),
751 );
752 dict.insert(
753 "U".to_string(),
754 PdfObject::String(PdfString::new(vec![0u8; 32])),
755 );
756 dict.insert("P".to_string(), PdfObject::Integer(-4));
757
758 let result = EncryptionHandler::parse_encryption_dict(&dict);
759 assert!(result.is_err());
760
761 let mut dict = create_test_encryption_dict();
763 dict.insert(
764 "R".to_string(),
765 PdfObject::Name(PdfName("not_a_number".to_string())),
766 );
767 let result = EncryptionHandler::parse_encryption_dict(&dict);
768 assert!(result.is_err());
769 }
770
771 #[test]
772 fn test_encryption_dictionary_edge_values() {
773 let mut dict = create_test_encryption_dict();
775 dict.insert("R".to_string(), PdfObject::Integer(0)); let result = EncryptionHandler::new(&dict, None);
777 assert!(result.is_err());
778
779 let mut dict = create_test_encryption_dict();
781 dict.insert("R".to_string(), PdfObject::Integer(-1));
782 let result = EncryptionHandler::new(&dict, None);
783 assert!(result.is_err());
784
785 let mut dict = create_test_encryption_dict();
787 dict.insert("R".to_string(), PdfObject::Integer(1000));
788 let result = EncryptionHandler::new(&dict, None);
789 assert!(result.is_err());
790 }
791
792 #[test]
793 fn test_encryption_dictionary_invalid_hash_lengths() {
794 let mut dict = create_test_encryption_dict();
796 dict.insert(
797 "O".to_string(),
798 PdfObject::String(PdfString::new(vec![0u8; 16])),
799 ); let result = EncryptionHandler::parse_encryption_dict(&dict);
801 assert!(result.is_ok());
803
804 let mut dict = create_test_encryption_dict();
806 dict.insert(
807 "U".to_string(),
808 PdfObject::String(PdfString::new(vec![0u8; 64])),
809 ); let result = EncryptionHandler::parse_encryption_dict(&dict);
811 assert!(result.is_ok());
812
813 let mut dict = create_test_encryption_dict();
815 dict.insert("O".to_string(), PdfObject::String(PdfString::new(vec![])));
816 dict.insert("U".to_string(), PdfObject::String(PdfString::new(vec![])));
817 let result = EncryptionHandler::parse_encryption_dict(&dict);
818 assert!(result.is_ok());
819 }
820
821 #[test]
822 fn test_encryption_with_different_key_lengths() {
823 let mut dict = create_test_encryption_dict();
825 dict.insert("R".to_string(), PdfObject::Integer(2));
826 let handler = EncryptionHandler::new(&dict, None).unwrap();
827 assert_eq!(handler.algorithm_info(), "RC4 40-bit");
828
829 let mut dict = create_test_encryption_dict();
831 dict.insert("R".to_string(), PdfObject::Integer(3));
832 dict.insert("Length".to_string(), PdfObject::Integer(128));
833 let handler = EncryptionHandler::new(&dict, None).unwrap();
834 assert_eq!(handler.algorithm_info(), "RC4 128-bit");
835
836 let mut dict = create_test_encryption_dict();
838 dict.insert("R".to_string(), PdfObject::Integer(4));
839 dict.insert("Length".to_string(), PdfObject::Integer(128));
840 let handler = EncryptionHandler::new(&dict, None).unwrap();
841 assert_eq!(
842 handler.algorithm_info(),
843 "RC4 128-bit with metadata control"
844 );
845
846 let mut dict = create_test_encryption_dict();
848 dict.insert("R".to_string(), PdfObject::Integer(5));
849 dict.insert("V".to_string(), PdfObject::Integer(5));
850 let handler = EncryptionHandler::new(&dict, None).unwrap();
851 assert_eq!(handler.algorithm_info(), "AES-256 (Revision 5)");
852
853 let mut dict = create_test_encryption_dict();
855 dict.insert("R".to_string(), PdfObject::Integer(6));
856 dict.insert("V".to_string(), PdfObject::Integer(5));
857 let handler = EncryptionHandler::new(&dict, None).unwrap();
858 assert_eq!(
859 handler.algorithm_info(),
860 "AES-256 (Revision 6, Unicode passwords)"
861 );
862 }
863
864 #[test]
865 fn test_file_id_handling() {
866 let dict = create_test_encryption_dict();
867
868 let file_id = Some(b"test_file_id_12345678".to_vec());
870 let handler = EncryptionHandler::new(&dict, file_id.clone()).unwrap();
871 assert_eq!(handler.file_id, file_id);
873
874 let handler = EncryptionHandler::new(&dict, None).unwrap();
876 assert_eq!(handler.file_id, None);
877
878 let empty_file_id = Some(vec![]);
880 let handler = EncryptionHandler::new(&dict, empty_file_id.clone()).unwrap();
881 assert_eq!(handler.file_id, empty_file_id);
882 }
883
884 #[test]
885 fn test_permissions_edge_cases() {
886 let permission_values = vec![0, -1, -4, -44, -100, i32::MAX, i32::MIN];
888
889 for p_value in permission_values {
890 let mut dict = create_test_encryption_dict();
891 dict.insert("P".to_string(), PdfObject::Integer(p_value as i64));
892 let handler = EncryptionHandler::new(&dict, None).unwrap();
893
894 let permissions = handler.permissions();
895 assert_eq!(permissions.bits(), p_value as u32);
896 }
897 }
898
899 #[test]
900 fn test_decrypt_with_different_object_ids() {
901 let dict = create_test_encryption_dict();
902 let handler = EncryptionHandler::new(&dict, None).unwrap();
903 let test_data = b"test data";
904
905 let object_ids = vec![
907 ObjectId::new(1, 0),
908 ObjectId::new(999, 0),
909 ObjectId::new(1, 999),
910 ObjectId::new(u32::MAX, u16::MAX),
911 ];
912
913 for obj_id in object_ids {
914 let result = handler.decrypt_string(test_data, &obj_id);
915 assert!(result.is_err());
916
917 let result = handler.decrypt_stream(test_data, &obj_id);
918 assert!(result.is_err());
919 }
920 }
921
922 #[test]
923 fn test_password_scenarios_comprehensive() {
924 let dict = create_test_encryption_dict();
925 let mut handler = EncryptionHandler::new(&dict, None).unwrap();
926
927 let test_passwords = vec![
929 "".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(), ];
942
943 for password in test_passwords {
944 let result = handler.unlock_with_user_password(&password);
946 assert!(result.is_ok());
947 assert!(!result.unwrap());
948
949 let result = handler.unlock_with_owner_password(&password);
950 assert!(result.is_ok());
951 assert!(!result.unwrap());
952 }
953 }
954
955 #[test]
956 fn test_encryption_handler_thread_safety_simulation() {
957 let dict = create_test_encryption_dict();
959 let handler = EncryptionHandler::new(&dict, None).unwrap();
960
961 for _ in 0..100 {
963 assert!(!handler.is_unlocked());
964 assert_eq!(handler.algorithm_info(), "RC4 40-bit");
965 assert!(handler.encrypt_strings());
966 assert!(handler.encrypt_streams());
967 assert!(handler.encrypt_metadata());
968 }
969 }
970
971 #[test]
972 fn test_encryption_state_transitions() {
973 let dict = create_test_encryption_dict();
974 let mut handler = EncryptionHandler::new(&dict, None).unwrap();
975
976 assert!(!handler.is_unlocked());
978
979 let result = handler.try_empty_password().unwrap();
981 assert!(!result);
982 assert!(!handler.is_unlocked());
983
984 let result = handler.unlock_with_user_password("test").unwrap();
986 assert!(!result);
987 assert!(!handler.is_unlocked());
988
989 let result = handler.unlock_with_owner_password("test").unwrap();
991 assert!(!result);
992 assert!(!handler.is_unlocked());
993
994 assert!(!handler.is_unlocked());
996 }
997
998 #[test]
999 fn test_interactive_decryption_edge_cases() {
1000 let provider = MockPasswordProvider {
1002 user_password: None,
1003 owner_password: None,
1004 };
1005
1006 let decryption = InteractiveDecryption::new(provider);
1007 let dict = create_test_encryption_dict();
1008 let mut handler = EncryptionHandler::new(&dict, None).unwrap();
1009
1010 let result = decryption.unlock_pdf(&mut handler).unwrap();
1011 matches!(result, PasswordResult::Cancelled);
1012
1013 let provider = MockPasswordProvider {
1015 user_password: Some("".to_string()),
1016 owner_password: Some("".to_string()),
1017 };
1018
1019 let decryption = InteractiveDecryption::new(provider);
1020 let mut handler = EncryptionHandler::new(&dict, None).unwrap();
1021
1022 let result = decryption.unlock_pdf(&mut handler).unwrap();
1023 matches!(result, PasswordResult::Rejected);
1024 }
1025
1026 struct EdgeCasePasswordProvider {
1028 call_count: std::cell::RefCell<usize>,
1029 passwords: Vec<Option<String>>,
1030 }
1031
1032 impl EdgeCasePasswordProvider {
1033 fn new(passwords: Vec<Option<String>>) -> Self {
1034 Self {
1035 call_count: std::cell::RefCell::new(0),
1036 passwords,
1037 }
1038 }
1039 }
1040
1041 impl PasswordProvider for EdgeCasePasswordProvider {
1042 fn prompt_user_password(&self) -> ParseResult<Option<String>> {
1043 let mut count = self.call_count.borrow_mut();
1044 if *count < self.passwords.len() {
1045 let result = self.passwords[*count].clone();
1046 *count += 1;
1047 Ok(result)
1048 } else {
1049 Ok(None)
1050 }
1051 }
1052
1053 fn prompt_owner_password(&self) -> ParseResult<Option<String>> {
1054 self.prompt_user_password()
1055 }
1056 }
1057
1058 #[test]
1059 fn test_interactive_decryption_with_sequence() {
1060 let passwords = vec![
1061 Some("first_attempt".to_string()),
1062 Some("second_attempt".to_string()),
1063 None, ];
1065
1066 let provider = EdgeCasePasswordProvider::new(passwords);
1067 let decryption = InteractiveDecryption::new(provider);
1068 let dict = create_test_encryption_dict();
1069 let mut handler = EncryptionHandler::new(&dict, None).unwrap();
1070
1071 let result = decryption.unlock_pdf(&mut handler).unwrap();
1072 matches!(result, PasswordResult::Cancelled);
1073 }
1074}