Skip to main content

pdfluent_lopdf/encryption/
crypt_filters.rs

1use super::DecryptionError;
2use super::pkcs5::Pkcs5;
3use super::rc4::Rc4;
4use crate::ObjectId;
5use aes::cipher::{BlockDecryptMut, BlockEncryptMut, KeyIvInit};
6use md5::{Digest as _, Md5};
7use rand::Rng as _;
8
9type Aes128CbcEnc = cbc::Encryptor<aes::Aes128>;
10type Aes256CbcEnc = cbc::Encryptor<aes::Aes256>;
11
12type Aes128CbcDec = cbc::Decryptor<aes::Aes128>;
13type Aes256CbcDec = cbc::Decryptor<aes::Aes256>;
14
15pub trait CryptFilter: std::fmt::Debug + Send + Sync {
16    fn method(&self) -> &[u8];
17    fn compute_key(&self, key: &[u8], obj_id: ObjectId) -> Result<Vec<u8>, DecryptionError>;
18    fn encrypt(&self, key: &[u8], plaintext: &[u8]) -> Result<Vec<u8>, DecryptionError>;
19    fn decrypt(&self, key: &[u8], ciphertext: &[u8]) -> Result<Vec<u8>, DecryptionError>;
20}
21
22#[derive(Clone, Copy, Debug)]
23pub struct IdentityCryptFilter;
24
25impl CryptFilter for IdentityCryptFilter {
26    fn method(&self) -> &[u8] {
27        b"Identity"
28    }
29
30    fn compute_key(&self, key: &[u8], _obj_id: ObjectId) -> Result<Vec<u8>, DecryptionError> {
31        Ok(key.to_vec())
32    }
33
34    fn encrypt(&self, _key: &[u8], plaintext: &[u8]) -> Result<Vec<u8>, DecryptionError> {
35        Ok(plaintext.to_vec())
36    }
37
38    fn decrypt(&self, _key: &[u8], ciphertext: &[u8]) -> Result<Vec<u8>, DecryptionError> {
39        Ok(ciphertext.to_vec())
40    }
41}
42
43#[derive(Clone, Copy, Debug)]
44pub struct Rc4CryptFilter;
45
46impl CryptFilter for Rc4CryptFilter {
47    fn method(&self) -> &[u8] {
48        b"V2"
49    }
50
51    fn compute_key(&self, key: &[u8], obj_id: ObjectId) -> Result<Vec<u8>, DecryptionError> {
52        let mut hasher = Md5::new();
53
54        hasher.update(key);
55
56        // For all strings and streams without crypt filter specifier; treating the object number
57        // and generation number as binary integers, extend the original n-byte file encryption key
58        // to n + 5 bytes by appending the low-order 3 bytes of the object number and the low-order
59        // 2 bytes of the generation number in that order, low-order byte first.
60        hasher.update(&obj_id.0.to_le_bytes()[..3]);
61        hasher.update(&obj_id.1.to_le_bytes()[..2]);
62
63        // Initialise the MD5 hash function and pass the result of the previous step as an input to
64        // this function.
65        //
66        // Use the first (n + 5) bytes, up to a maximum of 16, of the output from the MD5 hash as
67        // the key for the AES symmetric key algorithm.
68        let key_len = std::cmp::min(key.len() + 5, 16);
69        let key = hasher.finalize()[..key_len].to_vec();
70
71        Ok(key)
72    }
73
74    fn encrypt(&self, key: &[u8], plaintext: &[u8]) -> Result<Vec<u8>, DecryptionError> {
75        Ok(Rc4::new(key).encrypt(plaintext))
76    }
77
78    fn decrypt(&self, key: &[u8], ciphertext: &[u8]) -> Result<Vec<u8>, DecryptionError> {
79        Ok(Rc4::new(key).decrypt(ciphertext))
80    }
81}
82
83#[derive(Clone, Copy, Debug)]
84pub struct Aes128CryptFilter;
85
86impl CryptFilter for Aes128CryptFilter {
87    fn method(&self) -> &[u8] {
88        b"AESV2"
89    }
90
91    fn compute_key(&self, key: &[u8], obj_id: ObjectId) -> Result<Vec<u8>, DecryptionError> {
92        let mut builder = Vec::with_capacity(key.len() + 9);
93
94        builder.extend_from_slice(key);
95
96        // For all strings and streams without crypt filter specifier; treating the object number
97        // and generation number as binary integers, extend the original n-byte file encryption key
98        // to n + 5 bytes by appending the low-order 3 bytes of the object number and the low-order
99        // 2 bytes of the generation number in that order, low-order byte first.
100        builder.extend_from_slice(&obj_id.0.to_le_bytes()[..3]);
101        builder.extend_from_slice(&obj_id.1.to_le_bytes()[..2]);
102
103        // If using the AES algorithm, extend the file encryption key an additional 4 bytes by
104        // adding the value "sAlT".
105        builder.extend_from_slice(b"sAlT");
106
107        // Initialise the MD5 hash function and pass the result of the previous step as an input to
108        // this function.
109        //
110        // Use the first (n + 5) bytes, up to a maximum of 16, of the output from the MD5 hash as
111        // the key for the AES symmetric key algorithm.
112        let key_len = std::cmp::min(key.len() + 5, 16);
113        let key = Md5::digest(builder)[..key_len].to_vec();
114
115        Ok(key)
116    }
117
118    fn encrypt(&self, key: &[u8], plaintext: &[u8]) -> Result<Vec<u8>, DecryptionError> {
119        // Ensure that the key is 128 bits (i.e., 16 bytes).
120        if key.len() != 16 {
121            return Err(DecryptionError::InvalidKeyLength);
122        }
123
124        // The ciphertext needs to be a multiple of 16 bytes to include the padding.
125        let ciphertext_len = (plaintext.len() + 16) / 16 * 16;
126
127        // Allocate sufficient bytes for the initialization vector, the ciphertext and the padding
128        // combined.
129        let mut ciphertext = Vec::with_capacity(16 + ciphertext_len);
130
131        // Generate random numbers to populate the initialization vector.
132        let mut rng = rand::rng();
133        let mut iv = [0u8; 16];
134        rng.fill(&mut iv);
135
136        // Combine the IV and the plaintext.
137        ciphertext.extend_from_slice(&iv);
138        ciphertext.extend_from_slice(plaintext);
139        ciphertext.resize(16 + ciphertext_len, 0);
140
141        // Use the 128-bit AES-CBC algorithm with PKCS#5 padding to encrypt the plaintext.
142        //
143        // Strings and streams encrypted with AES shall use a padding scheme that is described in
144        // the Internet RFC 2898, PKCS #5: Password-Based Cryptography Specification Version 2.0;
145        // see the Bibliography. For an original message length of M, the pad shall consist of 16 -
146        // (M mod 16) bytes whose value shall also be 16 - (M mod 16).
147        Aes128CbcEnc::new(key.into(), &iv.into())
148            .encrypt_padded_mut::<Pkcs5>(&mut ciphertext[16..], plaintext.len())
149            // Padding errors should not occur when encrypting, but avoid causing a panic.
150            .map_err(|_| DecryptionError::Padding)?;
151
152        Ok(ciphertext)
153    }
154
155    fn decrypt(&self, key: &[u8], ciphertext: &[u8]) -> Result<Vec<u8>, DecryptionError> {
156        // Ensure that the key is 128 bits (i.e., 16 bytes).
157        if key.len() != 16 {
158            return Err(DecryptionError::InvalidKeyLength);
159        }
160
161        // Ensure that the ciphertext length is a multiple of 16 bytes.
162        if ciphertext.len() % 16 != 0 {
163            return Err(DecryptionError::InvalidCipherTextLength);
164        }
165
166        // There is nothing to decrypt if the ciphertext is empty or only contains the IV.
167        if ciphertext.is_empty() || ciphertext.len() == 16 {
168            return Ok(vec![]);
169        }
170
171        let mut iv = [0x00u8; 16];
172        iv.copy_from_slice(&ciphertext[..16]);
173
174        // Use the 128-bit AES-CBC algorithm with PKCS#5 padding to decrypt the ciphertext.
175        //
176        // Strings and streams encrypted with AES shall use a padding scheme that is described in
177        // the Internet RFC 2898, PKCS #5: Password-Based Cryptography Specification Version 2.0;
178        // see the Bibliography. For an original message length of M, the pad shall consist of 16 -
179        // (M mod 16) bytes whose value shall also be 16 - (M mod 16).
180        let data = &mut ciphertext[16..].to_vec();
181
182        Ok(Aes128CbcDec::new(key.into(), &iv.into())
183            .decrypt_padded_mut::<Pkcs5>(data)
184            .map_err(|_| DecryptionError::Padding)?
185            .to_vec())
186    }
187}
188
189#[derive(Clone, Copy, Debug)]
190pub struct Aes256CryptFilter;
191
192impl CryptFilter for Aes256CryptFilter {
193    fn method(&self) -> &[u8] {
194        b"AESV3"
195    }
196
197    fn compute_key(&self, key: &[u8], _obj_id: ObjectId) -> Result<Vec<u8>, DecryptionError> {
198        // Use the 32-byte file encryption key for the AES-256 symmetric key algorithm.
199        Ok(key.to_vec())
200    }
201
202    fn encrypt(&self, key: &[u8], plaintext: &[u8]) -> Result<Vec<u8>, DecryptionError> {
203        // Ensure that the key is 256 bits (i.e., 32 bytes).
204        if key.len() != 32 {
205            return Err(DecryptionError::InvalidKeyLength);
206        }
207
208        // The ciphertext needs to be a multiple of 16 bytes to include the padding.
209        let ciphertext_len = (plaintext.len() + 16) / 16 * 16;
210
211        // Allocate sufficient bytes for the initialization vector, the ciphertext and the padding
212        // combined.
213        let mut ciphertext = Vec::with_capacity(16 + ciphertext_len);
214
215        // Generate random numbers to populate the initialization vector.
216        let mut rng = rand::rng();
217        let mut iv = [0u8; 16];
218        rng.fill(&mut iv);
219
220        // Combine the IV and the plaintext.
221        ciphertext.extend_from_slice(&iv);
222        ciphertext.extend_from_slice(plaintext);
223        ciphertext.resize(16 + ciphertext_len, 0);
224
225        // Use the 256-bit AES-CBC algorithm with PKCS#5 padding to encrypt the plaintext.
226        //
227        // Strings and streams encrypted with AES shall use a padding scheme that is described in
228        // the Internet RFC 2898, PKCS #5: Password-Based Cryptography Specification Version 2.0;
229        // see the Bibliography. For an original message length of M, the pad shall consist of 16 -
230        // (M mod 16) bytes whose value shall also be 16 - (M mod 16).
231        Aes256CbcEnc::new(key.into(), &iv.into())
232            .encrypt_padded_mut::<Pkcs5>(&mut ciphertext[16..], plaintext.len())
233            // Padding errors should not occur when encrypting, but avoid causing a panic.
234            .map_err(|_| DecryptionError::Padding)?;
235
236        Ok(ciphertext)
237    }
238
239    fn decrypt(&self, key: &[u8], ciphertext: &[u8]) -> Result<Vec<u8>, DecryptionError> {
240        // Ensure that the key is 256 bits (i.e., 32 bytes).
241        if key.len() != 32 {
242            return Err(DecryptionError::InvalidKeyLength);
243        }
244
245        // Ensure that the ciphertext length is a multiple of 16 bytes.
246        if ciphertext.len() % 16 != 0 {
247            return Err(DecryptionError::InvalidCipherTextLength);
248        }
249
250        // There is nothing to decrypt if the ciphertext is empty or only contains the IV.
251        if ciphertext.is_empty() || ciphertext.len() == 16 {
252            return Ok(vec![]);
253        }
254
255        let mut iv = [0x00u8; 16];
256        iv.copy_from_slice(&ciphertext[..16]);
257
258        // Use the 256-bit AES-CBC algorithm with PKCS#7 padding to decrypt the ciphertext.
259        //
260        // Strings and streams encrypted with AES shall use a padding scheme that is described in
261        // the Internet RFC 2898, PKCS #5: Password-Based Cryptography Specification Version 2.0;
262        // see the Bibliography. For an original message length of M, the pad shall consist of 16 -
263        // (M mod 16) bytes whose value shall also be 16 - (M mod 16).
264        let data = &mut ciphertext[16..].to_vec();
265
266        Ok(Aes256CbcDec::new(key.into(), &iv.into())
267            .decrypt_padded_mut::<Pkcs5>(data)
268            .map_err(|_| DecryptionError::Padding)?
269            .to_vec())
270    }
271}