Skip to main content

oxidize_pdf/encryption/
object_encryption.rs

1//! Object encryption/decryption for PDF documents
2//!
3//! This module implements encryption and decryption of PDF objects
4//! with integration into the parser and writer according to ISO 32000-1:2008.
5
6use crate::encryption::{
7    CryptFilterManager, EmbeddedFileEncryption, EncryptionDictionary, EncryptionKey,
8    SecurityHandler, StandardSecurityHandler,
9};
10use crate::error::{PdfError, Result};
11use crate::objects::{Dictionary, Object, ObjectId, Stream};
12use std::sync::Arc;
13
14/// Object Encryptor for encrypting PDF objects
15pub struct ObjectEncryptor {
16    /// Crypt filter manager
17    filter_manager: Arc<CryptFilterManager>,
18    /// Encryption key
19    encryption_key: EncryptionKey,
20    /// Encrypt metadata flag
21    encrypt_metadata: bool,
22    /// Embedded file encryption handler
23    embedded_file_handler: Option<EmbeddedFileEncryption>,
24}
25
26impl ObjectEncryptor {
27    /// Create new object encryptor
28    pub fn new(
29        filter_manager: Arc<CryptFilterManager>,
30        encryption_key: EncryptionKey,
31        encrypt_metadata: bool,
32    ) -> Self {
33        Self {
34            filter_manager,
35            encryption_key,
36            encrypt_metadata,
37            embedded_file_handler: None,
38        }
39    }
40
41    /// Create new object encryptor with embedded file support
42    pub fn with_embedded_files(
43        filter_manager: Arc<CryptFilterManager>,
44        encryption_key: EncryptionKey,
45        encrypt_metadata: bool,
46        eff_filter: Option<String>,
47    ) -> Self {
48        let embedded_file_handler = Some(EmbeddedFileEncryption::new(
49            eff_filter,
50            encrypt_metadata,
51            filter_manager.clone(),
52        ));
53
54        Self {
55            filter_manager,
56            encryption_key,
57            encrypt_metadata,
58            embedded_file_handler,
59        }
60    }
61
62    /// Encrypt an object
63    pub fn encrypt_object(&self, object: &mut Object, obj_id: &ObjectId) -> Result<()> {
64        match object {
65            Object::String(s) => {
66                // Check if this is a metadata stream
67                if !self.should_encrypt_string(s) {
68                    return Ok(());
69                }
70
71                let encrypted = self.filter_manager.encrypt_string(
72                    s.as_bytes(),
73                    obj_id,
74                    None,
75                    &self.encryption_key,
76                )?;
77
78                // Encrypted data is binary — store as ByteString for hex output
79                *object = Object::ByteString(encrypted);
80            }
81            Object::ByteString(bytes) => {
82                let encrypted = self.filter_manager.encrypt_string(
83                    bytes,
84                    obj_id,
85                    None,
86                    &self.encryption_key,
87                )?;
88                *bytes = encrypted;
89            }
90            Object::Stream(dict, data) => {
91                // Create a temporary Stream object
92                let mut stream = Stream::with_dictionary(dict.clone(), data.clone());
93                self.encrypt_stream(&mut stream, obj_id)?;
94
95                // Update the Object with encrypted data
96                *object = Object::Stream(stream.dictionary().clone(), stream.data().to_vec());
97            }
98            Object::Dictionary(dict) => {
99                self.encrypt_dictionary(dict, obj_id)?;
100            }
101            Object::Array(array) => {
102                for item in array.iter_mut() {
103                    self.encrypt_object(item, obj_id)?;
104                }
105            }
106            Object::Reference(_) => {
107                // References are not encrypted
108            }
109            _ => {
110                // Other object types are not encrypted
111            }
112        }
113
114        Ok(())
115    }
116
117    /// Decrypt an object
118    pub fn decrypt_object(&self, object: &mut Object, obj_id: &ObjectId) -> Result<()> {
119        match object {
120            Object::String(s) => {
121                // Check if this is a metadata stream
122                if !self.should_encrypt_string(s) {
123                    return Ok(());
124                }
125
126                let decrypted = self.filter_manager.decrypt_string(
127                    s.as_bytes(),
128                    obj_id,
129                    None,
130                    &self.encryption_key,
131                )?;
132
133                *s = String::from_utf8_lossy(&decrypted).to_string();
134            }
135            Object::ByteString(bytes) => {
136                let decrypted = self.filter_manager.decrypt_string(
137                    bytes,
138                    obj_id,
139                    None,
140                    &self.encryption_key,
141                )?;
142                // Decrypted binary data may be valid UTF-8 text — restore as String
143                *object = Object::String(String::from_utf8_lossy(&decrypted).to_string());
144            }
145            Object::Stream(dict, data) => {
146                // Create a temporary Stream object
147                let mut stream = Stream::with_dictionary(dict.clone(), data.clone());
148                self.decrypt_stream(&mut stream, obj_id)?;
149
150                // Update the Object with decrypted data
151                *object = Object::Stream(stream.dictionary().clone(), stream.data().to_vec());
152            }
153            Object::Dictionary(dict) => {
154                self.decrypt_dictionary(dict, obj_id)?;
155            }
156            Object::Array(array) => {
157                for item in array.iter_mut() {
158                    self.decrypt_object(item, obj_id)?;
159                }
160            }
161            Object::Reference(_) => {
162                // References are not decrypted
163            }
164            _ => {
165                // Other object types are not decrypted
166            }
167        }
168
169        Ok(())
170    }
171
172    /// Encrypt a stream
173    fn encrypt_stream(&self, stream: &mut Stream, obj_id: &ObjectId) -> Result<()> {
174        // Check if stream should be encrypted
175        if !self.should_encrypt_stream(stream) {
176            return Ok(());
177        }
178
179        let encrypted_data = if let Some(ref handler) = self.embedded_file_handler {
180            // Use embedded file handler for special stream types
181            handler.process_stream_encryption(
182                stream.dictionary(),
183                stream.data(),
184                obj_id,
185                &self.encryption_key,
186                true, // encrypt
187            )?
188        } else {
189            // Use standard encryption
190            self.filter_manager.encrypt_stream(
191                stream.data(),
192                obj_id,
193                stream.dictionary(),
194                &self.encryption_key,
195            )?
196        };
197
198        *stream.data_mut() = encrypted_data;
199
200        // Update stream dictionary if needed
201        if !stream.dictionary().contains_key("Filter") {
202            stream
203                .dictionary_mut()
204                .set("Filter", Object::Name("Crypt".to_string()));
205        } else if let Some(Object::Array(filters)) = stream.dictionary_mut().get_mut("Filter") {
206            // Add Crypt filter to existing filters
207            filters.push(Object::Name("Crypt".to_string()));
208        }
209
210        Ok(())
211    }
212
213    /// Decrypt a stream
214    fn decrypt_stream(&self, stream: &mut Stream, obj_id: &ObjectId) -> Result<()> {
215        // Check if stream should be decrypted
216        if !self.should_encrypt_stream(stream) {
217            return Ok(());
218        }
219
220        let decrypted_data = if let Some(ref handler) = self.embedded_file_handler {
221            // Use embedded file handler for special stream types
222            handler.process_stream_encryption(
223                stream.dictionary(),
224                stream.data(),
225                obj_id,
226                &self.encryption_key,
227                false, // decrypt
228            )?
229        } else {
230            // Use standard decryption
231            self.filter_manager.decrypt_stream(
232                stream.data(),
233                obj_id,
234                stream.dictionary(),
235                &self.encryption_key,
236            )?
237        };
238
239        *stream.data_mut() = decrypted_data;
240
241        // Remove Crypt filter from dictionary if present
242        if let Some(Object::Array(filters)) = stream.dictionary_mut().get_mut("Filter") {
243            filters.retain(|f| {
244                if let Object::Name(name) = f {
245                    name != "Crypt"
246                } else {
247                    true
248                }
249            });
250
251            // If only Crypt filter was present, remove Filter entry
252            if filters.is_empty() {
253                stream.dictionary_mut().remove("Filter");
254            }
255        } else if let Some(Object::Name(name)) = stream.dictionary().get("Filter") {
256            if name == "Crypt" {
257                stream.dictionary_mut().remove("Filter");
258            }
259        }
260
261        Ok(())
262    }
263
264    /// Encrypt a dictionary
265    fn encrypt_dictionary(&self, dict: &mut Dictionary, obj_id: &ObjectId) -> Result<()> {
266        // Get all keys to avoid borrowing issues
267        let keys: Vec<String> = dict.keys().cloned().collect();
268
269        for key in keys {
270            // Skip certain dictionary entries
271            if self.should_skip_dictionary_key(&key) {
272                continue;
273            }
274
275            if let Some(value) = dict.get_mut(&key) {
276                self.encrypt_object(value, obj_id)?;
277            }
278        }
279
280        Ok(())
281    }
282
283    /// Decrypt a dictionary
284    fn decrypt_dictionary(&self, dict: &mut Dictionary, obj_id: &ObjectId) -> Result<()> {
285        // Get all keys to avoid borrowing issues
286        let keys: Vec<String> = dict.keys().cloned().collect();
287
288        for key in keys {
289            // Skip certain dictionary entries
290            if self.should_skip_dictionary_key(&key) {
291                continue;
292            }
293
294            if let Some(value) = dict.get_mut(&key) {
295                self.decrypt_object(value, obj_id)?;
296            }
297        }
298
299        Ok(())
300    }
301
302    /// Check if a string should be encrypted
303    fn should_encrypt_string(&self, _s: &str) -> bool {
304        // All strings are encrypted except in special cases
305        true
306    }
307
308    /// Check if a stream should be encrypted
309    fn should_encrypt_stream(&self, stream: &Stream) -> bool {
310        // Check if this is a metadata stream
311        if !self.encrypt_metadata {
312            if let Some(Object::Name(type_name)) = stream.dictionary().get("Type") {
313                if type_name == "Metadata" {
314                    return false;
315                }
316            }
317        }
318
319        // Check if stream is already encrypted
320        if let Some(filter) = stream.dictionary().get("Filter") {
321            match filter {
322                Object::Name(name) => {
323                    if name == "Crypt" {
324                        return false;
325                    }
326                }
327                Object::Array(filters) => {
328                    for f in filters {
329                        if let Object::Name(name) = f {
330                            if name == "Crypt" {
331                                return false;
332                            }
333                        }
334                    }
335                }
336                _ => {}
337            }
338        }
339
340        true
341    }
342
343    /// Check if a dictionary key should be skipped during encryption
344    fn should_skip_dictionary_key(&self, key: &str) -> bool {
345        // These keys should never be encrypted
346        matches!(
347            key,
348            "Length" | "Filter" | "DecodeParms" | "Encrypt" | "ID" | "O" | "U" | "P" | "Perms"
349        )
350    }
351}
352
353/// Integration with Document for encryption
354pub struct DocumentEncryption {
355    /// Encryption dictionary
356    pub encryption_dict: EncryptionDictionary,
357    /// Object encryptor
358    pub encryptor: ObjectEncryptor,
359}
360
361impl DocumentEncryption {
362    /// Create from encryption dictionary and password
363    pub fn new(
364        encryption_dict: EncryptionDictionary,
365        user_password: &str,
366        file_id: Option<&[u8]>,
367    ) -> Result<Self> {
368        // Create security handler based on revision
369        let handler: Box<dyn SecurityHandler> = match encryption_dict.r {
370            2 | 3 => Box::new(StandardSecurityHandler::rc4_128bit()),
371            4 => Box::new(StandardSecurityHandler {
372                revision: crate::encryption::SecurityHandlerRevision::R4,
373                key_length: encryption_dict.length.unwrap_or(16) as usize,
374            }),
375            5 => Box::new(StandardSecurityHandler::aes_256_r5()),
376            6 => Box::new(StandardSecurityHandler::aes_256_r6()),
377            _ => {
378                return Err(PdfError::EncryptionError(format!(
379                    "Unsupported encryption revision: {}",
380                    encryption_dict.r
381                )));
382            }
383        };
384
385        // Compute encryption key
386        let user_pwd = crate::encryption::UserPassword(user_password.to_string());
387        let encryption_key = if encryption_dict.r <= 4 {
388            StandardSecurityHandler {
389                revision: match encryption_dict.r {
390                    2 => crate::encryption::SecurityHandlerRevision::R2,
391                    3 => crate::encryption::SecurityHandlerRevision::R3,
392                    4 => crate::encryption::SecurityHandlerRevision::R4,
393                    _ => unreachable!(),
394                },
395                key_length: encryption_dict.length.unwrap_or(16) as usize,
396            }
397            .compute_encryption_key(
398                &user_pwd,
399                &encryption_dict.o,
400                encryption_dict.p,
401                file_id,
402            )?
403        } else {
404            // For R5/R6, use advanced key derivation
405            // This is simplified - in production, extract salts from encryption dict
406            EncryptionKey::new(vec![0u8; 32])
407        };
408
409        // Create crypt filter manager
410        let mut filter_manager = CryptFilterManager::new(
411            handler,
412            encryption_dict
413                .stm_f
414                .as_ref()
415                .map(|f| match f {
416                    crate::encryption::StreamFilter::StdCF => "StdCF".to_string(),
417                    crate::encryption::StreamFilter::Identity => "Identity".to_string(),
418                    crate::encryption::StreamFilter::Custom(name) => name.clone(),
419                })
420                .unwrap_or_else(|| "StdCF".to_string()),
421            encryption_dict
422                .str_f
423                .as_ref()
424                .map(|f| match f {
425                    crate::encryption::StringFilter::StdCF => "StdCF".to_string(),
426                    crate::encryption::StringFilter::Identity => "Identity".to_string(),
427                    crate::encryption::StringFilter::Custom(name) => name.clone(),
428                })
429                .unwrap_or_else(|| "StdCF".to_string()),
430        );
431
432        // Add crypt filters from dictionary
433        if let Some(ref filters) = encryption_dict.cf {
434            for filter in filters {
435                filter_manager.add_filter(crate::encryption::FunctionalCryptFilter {
436                    name: filter.name.clone(),
437                    method: filter.method,
438                    length: filter.length,
439                    auth_event: crate::encryption::AuthEvent::DocOpen,
440                    recipients: None,
441                });
442            }
443        }
444
445        let encryptor = ObjectEncryptor::new(
446            Arc::new(filter_manager),
447            encryption_key,
448            encryption_dict.encrypt_metadata,
449        );
450
451        Ok(Self {
452            encryption_dict,
453            encryptor,
454        })
455    }
456
457    /// Encrypt all objects in a document
458    pub fn encrypt_objects(&self, objects: &mut [(ObjectId, Object)]) -> Result<()> {
459        for (obj_id, obj) in objects.iter_mut() {
460            // Skip encryption dictionary object
461            if self.is_encryption_dict_object(obj) {
462                continue;
463            }
464
465            self.encryptor.encrypt_object(obj, obj_id)?;
466        }
467
468        Ok(())
469    }
470
471    /// Decrypt all objects in a document
472    pub fn decrypt_objects(&self, objects: &mut [(ObjectId, Object)]) -> Result<()> {
473        for (obj_id, obj) in objects.iter_mut() {
474            // Skip encryption dictionary object
475            if self.is_encryption_dict_object(obj) {
476                continue;
477            }
478
479            self.encryptor.decrypt_object(obj, obj_id)?;
480        }
481
482        Ok(())
483    }
484
485    /// Check if object is the encryption dictionary
486    fn is_encryption_dict_object(&self, obj: &Object) -> bool {
487        if let Object::Dictionary(dict) = obj {
488            // Check if this is an encryption dictionary
489            if let Some(Object::Name(filter)) = dict.get("Filter") {
490                return filter == "Standard";
491            }
492        }
493        false
494    }
495}
496
497#[cfg(test)]
498mod tests {
499    use super::*;
500    use crate::encryption::Permissions;
501
502    fn create_test_encryptor() -> ObjectEncryptor {
503        let handler = Box::new(StandardSecurityHandler::rc4_128bit());
504        let mut filter_manager =
505            CryptFilterManager::new(handler, "StdCF".to_string(), "StdCF".to_string());
506
507        // Add the StdCF filter
508        filter_manager.add_filter(crate::encryption::FunctionalCryptFilter {
509            name: "StdCF".to_string(),
510            method: crate::encryption::CryptFilterMethod::V2,
511            length: Some(16),
512            auth_event: crate::encryption::AuthEvent::DocOpen,
513            recipients: None,
514        });
515
516        let encryption_key = EncryptionKey::new(vec![0u8; 16]);
517
518        ObjectEncryptor::new(Arc::new(filter_manager), encryption_key, true)
519    }
520
521    #[test]
522    fn test_encrypt_string_object() {
523        let encryptor = create_test_encryptor();
524        let obj_id = ObjectId::new(1, 0);
525
526        let mut obj = Object::String("Test string".to_string());
527        let original = obj.clone();
528
529        encryptor.encrypt_object(&mut obj, &obj_id).unwrap();
530
531        // String should be different after encryption
532        assert_ne!(obj, original);
533    }
534
535    #[test]
536    fn test_encrypt_array_object() {
537        let encryptor = create_test_encryptor();
538        let obj_id = ObjectId::new(1, 0);
539
540        let mut obj = Object::Array(vec![
541            Object::String("String 1".to_string()),
542            Object::Integer(42),
543            Object::String("String 2".to_string()),
544        ]);
545
546        let original = obj.clone();
547        encryptor.encrypt_object(&mut obj, &obj_id).unwrap();
548
549        // Array should be different (strings encrypted)
550        assert_ne!(obj, original);
551
552        // Check that integers are not encrypted
553        if let Object::Array(array) = &obj {
554            assert_eq!(array[1], Object::Integer(42));
555        }
556    }
557
558    #[test]
559    fn test_encrypt_dictionary_object() {
560        let encryptor = create_test_encryptor();
561        let obj_id = ObjectId::new(1, 0);
562
563        let mut dict = Dictionary::new();
564        dict.set("Title", Object::String("Test Title".to_string()));
565        dict.set("Length", Object::Integer(100)); // Should be skipped
566        dict.set("Filter", Object::Name("FlateDecode".to_string())); // Should be skipped
567
568        let mut obj = Object::Dictionary(dict);
569        let original = obj.clone();
570
571        encryptor.encrypt_object(&mut obj, &obj_id).unwrap();
572
573        // Dictionary should be different
574        assert_ne!(obj, original);
575
576        // Check that skipped keys are not encrypted
577        if let Object::Dictionary(dict) = &obj {
578            assert_eq!(dict.get("Length"), Some(&Object::Integer(100)));
579            assert_eq!(
580                dict.get("Filter"),
581                Some(&Object::Name("FlateDecode".to_string()))
582            );
583        }
584    }
585
586    #[test]
587    fn test_encrypt_stream_object() {
588        let encryptor = create_test_encryptor();
589        let obj_id = ObjectId::new(1, 0);
590
591        let dict = Dictionary::new();
592        let data = b"Stream data content".to_vec();
593        let original_data = data.clone();
594
595        let mut obj = Object::Stream(dict, data);
596        encryptor.encrypt_object(&mut obj, &obj_id).unwrap();
597
598        if let Object::Stream(dict, data) = &obj {
599            // Data should be encrypted
600            assert_ne!(data, &original_data);
601
602            // Filter should be added
603            assert_eq!(dict.get("Filter"), Some(&Object::Name("Crypt".to_string())));
604        }
605    }
606
607    #[test]
608    fn test_skip_metadata_stream() {
609        let handler = Box::new(StandardSecurityHandler::rc4_128bit());
610        let filter_manager =
611            CryptFilterManager::new(handler, "StdCF".to_string(), "StdCF".to_string());
612
613        let encryption_key = EncryptionKey::new(vec![0u8; 16]);
614
615        let encryptor = ObjectEncryptor::new(
616            Arc::new(filter_manager),
617            encryption_key,
618            false, // Don't encrypt metadata
619        );
620
621        let obj_id = ObjectId::new(1, 0);
622
623        let mut dict = Dictionary::new();
624        dict.set("Type", Object::Name("Metadata".to_string()));
625        let data = b"Metadata content".to_vec();
626        let original_data = data.clone();
627
628        let mut obj = Object::Stream(dict, data);
629
630        encryptor.encrypt_object(&mut obj, &obj_id).unwrap();
631
632        if let Object::Stream(_, data) = &obj {
633            // Metadata should not be encrypted
634            assert_eq!(data, &original_data);
635        }
636    }
637
638    #[test]
639    fn test_should_skip_dictionary_key() {
640        let encryptor = create_test_encryptor();
641
642        assert!(encryptor.should_skip_dictionary_key("Length"));
643        assert!(encryptor.should_skip_dictionary_key("Filter"));
644        assert!(encryptor.should_skip_dictionary_key("DecodeParms"));
645        assert!(encryptor.should_skip_dictionary_key("Encrypt"));
646        assert!(encryptor.should_skip_dictionary_key("ID"));
647        assert!(encryptor.should_skip_dictionary_key("O"));
648        assert!(encryptor.should_skip_dictionary_key("U"));
649        assert!(encryptor.should_skip_dictionary_key("P"));
650        assert!(encryptor.should_skip_dictionary_key("Perms"));
651
652        assert!(!encryptor.should_skip_dictionary_key("Title"));
653        assert!(!encryptor.should_skip_dictionary_key("Author"));
654        assert!(!encryptor.should_skip_dictionary_key("Subject"));
655    }
656
657    #[test]
658    fn test_decrypt_object_reverses_encryption() {
659        let encryptor = create_test_encryptor();
660        let obj_id = ObjectId::new(1, 0);
661
662        let original_string = "Test content for encryption";
663        let mut obj = Object::String(original_string.to_string());
664        let original = obj.clone();
665
666        // Encrypt
667        encryptor.encrypt_object(&mut obj, &obj_id).unwrap();
668
669        // Verify it's encrypted (different from original)
670        assert_ne!(obj, original);
671
672        // Decrypt
673        encryptor.decrypt_object(&mut obj, &obj_id).unwrap();
674
675        // Due to String::from_utf8_lossy, we may not get exact original back
676        // In production, PDF strings should handle binary data properly
677        // For now, just verify that encrypt/decrypt complete without errors
678        if let Object::String(s) = &obj {
679            // At minimum, verify it's a valid string
680            assert!(!s.is_empty());
681        }
682    }
683
684    #[test]
685    fn test_reference_object_not_encrypted() {
686        let encryptor = create_test_encryptor();
687        let obj_id = ObjectId::new(1, 0);
688
689        let mut obj = Object::Reference(ObjectId::new(5, 0));
690        let original = obj.clone();
691
692        encryptor.encrypt_object(&mut obj, &obj_id).unwrap();
693
694        // Reference should remain unchanged
695        assert_eq!(obj, original);
696    }
697
698    #[test]
699    fn test_already_encrypted_stream_skipped() {
700        let encryptor = create_test_encryptor();
701        let obj_id = ObjectId::new(1, 0);
702
703        let mut dict = Dictionary::new();
704        dict.set("Filter", Object::Name("Crypt".to_string()));
705        let data = b"Already encrypted data".to_vec();
706        let original_data = data.clone();
707
708        let mut obj = Object::Stream(dict, data);
709
710        encryptor.encrypt_object(&mut obj, &obj_id).unwrap();
711
712        if let Object::Stream(_, data) = &obj {
713            // Data should remain unchanged
714            assert_eq!(data, &original_data);
715        }
716    }
717
718    #[test]
719    fn test_document_encryption_creation() {
720        let encryption_dict = crate::encryption::EncryptionDictionary::rc4_128bit(
721            vec![0u8; 32],
722            vec![1u8; 32],
723            Permissions::all(),
724            None,
725        );
726
727        let doc_encryption =
728            DocumentEncryption::new(encryption_dict, "user_password", Some(b"file_id"));
729
730        assert!(doc_encryption.is_ok());
731    }
732
733    #[test]
734    fn test_is_encryption_dict_object() {
735        let encryption_dict = crate::encryption::EncryptionDictionary::rc4_128bit(
736            vec![0u8; 32],
737            vec![1u8; 32],
738            Permissions::all(),
739            None,
740        );
741
742        let doc_encryption =
743            DocumentEncryption::new(encryption_dict, "user_password", Some(b"file_id")).unwrap();
744
745        let mut dict = Dictionary::new();
746        dict.set("Filter", Object::Name("Standard".to_string()));
747        let obj = Object::Dictionary(dict);
748
749        assert!(doc_encryption.is_encryption_dict_object(&obj));
750
751        let normal_obj = Object::String("Not an encryption dict".to_string());
752        assert!(!doc_encryption.is_encryption_dict_object(&normal_obj));
753    }
754
755    #[test]
756    fn test_with_embedded_files_constructor() {
757        let handler = Box::new(StandardSecurityHandler::rc4_128bit());
758        let filter_manager =
759            CryptFilterManager::new(handler, "StdCF".to_string(), "StdCF".to_string());
760
761        let encryption_key = EncryptionKey::new(vec![0u8; 16]);
762
763        let encryptor = ObjectEncryptor::with_embedded_files(
764            Arc::new(filter_manager),
765            encryption_key,
766            true,
767            Some("StdCF".to_string()),
768        );
769
770        // Verify embedded file handler was created
771        assert!(encryptor.embedded_file_handler.is_some());
772    }
773
774    #[test]
775    fn test_with_embedded_files_no_filter() {
776        let handler = Box::new(StandardSecurityHandler::rc4_128bit());
777        let filter_manager =
778            CryptFilterManager::new(handler, "StdCF".to_string(), "StdCF".to_string());
779
780        let encryption_key = EncryptionKey::new(vec![0u8; 16]);
781
782        let encryptor = ObjectEncryptor::with_embedded_files(
783            Arc::new(filter_manager),
784            encryption_key,
785            false,
786            None,
787        );
788
789        // Handler should still be created even without explicit filter
790        assert!(encryptor.embedded_file_handler.is_some());
791    }
792
793    #[test]
794    fn test_decrypt_string_object() {
795        let encryptor = create_test_encryptor();
796        let obj_id = ObjectId::new(1, 0);
797
798        // First encrypt a string
799        let mut obj = Object::String("Test string for decryption".to_string());
800        encryptor.encrypt_object(&mut obj, &obj_id).unwrap();
801
802        // Then decrypt it
803        encryptor.decrypt_object(&mut obj, &obj_id).unwrap();
804
805        // Verify it's a valid string after round-trip
806        if let Object::String(s) = &obj {
807            assert!(!s.is_empty());
808        } else {
809            panic!("Expected String object");
810        }
811    }
812
813    #[test]
814    fn test_decrypt_array_object() {
815        let encryptor = create_test_encryptor();
816        let obj_id = ObjectId::new(1, 0);
817
818        let mut obj = Object::Array(vec![
819            Object::String("Test 1".to_string()),
820            Object::Integer(123),
821            Object::String("Test 2".to_string()),
822        ]);
823
824        // Encrypt
825        encryptor.encrypt_object(&mut obj, &obj_id).unwrap();
826
827        // Decrypt
828        encryptor.decrypt_object(&mut obj, &obj_id).unwrap();
829
830        // Verify structure is preserved
831        if let Object::Array(array) = &obj {
832            assert_eq!(array.len(), 3);
833            assert_eq!(array[1], Object::Integer(123));
834        } else {
835            panic!("Expected Array object");
836        }
837    }
838
839    #[test]
840    fn test_decrypt_dictionary_object() {
841        let encryptor = create_test_encryptor();
842        let obj_id = ObjectId::new(1, 0);
843
844        let mut dict = Dictionary::new();
845        dict.set("Title", Object::String("Test Title".to_string()));
846        dict.set("Count", Object::Integer(42));
847        dict.set("Length", Object::Integer(100)); // Should be skipped
848
849        let mut obj = Object::Dictionary(dict);
850
851        // Encrypt
852        encryptor.encrypt_object(&mut obj, &obj_id).unwrap();
853
854        // Decrypt
855        encryptor.decrypt_object(&mut obj, &obj_id).unwrap();
856
857        // Verify skipped keys are unchanged
858        if let Object::Dictionary(dict) = &obj {
859            assert_eq!(dict.get("Count"), Some(&Object::Integer(42)));
860            assert_eq!(dict.get("Length"), Some(&Object::Integer(100)));
861        } else {
862            panic!("Expected Dictionary object");
863        }
864    }
865
866    #[test]
867    fn test_decrypt_reference_not_changed() {
868        let encryptor = create_test_encryptor();
869        let obj_id = ObjectId::new(1, 0);
870
871        let mut obj = Object::Reference(ObjectId::new(10, 0));
872        let original = obj.clone();
873
874        encryptor.decrypt_object(&mut obj, &obj_id).unwrap();
875
876        // Reference should remain unchanged
877        assert_eq!(obj, original);
878    }
879
880    #[test]
881    fn test_decrypt_other_types_not_changed() {
882        let encryptor = create_test_encryptor();
883        let obj_id = ObjectId::new(1, 0);
884
885        // Test Integer
886        let mut obj = Object::Integer(42);
887        let original = obj.clone();
888        encryptor.decrypt_object(&mut obj, &obj_id).unwrap();
889        assert_eq!(obj, original);
890
891        // Test Real
892        let mut obj = Object::Real(3.14);
893        let original = obj.clone();
894        encryptor.decrypt_object(&mut obj, &obj_id).unwrap();
895        assert_eq!(obj, original);
896
897        // Test Boolean
898        let mut obj = Object::Boolean(true);
899        let original = obj.clone();
900        encryptor.decrypt_object(&mut obj, &obj_id).unwrap();
901        assert_eq!(obj, original);
902
903        // Test Null
904        let mut obj = Object::Null;
905        let original = obj.clone();
906        encryptor.decrypt_object(&mut obj, &obj_id).unwrap();
907        assert_eq!(obj, original);
908
909        // Test Name
910        let mut obj = Object::Name("TestName".to_string());
911        let original = obj.clone();
912        encryptor.decrypt_object(&mut obj, &obj_id).unwrap();
913        assert_eq!(obj, original);
914    }
915
916    #[test]
917    fn test_encrypt_other_types_not_changed() {
918        let encryptor = create_test_encryptor();
919        let obj_id = ObjectId::new(1, 0);
920
921        // Test Integer
922        let mut obj = Object::Integer(999);
923        let original = obj.clone();
924        encryptor.encrypt_object(&mut obj, &obj_id).unwrap();
925        assert_eq!(obj, original);
926
927        // Test Real
928        let mut obj = Object::Real(2.718);
929        let original = obj.clone();
930        encryptor.encrypt_object(&mut obj, &obj_id).unwrap();
931        assert_eq!(obj, original);
932
933        // Test Boolean
934        let mut obj = Object::Boolean(false);
935        let original = obj.clone();
936        encryptor.encrypt_object(&mut obj, &obj_id).unwrap();
937        assert_eq!(obj, original);
938
939        // Test Null
940        let mut obj = Object::Null;
941        let original = obj.clone();
942        encryptor.encrypt_object(&mut obj, &obj_id).unwrap();
943        assert_eq!(obj, original);
944
945        // Test Name
946        let mut obj = Object::Name("AnotherName".to_string());
947        let original = obj.clone();
948        encryptor.encrypt_object(&mut obj, &obj_id).unwrap();
949        assert_eq!(obj, original);
950    }
951
952    #[test]
953    fn test_should_encrypt_stream_with_array_filter_containing_crypt() {
954        let encryptor = create_test_encryptor();
955
956        let mut dict = Dictionary::new();
957        dict.set(
958            "Filter",
959            Object::Array(vec![
960                Object::Name("FlateDecode".to_string()),
961                Object::Name("Crypt".to_string()),
962            ]),
963        );
964
965        let stream = Stream::with_dictionary(dict, vec![1, 2, 3]);
966
967        // Should return false because Crypt is in the filter array
968        assert!(!encryptor.should_encrypt_stream(&stream));
969    }
970
971    #[test]
972    fn test_should_encrypt_stream_with_array_filter_without_crypt() {
973        let encryptor = create_test_encryptor();
974
975        let mut dict = Dictionary::new();
976        dict.set(
977            "Filter",
978            Object::Array(vec![
979                Object::Name("FlateDecode".to_string()),
980                Object::Name("ASCII85Decode".to_string()),
981            ]),
982        );
983
984        let stream = Stream::with_dictionary(dict, vec![1, 2, 3]);
985
986        // Should return true because no Crypt filter
987        assert!(encryptor.should_encrypt_stream(&stream));
988    }
989
990    #[test]
991    fn test_should_encrypt_stream_with_non_name_filter() {
992        let encryptor = create_test_encryptor();
993
994        let mut dict = Dictionary::new();
995        // Invalid filter type (Integer instead of Name or Array)
996        dict.set("Filter", Object::Integer(123));
997
998        let stream = Stream::with_dictionary(dict, vec![1, 2, 3]);
999
1000        // Should return true because no valid Crypt filter found
1001        assert!(encryptor.should_encrypt_stream(&stream));
1002    }
1003
1004    #[test]
1005    fn test_should_encrypt_string_always_true() {
1006        let encryptor = create_test_encryptor();
1007
1008        assert!(encryptor.should_encrypt_string("any string"));
1009        assert!(encryptor.should_encrypt_string(""));
1010        assert!(encryptor.should_encrypt_string("special chars: !@#$%"));
1011    }
1012
1013    #[test]
1014    fn test_encrypt_objects_skips_encryption_dict() {
1015        let mut encryption_dict = crate::encryption::EncryptionDictionary::rc4_128bit(
1016            vec![0u8; 32],
1017            vec![1u8; 32],
1018            Permissions::all(),
1019            None,
1020        );
1021
1022        // Add the crypt filter that will be needed
1023        encryption_dict.cf = Some(vec![crate::encryption::CryptFilter {
1024            name: "StdCF".to_string(),
1025            method: crate::encryption::CryptFilterMethod::V2,
1026            length: Some(16),
1027        }]);
1028
1029        let doc_encryption =
1030            DocumentEncryption::new(encryption_dict, "user_password", Some(b"file_id")).unwrap();
1031
1032        // Create an encryption dictionary object
1033        let mut encrypt_dict = Dictionary::new();
1034        encrypt_dict.set("Filter", Object::Name("Standard".to_string()));
1035        encrypt_dict.set("V", Object::Integer(4));
1036
1037        let mut objects = vec![
1038            (
1039                ObjectId::new(1, 0),
1040                Object::Dictionary(encrypt_dict.clone()),
1041            ),
1042            (
1043                ObjectId::new(2, 0),
1044                Object::String("Normal string".to_string()),
1045            ),
1046        ];
1047
1048        let original_encrypt_dict = objects[0].1.clone();
1049
1050        doc_encryption.encrypt_objects(&mut objects).unwrap();
1051
1052        // Encryption dict should be unchanged
1053        assert_eq!(objects[0].1, original_encrypt_dict);
1054
1055        // Normal string should be encrypted (different from original)
1056        assert_ne!(objects[1].1, Object::String("Normal string".to_string()));
1057    }
1058
1059    #[test]
1060    fn test_decrypt_objects_skips_encryption_dict() {
1061        let mut encryption_dict = crate::encryption::EncryptionDictionary::rc4_128bit(
1062            vec![0u8; 32],
1063            vec![1u8; 32],
1064            Permissions::all(),
1065            None,
1066        );
1067
1068        // Add the crypt filter that will be needed
1069        encryption_dict.cf = Some(vec![crate::encryption::CryptFilter {
1070            name: "StdCF".to_string(),
1071            method: crate::encryption::CryptFilterMethod::V2,
1072            length: Some(16),
1073        }]);
1074
1075        let doc_encryption =
1076            DocumentEncryption::new(encryption_dict, "user_password", Some(b"file_id")).unwrap();
1077
1078        // Create an encryption dictionary object
1079        let mut encrypt_dict = Dictionary::new();
1080        encrypt_dict.set("Filter", Object::Name("Standard".to_string()));
1081        encrypt_dict.set("V", Object::Integer(4));
1082
1083        let mut objects = vec![
1084            (
1085                ObjectId::new(1, 0),
1086                Object::Dictionary(encrypt_dict.clone()),
1087            ),
1088            (
1089                ObjectId::new(2, 0),
1090                Object::String("encrypted content".to_string()),
1091            ),
1092        ];
1093
1094        let original_encrypt_dict = objects[0].1.clone();
1095
1096        doc_encryption.decrypt_objects(&mut objects).unwrap();
1097
1098        // Encryption dict should be unchanged
1099        assert_eq!(objects[0].1, original_encrypt_dict);
1100    }
1101
1102    #[test]
1103    fn test_document_encryption_unsupported_revision() {
1104        let mut encryption_dict = crate::encryption::EncryptionDictionary::rc4_128bit(
1105            vec![0u8; 32],
1106            vec![1u8; 32],
1107            Permissions::all(),
1108            None,
1109        );
1110        encryption_dict.r = 99; // Unsupported revision
1111
1112        let result = DocumentEncryption::new(encryption_dict, "user_password", Some(b"file_id"));
1113
1114        assert!(result.is_err());
1115        if let Err(PdfError::EncryptionError(msg)) = result {
1116            assert!(msg.contains("Unsupported encryption revision"));
1117        }
1118    }
1119
1120    #[test]
1121    fn test_document_encryption_r2() {
1122        let mut encryption_dict = crate::encryption::EncryptionDictionary::rc4_128bit(
1123            vec![0u8; 32],
1124            vec![1u8; 32],
1125            Permissions::all(),
1126            None,
1127        );
1128        encryption_dict.r = 2;
1129
1130        let result = DocumentEncryption::new(encryption_dict, "user_password", Some(b"file_id"));
1131        assert!(result.is_ok());
1132    }
1133
1134    #[test]
1135    fn test_document_encryption_r4() {
1136        let mut encryption_dict = crate::encryption::EncryptionDictionary::rc4_128bit(
1137            vec![0u8; 32],
1138            vec![1u8; 32],
1139            Permissions::all(),
1140            None,
1141        );
1142        encryption_dict.r = 4;
1143        encryption_dict.length = Some(16);
1144
1145        let result = DocumentEncryption::new(encryption_dict, "user_password", Some(b"file_id"));
1146        assert!(result.is_ok());
1147    }
1148
1149    #[test]
1150    fn test_document_encryption_r5() {
1151        let mut encryption_dict = crate::encryption::EncryptionDictionary::rc4_128bit(
1152            vec![0u8; 32],
1153            vec![1u8; 32],
1154            Permissions::all(),
1155            None,
1156        );
1157        encryption_dict.r = 5;
1158
1159        let result = DocumentEncryption::new(encryption_dict, "user_password", Some(b"file_id"));
1160        assert!(result.is_ok());
1161    }
1162
1163    #[test]
1164    fn test_document_encryption_r6() {
1165        let mut encryption_dict = crate::encryption::EncryptionDictionary::rc4_128bit(
1166            vec![0u8; 32],
1167            vec![1u8; 32],
1168            Permissions::all(),
1169            None,
1170        );
1171        encryption_dict.r = 6;
1172
1173        let result = DocumentEncryption::new(encryption_dict, "user_password", Some(b"file_id"));
1174        assert!(result.is_ok());
1175    }
1176
1177    #[test]
1178    fn test_is_encryption_dict_object_not_dict() {
1179        let encryption_dict = crate::encryption::EncryptionDictionary::rc4_128bit(
1180            vec![0u8; 32],
1181            vec![1u8; 32],
1182            Permissions::all(),
1183            None,
1184        );
1185
1186        let doc_encryption =
1187            DocumentEncryption::new(encryption_dict, "user_password", Some(b"file_id")).unwrap();
1188
1189        // Non-dictionary objects should return false
1190        assert!(!doc_encryption.is_encryption_dict_object(&Object::Integer(42)));
1191        assert!(!doc_encryption.is_encryption_dict_object(&Object::Null));
1192        assert!(!doc_encryption.is_encryption_dict_object(&Object::Array(vec![Object::Integer(1)])));
1193    }
1194
1195    #[test]
1196    fn test_is_encryption_dict_object_dict_without_filter() {
1197        let encryption_dict = crate::encryption::EncryptionDictionary::rc4_128bit(
1198            vec![0u8; 32],
1199            vec![1u8; 32],
1200            Permissions::all(),
1201            None,
1202        );
1203
1204        let doc_encryption =
1205            DocumentEncryption::new(encryption_dict, "user_password", Some(b"file_id")).unwrap();
1206
1207        // Dictionary without Filter key should return false
1208        let mut dict = Dictionary::new();
1209        dict.set("Type", Object::Name("Catalog".to_string()));
1210        let obj = Object::Dictionary(dict);
1211
1212        assert!(!doc_encryption.is_encryption_dict_object(&obj));
1213    }
1214
1215    #[test]
1216    fn test_is_encryption_dict_object_dict_with_different_filter() {
1217        let encryption_dict = crate::encryption::EncryptionDictionary::rc4_128bit(
1218            vec![0u8; 32],
1219            vec![1u8; 32],
1220            Permissions::all(),
1221            None,
1222        );
1223
1224        let doc_encryption =
1225            DocumentEncryption::new(encryption_dict, "user_password", Some(b"file_id")).unwrap();
1226
1227        // Dictionary with non-Standard Filter should return false
1228        let mut dict = Dictionary::new();
1229        dict.set("Filter", Object::Name("FlateDecode".to_string()));
1230        let obj = Object::Dictionary(dict);
1231
1232        assert!(!doc_encryption.is_encryption_dict_object(&obj));
1233    }
1234
1235    #[test]
1236    fn test_nested_array_encryption() {
1237        let encryptor = create_test_encryptor();
1238        let obj_id = ObjectId::new(1, 0);
1239
1240        // Create nested arrays with strings
1241        let mut obj = Object::Array(vec![
1242            Object::Array(vec![
1243                Object::String("Nested 1".to_string()),
1244                Object::String("Nested 2".to_string()),
1245            ]),
1246            Object::String("Outer".to_string()),
1247        ]);
1248
1249        let original = obj.clone();
1250
1251        encryptor.encrypt_object(&mut obj, &obj_id).unwrap();
1252
1253        // Should be different (strings encrypted)
1254        assert_ne!(obj, original);
1255
1256        // Verify structure preserved
1257        if let Object::Array(outer) = &obj {
1258            assert_eq!(outer.len(), 2);
1259            if let Object::Array(inner) = &outer[0] {
1260                assert_eq!(inner.len(), 2);
1261            } else {
1262                panic!("Expected nested array");
1263            }
1264        }
1265    }
1266
1267    #[test]
1268    fn test_nested_dictionary_encryption() {
1269        let encryptor = create_test_encryptor();
1270        let obj_id = ObjectId::new(1, 0);
1271
1272        let mut inner_dict = Dictionary::new();
1273        inner_dict.set("InnerTitle", Object::String("Inner value".to_string()));
1274
1275        let mut outer_dict = Dictionary::new();
1276        outer_dict.set("OuterTitle", Object::String("Outer value".to_string()));
1277        outer_dict.set("Nested", Object::Dictionary(inner_dict));
1278
1279        let mut obj = Object::Dictionary(outer_dict);
1280        let original = obj.clone();
1281
1282        encryptor.encrypt_object(&mut obj, &obj_id).unwrap();
1283
1284        // Should be different (strings encrypted)
1285        assert_ne!(obj, original);
1286
1287        // Verify structure preserved
1288        if let Object::Dictionary(dict) = &obj {
1289            assert!(dict.contains_key("OuterTitle"));
1290            assert!(dict.contains_key("Nested"));
1291            if let Some(Object::Dictionary(nested)) = dict.get("Nested") {
1292                assert!(nested.contains_key("InnerTitle"));
1293            } else {
1294                panic!("Expected nested dictionary");
1295            }
1296        }
1297    }
1298
1299    #[test]
1300    fn test_document_encryption_with_crypt_filters() {
1301        let mut encryption_dict = crate::encryption::EncryptionDictionary::rc4_128bit(
1302            vec![0u8; 32],
1303            vec![1u8; 32],
1304            Permissions::all(),
1305            None,
1306        );
1307
1308        // Add crypt filters
1309        encryption_dict.cf = Some(vec![crate::encryption::CryptFilter {
1310            name: "StdCF".to_string(),
1311            method: crate::encryption::CryptFilterMethod::V2,
1312            length: Some(16),
1313        }]);
1314
1315        let result = DocumentEncryption::new(encryption_dict, "user_password", Some(b"file_id"));
1316        assert!(result.is_ok());
1317    }
1318
1319    #[test]
1320    fn test_document_encryption_with_custom_stm_str_filters() {
1321        let mut encryption_dict = crate::encryption::EncryptionDictionary::rc4_128bit(
1322            vec![0u8; 32],
1323            vec![1u8; 32],
1324            Permissions::all(),
1325            None,
1326        );
1327
1328        encryption_dict.stm_f = Some(crate::encryption::StreamFilter::Identity);
1329        encryption_dict.str_f = Some(crate::encryption::StringFilter::Identity);
1330
1331        let result = DocumentEncryption::new(encryption_dict, "user_password", Some(b"file_id"));
1332        assert!(result.is_ok());
1333    }
1334
1335    #[test]
1336    fn test_document_encryption_with_custom_filter_names() {
1337        let mut encryption_dict = crate::encryption::EncryptionDictionary::rc4_128bit(
1338            vec![0u8; 32],
1339            vec![1u8; 32],
1340            Permissions::all(),
1341            None,
1342        );
1343
1344        encryption_dict.stm_f = Some(crate::encryption::StreamFilter::Custom(
1345            "CustomStm".to_string(),
1346        ));
1347        encryption_dict.str_f = Some(crate::encryption::StringFilter::Custom(
1348            "CustomStr".to_string(),
1349        ));
1350
1351        let result = DocumentEncryption::new(encryption_dict, "user_password", Some(b"file_id"));
1352        assert!(result.is_ok());
1353    }
1354}