lopdf/encryption/algorithms.rs
1use super::DecryptionError;
2use super::rc4::Rc4;
3use crate::encodings;
4use crate::encryption::Permissions;
5use crate::{Document, Error, Object};
6use aes::cipher::{BlockDecryptMut as _, BlockEncryptMut as _, KeyInit as _, KeyIvInit as _};
7use md5::{Digest as _, Md5};
8use rand::RngExt as _;
9use sha2::{Sha256, Sha384, Sha512};
10
11type Aes128CbcEnc = cbc::Encryptor<aes::Aes128>;
12type Aes256CbcEnc = cbc::Encryptor<aes::Aes256>;
13type Aes256EbcEnc = ecb::Encryptor<aes::Aes256>;
14
15type Aes256CbcDec = cbc::Decryptor<aes::Aes256>;
16type Aes256EbcDec = ecb::Decryptor<aes::Aes256>;
17
18// If the password string is less than 32 bytes long, pad it by appending the required number of
19// additional bytes from the beginning of the following padding string.
20const PAD_BYTES: [u8; 32] = [
21 0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08, 0x2E, 0x2E, 0x00,
22 0xB6, 0xD0, 0x68, 0x3E, 0x80, 0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A,
23];
24
25#[derive(Clone, Debug, Default)]
26pub struct PasswordAlgorithm {
27 pub(crate) encrypt_metadata: bool,
28 pub(crate) length: Option<usize>,
29 pub(crate) version: i64,
30 pub(crate) revision: i64,
31 pub(crate) owner_value: Vec<u8>,
32 pub(crate) owner_encrypted: Vec<u8>,
33 pub(crate) user_value: Vec<u8>,
34 pub(crate) user_encrypted: Vec<u8>,
35 pub(crate) permissions: Permissions,
36 pub(crate) permission_encrypted: Vec<u8>,
37}
38
39impl TryFrom<&Document> for PasswordAlgorithm {
40 type Error = Error;
41
42 fn try_from(value: &Document) -> Result<Self, Self::Error> {
43 // Get the encrypted dictionary.
44 let encrypted = value
45 .get_encrypted()
46 .map_err(|_| DecryptionError::MissingEncryptDictionary)?;
47
48 // Get the EncryptMetadata field.
49 let encrypt_metadata = encrypted
50 .get(b"EncryptMetadata")
51 .unwrap_or(&Object::Boolean(true))
52 .as_bool()
53 .map_err(|_| DecryptionError::InvalidType)?;
54
55 // Get the Length field if any. Make sure that if it is present that it is a 64-bit integer and
56 // that it can be converted to an unsigned size.
57 let length: Option<usize> = if encrypted.get(b"Length").is_ok() {
58 Some(encrypted.get(b"Length")?.as_i64()?.try_into()?)
59 } else {
60 None
61 };
62
63 // Get the V field.
64 let version = encrypted
65 .get(b"V")
66 .map_err(|_| DecryptionError::MissingVersion)?
67 .as_i64()
68 .map_err(|_| DecryptionError::InvalidType)?;
69
70 // A code specifying the algorithm to be used in encrypting and decrypting the document.
71 match version {
72 // (Deprecated in PDF 2.0) An algorithm that is undocumented. This value shall not be
73 // used.
74 0 => return Err(DecryptionError::InvalidVersion)?,
75 // (PDF 1.4; deprecated in PDF 2.0) Indicates the use of encryption of data using the
76 // RC4 or AES algorithms with a file encryption key length of 40 bits.
77 1 => (),
78 // (PDF 1.4; deprecated in PDF 2.0) Indicates the use of encryption of data using the
79 // RC4 or AES algorithms but permitting file encryption key lengths greater or 40 bits.
80 2 => (),
81 // (PDF 1.4; deprecated in PDF 2.0) An unpublished algorithm that permits encryption
82 // key lengths ranging from 40 to 128 bits. This value shall not appear in a conforming
83 // PDF file.
84 3 => return Err(DecryptionError::InvalidVersion)?,
85 // (PDF 1.5; deprecated in PDF 2.0) The security handler defines the use of encryption
86 // and decryption in the document, using the rules specified by the CF, StmF and StrF
87 // entries using encryption of data using the RC4 or AES algorithms (deprecated in PDF
88 // 2.0) with a file encryption key length of 128 bits.
89 4 => (),
90 // (PDF 2.0) The security handler defines the use of encryption and decryption in the
91 // document, using the rules specified by the CF, StmF, StrF and EFF entries using
92 // encryption of data using the AES algorithms with a file encryption key length of 256
93 // bits.
94 5 => (),
95 // Unknown codes.
96 _ => return Err(DecryptionError::UnsupportedVersion)?,
97 }
98
99 // The length of the file encryption key shall only be present if V is 2 or 3 (but
100 // documents with higher values for V seem to have this field).
101 if let Some(length) = length {
102 match version {
103 // Although "Optional" and/or not required for V1 it appears in some documents
104 // with a default value of 40.
105 1 => {
106 if length != 40 {
107 return Err(DecryptionError::InvalidKeyLength)?;
108 }
109 }
110 // The length of the file encryption key shall be a multiple of 8 in the range 40
111 // to and including 128.
112 2..=3 => {
113 if length % 8 != 0 || !(40..=128).contains(&length) {
114 return Err(DecryptionError::InvalidKeyLength)?;
115 }
116 }
117 // The Length field should not be present if V is 4. However, if it is present it
118 // must be 128.
119 4 => {
120 if length != 128 {
121 return Err(DecryptionError::InvalidKeyLength)?;
122 }
123 }
124 // The Length field should not be present if V is 5. However, if it is present it
125 // must be 256.
126 5 => {
127 if length != 256 {
128 return Err(DecryptionError::InvalidKeyLength)?;
129 }
130 }
131 // The Length field may not be present otherwise.
132 _ => return Err(DecryptionError::InvalidKeyLength)?,
133 }
134 }
135
136 // Get the R field.
137 let revision = encrypted
138 .get(b"R")
139 .map_err(|_| DecryptionError::MissingRevision)?
140 .as_i64()
141 .map_err(|_| DecryptionError::InvalidType)?;
142
143 // Get the owner value and owner encrypted blobs.
144 let mut owner_value = encrypted
145 .get(b"O")
146 .map_err(|_| DecryptionError::MissingOwnerPassword)?
147 .as_str()
148 .map_err(|_| DecryptionError::InvalidType)?
149 .to_vec();
150
151 // The owner value is 32 bytes long if the value of R is 4 or less.
152 if revision <= 4 && owner_value.len() != 32 {
153 return Err(DecryptionError::InvalidHashLength)?;
154 }
155
156 // The owner value is 48 bytes long if the value of R is 5 or greater.
157 // Some PDF writers pad /O with trailing zeros beyond 48 bytes; truncate
158 // to the spec-required length so these documents are accepted.
159 if revision >= 5 {
160 if owner_value.len() < 48 {
161 return Err(DecryptionError::InvalidHashLength)?;
162 }
163 owner_value.truncate(48);
164 }
165
166 let owner_encrypted = encrypted
167 .get(b"OE")
168 .and_then(Object::as_str)
169 .map(|s| s.to_vec())
170 .ok()
171 .unwrap_or_default();
172
173 // The owner encrypted blob is required if R is 5 or greater and the blob shall be 32 bytes
174 // long.
175 if revision >= 5 && owner_encrypted.len() != 32 {
176 return Err(DecryptionError::InvalidCipherTextLength)?;
177 }
178
179 // Get the user value and user encrypted blobs.
180 let mut user_value = encrypted
181 .get(b"U")
182 .map_err(|_| DecryptionError::MissingUserPassword)?
183 .as_str()
184 .map_err(|_| DecryptionError::InvalidType)?
185 .to_vec();
186
187 // The user value is 32 bytes long if the value of R is 4 or less.
188 if revision <= 4 && user_value.len() != 32 {
189 return Err(DecryptionError::InvalidHashLength)?;
190 }
191
192 // The user value is 48 bytes long if the value of R is 5 or greater.
193 // Some PDF writers pad /U with trailing zeros beyond 48 bytes; truncate
194 // to the spec-required length so these documents are accepted.
195 if revision >= 5 {
196 if user_value.len() < 48 {
197 return Err(DecryptionError::InvalidHashLength)?;
198 }
199 user_value.truncate(48);
200 }
201
202 let user_encrypted = encrypted
203 .get(b"UE")
204 .and_then(Object::as_str)
205 .map(|s| s.to_vec())
206 .ok()
207 .unwrap_or_default();
208
209 // The user encrypted blob is required if R is 5 or greater and the blob shall be 32 bytes
210 // long.
211 if revision >= 5 && user_encrypted.len() != 32 {
212 return Err(DecryptionError::InvalidCipherTextLength)?;
213 }
214
215 // Get the permission value and permission encrypted blobs.
216 let permission_value = encrypted
217 .get(b"P")
218 .map_err(|_| DecryptionError::MissingPermissions)?
219 .as_i64()
220 .map_err(|_| DecryptionError::InvalidType)? as u64;
221
222 let permissions = Permissions::from_bits_retain(permission_value);
223
224 let permission_encrypted = encrypted
225 .get(b"Perms")
226 .and_then(Object::as_str)
227 .map(|s| s.to_vec())
228 .ok()
229 .unwrap_or_default();
230
231 // The permission encrypted blob is required if R is 65 or greater and the blob shall be
232 // 16 bytes long.
233 if revision >= 5 && permission_encrypted.len() != 16 {
234 return Err(DecryptionError::InvalidCipherTextLength)?;
235 }
236
237 Ok(Self {
238 encrypt_metadata,
239 length,
240 version,
241 revision,
242 owner_value,
243 owner_encrypted,
244 user_value,
245 user_encrypted,
246 permissions,
247 permission_encrypted,
248 })
249 }
250}
251
252impl PasswordAlgorithm {
253 /// Sanitize the password (revision 4 and earlier).
254 ///
255 /// This implements the first step of Algorithm 2 as described in ISO 32000-2:2020 (PDF 2.0).
256 ///
257 /// This algorithm is deprecated in PDF 2.0.
258 pub(crate) fn sanitize_password_r4(&self, password: &str) -> Result<Vec<u8>, DecryptionError> {
259 // The password string is generated from host system codepage characters (or system scripts) by
260 // first converting the string to PDFDocEncoding. If the input is Unicode, first convert to a
261 // codepage encoding, and then to PDFDocEncoding for backward compatibility.
262 let password = encodings::string_to_bytes(&encodings::PDF_DOC_ENCODING, password);
263
264 Ok(password)
265 }
266
267 /// Compute a file encryption key in order to encrypt/decrypt a document (revision 4 and
268 /// earlier).
269 ///
270 /// This implements Algorithm 2 as described in ISO 32000-2:2020 (PDF 2.0).
271 ///
272 /// This algorithm is deprecated in PDF 2.0.
273 pub(crate) fn compute_file_encryption_key_r4<P>(
274 &self, doc: &Document, password: P,
275 ) -> Result<Vec<u8>, DecryptionError>
276 where
277 P: AsRef<[u8]>,
278 {
279 let password = password.as_ref();
280
281 // Pad or truncate the resulting password string to exactly 32 bytes. If the password string is
282 // more than 32 bytes long, use only its first 32 bytes; if it is less than 32 bytes long, pad
283 // it by appending the required number of additional bytes from the beginning of the following
284 // padding string (see `PAD_BYTES`).
285 //
286 // That is, if the password is n bytes long, append the first 32 - n bytes of the padding
287 // string to the end of the password string. If the password string is empty (zero-length),
288 // meaning there is no user password, substitute the entire padding string in its place.
289 //
290 // i.e., we will simply calculate `len = min(password length, 32)` and use the first len bytes
291 // of password and the first len bytes of `PAD_BYTES`.
292 let len = password.len().min(32);
293
294 // Initialize the MD5 hash function and pass the result as input to this function.
295 let mut hasher = Md5::new();
296
297 hasher.update(&password[..len]);
298 hasher.update(&PAD_BYTES[..32 - len]);
299
300 // Pass the value of the encryption dictionary's O entry (owner password hash) to the MD5 hash
301 // function.
302 hasher.update(&self.owner_value);
303
304 // Convert the integer value of the P entry (permissions) to a 32-bit unsigned binary number
305 // and pass these bytes to the MD5 hash function, low-order byte first.
306 //
307 // We don't actually care about the permissions, but we need the correct value to derive the
308 // correct key.
309 hasher.update((self.permissions.bits() as u32).to_le_bytes());
310
311 // Pass the first element of the file's file identifier array (the value of the ID entry in the
312 // document's trailer dictionary to the MD5 hash function.
313 let file_id_0 = doc
314 .trailer
315 .get(b"ID")
316 .map_err(|_| DecryptionError::MissingFileID)?
317 .as_array()
318 .map_err(|_| DecryptionError::InvalidType)?
319 .first()
320 .ok_or(DecryptionError::InvalidType)?
321 .as_str()
322 .map_err(|_| DecryptionError::InvalidType)?;
323 hasher.update(file_id_0);
324
325 // (Security handlers of revision 4 or greater) If document metadata is not being encrypted,
326 // pass 4 bytes with the value 0xFFFFFFFF to the MD5 hash function.
327 if self.revision >= 4 && !self.encrypt_metadata {
328 hasher.update(b"\xff\xff\xff\xff");
329 }
330
331 // Finish the hash.
332 let mut hash = hasher.finalize();
333
334 // (Security handlers of revision 3 or greater) Do the following 50 times: take the output from
335 // the previous MD5 hash and pass the first n bytes of the output as input into a new MD5 hash,
336 // where n is the number of bytes of the file encryption key as defined by the value of the
337 // encryption dictionary's Length entry.
338 let n = if self.revision >= 3 {
339 self.length.unwrap_or(40) / 8
340 } else {
341 5
342 };
343
344 // The maximum supported key length is 16 bytes (128 bits) due to the use of MD5.
345 if n > 16 {
346 return Err(DecryptionError::InvalidKeyLength);
347 }
348
349 if self.revision >= 3 {
350 for _ in 0..50 {
351 hash = Md5::digest(&hash[..n]);
352 }
353 }
354
355 // Set the file encryption key to the first n bytes of the output from the final MD5 hash,
356 // where n shall always be 5 for security handlers of revision 2 but, for security handlers of
357 // revision 3 or greater, shall depend on the value of the encrpytion dictionary's Length
358 // entry.
359 Ok(hash[..n].to_vec())
360 }
361
362 /// Sanitize the password (revision 6 and later).
363 ///
364 /// This implements the first step of Algorithm 2.A as described in ISO 32000-2:2020 (PDF 2.0).
365 pub(crate) fn sanitize_password_r6(&self, password: &str) -> Result<Vec<u8>, DecryptionError> {
366 // The UTF-8 password string shall be generated from Unicode input by processing the input
367 // with the SASLprep (Internet RFC 4013) profile of stringprep (Internet RFC 3454) using
368 // the Normalize and BiDi options, and then coverting to a UTF-8 representation.
369 Ok(stringprep::saslprep(password)?.as_bytes().to_vec())
370 }
371
372 /// Compute a file encryption key in order to encrypt/decrypt a document (revision 6 and
373 /// later).
374 ///
375 /// This implements Algorithm 2.A as described in ISO 32000-2:2020 (PDF 2.0).
376 fn compute_file_encryption_key_r6<P>(&self, password: P) -> Result<Vec<u8>, DecryptionError>
377 where
378 P: AsRef<[u8]>,
379 {
380 let mut password = password.as_ref();
381
382 let hashed_owner_password = &self.owner_value[0..][..32];
383 let owner_validation_salt = &self.owner_value[32..][..8];
384 let owner_key_salt = &self.owner_value[40..][..8];
385
386 let hashed_user_password = &self.user_value[0..][..32];
387 let user_validation_salt = &self.user_value[32..][..8];
388 let user_key_salt = &self.user_value[40..][..8];
389
390 // Truncate the UTF-8 representation to 127 bytes if it is longer than 127 bytes.
391 if password.len() > 127 {
392 password = &password[..127];
393 }
394
395 // Test the password against the owner key by computing a hash using algorithm 2.B with an
396 // input string consisting of the UTF-8 password concatenated with the 8 bytes of owner
397 // validation salt, concatenated with the 48-byte U string. If the 32-byte result matches
398 // the first 32 bytes of the O string, this is the owner password.
399 if self.compute_hash(password, owner_validation_salt, Some(&self.user_value))? == hashed_owner_password {
400 // Compute an intermediate owner key by computing a hash using algorithm 2.B with an
401 // input string consisting of the UTF-8 owner password concatenated with the 8 bytes of
402 // owner key salt, concatenated with the 48-byte U string.
403 let hash = self.compute_hash(password, owner_key_salt, Some(&self.user_value))?;
404
405 let mut key = [0u8; 32];
406 key.copy_from_slice(&hash);
407
408 // The 32-byte result is the key used to decrypt the 32-byte OE string using AES-256 in
409 // CBC mode with no padding and an initialization vector of zero. The 32-byte result is
410 // the file encryption key.
411 let iv = [0u8; 16];
412
413 let mut owner_encrypted = self.owner_encrypted.clone();
414 let mut decryptor = Aes256CbcDec::new(&key.into(), &iv.into());
415
416 for block in owner_encrypted.chunks_exact_mut(16) {
417 decryptor.decrypt_block_mut(block.into());
418 }
419
420 return Ok(owner_encrypted);
421 }
422
423 // Note: this step is not in the specification, but is a precaution.
424 //
425 // Test the password against the user key by computing a hash using algorithm 2.B with an
426 // input string consisting of the UTF-8 password concatenated with the 8 bytes of user
427 // validation salt. If the 32-byte result matches the first 32-bytes of the U string, this
428 // is the user password.
429
430 if self.compute_hash(password, user_validation_salt, None)? == hashed_user_password {
431 // Compute an intermediate user key by computing a hash using algorithm 2.B with an
432 // input string consisting of the UTF-8 owner password concatenated with the 8 bytes of
433 // user key salt.
434 let hash = self.compute_hash(password, user_key_salt, None)?;
435
436 let mut key = [0u8; 32];
437 key.copy_from_slice(&hash);
438
439 // The 32-byte result is the key used to decrypt the 32-byte UE string using AES-256 in
440 // CBC mode with no padding and an initialization vector of zero. The 32-byte result is
441 // the file encryption key.
442 let iv = [0u8; 16];
443 let mut user_encrypted = self.user_encrypted.clone();
444 let mut decryptor = Aes256CbcDec::new(&key.into(), &iv.into());
445
446 for block in user_encrypted.chunks_exact_mut(16) {
447 decryptor.decrypt_block_mut(block.into());
448 }
449
450 // Decrypt the 16-byte Perms string using AES-256 in EBC mode with an initialization
451 // vector of zero and the file encryption key as the key. Verify that bytes 9-11 of the
452 // result are the characters "a", "d", "b". Bytes 0-3 of the decrypted Perms entry,
453 // treated as a little-endian integer, are the user permissions. They shall match the
454 // value in the P key.
455 //
456 // i.e., use algorithm 13 to validate the permissions.
457 self.validate_permissions(&user_encrypted)?;
458
459 return Ok(user_encrypted);
460 }
461
462 Err(DecryptionError::IncorrectPassword)
463 }
464
465 /// Compute a hash (revision 6 and later).
466 ///
467 /// This implements Algorithm 2.B as described in ISO 32000-2:2020 (PDF 2.0).
468 fn compute_hash<P, S>(&self, password: P, salt: S, user_key: Option<&[u8]>) -> Result<Vec<u8>, DecryptionError>
469 where
470 P: AsRef<[u8]>,
471 S: AsRef<[u8]>,
472 {
473 let password = password.as_ref();
474 let salt = salt.as_ref();
475
476 // Take the SHA-256 hash of the original input to the algorithm and name the resulting 32
477 // bytes, K.
478 let mut hasher = Sha256::new();
479
480 hasher.update(password);
481 hasher.update(salt);
482
483 if let Some(user_key) = user_key {
484 hasher.update(user_key);
485 }
486
487 let mut k = hasher.finalize().to_vec();
488
489 // Revision 5 uses a simplified hash algorithm that simply calculates the SHA-256 hash of
490 // the original input to the algorithm.
491 if self.revision == 5 {
492 return Ok(k);
493 }
494
495 let mut k1 =
496 Vec::with_capacity(64 * (password.len() + 64 + user_key.map(|user_key| user_key.len()).unwrap_or(0)));
497
498 // Perform the following steps at least 64 times, until the value of the last byte in K is
499 // less than or equal to (round number) - 32.
500 for round in 1.. {
501 // Make a new string K0 as follows:
502 //
503 // * When checking the owner password or creating the owner key, K0 is the concatenation of the input
504 // password, K, and the 48-byte user key.
505 // * Otherwise, K0 is the concatenation of the input password and K.
506 //
507 // Next, set K1 to 64 repetitions of K0.
508 k1.clear();
509
510 for _ in 0..64 {
511 k1.extend_from_slice(password);
512 k1.extend_from_slice(&k);
513
514 if let Some(user_key) = user_key {
515 k1.extend_from_slice(user_key);
516 }
517 }
518
519 // Encrypt K1 with the AES-128 (CBC, no padding) algorithm, using the first 16 bytes of
520 // K as the key, and the second 16 bytes of K as the initialization vector. The result
521 // of this encryption is E.
522 //
523 // The 64 repetitions of K0 ensure that K1 is a multiple of 64 bytes, thus a multiple
524 // of 16 bytes, i.e., it does not require padding.
525 let key = &k[0..][..16];
526 let iv = &k[16..][..16];
527
528 let mut encryptor = Aes128CbcEnc::new(key.into(), iv.into());
529
530 for block in k1.chunks_exact_mut(16) {
531 encryptor.encrypt_block_mut(block.into());
532 }
533
534 let e = k1;
535
536 // Taking the first 16 bytes of E as an unsigned big-endian integer, compute the
537 // remainder, modulo 3. If the result is 0, the next hash used is SHA-256. If the
538 // result is 1, the next hash used is SHA-384. If the result is 2, the next hash used
539 // is SHA-256.
540 //
541 // Using the hash algorithm determined in the previous step, take the hash of E. The
542 // result is a new value of K, which will be 32, 48 or 64 bytes in length.
543 k = match e[..16].iter().map(|v| *v as u32).sum::<u32>() % 3 {
544 0 => Sha256::digest(&e).to_vec(),
545 1 => Sha384::digest(&e).to_vec(),
546 2 => Sha512::digest(&e).to_vec(),
547 _ => unreachable!(),
548 };
549
550 // Look at the very last byte of E. If the value of that byte (taken as an unsigned
551 // integer) is greater than the round number - 32, repeat the round again.
552 //
553 // Repeat rounds until the value of the last byte is less than or equal to (round
554 // number) - 32.
555 if round >= 64 && e.last().copied().unwrap_or(0) as u32 <= round - 32 {
556 break;
557 }
558
559 // Move e into k1 for the next round (to reuse k1).
560 k1 = e;
561 }
562
563 // The first 32 bytes of the final K are the output of the algorithm.
564 k.truncate(32);
565
566 Ok(k)
567 }
568
569 /// Compute the encryption dictionary's O-entry value (revision 4 and earlier).
570 ///
571 /// This implements Algorithm 3 as described in ISO 32000-2:2020 (PDF 2.0).
572 ///
573 /// This algorithm is deprecated in PDF 2.0.
574 pub(crate) fn compute_hashed_owner_password_r4<O, U>(
575 &self, owner_password: Option<O>, user_password: U,
576 ) -> Result<Vec<u8>, DecryptionError>
577 where
578 O: AsRef<[u8]>,
579 U: AsRef<[u8]>,
580 {
581 let user_password = user_password.as_ref();
582
583 // Pad or truncate the owner string. If there is no owner password, use the user password
584 // instead.
585 let password = owner_password
586 .as_ref()
587 .map(|password| password.as_ref())
588 .unwrap_or(user_password);
589
590 // Pad or truncate the resulting password string to exactly 32 bytes. If the password string is
591 // more than 32 bytes long, use only its first 32 bytes; if it is less than 32 bytes long, pad
592 // it by appending the required number of additional bytes from the beginning of the following
593 // padding string (see `PAD_BYTES`).
594 //
595 // That is, if the password is n bytes long, append the first 32 - n bytes of the padding
596 // string to the end of the password string. If the password string is empty (zero-length),
597 // meaning there is no user password, substitute the entire padding string in its place.
598 //
599 // i.e., we will simply calculate `len = min(password length, 32)` and use the first len bytes
600 // of password and the first len bytes of `PAD_BYTES`.
601 let len = password.len().min(32);
602
603 // Initialize the MD5 hash function and pass the result as input to this function.
604 let mut hasher = Md5::new();
605
606 hasher.update(&password[..len]);
607 hasher.update(&PAD_BYTES[..32 - len]);
608
609 let mut hash = hasher.finalize();
610
611 // (Security handlers of revision 3 or greater) Do the following 50 times: take the output from
612 // the previous MD5 hash and pass it as input into a new MD5 hash.
613 if self.revision >= 3 {
614 for _ in 0..50 {
615 hash = Md5::digest(hash);
616 }
617 }
618
619 // Create an RC4 file encryption key using the first n bytes of the output from the final MD5
620 // hash, where n shall always be 5 for security handlers of revision 2 but, for security
621 // handlers of revision 3 or greater, shall depend on the value of the encryption dictionary's
622 // Length entry.
623 let n = if self.revision >= 3 {
624 self.length.unwrap_or(40) / 8
625 } else {
626 5
627 };
628
629 // The maximum supported key length is 16 bytes (128 bits) due to the use of MD5.
630 if n > 16 {
631 return Err(DecryptionError::InvalidKeyLength);
632 }
633
634 // Pad or truncate the user password string to exactly 32 bytes. If the user password string is
635 // more than 32 bytes long, use only its first 32 bytes; if it is less than 32 bytes long, pad
636 // it by appending the required number of additional bytes from the beginning of the following
637 // padding string (see `PAD_BYTES`).
638 //
639 // That is, if the password is n bytes long, append the first 32 - n bytes of the padding
640 // string to the end of the password string. If the password string is empty (zero-length),
641 // meaning there is no user password, substitute the entire padding string in its place.
642 //
643 // i.e., we will simply calculate `len = min(password length, 32)` and use the first len bytes
644 // of password and the first len bytes of `PAD_BYTES`.
645 let len = user_password.len().min(32);
646
647 // Encrypt the result of the previous step using an RC4 encryption function with the RC4 file
648 // encryption key obtained in the step before the previous step.
649 let mut bytes = [0u8; 32];
650
651 bytes[..len].copy_from_slice(&user_password[..len]);
652 bytes[len..].copy_from_slice(&PAD_BYTES[..32 - len]);
653
654 let mut result = Rc4::new(&hash[..n]).encrypt(bytes);
655
656 // (Security handlers of revision 3 or greater) Do the following 19 times: Take the output from
657 // the previous invocation of the RC4 function and pass it as input to a new invocation of the
658 // function; use a file encryption key generated by taking each byte of the RC4 file encryption
659 // key and performing an XOR (exclusive or) operation between that byte and the single-byte
660 // value of the iteration counter (from 1 to 19).
661 if self.revision >= 3 {
662 let mut key = vec![0u8; n];
663
664 for i in 1..=19 {
665 for (in_byte, out_byte) in hash[..n].iter().zip(key.iter_mut()) {
666 *out_byte = in_byte ^ i;
667 }
668
669 result = Rc4::new(&key).encrypt(&result);
670 }
671 }
672
673 // Store the output from the final invocation of the RC4 function as the value of the O entry
674 // in the encryption dictionary.
675 Ok(result)
676 }
677
678 /// Compute the encryption dictionary's U-entry value (revision 2).
679 ///
680 /// This implements Algorithm 4 as described in ISO 32000-2:2020 (PDF 2.0).
681 ///
682 /// This algorithm is deprecated in PDF 2.0.
683 pub(crate) fn compute_hashed_user_password_r2<U>(
684 &self, doc: &Document, user_password: U,
685 ) -> Result<Vec<u8>, DecryptionError>
686 where
687 U: AsRef<[u8]>,
688 {
689 // Create a file encryption key based on the user password string.
690 let file_encryption_key = self.compute_file_encryption_key_r4(doc, user_password)?;
691
692 // Encrypt the 32-byte padding string using an RC4 encryption function with the file encryption
693 // key from the preceding step.
694 let result = Rc4::new(&file_encryption_key).encrypt(PAD_BYTES);
695
696 // Store the result of the previous step as the value of the U entry in the encryption dictionary.
697 Ok(result)
698 }
699
700 /// Compute the encryption dictionary's U-entry value (revision 3 or 4).
701 ///
702 /// This implements Algorithm 5 as described in ISO 32000-2:2020 (PDF 2.0).
703 ///
704 /// This algorithm is deprecated in PDF 2.0.
705 pub(crate) fn compute_hashed_user_password_r3_r4<U>(
706 &self, doc: &Document, user_password: U,
707 ) -> Result<Vec<u8>, DecryptionError>
708 where
709 U: AsRef<[u8]>,
710 {
711 // Create a file encryption key based on the user password string.
712 let file_encryption_key = self.compute_file_encryption_key_r4(doc, user_password)?;
713
714 // Initialize the MD5 hash function and pass the 32-byte padding string.
715 let mut hasher = Md5::new();
716
717 hasher.update(PAD_BYTES);
718
719 // Pass the first element of the file's file identifier array (the value of the ID entry in the
720 // document's trailer dictionary) to the hash function and finish the hash.
721 let file_id_0 = doc
722 .trailer
723 .get(b"ID")
724 .map_err(|_| DecryptionError::MissingFileID)?
725 .as_array()
726 .map_err(|_| DecryptionError::InvalidType)?
727 .first()
728 .ok_or(DecryptionError::InvalidType)?
729 .as_str()
730 .map_err(|_| DecryptionError::InvalidType)?;
731 hasher.update(file_id_0);
732
733 let hash = hasher.finalize();
734
735 // Encrypt the 16-byte result of the hash, using an RC4 encryption function with the file
736 // encryption key.
737 let mut result = Rc4::new(&file_encryption_key).encrypt(hash);
738
739 // Do the following 19 times: Take the output from the previous invocation of the RC4 function
740 // and pass it as input to a new invocation of the function; use a file encryption key
741 // generated by taking each byte of the RC4 file encryption key and performing an XOR
742 // (exclusive or) operation between that byte and the single-byte value of the iteration
743 // counter (from 1 to 19).
744 let mut key = vec![0u8; file_encryption_key.len()];
745
746 for i in 1..=19 {
747 for (in_byte, out_byte) in file_encryption_key.iter().zip(key.iter_mut()) {
748 *out_byte = in_byte ^ i;
749 }
750
751 result = Rc4::new(&key).encrypt(&result);
752 }
753
754 // Append 16 bytes of arbitrary padding to the output from the final invocation of the RC4
755 // function and store the 32-byte result as the value of the U entry in the encryption
756 // dictionary.
757 result.resize(32, 0);
758
759 let mut rng = rand::rng();
760 rng.fill(&mut result[16..]);
761
762 Ok(result)
763 }
764
765 /// Authenticate the user password (revision 4 and earlier).
766 ///
767 /// This implements Algorithm 6 as described in ISO 32000-2:2020 (PDF 2.0).
768 ///
769 /// This algorithm is deprecated in PDF 2.0.
770 fn authenticate_user_password_r4<U>(&self, doc: &Document, user_password: U) -> Result<(), DecryptionError>
771 where
772 U: AsRef<[u8]>,
773 {
774 // Perform all but the last step of Algorithm 4 (security handlers of revision 2) or Algorithm
775 // 5 (security handlers of revision 3 or 4) using the supplied password string to compute the
776 // encryption dictionary's U-entry value.
777 let hashed_user_password = match self.revision {
778 2 => self.compute_hashed_user_password_r2(doc, &user_password)?,
779 3 | 4 => self.compute_hashed_user_password_r3_r4(doc, &user_password)?,
780 _ => return Err(DecryptionError::InvalidRevision),
781 };
782
783 // If the result of the previous step is equal to the value of the encryption dictionary's U
784 // entry (comparing on the first 16 bytes in the case of security handlers of revision 3 or
785 // greater), the password supplied is the correct user password.
786 let len = match self.revision {
787 3 | 4 => 16,
788 _ => hashed_user_password.len(),
789 };
790
791 if self.user_value.len() < len {
792 return Err(DecryptionError::InvalidHashLength);
793 }
794
795 if hashed_user_password[..len] != self.user_value[..len] {
796 return Err(DecryptionError::IncorrectPassword);
797 }
798
799 Ok(())
800 }
801
802 /// Authenticate the owner password (revision 4 and earlier).
803 ///
804 /// This implements Algorithm 7 as described in ISO 32000-2:2020 (PDF 2.0).
805 ///
806 /// This algorithm is deprecated in PDF 2.0.
807 fn authenticate_owner_password_r4<O>(&self, doc: &Document, owner_password: O) -> Result<(), DecryptionError>
808 where
809 O: AsRef<[u8]>,
810 {
811 // Pad or truncate the owner string. If there is no owner password, use the user password
812 // instead.
813 let password = owner_password.as_ref();
814
815 // Pad or truncate the resulting password string to exactly 32 bytes. If the password string is
816 // more than 32 bytes long, use only its first 32 bytes; if it is less than 32 bytes long, pad
817 // it by appending the required number of additional bytes from the beginning of the following
818 // padding string (see `PAD_BYTES`).
819 //
820 // That is, if the password is n bytes long, append the first 32 - n bytes of the padding
821 // string to the end of the password string. If the password string is empty (zero-length),
822 // meaning there is no user password, substitute the entire padding string in its place.
823 //
824 // i.e., we will simply calculate `len = min(password length, 32)` and use the first len bytes
825 // of password and the first len bytes of `PAD_BYTES`.
826 let len = password.len().min(32);
827
828 // Initialize the MD5 hash function and pass the result as input to this function.
829 let mut hasher = Md5::new();
830
831 hasher.update(&password[..len]);
832 hasher.update(&PAD_BYTES[..32 - len]);
833
834 let mut hash = hasher.finalize();
835
836 // (Security handlers of revision 3 or greater) Do the following 50 times: take the output from
837 // the previous MD5 hash and pass it as input into a new MD5 hash.
838 if self.revision >= 3 {
839 for _ in 0..50 {
840 hash = Md5::digest(hash);
841 }
842 }
843
844 // Create an RC4 file encryption key using the first n bytes of the output from the final MD5
845 // hash, where n shall always be 5 for security handlers of revision 2 but, for security
846 // handlers of revision 3 or greater, shall depend on the value of the encryption dictionary's
847 // Length entry.
848 let n = if self.revision >= 3 {
849 self.length.unwrap_or(40) / 8
850 } else {
851 5
852 };
853
854 // The maximum supported key length is 16 bytes (128 bits) due to the use of MD5.
855 if n > 16 {
856 return Err(DecryptionError::InvalidKeyLength);
857 }
858
859 // Decrypt the value of the encryption dictionary's O entry, using an RC4 encryption function
860 // with the file encryption key to retrieve the user password.
861 let mut result = self.owner_value.to_vec();
862
863 // (Security handlers of revision 3 or greater) Do the following 19 times: Take the output from
864 // the previous invocation of the RC4 function and pass it as input to a new invocation of the
865 // function; use a file encryption key generated by taking each byte of the RC4 file encryption
866 // key and performing an XOR (exclusive or) operation between that byte and the single-byte
867 // value of the iteration counter (from 19 to 1).
868 if self.revision >= 3 {
869 let mut key = vec![0u8; n];
870
871 for i in (1..=19).rev() {
872 for (in_byte, out_byte) in hash[..n].iter().zip(key.iter_mut()) {
873 *out_byte = in_byte ^ i;
874 }
875
876 result = Rc4::new(&key).decrypt(&result);
877 }
878 }
879
880 // (Security handler of revision 2 and the final step for revision 3 or greater) Decrypt the
881 // value of the encryption dictionary's O entry, using an RC4 encryption function with the file
882 // encryption key.
883 result = Rc4::new(&hash[..n]).decrypt(&result);
884
885 // The result of the previous step purports to be the user password. Authenticate this user
886 // password using Algorithm 5. If it is correct, the password supplied is the correct owner
887 // password.
888 self.authenticate_user_password_r4(doc, &result)
889 }
890
891 /// Compute the encryption dictionary's U-entry value (revision 6).
892 ///
893 /// This implements Algorithm 8 as described in ISO 32000-2:2020 (PDF 2.0).
894 pub(crate) fn compute_hashed_user_password_r6<K, U>(
895 &self, file_encryption_key: K, user_password: U,
896 ) -> Result<(Vec<u8>, Vec<u8>), DecryptionError>
897 where
898 K: AsRef<[u8]>,
899 U: AsRef<[u8]>,
900 {
901 let file_encryption_key = file_encryption_key.as_ref();
902 let user_password = user_password.as_ref();
903
904 // Generate 16 random bytes of data using a strong random number generator. The first 8
905 // bytes are the user validation salt. The second 8 bytes are the user key salt. Compute
906 // the 32-byte hash using algorithm 2.B with an input string consisting of the UTF-8
907 // password concatenated with the user validation salt. The 48-byte string consisting of
908 // the 32-byte hash followed by the user validation salt followed by the user key salt is
909 // stored as the U key.
910 let mut user_value = [0u8; 48];
911 let mut rng = rand::rng();
912
913 rng.fill(&mut user_value[32..]);
914
915 let user_validation_salt = &user_value[32..][..8];
916
917 let mut input = Vec::with_capacity(user_password.len() + user_validation_salt.len());
918
919 input.extend_from_slice(user_password);
920 input.extend_from_slice(user_validation_salt);
921
922 let hashed_user_password = self.compute_hash(user_password, user_validation_salt, None)?;
923 user_value[..32].copy_from_slice(&hashed_user_password);
924
925 // Compute the 32-byte hash using algorithm 2.B with an input string consisting of the
926 // UTF-8 password concatenated with the user key salt.
927 let user_key_salt = &user_value[40..][..8];
928
929 input.clear();
930
931 input.extend_from_slice(user_password);
932 input.extend_from_slice(user_key_salt);
933
934 let hash = self.compute_hash(user_password, user_key_salt, None)?;
935
936 // Using this hash as the key, encrypt the file encryption key using AES-256 in CBC mode
937 // with no padding and initialization vector of zero. The resulting 32-byte string is
938 // stored as the UE key.
939 let mut key = [0u8; 32];
940 key.copy_from_slice(&hash);
941
942 let iv = [0u8; 16];
943
944 let mut user_encrypted = file_encryption_key.to_vec();
945 let mut encryptor = Aes256CbcEnc::new(&key.into(), &iv.into());
946
947 for block in user_encrypted.chunks_exact_mut(16) {
948 encryptor.encrypt_block_mut(block.into());
949 }
950
951 Ok((user_value.to_vec(), user_encrypted))
952 }
953
954 /// Compute the encryption dictionary's O-entry value (revision 6).
955 ///
956 /// This implements Algorithm 9 as described in ISO 32000-2:2020 (PDF 2.0).
957 pub(crate) fn compute_hashed_owner_password_r6<K, O>(
958 &self, file_encryption_key: K, owner_password: O,
959 ) -> Result<(Vec<u8>, Vec<u8>), DecryptionError>
960 where
961 K: AsRef<[u8]>,
962 O: AsRef<[u8]>,
963 {
964 let file_encryption_key = file_encryption_key.as_ref();
965 let owner_password = owner_password.as_ref();
966
967 // Generate 16 random bytes of data using a strong random number generator. The first 8
968 // bytes are the owner validation salt. The second 8 bytes are the owner key salt. Compute
969 // the 32-byte hash using algorithm 2.B with an input string consisting of the UTF-8
970 // password concatenated with the owner validation salt and then concatenated with the
971 // 48-byte U string as generated in Algorithm 8. The 48-byte string consisting of the
972 // 32-byte hash followed by the owner validation salt followed by the owner key salt is
973 // stored as the O key.
974 let mut owner_value = [0u8; 48];
975 let mut rng = rand::rng();
976
977 rng.fill(&mut owner_value[32..]);
978
979 let owner_validation_salt = &owner_value[32..][..8];
980
981 let hashed_owner_password = self.compute_hash(owner_password, owner_validation_salt, Some(&self.user_value))?;
982 owner_value[..32].copy_from_slice(&hashed_owner_password);
983
984 // Compute the 32-byte hash using algorithm 2.B with an input string consisting of the
985 // UTF-8 password concatenated with the owner key salt.
986 let owner_key_salt = &owner_value[40..][..8];
987
988 let hash = self.compute_hash(owner_password, owner_key_salt, Some(&self.user_value))?;
989
990 // Using this hash as the key, encrypt the file encryption key using AES-256 in CBC mode
991 // with no padding and initialization vector of zero. The resulting 32-byte string is
992 // stored as the OE key.
993 let mut key = [0u8; 32];
994 key.copy_from_slice(&hash);
995
996 let iv = [0u8; 16];
997
998 let mut owner_encrypted = file_encryption_key.to_vec();
999 let mut encryptor = Aes256CbcEnc::new(&key.into(), &iv.into());
1000
1001 for block in owner_encrypted.chunks_exact_mut(16) {
1002 encryptor.encrypt_block_mut(block.into());
1003 }
1004
1005 Ok((owner_value.to_vec(), owner_encrypted))
1006 }
1007
1008 /// Compute the encryption dictionary's Perms (permissions) value (revision 6 and later).
1009 ///
1010 /// This implements Algorithm 10 as described in ISO 32000-2:2020 (PDF 2.0).
1011 pub(crate) fn compute_permissions<K>(&self, file_encryption_key: K) -> Result<Vec<u8>, DecryptionError>
1012 where
1013 K: AsRef<[u8]>,
1014 {
1015 let file_encryption_key = file_encryption_key.as_ref();
1016 let mut bytes = [0u8; 16];
1017
1018 // Record the 8 bytes of permission in the bytes 0-7 of the block, low order byte first.
1019 bytes[..8].copy_from_slice(&u64::to_le_bytes(self.permissions.bits()));
1020
1021 // Set byte 8 to ASCII character "T" or "F" according to the EncryptMetadata boolean.
1022 bytes[8] = if self.encrypt_metadata { b'T' } else { b'F' };
1023
1024 // Set bytes 9-11 to the ASCII characters "a", "d", "b".
1025 bytes[9..][..3].copy_from_slice(b"adb");
1026
1027 // Set bytes 12-15 to 4 bytes of random data, which will be ignored.
1028 let mut rng = rand::rng();
1029 rng.fill(&mut bytes[12..][..4]);
1030
1031 // Encrypt the 16-byte block using AES-256 in ECB mode with an initialization vector of
1032 // zero, using the file encryption key as the key.
1033 let mut key = [0u8; 32];
1034 key.copy_from_slice(file_encryption_key);
1035
1036 let mut encryptor = Aes256EbcEnc::new(&key.into());
1037
1038 for block in bytes.chunks_exact_mut(16) {
1039 encryptor.encrypt_block_mut(block.into());
1040 }
1041
1042 // The result (16 bytes) is stored as the Perms string, and checked for validity when the
1043 // file is opened.
1044 Ok(bytes.to_vec())
1045 }
1046
1047 /// Authenticate the user password (revision 6 and later).
1048 ///
1049 /// This implements Algorithm 11 as described in ISO 32000-2:2020 (PDF 2.0).
1050 fn authenticate_user_password_r6<U>(&self, user_password: U) -> Result<(), DecryptionError>
1051 where
1052 U: AsRef<[u8]>,
1053 {
1054 let mut user_password = user_password.as_ref();
1055
1056 let hashed_user_password = &self.user_value[0..][..32];
1057 let user_validation_salt = &self.user_value[32..][..8];
1058
1059 // Truncate the UTF-8 representation to 127 bytes if it is longer than 127 bytes.
1060 if user_password.len() > 127 {
1061 user_password = &user_password[..127];
1062 }
1063
1064 // Test the password against the user key by computing a hash using algorithm 2.B with an
1065 // input string consisting of the UTF-8 password concatenated with the 8 bytes of user
1066 // validation salt. If the 32-byte result matches the first 32-bytes of the U string, this
1067 // is the user password.
1068 let mut input = Vec::with_capacity(user_password.len() + user_validation_salt.len());
1069
1070 input.extend_from_slice(user_password);
1071 input.extend_from_slice(user_validation_salt);
1072
1073 if self.compute_hash(user_password, user_validation_salt, None)? != hashed_user_password {
1074 return Err(DecryptionError::IncorrectPassword);
1075 }
1076
1077 Ok(())
1078 }
1079
1080 /// Authenticate the owner password (revision 6 and later).
1081 ///
1082 /// This implements Algorithm 12 as described in ISO 32000-2:2020 (PDF 2.0).
1083 fn authenticate_owner_password_r6<O>(&self, owner_password: O) -> Result<(), DecryptionError>
1084 where
1085 O: AsRef<[u8]>,
1086 {
1087 let mut owner_password = owner_password.as_ref();
1088
1089 let hashed_owner_password = &self.owner_value[0..][..32];
1090 let owner_validation_salt = &self.owner_value[32..][..8];
1091
1092 // Truncate the UTF-8 representation to 127 bytes if it is longer than 127 bytes.
1093 if owner_password.len() > 127 {
1094 owner_password = &owner_password[..127];
1095 }
1096
1097 // Test the password against the owner key by computing a hash using algorithm 2.B with an
1098 // input string consisting of the UTF-8 password concatenated with the 8 bytes of owner
1099 // validation salt and the 48 byte U string. If the 32-byte result matches the first
1100 // 32-bytes of the O string, this is the owner password.
1101 let mut input = Vec::with_capacity(owner_password.len() + owner_validation_salt.len());
1102
1103 input.extend_from_slice(owner_password);
1104 input.extend_from_slice(owner_validation_salt);
1105
1106 if self.compute_hash(owner_password, owner_validation_salt, Some(&self.user_value))? != hashed_owner_password {
1107 return Err(DecryptionError::IncorrectPassword);
1108 }
1109
1110 Ok(())
1111 }
1112
1113 /// Validate the permissions (revision 6 and later).
1114 ///
1115 /// This implements Algorithm 13 as described in ISO 32000-2:2020 (PDF 2.0).
1116 fn validate_permissions<K>(&self, file_encryption_key: K) -> Result<(), DecryptionError>
1117 where
1118 K: AsRef<[u8]>,
1119 {
1120 let file_encryption_key = file_encryption_key.as_ref();
1121
1122 // Decrypt the 16 byte Perms string using AES-256 in ECB mode with an initialization vector
1123 // of zero and the file encryption key as the key.
1124 let mut bytes = [0u8; 16];
1125 bytes.copy_from_slice(&self.permission_encrypted);
1126
1127 let mut key = [0u8; 32];
1128 key.copy_from_slice(file_encryption_key);
1129
1130 let mut decryptor = Aes256EbcDec::new(&key.into());
1131
1132 for block in bytes.chunks_exact_mut(16) {
1133 decryptor.decrypt_block_mut(block.into());
1134 }
1135
1136 // Verify that bytes 9-11 of the result are the characters "a", "d", "b".
1137 if &bytes[9..][..3] != b"adb" {
1138 return Err(DecryptionError::IncorrectPassword);
1139 }
1140
1141 // Bytes 0-3 of the decrypted Perms entry, treated as a little-endian integer, are the
1142 // user permissions. They should match the value in the P key.
1143 if bytes[..3] != u64::to_le_bytes(self.permissions.bits())[..3] {
1144 return Err(DecryptionError::IncorrectPassword);
1145 }
1146
1147 // Byte 8 should match the ASCII character "T" or "F" according to the boolean value of the
1148 // EncryptMetadata key.
1149 if bytes[8] != if self.encrypt_metadata { b'T' } else { b'F' } {
1150 return Err(DecryptionError::IncorrectPassword);
1151 }
1152
1153 Ok(())
1154 }
1155
1156 /// Sanitize the password.
1157 pub fn sanitize_password(&self, password: &str) -> Result<Vec<u8>, DecryptionError> {
1158 match self.revision {
1159 2..=4 => self.sanitize_password_r4(password),
1160 5..=6 => self.sanitize_password_r6(password),
1161 _ => Err(DecryptionError::UnsupportedRevision),
1162 }
1163 }
1164
1165 /// Compute the file encryption key used to encrypt/decrypt the document.
1166 pub fn compute_file_encryption_key<P>(&self, doc: &Document, password: P) -> Result<Vec<u8>, DecryptionError>
1167 where
1168 P: AsRef<[u8]>,
1169 {
1170 match self.revision {
1171 2..=4 => self.compute_file_encryption_key_r4(doc, password),
1172 5..=6 => self.compute_file_encryption_key_r6(password),
1173 _ => Err(DecryptionError::UnsupportedRevision),
1174 }
1175 }
1176
1177 /// Authenticate the owner password.
1178 pub fn authenticate_user_password<U>(&self, doc: &Document, user_password: U) -> Result<(), DecryptionError>
1179 where
1180 U: AsRef<[u8]>,
1181 {
1182 match self.revision {
1183 2..=4 => self.authenticate_user_password_r4(doc, user_password),
1184 5..=6 => self.authenticate_user_password_r6(user_password),
1185 _ => Err(DecryptionError::UnsupportedRevision),
1186 }
1187 }
1188
1189 /// Authenticate the owner password.
1190 pub fn authenticate_owner_password<O>(&self, doc: &Document, owner_password: O) -> Result<(), DecryptionError>
1191 where
1192 O: AsRef<[u8]>,
1193 {
1194 match self.revision {
1195 2..=4 => self.authenticate_owner_password_r4(doc, owner_password),
1196 5..=6 => self.authenticate_owner_password_r6(owner_password),
1197 _ => Err(DecryptionError::UnsupportedRevision),
1198 }
1199 }
1200}
1201
1202#[cfg(test)]
1203mod tests {
1204 use crate::Permissions;
1205 use crate::creator::tests::create_document;
1206 use crate::encryption::PasswordAlgorithm;
1207 use rand::RngExt as _;
1208
1209 #[test]
1210 fn authenticate_password_r2() {
1211 let document = create_document();
1212
1213 let mut algorithm = PasswordAlgorithm {
1214 encrypt_metadata: true,
1215 length: None,
1216 version: 1,
1217 revision: 2,
1218 permissions: Permissions::all(),
1219 ..Default::default()
1220 };
1221
1222 let owner_password = "owner";
1223 let user_password = "user";
1224
1225 // Sanitize the passwords.
1226 let owner_password = algorithm.sanitize_password_r4(owner_password).unwrap();
1227 let user_password = algorithm.sanitize_password_r4(user_password).unwrap();
1228
1229 // Compute the hashed values.
1230 algorithm.owner_value = algorithm
1231 .compute_hashed_owner_password_r4(Some(&owner_password), &user_password)
1232 .unwrap();
1233
1234 algorithm.user_value = algorithm
1235 .compute_hashed_user_password_r2(&document, &user_password)
1236 .unwrap();
1237
1238 // Assert that the correct passwords authenticate.
1239 assert!(
1240 algorithm
1241 .authenticate_owner_password_r4(&document, &owner_password)
1242 .is_ok()
1243 );
1244 assert!(
1245 algorithm
1246 .authenticate_user_password_r4(&document, &user_password)
1247 .is_ok()
1248 );
1249
1250 // Assert that the swapped passwords do not authenticate.
1251 assert!(
1252 algorithm
1253 .authenticate_owner_password_r4(&document, user_password)
1254 .is_err()
1255 );
1256 assert!(
1257 algorithm
1258 .authenticate_user_password_r4(&document, owner_password)
1259 .is_err()
1260 );
1261 }
1262
1263 #[test]
1264 fn authenticate_password_r3() {
1265 let document = create_document();
1266
1267 let mut algorithm = PasswordAlgorithm {
1268 encrypt_metadata: true,
1269 length: Some(40),
1270 version: 2,
1271 revision: 3,
1272 permissions: Permissions::all(),
1273 ..Default::default()
1274 };
1275
1276 let owner_password = "owner";
1277 let user_password = "user";
1278
1279 // Sanitize the passwords.
1280 let owner_password = algorithm.sanitize_password_r4(owner_password).unwrap();
1281 let user_password = algorithm.sanitize_password_r4(user_password).unwrap();
1282
1283 // Compute the hashed values.
1284 algorithm.owner_value = algorithm
1285 .compute_hashed_owner_password_r4(Some(&owner_password), &user_password)
1286 .unwrap();
1287
1288 algorithm.user_value = algorithm
1289 .compute_hashed_user_password_r3_r4(&document, &user_password)
1290 .unwrap();
1291
1292 // Assert that the correct passwords authenticate.
1293 assert!(
1294 algorithm
1295 .authenticate_owner_password_r4(&document, &owner_password)
1296 .is_ok()
1297 );
1298 assert!(
1299 algorithm
1300 .authenticate_user_password_r4(&document, &user_password)
1301 .is_ok()
1302 );
1303
1304 // Assert that the swapped passwords do not authenticate.
1305 assert!(
1306 algorithm
1307 .authenticate_owner_password_r4(&document, user_password)
1308 .is_err()
1309 );
1310 assert!(
1311 algorithm
1312 .authenticate_user_password_r4(&document, owner_password)
1313 .is_err()
1314 );
1315 }
1316
1317 #[test]
1318 fn authenticate_password_r4() {
1319 let document = create_document();
1320
1321 let mut algorithm = PasswordAlgorithm {
1322 encrypt_metadata: true,
1323 length: Some(128),
1324 version: 4,
1325 revision: 4,
1326 permissions: Permissions::all(),
1327 ..Default::default()
1328 };
1329
1330 let owner_password = "owner";
1331 let user_password = "user";
1332
1333 // Sanitize the passwords.
1334 let owner_password = algorithm.sanitize_password_r4(owner_password).unwrap();
1335 let user_password = algorithm.sanitize_password_r4(user_password).unwrap();
1336
1337 // Compute the hashed values.
1338 algorithm.owner_value = algorithm
1339 .compute_hashed_owner_password_r4(Some(&owner_password), &user_password)
1340 .unwrap();
1341
1342 algorithm.user_value = algorithm
1343 .compute_hashed_user_password_r3_r4(&document, &user_password)
1344 .unwrap();
1345
1346 // Assert that the correct passwords authenticate.
1347 assert!(
1348 algorithm
1349 .authenticate_owner_password_r4(&document, &owner_password)
1350 .is_ok()
1351 );
1352 assert!(
1353 algorithm
1354 .authenticate_user_password_r4(&document, &user_password)
1355 .is_ok()
1356 );
1357
1358 // Assert that the swapped passwords do not authenticate.
1359 assert!(
1360 algorithm
1361 .authenticate_owner_password_r4(&document, user_password)
1362 .is_err()
1363 );
1364 assert!(
1365 algorithm
1366 .authenticate_user_password_r4(&document, owner_password)
1367 .is_err()
1368 );
1369 }
1370
1371 #[test]
1372 fn authenticate_password_r5() {
1373 let mut algorithm = PasswordAlgorithm {
1374 encrypt_metadata: true,
1375 version: 5,
1376 revision: 5,
1377 permissions: Permissions::all(),
1378 ..Default::default()
1379 };
1380
1381 let owner_password = "owner";
1382 let user_password = "user";
1383
1384 // Sanitize the passwords.
1385 let owner_password = algorithm.sanitize_password_r6(owner_password).unwrap();
1386 let user_password = algorithm.sanitize_password_r6(user_password).unwrap();
1387
1388 // Compute the hashed values.
1389 let mut file_encryption_key = [0u8; 32];
1390
1391 let mut rng = rand::rng();
1392 rng.fill(&mut file_encryption_key);
1393
1394 let (user_value, user_encrypted) = algorithm
1395 .compute_hashed_user_password_r6(file_encryption_key, &user_password)
1396 .unwrap();
1397
1398 algorithm.user_value = user_value;
1399 algorithm.user_encrypted = user_encrypted;
1400
1401 let (owner_value, owner_encrypted) = algorithm
1402 .compute_hashed_owner_password_r6(file_encryption_key, &owner_password)
1403 .unwrap();
1404
1405 algorithm.owner_value = owner_value;
1406 algorithm.owner_encrypted = owner_encrypted;
1407
1408 algorithm.permission_encrypted = algorithm.compute_permissions(file_encryption_key).unwrap();
1409
1410 // Assert that the correct passwords authenticate.
1411 assert!(algorithm.authenticate_owner_password_r6(&owner_password).is_ok());
1412 assert!(algorithm.authenticate_user_password_r6(&user_password).is_ok());
1413
1414 // Assert that the swapped passwords do not authenticate.
1415 assert!(algorithm.authenticate_owner_password_r6(&user_password).is_err());
1416 assert!(algorithm.authenticate_user_password_r6(&owner_password).is_err());
1417
1418 // Assert that the permissions validate correctly.
1419 assert!(algorithm.validate_permissions(file_encryption_key).is_ok());
1420
1421 // Assert that the file encryption key is equal for the owner password.
1422 let key = algorithm.compute_file_encryption_key_r6(&owner_password).unwrap();
1423 assert_eq!(&file_encryption_key[..], key);
1424
1425 // Assert that the file encryption key is equal for the user password.
1426 let key = algorithm.compute_file_encryption_key_r6(&user_password).unwrap();
1427 assert_eq!(&file_encryption_key[..], key);
1428 }
1429
1430 #[test]
1431 fn authenticate_password_r6() {
1432 let mut algorithm = PasswordAlgorithm {
1433 encrypt_metadata: true,
1434 version: 5,
1435 revision: 6,
1436 permissions: Permissions::all(),
1437 ..Default::default()
1438 };
1439
1440 let owner_password = "owner";
1441 let user_password = "user";
1442
1443 // Sanitize the passwords.
1444 let owner_password = algorithm.sanitize_password_r6(owner_password).unwrap();
1445 let user_password = algorithm.sanitize_password_r6(user_password).unwrap();
1446
1447 // Compute the hashed values.
1448 let mut file_encryption_key = [0u8; 32];
1449
1450 let mut rng = rand::rng();
1451 rng.fill(&mut file_encryption_key);
1452
1453 let (user_value, user_encrypted) = algorithm
1454 .compute_hashed_user_password_r6(file_encryption_key, &user_password)
1455 .unwrap();
1456
1457 algorithm.user_value = user_value;
1458 algorithm.user_encrypted = user_encrypted;
1459
1460 let (owner_value, owner_encrypted) = algorithm
1461 .compute_hashed_owner_password_r6(file_encryption_key, &owner_password)
1462 .unwrap();
1463
1464 algorithm.owner_value = owner_value;
1465 algorithm.owner_encrypted = owner_encrypted;
1466
1467 algorithm.permission_encrypted = algorithm.compute_permissions(file_encryption_key).unwrap();
1468
1469 // Assert that the correct passwords authenticate.
1470 assert!(algorithm.authenticate_owner_password_r6(&owner_password).is_ok());
1471 assert!(algorithm.authenticate_user_password_r6(&user_password).is_ok());
1472
1473 // Assert that the swapped passwords do not authenticate.
1474 assert!(algorithm.authenticate_owner_password_r6(&user_password).is_err());
1475 assert!(algorithm.authenticate_user_password_r6(&owner_password).is_err());
1476
1477 // Assert that the permissions validate correctly.
1478 assert!(algorithm.validate_permissions(file_encryption_key).is_ok());
1479
1480 // Assert that the file encryption key is equal for the owner password.
1481 let key = algorithm.compute_file_encryption_key_r6(&owner_password).unwrap();
1482 assert_eq!(&file_encryption_key[..], key);
1483
1484 // Assert that the file encryption key is equal for the user password.
1485 let key = algorithm.compute_file_encryption_key_r6(&user_password).unwrap();
1486 assert_eq!(&file_encryption_key[..], key);
1487 }
1488
1489 /// Some PDF writers (e.g. Adobe) pad /O and /U to 127 bytes with trailing
1490 /// zeros instead of the spec-required 48. Verify that `try_from` accepts
1491 /// these and truncates to the correct 48-byte length.
1492 #[test]
1493 fn r6_padded_owner_user_values_accepted() {
1494 use crate::{Document, Object, StringFormat, dictionary};
1495
1496 let mut doc = Document::with_version("2.0");
1497
1498 // Build valid 48-byte /O and /U (contents don't matter for parsing).
1499 let o_48 = vec![0xAAu8; 48];
1500 let u_48 = vec![0xBBu8; 48];
1501
1502 // Pad to 127 bytes with trailing zeros — mimics real-world Adobe PDFs.
1503 let mut o_127 = o_48.clone();
1504 o_127.resize(127, 0u8);
1505 let mut u_127 = u_48.clone();
1506 u_127.resize(127, 0u8);
1507
1508 let encrypt_dict = dictionary! {
1509 "Filter" => "Standard",
1510 "V" => Object::Integer(5),
1511 "R" => Object::Integer(6),
1512 "Length" => Object::Integer(256),
1513 "O" => Object::String(o_127, StringFormat::Literal),
1514 "OE" => Object::String(vec![0xCCu8; 32], StringFormat::Literal),
1515 "U" => Object::String(u_127, StringFormat::Literal),
1516 "UE" => Object::String(vec![0xDDu8; 32], StringFormat::Literal),
1517 "P" => Object::Integer(-3388),
1518 "Perms" => Object::String(vec![0xEEu8; 16], StringFormat::Literal)
1519 };
1520
1521 let encrypt_id = doc.add_object(encrypt_dict);
1522 doc.trailer.set("Encrypt", Object::Reference(encrypt_id));
1523
1524 let algo = PasswordAlgorithm::try_from(&doc).expect("should accept padded /O and /U longer than 48 bytes");
1525
1526 // Verify the values were truncated to the spec-required 48 bytes.
1527 assert_eq!(algo.owner_value.len(), 48);
1528 assert_eq!(algo.user_value.len(), 48);
1529 assert_eq!(&algo.owner_value, &o_48);
1530 assert_eq!(&algo.user_value, &u_48);
1531 }
1532
1533 /// Verify that /O and /U values shorter than 48 bytes are still rejected
1534 /// for R >= 5.
1535 #[test]
1536 fn r6_short_owner_user_values_rejected() {
1537 use crate::{Document, Object, StringFormat, dictionary};
1538
1539 let mut doc = Document::with_version("2.0");
1540
1541 let encrypt_dict = dictionary! {
1542 "Filter" => "Standard",
1543 "V" => Object::Integer(5),
1544 "R" => Object::Integer(6),
1545 "Length" => Object::Integer(256),
1546 "O" => Object::String(vec![0xAAu8; 47], StringFormat::Literal),
1547 "OE" => Object::String(vec![0xCCu8; 32], StringFormat::Literal),
1548 "U" => Object::String(vec![0xBBu8; 48], StringFormat::Literal),
1549 "UE" => Object::String(vec![0xDDu8; 32], StringFormat::Literal),
1550 "P" => Object::Integer(-3388),
1551 "Perms" => Object::String(vec![0xEEu8; 16], StringFormat::Literal)
1552 };
1553
1554 let encrypt_id = doc.add_object(encrypt_dict);
1555 doc.trailer.set("Encrypt", Object::Reference(encrypt_id));
1556
1557 assert!(
1558 PasswordAlgorithm::try_from(&doc).is_err(),
1559 "should reject /O shorter than 48 bytes"
1560 );
1561 }
1562}