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}