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