Skip to main content

oxidize_pdf/document/
encryption.rs

1//! Document encryption support
2
3use crate::encryption::{
4    EncryptionDictionary, EncryptionKey, OwnerPassword, Permissions, StandardSecurityHandler,
5    UserPassword,
6};
7use crate::error::Result;
8use crate::objects::ObjectId;
9
10/// Encryption settings for a document
11#[derive(Debug, Clone)]
12pub struct DocumentEncryption {
13    /// User password
14    pub user_password: UserPassword,
15    /// Owner password
16    pub owner_password: OwnerPassword,
17    /// Permissions
18    pub permissions: Permissions,
19    /// Encryption strength
20    pub strength: EncryptionStrength,
21}
22
23/// Encryption strength
24#[derive(Debug, Clone, Copy)]
25pub enum EncryptionStrength {
26    /// RC4 40-bit encryption
27    Rc4_40bit,
28    /// RC4 128-bit encryption
29    Rc4_128bit,
30}
31
32impl DocumentEncryption {
33    /// Create new encryption settings
34    pub fn new(
35        user_password: impl Into<String>,
36        owner_password: impl Into<String>,
37        permissions: Permissions,
38        strength: EncryptionStrength,
39    ) -> Self {
40        Self {
41            user_password: UserPassword(user_password.into()),
42            owner_password: OwnerPassword(owner_password.into()),
43            permissions,
44            strength,
45        }
46    }
47
48    /// Create with default permissions (all allowed)
49    pub fn with_passwords(
50        user_password: impl Into<String>,
51        owner_password: impl Into<String>,
52    ) -> Self {
53        Self::new(
54            user_password,
55            owner_password,
56            Permissions::all(),
57            EncryptionStrength::Rc4_128bit,
58        )
59    }
60
61    /// Get the security handler
62    pub fn handler(&self) -> StandardSecurityHandler {
63        match self.strength {
64            EncryptionStrength::Rc4_40bit => StandardSecurityHandler::rc4_40bit(),
65            EncryptionStrength::Rc4_128bit => StandardSecurityHandler::rc4_128bit(),
66        }
67    }
68
69    /// Create encryption dictionary
70    pub fn create_encryption_dict(&self, file_id: Option<&[u8]>) -> Result<EncryptionDictionary> {
71        let handler = self.handler();
72
73        // Compute password hashes
74        let owner_hash = handler.compute_owner_hash(&self.owner_password, &self.user_password);
75        let user_hash = handler.compute_user_hash(
76            &self.user_password,
77            &owner_hash,
78            self.permissions,
79            file_id,
80        )?;
81
82        // Create encryption dictionary
83        let enc_dict = match self.strength {
84            EncryptionStrength::Rc4_40bit => EncryptionDictionary::rc4_40bit(
85                owner_hash,
86                user_hash,
87                self.permissions,
88                file_id.map(|id| id.to_vec()),
89            ),
90            EncryptionStrength::Rc4_128bit => EncryptionDictionary::rc4_128bit(
91                owner_hash,
92                user_hash,
93                self.permissions,
94                file_id.map(|id| id.to_vec()),
95            ),
96        };
97
98        Ok(enc_dict)
99    }
100
101    /// Get encryption key
102    pub fn get_encryption_key(
103        &self,
104        enc_dict: &EncryptionDictionary,
105        file_id: Option<&[u8]>,
106    ) -> Result<EncryptionKey> {
107        let handler = self.handler();
108        handler.compute_encryption_key(&self.user_password, &enc_dict.o, self.permissions, file_id)
109    }
110}
111
112/// Encryption context for encrypting objects
113#[allow(dead_code)]
114pub struct EncryptionContext {
115    /// Security handler
116    handler: StandardSecurityHandler,
117    /// Encryption key
118    key: EncryptionKey,
119}
120
121#[allow(dead_code)]
122impl EncryptionContext {
123    /// Create new encryption context
124    pub fn new(handler: StandardSecurityHandler, key: EncryptionKey) -> Self {
125        Self { handler, key }
126    }
127
128    /// Encrypt a string
129    pub fn encrypt_string(&self, data: &[u8], obj_id: &ObjectId) -> Vec<u8> {
130        self.handler.encrypt_string(data, &self.key, obj_id)
131    }
132
133    /// Decrypt a string
134    pub fn decrypt_string(&self, data: &[u8], obj_id: &ObjectId) -> Vec<u8> {
135        self.handler.decrypt_string(data, &self.key, obj_id)
136    }
137
138    /// Encrypt a stream
139    pub fn encrypt_stream(&self, data: &[u8], obj_id: &ObjectId) -> Vec<u8> {
140        self.handler.encrypt_stream(data, &self.key, obj_id)
141    }
142
143    /// Decrypt a stream
144    pub fn decrypt_stream(&self, data: &[u8], obj_id: &ObjectId) -> Vec<u8> {
145        self.handler.decrypt_stream(data, &self.key, obj_id)
146    }
147}
148
149#[cfg(test)]
150mod tests {
151    use super::*;
152
153    #[test]
154    fn test_document_encryption_new() {
155        let enc = DocumentEncryption::new(
156            "user123",
157            "owner456",
158            Permissions::all(),
159            EncryptionStrength::Rc4_128bit,
160        );
161
162        assert_eq!(enc.user_password.0, "user123");
163        assert_eq!(enc.owner_password.0, "owner456");
164    }
165
166    #[test]
167    fn test_with_passwords() {
168        let enc = DocumentEncryption::with_passwords("user", "owner");
169        assert_eq!(enc.user_password.0, "user");
170        assert_eq!(enc.owner_password.0, "owner");
171        assert!(enc.permissions.can_print());
172        assert!(enc.permissions.can_modify_contents());
173    }
174
175    #[test]
176    fn test_encryption_dict_creation() {
177        let enc = DocumentEncryption::new(
178            "test",
179            "owner",
180            Permissions::new(),
181            EncryptionStrength::Rc4_40bit,
182        );
183
184        let enc_dict = enc.create_encryption_dict(None).unwrap();
185        assert_eq!(enc_dict.v, 1);
186        assert_eq!(enc_dict.r, 2);
187        assert_eq!(enc_dict.length, Some(5));
188    }
189
190    #[test]
191    fn test_encryption_context() {
192        let handler = StandardSecurityHandler::rc4_40bit();
193        let key = EncryptionKey::new(vec![1, 2, 3, 4, 5]);
194        let ctx = EncryptionContext::new(handler, key);
195
196        let obj_id = ObjectId::new(1, 0);
197        let plaintext = b"Hello, World!";
198
199        let encrypted = ctx.encrypt_string(plaintext, &obj_id);
200        assert_ne!(encrypted, plaintext);
201
202        let decrypted = ctx.decrypt_string(&encrypted, &obj_id);
203        assert_eq!(decrypted, plaintext);
204    }
205
206    #[test]
207    fn test_encryption_strength_variants() {
208        let enc_40 = DocumentEncryption::new(
209            "user",
210            "owner",
211            Permissions::new(),
212            EncryptionStrength::Rc4_40bit,
213        );
214
215        let enc_128 = DocumentEncryption::new(
216            "user",
217            "owner",
218            Permissions::new(),
219            EncryptionStrength::Rc4_128bit,
220        );
221
222        // Check handlers
223        let _handler_40 = enc_40.handler();
224        let _handler_128 = enc_128.handler();
225
226        // Verify different encryption dictionary versions
227        let dict_40 = enc_40.create_encryption_dict(None).unwrap();
228        let dict_128 = enc_128.create_encryption_dict(None).unwrap();
229
230        assert_eq!(dict_40.v, 1);
231        assert_eq!(dict_40.r, 2);
232        assert_eq!(dict_40.length, Some(5));
233
234        assert_eq!(dict_128.v, 2);
235        assert_eq!(dict_128.r, 3);
236        assert_eq!(dict_128.length, Some(16));
237    }
238
239    #[test]
240    fn test_empty_passwords() {
241        let enc =
242            DocumentEncryption::new("", "", Permissions::all(), EncryptionStrength::Rc4_128bit);
243
244        assert_eq!(enc.user_password.0, "");
245        assert_eq!(enc.owner_password.0, "");
246
247        // Should still create valid encryption dictionary
248        let dict = enc.create_encryption_dict(None);
249        assert!(dict.is_ok());
250    }
251
252    #[test]
253    fn test_long_passwords() {
254        let long_user = "a".repeat(100);
255        let long_owner = "b".repeat(100);
256
257        let enc = DocumentEncryption::new(
258            &long_user,
259            &long_owner,
260            Permissions::new(),
261            EncryptionStrength::Rc4_128bit,
262        );
263
264        assert_eq!(enc.user_password.0.len(), 100);
265        assert_eq!(enc.owner_password.0.len(), 100);
266
267        let dict = enc.create_encryption_dict(None);
268        assert!(dict.is_ok());
269    }
270
271    #[test]
272    fn test_unicode_passwords() {
273        let enc = DocumentEncryption::new(
274            "contraseña",
275            "密码",
276            Permissions::all(),
277            EncryptionStrength::Rc4_40bit,
278        );
279
280        assert_eq!(enc.user_password.0, "contraseña");
281        assert_eq!(enc.owner_password.0, "密码");
282
283        let dict = enc.create_encryption_dict(None);
284        assert!(dict.is_ok());
285    }
286
287    #[test]
288    fn test_encryption_with_file_id() {
289        let enc = DocumentEncryption::new(
290            "user",
291            "owner",
292            Permissions::new(),
293            EncryptionStrength::Rc4_128bit,
294        );
295
296        let file_id = b"test_file_id_12345";
297        let dict = enc.create_encryption_dict(Some(file_id)).unwrap();
298
299        // Should be able to get encryption key with same file ID
300        let key = enc.get_encryption_key(&dict, Some(file_id));
301        assert!(key.is_ok());
302    }
303
304    #[test]
305    fn test_different_permissions() {
306        let perms_none = Permissions::new();
307        let perms_all = Permissions::all();
308        let mut perms_custom = Permissions::new();
309        perms_custom.set_print(true);
310        perms_custom.set_modify_contents(false);
311
312        let enc1 =
313            DocumentEncryption::new("user", "owner", perms_none, EncryptionStrength::Rc4_128bit);
314
315        let enc2 =
316            DocumentEncryption::new("user", "owner", perms_all, EncryptionStrength::Rc4_128bit);
317
318        let enc3 = DocumentEncryption::new(
319            "user",
320            "owner",
321            perms_custom,
322            EncryptionStrength::Rc4_128bit,
323        );
324
325        // Create encryption dictionaries
326        let _dict1 = enc1.create_encryption_dict(None).unwrap();
327        let _dict2 = enc2.create_encryption_dict(None).unwrap();
328        let _dict3 = enc3.create_encryption_dict(None).unwrap();
329
330        // Permissions should be encoded differently
331        // Note: p field contains encoded permissions as i32
332        // Different permission sets should have different values
333    }
334
335    #[test]
336    fn test_encryption_context_stream() {
337        let handler = StandardSecurityHandler::rc4_128bit();
338        let key = EncryptionKey::new(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
339        let ctx = EncryptionContext::new(handler, key);
340
341        let obj_id = ObjectId::new(5, 0);
342        let stream_data = b"This is a PDF stream content that needs encryption";
343
344        let encrypted = ctx.encrypt_stream(stream_data, &obj_id);
345        assert_ne!(encrypted, stream_data);
346
347        let decrypted = ctx.decrypt_stream(&encrypted, &obj_id);
348        assert_eq!(decrypted, stream_data);
349    }
350
351    #[test]
352    fn test_encryption_context_different_objects() {
353        let handler = StandardSecurityHandler::rc4_40bit();
354        let key = EncryptionKey::new(vec![1, 2, 3, 4, 5]);
355        let ctx = EncryptionContext::new(handler, key);
356
357        let obj_id1 = ObjectId::new(1, 0);
358        let obj_id2 = ObjectId::new(2, 0);
359        let plaintext = b"Test data";
360
361        let encrypted1 = ctx.encrypt_string(plaintext, &obj_id1);
362        let encrypted2 = ctx.encrypt_string(plaintext, &obj_id2);
363
364        // Same plaintext encrypted with different object IDs should produce different ciphertext
365        assert_ne!(encrypted1, encrypted2);
366
367        // But both should decrypt to the same plaintext
368        assert_eq!(ctx.decrypt_string(&encrypted1, &obj_id1), plaintext);
369        assert_eq!(ctx.decrypt_string(&encrypted2, &obj_id2), plaintext);
370    }
371
372    #[test]
373    fn test_get_encryption_key_consistency() {
374        let enc = DocumentEncryption::new(
375            "user123",
376            "owner456",
377            Permissions::all(),
378            EncryptionStrength::Rc4_128bit,
379        );
380
381        let file_id = b"consistent_file_id";
382        let dict = enc.create_encryption_dict(Some(file_id)).unwrap();
383
384        // Getting key multiple times should produce consistent results
385        let key1 = enc.get_encryption_key(&dict, Some(file_id));
386        let key2 = enc.get_encryption_key(&dict, Some(file_id));
387
388        // Both should succeed
389        assert!(key1.is_ok());
390        assert!(key2.is_ok());
391    }
392
393    #[test]
394    fn test_handler_selection() {
395        let enc_40 = DocumentEncryption::new(
396            "test",
397            "test",
398            Permissions::new(),
399            EncryptionStrength::Rc4_40bit,
400        );
401
402        let enc_128 = DocumentEncryption::new(
403            "test",
404            "test",
405            Permissions::new(),
406            EncryptionStrength::Rc4_128bit,
407        );
408
409        // Handlers should be different for different strengths
410        let _handler_40 = enc_40.handler();
411        let _handler_128 = enc_128.handler();
412
413        // Create dictionaries to verify correct configuration
414        let dict_40 = enc_40.create_encryption_dict(None).unwrap();
415        let dict_128 = enc_128.create_encryption_dict(None).unwrap();
416
417        // 40-bit should have length 5, 128-bit should have length 16
418        assert_eq!(dict_40.length, Some(5));
419        assert_eq!(dict_128.length, Some(16));
420    }
421}