1use super::objects::PdfDictionary;
7use super::{ParseError, ParseResult};
8use crate::encryption::{
9 EncryptionKey, OwnerPassword, Permissions, Rc4, Rc4Key, StandardSecurityHandler, UserPassword,
10};
11use crate::objects::ObjectId;
12
13#[derive(Debug, Clone)]
19#[non_exhaustive]
20pub struct EncryptionInfo {
21 pub filter: String,
23 pub v: i32,
25 pub r: i32,
27 pub o: Vec<u8>,
29 pub u: Vec<u8>,
31 pub p: i32,
33 pub length: Option<i32>,
35 pub ue: Option<Vec<u8>>,
37 pub oe: Option<Vec<u8>>,
39 pub(crate) cfm: Option<String>,
45}
46
47pub struct EncryptionHandler {
49 encryption_info: EncryptionInfo,
51 security_handler: StandardSecurityHandler,
53 encryption_key: Option<EncryptionKey>,
55 file_id: Option<Vec<u8>>,
57}
58
59impl EncryptionHandler {
60 pub fn new(encrypt_dict: &PdfDictionary, file_id: Option<Vec<u8>>) -> ParseResult<Self> {
62 let encryption_info = Self::parse_encryption_dict(encrypt_dict)?;
63
64 let security_handler = match encryption_info.r {
69 2 => StandardSecurityHandler::rc4_40bit(),
70 3 => StandardSecurityHandler::rc4_128bit(),
71 4 => match encryption_info.cfm.as_deref() {
72 Some("V2") => StandardSecurityHandler::rc4_128bit(),
74 _ => StandardSecurityHandler::aes_128_r4(),
79 },
80 5 => StandardSecurityHandler::aes_256_r5(),
81 6 => StandardSecurityHandler::aes_256_r6(),
82 _ => {
83 return Err(ParseError::SyntaxError {
84 position: 0,
85 message: format!("Encryption revision {} not supported", encryption_info.r),
86 });
87 }
88 };
89
90 Ok(Self {
91 encryption_info,
92 security_handler,
93 encryption_key: None,
94 file_id,
95 })
96 }
97
98 fn parse_encryption_dict(dict: &PdfDictionary) -> ParseResult<EncryptionInfo> {
100 let filter = dict
102 .get("Filter")
103 .and_then(|obj| obj.as_name())
104 .map(|name| name.0.as_str())
105 .ok_or_else(|| ParseError::MissingKey("Filter".to_string()))?;
106
107 if filter != "Standard" {
108 return Err(ParseError::SyntaxError {
109 position: 0,
110 message: format!("Encryption filter '{filter}' not supported"),
111 });
112 }
113
114 let v = dict
116 .get("V")
117 .and_then(|obj| obj.as_integer())
118 .map(|i| i as i32)
119 .unwrap_or(0);
120
121 let r = dict
123 .get("R")
124 .and_then(|obj| obj.as_integer())
125 .map(|i| i as i32)
126 .ok_or_else(|| ParseError::MissingKey("R".to_string()))?;
127
128 let o = dict
130 .get("O")
131 .and_then(|obj| obj.as_string())
132 .ok_or_else(|| ParseError::MissingKey("O".to_string()))?
133 .as_bytes()
134 .to_vec();
135
136 let u = dict
138 .get("U")
139 .and_then(|obj| obj.as_string())
140 .ok_or_else(|| ParseError::MissingKey("U".to_string()))?
141 .as_bytes()
142 .to_vec();
143
144 let p = dict
146 .get("P")
147 .and_then(|obj| obj.as_integer())
148 .map(|i| i as i32)
149 .ok_or_else(|| ParseError::MissingKey("P".to_string()))?;
150
151 let length = dict
153 .get("Length")
154 .and_then(|obj| obj.as_integer())
155 .map(|i| i as i32);
156
157 let ue = dict
159 .get("UE")
160 .and_then(|obj| obj.as_string())
161 .map(|s| s.as_bytes().to_vec());
162
163 let oe = dict
165 .get("OE")
166 .and_then(|obj| obj.as_string())
167 .map(|s| s.as_bytes().to_vec());
168
169 let cfm = if v >= 4 {
172 Self::parse_stream_cfm(dict)
173 } else {
174 None
175 };
176
177 Ok(EncryptionInfo {
178 filter: filter.to_string(),
179 v,
180 r,
181 o,
182 u,
183 p,
184 length,
185 ue,
186 oe,
187 cfm,
188 })
189 }
190
191 fn parse_stream_cfm(dict: &PdfDictionary) -> Option<String> {
197 let stmf = dict
198 .get("StmF")
199 .and_then(|o| o.as_name())
200 .map(|n| n.0.as_str())
201 .unwrap_or("Identity"); if stmf == "Identity" {
204 return Some("Identity".to_string());
205 }
206
207 let cf = dict.get("CF").and_then(|o| o.as_dict())?;
208 cf.get(stmf)
209 .and_then(|o| o.as_dict())
210 .and_then(|f| f.get("CFM"))
211 .and_then(|o| o.as_name())
212 .map(|n| n.0.clone())
213 }
214
215 pub fn detect_encryption(trailer: &PdfDictionary) -> bool {
217 trailer.contains_key("Encrypt")
218 }
219
220 pub fn unlock_with_user_password(&mut self, password: &str) -> ParseResult<bool> {
222 let user_password = UserPassword(password.to_string());
223
224 match self.encryption_info.r {
225 5 | 6 => self.unlock_user_r5_r6(&user_password),
226 _ => self.unlock_user_r2_r4(&user_password),
227 }
228 }
229
230 fn unlock_user_r2_r4(&mut self, user_password: &UserPassword) -> ParseResult<bool> {
232 let permissions = Permissions::from_bits(self.encryption_info.p as u32);
233
234 let computed_u = self
235 .security_handler
236 .compute_user_hash(
237 user_password,
238 &self.encryption_info.o,
239 permissions,
240 self.file_id.as_deref(),
241 )
242 .map_err(|e| ParseError::SyntaxError {
243 position: 0,
244 message: format!("Failed to compute user hash: {e}"),
245 })?;
246
247 let comparison_length = if self.encryption_info.r >= 3 { 16 } else { 32 };
249
250 if computed_u.len() < comparison_length || self.encryption_info.u.len() < comparison_length
251 {
252 return Ok(false);
253 }
254
255 let matches =
256 computed_u[..comparison_length] == self.encryption_info.u[..comparison_length];
257
258 if matches {
259 let key = self
260 .security_handler
261 .compute_encryption_key(
262 user_password,
263 &self.encryption_info.o,
264 permissions,
265 self.file_id.as_deref(),
266 )
267 .map_err(|e| ParseError::SyntaxError {
268 position: 0,
269 message: format!("Failed to compute encryption key: {e}"),
270 })?;
271 self.encryption_key = Some(key);
272 }
273
274 Ok(matches)
275 }
276
277 fn unlock_user_r5_r6(&mut self, user_password: &UserPassword) -> ParseResult<bool> {
279 let u_entry = &self.encryption_info.u;
280
281 let is_valid = if self.encryption_info.r == 5 {
283 self.security_handler
284 .validate_r5_user_password(user_password, u_entry)
285 } else {
286 self.security_handler
287 .validate_r6_user_password(user_password, u_entry)
288 }
289 .map_err(|e| ParseError::SyntaxError {
290 position: 0,
291 message: format!(
292 "Failed to validate R{} user password: {e}",
293 self.encryption_info.r
294 ),
295 })?;
296
297 if is_valid {
298 let ue_entry =
300 self.encryption_info
301 .ue
302 .as_deref()
303 .ok_or_else(|| ParseError::SyntaxError {
304 position: 0,
305 message: format!(
306 "R{} encryption requires UE entry but it is missing",
307 self.encryption_info.r
308 ),
309 })?;
310
311 let key = if self.encryption_info.r == 5 {
312 self.security_handler
313 .recover_r5_encryption_key(user_password, u_entry, ue_entry)
314 } else {
315 self.security_handler
316 .recover_r6_encryption_key(user_password, u_entry, ue_entry)
317 }
318 .map_err(|e| ParseError::SyntaxError {
319 position: 0,
320 message: format!(
321 "Failed to recover R{} encryption key: {e}",
322 self.encryption_info.r
323 ),
324 })?;
325
326 self.encryption_key = Some(key);
327 }
328
329 Ok(is_valid)
330 }
331
332 fn unlock_owner_r5_r6(&mut self, owner_password: &OwnerPassword) -> ParseResult<bool> {
337 let o_entry = self.encryption_info.o.clone();
338 let u_entry = self.encryption_info.u.clone();
339
340 let is_valid = if self.encryption_info.r == 5 {
341 self.security_handler
342 .validate_r5_owner_password(owner_password, &o_entry)
343 } else {
344 self.security_handler
345 .validate_r6_owner_password(owner_password, &o_entry, &u_entry)
346 }
347 .map_err(|e| ParseError::SyntaxError {
348 position: 0,
349 message: format!(
350 "Failed to validate R{} owner password: {e}",
351 self.encryption_info.r
352 ),
353 })?;
354
355 if is_valid {
356 let oe_entry =
357 self.encryption_info
358 .oe
359 .as_deref()
360 .ok_or_else(|| ParseError::SyntaxError {
361 position: 0,
362 message: format!(
363 "R{} encryption requires OE entry but it is missing",
364 self.encryption_info.r
365 ),
366 })?;
367
368 let key = if self.encryption_info.r == 5 {
369 self.security_handler.recover_r5_owner_encryption_key(
370 owner_password,
371 &o_entry,
372 oe_entry,
373 )
374 } else {
375 self.security_handler.recover_r6_owner_encryption_key(
376 owner_password,
377 &o_entry,
378 &u_entry,
379 oe_entry,
380 )
381 }
382 .map_err(|e| ParseError::SyntaxError {
383 position: 0,
384 message: format!(
385 "Failed to recover R{} owner encryption key: {e}",
386 self.encryption_info.r
387 ),
388 })?;
389
390 self.encryption_key = Some(EncryptionKey::new(key));
391 }
392
393 Ok(is_valid)
394 }
395
396 pub fn unlock_with_owner_password(&mut self, password: &str) -> ParseResult<bool> {
403 if self.encryption_info.r >= 5 {
407 return self.unlock_owner_r5_r6(&OwnerPassword(password.to_string()));
408 }
409
410 const PADDING: [u8; 32] = [
412 0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA,
413 0x01, 0x08, 0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, 0x2F, 0x0C, 0xA9, 0xFE,
414 0x64, 0x53, 0x69, 0x7A,
415 ];
416
417 let mut padded = [0u8; 32];
419 let password_bytes = password.as_bytes();
420 let len = password_bytes.len().min(32);
421 padded[..len].copy_from_slice(&password_bytes[..len]);
422 if len < 32 {
423 padded[len..].copy_from_slice(&PADDING[..32 - len]);
424 }
425
426 let mut hash = md5::compute(&padded).to_vec();
428
429 let key_length = self.security_handler.key_length;
431 if self.encryption_info.r >= 3 {
432 for _ in 0..50 {
433 hash = md5::compute(&hash).to_vec();
434 }
435 }
436
437 let mut decrypted = self.encryption_info.o[..32].to_vec();
439
440 if self.encryption_info.r >= 3 {
441 for i in (0..20).rev() {
443 let mut key_bytes = hash[..key_length].to_vec();
444 for byte in &mut key_bytes {
445 *byte ^= i as u8;
446 }
447 let rc4_key = Rc4Key::from_slice(&key_bytes);
448 let mut cipher = Rc4::new(&rc4_key);
449 decrypted = cipher.process(&decrypted);
450 }
451 } else {
452 let rc4_key = Rc4Key::from_slice(&hash[..key_length]);
454 let mut cipher = Rc4::new(&rc4_key);
455 decrypted = cipher.process(&decrypted);
456 }
457
458 let user_pwd_end = decrypted
461 .iter()
462 .position(|&b| {
463 b == PADDING[0] && decrypted.len() > 1
465 })
466 .unwrap_or(32);
467
468 let user_password = String::from_utf8_lossy(&decrypted[..user_pwd_end]).to_string();
469
470 if self.unlock_with_user_password(&user_password)? {
472 return Ok(true);
473 }
474
475 let full_user_password = String::from_utf8_lossy(&decrypted).to_string();
478 self.unlock_with_user_password(&full_user_password)
479 }
480
481 pub fn try_empty_password(&mut self) -> ParseResult<bool> {
483 self.unlock_with_user_password("")
484 }
485
486 pub fn is_unlocked(&self) -> bool {
488 self.encryption_key.is_some()
489 }
490
491 pub fn encryption_key(&self) -> Option<&EncryptionKey> {
493 self.encryption_key.as_ref()
494 }
495
496 pub fn decrypt_string(&self, data: &[u8], obj_id: &ObjectId) -> ParseResult<Vec<u8>> {
501 match &self.encryption_key {
502 Some(key) => self
503 .security_handler
504 .try_decrypt_string(data, key, obj_id)
505 .map_err(|e| ParseError::SyntaxError {
506 position: 0,
507 message: format!("Failed to decrypt string for object {obj_id:?}: {e}"),
508 }),
509 None => Err(ParseError::EncryptionNotSupported),
510 }
511 }
512
513 pub fn decrypt_stream(&self, data: &[u8], obj_id: &ObjectId) -> ParseResult<Vec<u8>> {
518 match &self.encryption_key {
519 Some(key) => self
520 .security_handler
521 .try_decrypt_stream(data, key, obj_id)
522 .map_err(|e| ParseError::SyntaxError {
523 position: 0,
524 message: format!("Failed to decrypt stream for object {obj_id:?}: {e}"),
525 }),
526 None => Err(ParseError::EncryptionNotSupported),
527 }
528 }
529
530 pub fn algorithm_info(&self) -> String {
532 match (
533 self.encryption_info.r,
534 self.encryption_info.length.unwrap_or(40),
535 ) {
536 (2, _) => "RC4 40-bit".to_string(),
537 (3, len) => format!("RC4 {len}-bit"),
538 (4, len) => match self.encryption_info.cfm.as_deref() {
540 Some("V2") => format!("RC4 {len}-bit with metadata control"),
541 _ => "AES-128 (Revision 4)".to_string(),
542 },
543 (5, _) => "AES-256 (Revision 5)".to_string(),
544 (6, _) => "AES-256 (Revision 6, Unicode passwords)".to_string(),
545 (r, len) => format!("Unknown revision {r} with {len}-bit key"),
546 }
547 }
548
549 pub fn permissions(&self) -> Permissions {
551 Permissions::from_bits(self.encryption_info.p as u32)
552 }
553
554 pub fn has_file_id(&self) -> bool {
556 self.file_id.is_some()
557 }
558
559 pub fn revision(&self) -> i32 {
561 self.encryption_info.r
562 }
563
564 pub fn encrypt_strings(&self) -> bool {
566 true
568 }
569
570 pub fn encrypt_streams(&self) -> bool {
572 true
574 }
575
576 pub fn encrypt_metadata(&self) -> bool {
578 true
581 }
582}
583
584#[derive(Debug)]
586pub enum PasswordResult {
587 Success,
589 Rejected,
591 Cancelled,
593}
594
595pub trait PasswordProvider {
597 fn prompt_user_password(&self) -> ParseResult<Option<String>>;
599
600 fn prompt_owner_password(&self) -> ParseResult<Option<String>>;
602}
603
604pub struct ConsolePasswordProvider;
606
607impl PasswordProvider for ConsolePasswordProvider {
608 fn prompt_user_password(&self) -> ParseResult<Option<String>> {
609 tracing::debug!(
610 "PDF is encrypted. Enter user password (or press Enter for empty password):"
611 );
612
613 let mut input = String::new();
614 std::io::stdin()
615 .read_line(&mut input)
616 .map_err(|e| ParseError::SyntaxError {
617 position: 0,
618 message: format!("Failed to read password: {e}"),
619 })?;
620
621 input.truncate(input.trim_end().len());
623 Ok(Some(input))
624 }
625
626 fn prompt_owner_password(&self) -> ParseResult<Option<String>> {
627 tracing::debug!("User password failed. Enter owner password:");
628
629 let mut input = String::new();
630 std::io::stdin()
631 .read_line(&mut input)
632 .map_err(|e| ParseError::SyntaxError {
633 position: 0,
634 message: format!("Failed to read password: {e}"),
635 })?;
636
637 input.truncate(input.trim_end().len());
639 Ok(Some(input))
640 }
641}
642
643pub struct InteractiveDecryption<P: PasswordProvider> {
645 password_provider: P,
646}
647
648impl<P: PasswordProvider> InteractiveDecryption<P> {
649 pub fn new(password_provider: P) -> Self {
651 Self { password_provider }
652 }
653
654 pub fn unlock_pdf(&self, handler: &mut EncryptionHandler) -> ParseResult<PasswordResult> {
656 if handler.try_empty_password()? {
658 return Ok(PasswordResult::Success);
659 }
660
661 if let Some(password) = self.password_provider.prompt_user_password()? {
663 if handler.unlock_with_user_password(&password)? {
664 return Ok(PasswordResult::Success);
665 }
666 } else {
667 return Ok(PasswordResult::Cancelled);
668 }
669
670 if let Some(password) = self.password_provider.prompt_owner_password()? {
672 if handler.unlock_with_owner_password(&password)? {
673 return Ok(PasswordResult::Success);
674 }
675 } else {
676 return Ok(PasswordResult::Cancelled);
677 }
678
679 Ok(PasswordResult::Rejected)
680 }
681}
682
683#[cfg(test)]
684mod tests {
685 use super::*;
686 use crate::parser::objects::{PdfDictionary, PdfName, PdfObject, PdfString};
687
688 fn create_test_encryption_dict() -> PdfDictionary {
689 let mut dict = PdfDictionary::new();
690 dict.insert(
691 "Filter".to_string(),
692 PdfObject::Name(PdfName("Standard".to_string())),
693 );
694 dict.insert("V".to_string(), PdfObject::Integer(1));
695 dict.insert("R".to_string(), PdfObject::Integer(2));
696 dict.insert(
697 "O".to_string(),
698 PdfObject::String(PdfString::new(vec![0u8; 32])),
699 );
700 dict.insert(
701 "U".to_string(),
702 PdfObject::String(PdfString::new(vec![0u8; 32])),
703 );
704 dict.insert("P".to_string(), PdfObject::Integer(-4));
705 dict
706 }
707
708 #[test]
709 fn test_encryption_detection() {
710 let mut trailer = PdfDictionary::new();
711 assert!(!EncryptionHandler::detect_encryption(&trailer));
712
713 trailer.insert("Encrypt".to_string(), PdfObject::Reference(1, 0));
714 assert!(EncryptionHandler::detect_encryption(&trailer));
715 }
716
717 #[test]
718 fn test_encryption_info_parsing() {
719 let dict = create_test_encryption_dict();
720 let info = EncryptionHandler::parse_encryption_dict(&dict).unwrap();
721
722 assert_eq!(info.filter, "Standard");
723 assert_eq!(info.v, 1);
724 assert_eq!(info.r, 2);
725 assert_eq!(info.o.len(), 32);
726 assert_eq!(info.u.len(), 32);
727 assert_eq!(info.p, -4);
728 assert_eq!(info.cfm, None);
730 }
731
732 fn create_v4_encryption_dict(cfm: &str) -> PdfDictionary {
734 let mut dict = PdfDictionary::new();
735 dict.insert(
736 "Filter".to_string(),
737 PdfObject::Name(PdfName("Standard".to_string())),
738 );
739 dict.insert("V".to_string(), PdfObject::Integer(4));
740 dict.insert("R".to_string(), PdfObject::Integer(4));
741 dict.insert("Length".to_string(), PdfObject::Integer(128));
742 dict.insert(
743 "O".to_string(),
744 PdfObject::String(PdfString::new(vec![0u8; 32])),
745 );
746 dict.insert(
747 "U".to_string(),
748 PdfObject::String(PdfString::new(vec![0u8; 32])),
749 );
750 dict.insert("P".to_string(), PdfObject::Integer(-4));
751
752 let mut std_cf = PdfDictionary::new();
753 std_cf.insert("CFM".to_string(), PdfObject::Name(PdfName(cfm.to_string())));
754 let mut cf = PdfDictionary::new();
755 cf.insert("StdCF".to_string(), PdfObject::Dictionary(std_cf));
756 dict.insert("CF".to_string(), PdfObject::Dictionary(cf));
757 dict.insert(
758 "StmF".to_string(),
759 PdfObject::Name(PdfName("StdCF".to_string())),
760 );
761 dict
762 }
763
764 #[test]
765 fn test_cfm_parsed_from_crypt_filter() {
766 let aes =
768 EncryptionHandler::parse_encryption_dict(&create_v4_encryption_dict("AESV2")).unwrap();
769 assert_eq!(aes.cfm.as_deref(), Some("AESV2"));
770
771 let rc4 =
772 EncryptionHandler::parse_encryption_dict(&create_v4_encryption_dict("V2")).unwrap();
773 assert_eq!(rc4.cfm.as_deref(), Some("V2"));
774 }
775
776 #[test]
777 fn test_r4_algorithm_info_reflects_cipher() {
778 let aes = EncryptionHandler::new(&create_v4_encryption_dict("AESV2"), None).unwrap();
780 assert_eq!(aes.algorithm_info(), "AES-128 (Revision 4)");
781
782 let rc4 = EncryptionHandler::new(&create_v4_encryption_dict("V2"), None).unwrap();
784 assert!(
785 rc4.algorithm_info().starts_with("RC4"),
786 "got: {}",
787 rc4.algorithm_info()
788 );
789 }
790
791 #[test]
792 fn test_encryption_handler_creation() {
793 let dict = create_test_encryption_dict();
794 let handler = EncryptionHandler::new(&dict, None).unwrap();
795
796 assert_eq!(handler.encryption_info.r, 2);
797 assert!(!handler.is_unlocked());
798 assert_eq!(handler.algorithm_info(), "RC4 40-bit");
799 }
800
801 #[test]
802 fn test_empty_password_attempt() {
803 let dict = create_test_encryption_dict();
804 let mut handler = EncryptionHandler::new(&dict, None).unwrap();
805
806 let result = handler.try_empty_password().unwrap();
808 assert!(!result);
809 assert!(!handler.is_unlocked());
810 }
811
812 #[test]
813 fn test_permissions() {
814 let dict = create_test_encryption_dict();
815 let handler = EncryptionHandler::new(&dict, None).unwrap();
816
817 let permissions = handler.permissions();
818 assert!(permissions.bits() != 0);
820 }
821
822 #[test]
823 fn test_encryption_flags() {
824 let dict = create_test_encryption_dict();
825 let handler = EncryptionHandler::new(&dict, None).unwrap();
826
827 assert!(handler.encrypt_strings());
828 assert!(handler.encrypt_streams());
829 assert!(handler.encrypt_metadata());
830 }
831
832 #[test]
833 fn test_decrypt_without_key() {
834 let dict = create_test_encryption_dict();
835 let handler = EncryptionHandler::new(&dict, None).unwrap();
836
837 let obj_id = ObjectId::new(1, 0);
838 let result = handler.decrypt_string(b"test", &obj_id);
839 assert!(result.is_err());
840 }
841
842 #[test]
843 fn test_unsupported_filter() {
844 let mut dict = PdfDictionary::new();
845 dict.insert(
846 "Filter".to_string(),
847 PdfObject::Name(PdfName("UnsupportedFilter".to_string())),
848 );
849 dict.insert("R".to_string(), PdfObject::Integer(2));
850 dict.insert(
851 "O".to_string(),
852 PdfObject::String(PdfString::new(vec![0u8; 32])),
853 );
854 dict.insert(
855 "U".to_string(),
856 PdfObject::String(PdfString::new(vec![0u8; 32])),
857 );
858 dict.insert("P".to_string(), PdfObject::Integer(-4));
859
860 let result = EncryptionHandler::new(&dict, None);
861 assert!(result.is_err());
862 }
863
864 #[test]
865 fn test_unsupported_revision() {
866 let mut dict = create_test_encryption_dict();
867 dict.insert("R".to_string(), PdfObject::Integer(99)); let result = EncryptionHandler::new(&dict, None);
870 assert!(result.is_err());
871 }
872
873 #[test]
874 fn test_missing_required_keys() {
875 let test_cases = vec![
876 ("Filter", PdfObject::Name(PdfName("Standard".to_string()))),
877 ("R", PdfObject::Integer(2)),
878 ("O", PdfObject::String(PdfString::new(vec![0u8; 32]))),
879 ("U", PdfObject::String(PdfString::new(vec![0u8; 32]))),
880 ("P", PdfObject::Integer(-4)),
881 ];
882
883 for (skip_key, _) in test_cases {
884 let mut dict = create_test_encryption_dict();
885 dict.0.remove(&PdfName(skip_key.to_string()));
886
887 let result = EncryptionHandler::parse_encryption_dict(&dict);
888 assert!(result.is_err(), "Should fail when {skip_key} is missing");
889 }
890 }
891
892 struct MockPasswordProvider {
894 user_password: Option<String>,
895 owner_password: Option<String>,
896 }
897
898 impl PasswordProvider for MockPasswordProvider {
899 fn prompt_user_password(&self) -> ParseResult<Option<String>> {
900 Ok(self.user_password.clone())
901 }
902
903 fn prompt_owner_password(&self) -> ParseResult<Option<String>> {
904 Ok(self.owner_password.clone())
905 }
906 }
907
908 #[test]
909 fn test_interactive_decryption_cancelled() {
910 let provider = MockPasswordProvider {
911 user_password: None,
912 owner_password: None,
913 };
914
915 let decryption = InteractiveDecryption::new(provider);
916 let dict = create_test_encryption_dict();
917 let mut handler = EncryptionHandler::new(&dict, None).unwrap();
918
919 let result = decryption.unlock_pdf(&mut handler).unwrap();
920 matches!(result, PasswordResult::Cancelled);
921 }
922
923 #[test]
924 fn test_interactive_decryption_rejected() {
925 let provider = MockPasswordProvider {
926 user_password: Some("wrong_password".to_string()),
927 owner_password: Some("also_wrong".to_string()),
928 };
929
930 let decryption = InteractiveDecryption::new(provider);
931 let dict = create_test_encryption_dict();
932 let mut handler = EncryptionHandler::new(&dict, None).unwrap();
933
934 let result = decryption.unlock_pdf(&mut handler).unwrap();
935 matches!(result, PasswordResult::Rejected);
936 }
937
938 #[test]
941 fn test_malformed_encryption_dictionary_invalid_types() {
942 let mut dict = PdfDictionary::new();
944 dict.insert("Filter".to_string(), PdfObject::Integer(123)); dict.insert("R".to_string(), PdfObject::Integer(2));
946 dict.insert(
947 "O".to_string(),
948 PdfObject::String(PdfString::new(vec![0u8; 32])),
949 );
950 dict.insert(
951 "U".to_string(),
952 PdfObject::String(PdfString::new(vec![0u8; 32])),
953 );
954 dict.insert("P".to_string(), PdfObject::Integer(-4));
955
956 let result = EncryptionHandler::parse_encryption_dict(&dict);
957 assert!(result.is_err());
958
959 let mut dict = create_test_encryption_dict();
961 dict.insert(
962 "R".to_string(),
963 PdfObject::Name(PdfName("not_a_number".to_string())),
964 );
965 let result = EncryptionHandler::parse_encryption_dict(&dict);
966 assert!(result.is_err());
967 }
968
969 #[test]
970 fn test_encryption_dictionary_edge_values() {
971 let mut dict = create_test_encryption_dict();
973 dict.insert("R".to_string(), PdfObject::Integer(0)); let result = EncryptionHandler::new(&dict, None);
975 assert!(result.is_err());
976
977 let mut dict = create_test_encryption_dict();
979 dict.insert("R".to_string(), PdfObject::Integer(-1));
980 let result = EncryptionHandler::new(&dict, None);
981 assert!(result.is_err());
982
983 let mut dict = create_test_encryption_dict();
985 dict.insert("R".to_string(), PdfObject::Integer(1000));
986 let result = EncryptionHandler::new(&dict, None);
987 assert!(result.is_err());
988 }
989
990 #[test]
991 fn test_encryption_dictionary_invalid_hash_lengths() {
992 let mut dict = create_test_encryption_dict();
994 dict.insert(
995 "O".to_string(),
996 PdfObject::String(PdfString::new(vec![0u8; 16])),
997 ); let result = EncryptionHandler::parse_encryption_dict(&dict);
999 assert!(result.is_ok());
1001
1002 let mut dict = create_test_encryption_dict();
1004 dict.insert(
1005 "U".to_string(),
1006 PdfObject::String(PdfString::new(vec![0u8; 64])),
1007 ); let result = EncryptionHandler::parse_encryption_dict(&dict);
1009 assert!(result.is_ok());
1010
1011 let mut dict = create_test_encryption_dict();
1013 dict.insert("O".to_string(), PdfObject::String(PdfString::new(vec![])));
1014 dict.insert("U".to_string(), PdfObject::String(PdfString::new(vec![])));
1015 let result = EncryptionHandler::parse_encryption_dict(&dict);
1016 assert!(result.is_ok());
1017 }
1018
1019 #[test]
1020 fn test_encryption_with_different_key_lengths() {
1021 let mut dict = create_test_encryption_dict();
1023 dict.insert("R".to_string(), PdfObject::Integer(2));
1024 let handler = EncryptionHandler::new(&dict, None).unwrap();
1025 assert_eq!(handler.algorithm_info(), "RC4 40-bit");
1026
1027 let mut dict = create_test_encryption_dict();
1029 dict.insert("R".to_string(), PdfObject::Integer(3));
1030 dict.insert("Length".to_string(), PdfObject::Integer(128));
1031 let handler = EncryptionHandler::new(&dict, None).unwrap();
1032 assert_eq!(handler.algorithm_info(), "RC4 128-bit");
1033
1034 let mut dict = create_test_encryption_dict();
1038 dict.insert("R".to_string(), PdfObject::Integer(4));
1039 dict.insert("Length".to_string(), PdfObject::Integer(128));
1040 let handler = EncryptionHandler::new(&dict, None).unwrap();
1041 assert_eq!(handler.algorithm_info(), "AES-128 (Revision 4)");
1042
1043 let mut dict = create_test_encryption_dict();
1045 dict.insert("R".to_string(), PdfObject::Integer(5));
1046 dict.insert("V".to_string(), PdfObject::Integer(5));
1047 let handler = EncryptionHandler::new(&dict, None).unwrap();
1048 assert_eq!(handler.algorithm_info(), "AES-256 (Revision 5)");
1049
1050 let mut dict = create_test_encryption_dict();
1052 dict.insert("R".to_string(), PdfObject::Integer(6));
1053 dict.insert("V".to_string(), PdfObject::Integer(5));
1054 let handler = EncryptionHandler::new(&dict, None).unwrap();
1055 assert_eq!(
1056 handler.algorithm_info(),
1057 "AES-256 (Revision 6, Unicode passwords)"
1058 );
1059 }
1060
1061 #[test]
1062 fn test_file_id_handling() {
1063 let dict = create_test_encryption_dict();
1064
1065 let file_id = Some(b"test_file_id_12345678".to_vec());
1067 let handler = EncryptionHandler::new(&dict, file_id.clone()).unwrap();
1068 assert_eq!(handler.file_id, file_id);
1070
1071 let handler = EncryptionHandler::new(&dict, None).unwrap();
1073 assert_eq!(handler.file_id, None);
1074
1075 let empty_file_id = Some(vec![]);
1077 let handler = EncryptionHandler::new(&dict, empty_file_id.clone()).unwrap();
1078 assert_eq!(handler.file_id, empty_file_id);
1079 }
1080
1081 #[test]
1082 fn test_permissions_edge_cases() {
1083 let permission_values = vec![0, -1, -4, -44, -100, i32::MAX, i32::MIN];
1085
1086 for p_value in permission_values {
1087 let mut dict = create_test_encryption_dict();
1088 dict.insert("P".to_string(), PdfObject::Integer(p_value as i64));
1089 let handler = EncryptionHandler::new(&dict, None).unwrap();
1090
1091 let permissions = handler.permissions();
1092 assert_eq!(permissions.bits(), p_value as u32);
1093 }
1094 }
1095
1096 #[test]
1097 fn test_decrypt_with_different_object_ids() {
1098 let dict = create_test_encryption_dict();
1099 let handler = EncryptionHandler::new(&dict, None).unwrap();
1100 let test_data = b"test data";
1101
1102 let object_ids = vec![
1104 ObjectId::new(1, 0),
1105 ObjectId::new(999, 0),
1106 ObjectId::new(1, 999),
1107 ObjectId::new(u32::MAX, u16::MAX),
1108 ];
1109
1110 for obj_id in object_ids {
1111 let result = handler.decrypt_string(test_data, &obj_id);
1112 assert!(result.is_err());
1113
1114 let result = handler.decrypt_stream(test_data, &obj_id);
1115 assert!(result.is_err());
1116 }
1117 }
1118
1119 #[test]
1120 fn test_password_scenarios_comprehensive() {
1121 let dict = create_test_encryption_dict();
1122 let mut handler = EncryptionHandler::new(&dict, None).unwrap();
1123
1124 let test_passwords = vec![
1126 "".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(), ];
1139
1140 for password in test_passwords {
1141 let result = handler.unlock_with_user_password(&password);
1143 assert!(result.is_ok());
1144 assert!(!result.unwrap());
1145
1146 let result = handler.unlock_with_owner_password(&password);
1147 assert!(result.is_ok());
1148 assert!(!result.unwrap());
1149 }
1150 }
1151
1152 #[test]
1153 fn test_encryption_handler_thread_safety_simulation() {
1154 let dict = create_test_encryption_dict();
1156 let handler = EncryptionHandler::new(&dict, None).unwrap();
1157
1158 for _ in 0..100 {
1160 assert!(!handler.is_unlocked());
1161 assert_eq!(handler.algorithm_info(), "RC4 40-bit");
1162 assert!(handler.encrypt_strings());
1163 assert!(handler.encrypt_streams());
1164 assert!(handler.encrypt_metadata());
1165 }
1166 }
1167
1168 #[test]
1169 fn test_encryption_state_transitions() {
1170 let dict = create_test_encryption_dict();
1171 let mut handler = EncryptionHandler::new(&dict, None).unwrap();
1172
1173 assert!(!handler.is_unlocked());
1175
1176 let result = handler.try_empty_password().unwrap();
1178 assert!(!result);
1179 assert!(!handler.is_unlocked());
1180
1181 let result = handler.unlock_with_user_password("test").unwrap();
1183 assert!(!result);
1184 assert!(!handler.is_unlocked());
1185
1186 let result = handler.unlock_with_owner_password("test").unwrap();
1188 assert!(!result);
1189 assert!(!handler.is_unlocked());
1190
1191 assert!(!handler.is_unlocked());
1193 }
1194
1195 #[test]
1196 fn test_interactive_decryption_edge_cases() {
1197 let provider = MockPasswordProvider {
1199 user_password: None,
1200 owner_password: None,
1201 };
1202
1203 let decryption = InteractiveDecryption::new(provider);
1204 let dict = create_test_encryption_dict();
1205 let mut handler = EncryptionHandler::new(&dict, None).unwrap();
1206
1207 let result = decryption.unlock_pdf(&mut handler).unwrap();
1208 matches!(result, PasswordResult::Cancelled);
1209
1210 let provider = MockPasswordProvider {
1212 user_password: Some("".to_string()),
1213 owner_password: Some("".to_string()),
1214 };
1215
1216 let decryption = InteractiveDecryption::new(provider);
1217 let mut handler = EncryptionHandler::new(&dict, None).unwrap();
1218
1219 let result = decryption.unlock_pdf(&mut handler).unwrap();
1220 matches!(result, PasswordResult::Rejected);
1221 }
1222
1223 struct EdgeCasePasswordProvider {
1225 call_count: std::cell::RefCell<usize>,
1226 passwords: Vec<Option<String>>,
1227 }
1228
1229 impl EdgeCasePasswordProvider {
1230 fn new(passwords: Vec<Option<String>>) -> Self {
1231 Self {
1232 call_count: std::cell::RefCell::new(0),
1233 passwords,
1234 }
1235 }
1236 }
1237
1238 impl PasswordProvider for EdgeCasePasswordProvider {
1239 fn prompt_user_password(&self) -> ParseResult<Option<String>> {
1240 let mut count = self.call_count.borrow_mut();
1241 if *count < self.passwords.len() {
1242 let result = self.passwords[*count].clone();
1243 *count += 1;
1244 Ok(result)
1245 } else {
1246 Ok(None)
1247 }
1248 }
1249
1250 fn prompt_owner_password(&self) -> ParseResult<Option<String>> {
1251 self.prompt_user_password()
1252 }
1253 }
1254
1255 #[test]
1256 fn test_interactive_decryption_with_sequence() {
1257 let passwords = vec![
1258 Some("first_attempt".to_string()),
1259 Some("second_attempt".to_string()),
1260 None, ];
1262
1263 let provider = EdgeCasePasswordProvider::new(passwords);
1264 let decryption = InteractiveDecryption::new(provider);
1265 let dict = create_test_encryption_dict();
1266 let mut handler = EncryptionHandler::new(&dict, None).unwrap();
1267
1268 let result = decryption.unlock_pdf(&mut handler).unwrap();
1269 matches!(result, PasswordResult::Cancelled);
1270 }
1271}