Skip to main content

pdf_cos/
encryption.rs

1mod algorithms;
2pub mod crypt_filters;
3mod pkcs5;
4mod rc4;
5
6use crate::{Dictionary, Document, Error, Object, ObjectId};
7use bitflags::bitflags;
8use crypt_filters::*;
9use std::collections::BTreeMap;
10use std::sync::Arc;
11use thiserror::Error;
12
13pub use algorithms::PasswordAlgorithm;
14
15#[derive(Error, Debug)]
16pub enum DecryptionError {
17    #[error("the /Encrypt dictionary is missing")]
18    MissingEncryptDictionary,
19    #[error("missing encryption version")]
20    MissingVersion,
21    #[error("missing encryption revision")]
22    MissingRevision,
23    #[error("missing the owner password (/O)")]
24    MissingOwnerPassword,
25    #[error("missing the user password (/U)")]
26    MissingUserPassword,
27    #[error("missing the permissions field (/P)")]
28    MissingPermissions,
29    #[error("missing the file /ID elements")]
30    MissingFileID,
31
32    #[error("invalid hash length")]
33    InvalidHashLength,
34    #[error("invalid key length")]
35    InvalidKeyLength,
36    #[error("invalid ciphertext length")]
37    InvalidCipherTextLength,
38    #[error("invalid permission length")]
39    InvalidPermissionLength,
40    #[error("invalid version")]
41    InvalidVersion,
42    #[error("invalid revision")]
43    InvalidRevision,
44    // Used generically when the object type violates the spec
45    #[error("unexpected type; document does not comply with the spec")]
46    InvalidType,
47
48    #[error("the object is not capable of being decrypted")]
49    NotDecryptable,
50    #[error("the supplied password is incorrect")]
51    IncorrectPassword,
52
53    #[error("the document uses an encryption scheme that is not implemented in lopdf")]
54    UnsupportedEncryption,
55    #[error("the encryption version is not implemented in lopdf")]
56    UnsupportedVersion,
57    #[error("the encryption revision is not implemented in lopdf")]
58    UnsupportedRevision,
59
60    #[error(transparent)]
61    StringPrep(#[from] stringprep::Error),
62    #[error("invalid padding encountered when decrypting, key might be incorrect")]
63    Padding,
64}
65
66bitflags! {
67    #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
68    pub struct Permissions: u64 {
69        /// (Security handlers of revision 2) Print the document.
70        /// (Security handlers of revision 3 or greater) Print the document (possibly not at the
71        /// highest quality level, depending on whether [`Permissions::PRINTABLE_IN_HIGH_QUALITY`]
72        /// is also set).
73        const PRINTABLE = 1 << 2;
74
75        /// Modify the contents of the document by operations other than those controlled by
76        /// [`Permissions::ANNOTABLE`], [`Permissions::FILLABLE`] and [`Permissions::ASSEMBLABLE`].
77        const MODIFIABLE = 1 << 3;
78
79        /// Copy or otherwise extract text and graphics from the document. However, for the limited
80        /// purpose of providing this content to assistive technology, a PDF reader should behave
81        /// as if this bit was set to 1.
82        const COPYABLE = 1 << 4;
83
84        /// Add or modify text annotations, fill in interactive form fields, and if
85        /// [`Permissions::MODIFIABLE`] is also set, create or modify interactive form fields
86        /// (including signature fields).
87        const ANNOTABLE = 1 << 5;
88
89        /// Fill in existing interactive fields (including signature fields), even if
90        /// [`Permissions::ANNOTABLE`] is clear.
91        const FILLABLE = 1 << 8;
92
93        /// Copy or otherwise extract text and graphics from the document for the purpose of
94        /// providing this content to assistive technology.
95        ///
96        /// Deprecated since PDF 2.0: must always be set for backward compatibility with PDF
97        /// viewers following earlier specifications.
98        const COPYABLE_FOR_ACCESSIBILITY = 1 << 9;
99
100        /// (Security handlers of revision 3 or greater) Assemble the document (insert, rotate, or
101        /// delete pages and create document outline items or thumbnail images), even if
102        /// [`Permissions::MODIFIABLE`] is not set.
103        const ASSEMBLABLE = 1 << 10;
104
105        /// (Security handlers of revision 3 or greater) Print the document to a representation
106        /// from which a faithful copy of the PDF content could be generated, based on an
107        /// implementation-dependent algorithm. When this bit is clear (and
108        /// [`Permissions::PRINTABLE`] is set), printing shall be limited to a low-level
109        /// representation of the appearance, possibly of degraded quality.
110        const PRINTABLE_IN_HIGH_QUALITY = 1 << 11;
111    }
112}
113
114impl Default for Permissions {
115    fn default() -> Self {
116        Self::all()
117    }
118}
119
120impl Permissions {
121    fn correct_bits(self) -> Self {
122        let mut bits = self.bits();
123
124        // 7-8: Reserved. Must be 1.
125        bits |= 0b11 << 6;
126
127        // 13-32: Reserved. Must be 1.
128        bits |= 0b1111 << 12 | 0xffff << 16;
129
130        // Extend the permissions (contents of the P integer) to 64 bits by setting the upper 32
131        // bits to all 1s.
132        bits |= 0xffffffff << 32;
133
134        Permissions::from_bits_retain(bits)
135    }
136}
137
138#[derive(Clone, Debug)]
139pub enum EncryptionVersion<'a> {
140    /// (PDF 1.4; deprecated in PDF 2.0) Indicates the use of encryption of data using the RC4 or
141    /// AES algorithms with a file encryption key length of 40 bits.
142    V1 {
143        document: &'a Document,
144        owner_password: &'a str,
145        user_password: &'a str,
146        permissions: Permissions,
147    },
148    /// (PDF 1.4; deprecated in PDF 2.0) Indicates the use of encryption of data using the RC4 or
149    /// AES algorithms but permitting file encryption key lengths greater or 40 bits.
150    V2 {
151        document: &'a Document,
152        owner_password: &'a str,
153        user_password: &'a str,
154        key_length: usize,
155        permissions: Permissions,
156    },
157    /// (PDF 1.5; deprecated in PDF 2.0) The security handler defines the use of encryption and
158    /// decryption in the document, using the rules specified by the CF, StmF and StrF entries
159    /// using encryption of data using the RC4 or AES algorithms (deprecated in PDF  2.0) with a
160    /// file encryption key length of 128 bits.
161    V4 {
162        document: &'a Document,
163        encrypt_metadata: bool,
164        crypt_filters: BTreeMap<Vec<u8>, Arc<dyn CryptFilter>>,
165        stream_filter: Vec<u8>,
166        string_filter: Vec<u8>,
167        owner_password: &'a str,
168        user_password: &'a str,
169        permissions: Permissions,
170    },
171    /// (PDF 2.0; deprecated in PDF 2.0) Shall not be used. This value was used by a deprecated
172    /// proprietary Adobe extension.
173    ///
174    /// This exists for testing purposes to guarantee improved compatibility.
175    #[deprecated(
176        note = "R5 is a proprietary Adobe extension and should not be used in newly produced documents other than for testing purposes."
177    )]
178    R5 {
179        encrypt_metadata: bool,
180        crypt_filters: BTreeMap<Vec<u8>, Arc<dyn CryptFilter>>,
181        file_encryption_key: &'a [u8],
182        stream_filter: Vec<u8>,
183        string_filter: Vec<u8>,
184        owner_password: &'a str,
185        user_password: &'a str,
186        permissions: Permissions,
187    },
188    /// (PDF 2.0) The security handler defines the use of encryption and decryption in the
189    /// document, using the rules specified by the CF, StmF, StrF and EFF entries using encryption
190    /// of data using the AES algorithms with a file encryption key length of 256 bits.
191    V5 {
192        encrypt_metadata: bool,
193        crypt_filters: BTreeMap<Vec<u8>, Arc<dyn CryptFilter>>,
194        file_encryption_key: &'a [u8],
195        stream_filter: Vec<u8>,
196        string_filter: Vec<u8>,
197        owner_password: &'a str,
198        user_password: &'a str,
199        permissions: Permissions,
200    },
201}
202
203#[derive(Clone, Debug, Default)]
204pub struct EncryptionState {
205    pub(crate) version: i64,
206    pub(crate) revision: i64,
207    pub(crate) key_length: Option<usize>,
208    pub(crate) encrypt_metadata: bool,
209    pub(crate) crypt_filters: BTreeMap<Vec<u8>, Arc<dyn CryptFilter>>,
210    pub(crate) file_encryption_key: Vec<u8>,
211    pub(crate) stream_filter: Vec<u8>,
212    pub(crate) string_filter: Vec<u8>,
213    pub(crate) owner_value: Vec<u8>,
214    pub(crate) owner_encrypted: Vec<u8>,
215    pub(crate) user_value: Vec<u8>,
216    pub(crate) user_encrypted: Vec<u8>,
217    pub(crate) permissions: Permissions,
218    pub(crate) permission_encrypted: Vec<u8>,
219}
220
221impl TryFrom<EncryptionVersion<'_>> for EncryptionState {
222    type Error = Error;
223
224    fn try_from(version: EncryptionVersion) -> Result<EncryptionState, Self::Error> {
225        match version {
226            EncryptionVersion::V1 {
227                document,
228                owner_password,
229                user_password,
230                permissions,
231            } => {
232                let permissions = permissions.correct_bits();
233
234                let mut algorithm = PasswordAlgorithm {
235                    encrypt_metadata: true,
236                    length: None,
237                    version: 1,
238                    revision: 2,
239                    permissions,
240                    ..Default::default()
241                };
242
243                let owner_password = algorithm.sanitize_password_r4(owner_password)?;
244                let user_password = algorithm.sanitize_password_r4(user_password)?;
245
246                algorithm.owner_value =
247                    algorithm.compute_hashed_owner_password_r4(Some(&owner_password), &user_password)?;
248
249                algorithm.user_value = algorithm.compute_hashed_user_password_r2(document, &user_password)?;
250
251                let file_encryption_key = algorithm.compute_file_encryption_key_r4(document, &user_password)?;
252
253                Ok(Self {
254                    version: algorithm.version,
255                    revision: algorithm.revision,
256                    key_length: algorithm.length,
257                    encrypt_metadata: algorithm.encrypt_metadata,
258                    file_encryption_key,
259                    owner_value: algorithm.owner_value,
260                    user_value: algorithm.user_value,
261                    permissions: algorithm.permissions,
262                    ..Default::default()
263                })
264            }
265            EncryptionVersion::V2 {
266                document,
267                owner_password,
268                user_password,
269                key_length,
270                permissions,
271            } => {
272                let permissions = permissions.correct_bits();
273
274                let mut algorithm = PasswordAlgorithm {
275                    encrypt_metadata: true,
276                    length: Some(key_length),
277                    version: 2,
278                    revision: 3,
279                    permissions,
280                    ..Default::default()
281                };
282
283                let owner_password = algorithm.sanitize_password_r4(owner_password)?;
284                let user_password = algorithm.sanitize_password_r4(user_password)?;
285
286                algorithm.owner_value =
287                    algorithm.compute_hashed_owner_password_r4(Some(&owner_password), &user_password)?;
288
289                algorithm.user_value = algorithm.compute_hashed_user_password_r3_r4(document, &user_password)?;
290
291                let file_encryption_key = algorithm.compute_file_encryption_key_r4(document, &user_password)?;
292
293                Ok(Self {
294                    version: algorithm.version,
295                    revision: algorithm.revision,
296                    key_length: algorithm.length,
297                    encrypt_metadata: algorithm.encrypt_metadata,
298                    file_encryption_key,
299                    owner_value: algorithm.owner_value,
300                    user_value: algorithm.user_value,
301                    permissions,
302                    ..Default::default()
303                })
304            }
305            EncryptionVersion::V4 {
306                document,
307                encrypt_metadata,
308                crypt_filters,
309                stream_filter,
310                string_filter,
311                owner_password,
312                user_password,
313                permissions,
314            } => {
315                let permissions = permissions.correct_bits();
316
317                let mut algorithm = PasswordAlgorithm {
318                    encrypt_metadata,
319                    length: Some(128),
320                    version: 4,
321                    revision: 4,
322                    permissions,
323                    ..Default::default()
324                };
325
326                let owner_password = algorithm.sanitize_password_r4(owner_password)?;
327                let user_password = algorithm.sanitize_password_r4(user_password)?;
328
329                algorithm.owner_value =
330                    algorithm.compute_hashed_owner_password_r4(Some(&owner_password), &user_password)?;
331
332                algorithm.user_value = algorithm.compute_hashed_user_password_r3_r4(document, &user_password)?;
333
334                let file_encryption_key = algorithm.compute_file_encryption_key_r4(document, &user_password)?;
335
336                Ok(Self {
337                    version: algorithm.version,
338                    revision: algorithm.revision,
339                    key_length: algorithm.length,
340                    encrypt_metadata: algorithm.encrypt_metadata,
341                    file_encryption_key,
342                    crypt_filters,
343                    stream_filter,
344                    string_filter,
345                    owner_value: algorithm.owner_value,
346                    user_value: algorithm.user_value,
347                    permissions: algorithm.permissions,
348                    ..Default::default()
349                })
350            }
351            #[allow(deprecated)]
352            EncryptionVersion::R5 {
353                encrypt_metadata,
354                crypt_filters,
355                file_encryption_key,
356                stream_filter,
357                string_filter,
358                owner_password,
359                user_password,
360                permissions,
361            } => {
362                if file_encryption_key.len() != 32 {
363                    return Err(DecryptionError::InvalidKeyLength)?;
364                }
365
366                let permissions = permissions.correct_bits();
367
368                let mut algorithm = PasswordAlgorithm {
369                    encrypt_metadata,
370                    version: 5,
371                    revision: 5,
372                    permissions,
373                    ..Default::default()
374                };
375
376                let owner_password = algorithm.sanitize_password_r6(owner_password)?;
377                let user_password = algorithm.sanitize_password_r6(user_password)?;
378
379                let (user_value, user_encrypted) =
380                    algorithm.compute_hashed_user_password_r6(file_encryption_key, user_password)?;
381
382                algorithm.user_value = user_value;
383                algorithm.user_encrypted = user_encrypted;
384
385                let (owner_value, owner_encrypted) =
386                    algorithm.compute_hashed_owner_password_r6(file_encryption_key, owner_password)?;
387
388                algorithm.owner_value = owner_value;
389                algorithm.owner_encrypted = owner_encrypted;
390
391                algorithm.permission_encrypted = algorithm.compute_permissions(file_encryption_key)?;
392
393                Ok(Self {
394                    version: algorithm.version,
395                    revision: algorithm.revision,
396                    key_length: algorithm.length,
397                    encrypt_metadata: algorithm.encrypt_metadata,
398                    crypt_filters,
399                    file_encryption_key: file_encryption_key.to_vec(),
400                    stream_filter,
401                    string_filter,
402                    owner_value: algorithm.owner_value,
403                    owner_encrypted: algorithm.owner_encrypted,
404                    user_value: algorithm.user_value,
405                    user_encrypted: algorithm.user_encrypted,
406                    permissions: algorithm.permissions,
407                    permission_encrypted: algorithm.permission_encrypted,
408                })
409            }
410            EncryptionVersion::V5 {
411                encrypt_metadata,
412                crypt_filters,
413                file_encryption_key,
414                stream_filter,
415                string_filter,
416                owner_password,
417                user_password,
418                permissions,
419            } => {
420                if file_encryption_key.len() != 32 {
421                    return Err(DecryptionError::InvalidKeyLength)?;
422                }
423
424                let permissions = permissions.correct_bits();
425
426                let mut algorithm = PasswordAlgorithm {
427                    encrypt_metadata,
428                    version: 5,
429                    revision: 6,
430                    permissions,
431                    ..Default::default()
432                };
433
434                let owner_password = algorithm.sanitize_password_r6(owner_password)?;
435                let user_password = algorithm.sanitize_password_r6(user_password)?;
436
437                let (user_value, user_encrypted) =
438                    algorithm.compute_hashed_user_password_r6(file_encryption_key, user_password)?;
439
440                algorithm.user_value = user_value;
441                algorithm.user_encrypted = user_encrypted;
442
443                let (owner_value, owner_encrypted) =
444                    algorithm.compute_hashed_owner_password_r6(file_encryption_key, owner_password)?;
445
446                algorithm.owner_value = owner_value;
447                algorithm.owner_encrypted = owner_encrypted;
448
449                algorithm.permission_encrypted = algorithm.compute_permissions(file_encryption_key)?;
450
451                Ok(Self {
452                    version: algorithm.version,
453                    revision: algorithm.revision,
454                    key_length: algorithm.length,
455                    encrypt_metadata: algorithm.encrypt_metadata,
456                    crypt_filters,
457                    file_encryption_key: file_encryption_key.to_vec(),
458                    stream_filter,
459                    string_filter,
460                    owner_value: algorithm.owner_value,
461                    owner_encrypted: algorithm.owner_encrypted,
462                    user_value: algorithm.user_value,
463                    user_encrypted: algorithm.user_encrypted,
464                    permissions: algorithm.permissions,
465                    permission_encrypted: algorithm.permission_encrypted,
466                })
467            }
468        }
469    }
470}
471
472impl EncryptionState {
473    pub fn version(&self) -> i64 {
474        self.version
475    }
476
477    pub fn revision(&self) -> i64 {
478        self.revision
479    }
480
481    pub fn key_length(&self) -> Option<usize> {
482        self.key_length
483    }
484
485    pub fn encrypt_metadata(&self) -> bool {
486        self.encrypt_metadata
487    }
488
489    pub fn crypt_filters(&self) -> &BTreeMap<Vec<u8>, Arc<dyn CryptFilter>> {
490        &self.crypt_filters
491    }
492
493    pub fn file_encryption_key(&self) -> &[u8] {
494        self.file_encryption_key.as_ref()
495    }
496
497    pub fn default_stream_filter(&self) -> &[u8] {
498        self.stream_filter.as_ref()
499    }
500
501    pub fn default_string_filter(&self) -> &[u8] {
502        self.string_filter.as_ref()
503    }
504
505    pub fn owner_value(&self) -> &[u8] {
506        self.owner_value.as_ref()
507    }
508
509    pub fn owner_encrypted(&self) -> &[u8] {
510        self.owner_encrypted.as_ref()
511    }
512
513    pub fn user_value(&self) -> &[u8] {
514        self.user_value.as_ref()
515    }
516
517    pub fn user_encrypted(&self) -> &[u8] {
518        self.user_encrypted.as_ref()
519    }
520
521    pub fn permissions(&self) -> Permissions {
522        self.permissions
523    }
524
525    pub fn permission_encrypted(&self) -> &[u8] {
526        self.permission_encrypted.as_ref()
527    }
528
529    pub fn decode<P>(document: &Document, password: P) -> Result<Self, Error>
530    where
531        P: AsRef<[u8]>,
532    {
533        if !document.is_encrypted() {
534            return Err(Error::NotEncrypted);
535        }
536
537        // The name of the preferred security handler for this document. It shall be the name of
538        // the security handler that was used to encrypt the document.
539        //
540        // Standard shall be the name of the built-in password-based security handler.
541        let filter = document
542            .get_encrypted()
543            .and_then(|dict| dict.get(b"Filter"))
544            .and_then(|object| object.as_name())
545            .map_err(|_| Error::DictKey("Filter".to_string()))?;
546
547        if filter != b"Standard" {
548            return Err(Error::UnsupportedSecurityHandler(filter.to_vec()));
549        }
550
551        let algorithm = PasswordAlgorithm::try_from(document)?;
552        let file_encryption_key = algorithm.compute_file_encryption_key(document, password)?;
553
554        let mut crypt_filters = document.get_crypt_filters();
555
556        // CF is meaningful only when the value of V is 4 (PDF 1.5) or 5 (PDF 2.0).
557        if algorithm.version < 4 {
558            crypt_filters.clear();
559        }
560
561        let mut state = Self {
562            version: algorithm.version,
563            revision: algorithm.revision,
564            key_length: algorithm.length,
565            encrypt_metadata: algorithm.encrypt_metadata,
566            crypt_filters,
567            file_encryption_key,
568            owner_value: algorithm.owner_value,
569            owner_encrypted: algorithm.owner_encrypted,
570            user_value: algorithm.user_value,
571            user_encrypted: algorithm.user_encrypted,
572            permissions: algorithm.permissions,
573            permission_encrypted: algorithm.permission_encrypted,
574            ..Default::default()
575        };
576
577        // StmF and StrF are meaningful only when the value of V is 4 (PDF 1.5) or 5 (PDF 2.0).
578        if algorithm.version == 4 || algorithm.version == 5 {
579            if let Ok(stream_filter) = document
580                .get_encrypted()
581                .and_then(|dict| dict.get(b"StmF"))
582                .and_then(|object| object.as_name())
583            {
584                state.stream_filter = stream_filter.to_vec();
585            }
586
587            if let Ok(string_filter) = document
588                .get_encrypted()
589                .and_then(|dict| dict.get(b"StrF"))
590                .and_then(|object| object.as_name())
591            {
592                state.string_filter = string_filter.to_vec();
593            }
594        }
595
596        Ok(state)
597    }
598
599    pub fn encode(&self) -> Result<Dictionary, DecryptionError> {
600        let mut encrypted = Dictionary::new();
601
602        encrypted.set(b"Filter", Object::Name(b"Standard".to_vec()));
603
604        encrypted.set(b"V", Object::Integer(self.version));
605        encrypted.set(b"R", Object::Integer(self.revision));
606
607        if let Some(key_length) = self.key_length {
608            encrypted.set(b"Length", Object::Integer(key_length as i64));
609        }
610
611        // Optional; meaningful only when the value of V is 4 (PDF 1.5) or 5 (PDF 2.0)). Indicates
612        // whether the document-level metadata stream shall be encrypted. Default value: true.
613        if self.version >= 4 {
614            encrypted.set(b"EncryptMetadata", Object::Boolean(self.encrypt_metadata));
615        }
616
617        encrypted.set(b"O", Object::string_literal(self.owner_value.clone()));
618        encrypted.set(b"U", Object::string_literal(self.user_value.clone()));
619        encrypted.set(b"P", Object::Integer(self.permissions.bits() as i64));
620
621        if self.revision >= 4 {
622            let mut filters = Dictionary::new();
623
624            for (name, crypt_filter) in &self.crypt_filters {
625                let mut filter = Dictionary::new();
626
627                filter.set(b"Type", Object::Name(b"CryptFilter".to_vec()));
628                filter.set(b"CFM", Object::Name(crypt_filter.method().to_vec()));
629
630                filters.set(name.to_vec(), Object::Dictionary(filter));
631            }
632
633            encrypted.set(b"CF", Object::Dictionary(filters));
634            encrypted.set(b"StmF", Object::Name(self.stream_filter.clone()));
635            encrypted.set(b"StrF", Object::Name(self.string_filter.clone()));
636        }
637
638        if self.revision >= 5 {
639            encrypted.set(b"OE", Object::string_literal(self.owner_encrypted.clone()));
640            encrypted.set(b"UE", Object::string_literal(self.user_encrypted.clone()));
641            encrypted.set(b"Perms", Object::string_literal(self.permission_encrypted.clone()));
642        }
643
644        Ok(encrypted)
645    }
646
647    pub fn get_stream_filter(&self) -> Arc<dyn CryptFilter> {
648        self.crypt_filters
649            .get(&self.stream_filter)
650            .cloned()
651            .unwrap_or(Arc::new(Rc4CryptFilter))
652    }
653
654    pub fn get_string_filter(&self) -> Arc<dyn CryptFilter> {
655        self.crypt_filters
656            .get(&self.string_filter)
657            .cloned()
658            .unwrap_or(Arc::new(Rc4CryptFilter))
659    }
660}
661
662/// Encrypts `obj`.
663pub fn encrypt_object(state: &EncryptionState, obj_id: ObjectId, obj: &mut Object) -> Result<(), DecryptionError> {
664    // The cross-reference stream shall not be encrypted and strings appearing in the
665    // cross-reference stream dictionary shall not be encrypted.
666    let is_xref_stream = obj
667        .as_stream()
668        .map(|stream| stream.dict.has_type(b"XRef"))
669        .unwrap_or(false);
670
671    if is_xref_stream {
672        return Ok(());
673    }
674
675    // The Metadata stream shall only be encrypted if EncryptMetadata is set to true.
676    if obj.type_name().ok() == Some(b"Metadata") && !state.encrypt_metadata {
677        return Ok(());
678    }
679
680    // A stream filter type, the Crypt filter can be specified for any stream in the document to
681    // override the default filter for streams. The stream's DecodeParms entry shall contain a
682    // Crypt filter decode parameters dictionary whose Name entry specifies the particular crypt
683    // filter that shell be used (if missing, Identity is used).
684    let override_crypt_filter = obj
685        .as_stream()
686        .ok()
687        .filter(|stream| {
688            stream
689                .filters()
690                .map(|filters| filters.contains(&&b"Crypt"[..]))
691                .unwrap_or(false)
692        })
693        .and_then(|stream| stream.dict.get(b"DecodeParms").ok())
694        .and_then(|object| object.as_dict().ok())
695        .map(|dict| {
696            dict.get(b"Name")
697                .and_then(|object| object.as_name())
698                .ok()
699                .and_then(|name| state.crypt_filters.get(name).cloned())
700                .unwrap_or(Arc::new(IdentityCryptFilter))
701        });
702
703    // Retrieve the plaintext and the crypt filter to use to decrypt the ciphertext from the given
704    // object.
705    let (mut crypt_filter, plaintext) = match obj {
706        // Encryption applies to all strings and streams in the document's PDF file, i.e., we have to
707        // recursively process array and dictionary objects to decrypt any string and stream objects
708        // stored inside of those.
709        Object::Array(objects) => {
710            for obj in objects {
711                encrypt_object(state, obj_id, obj)?;
712            }
713
714            return Ok(());
715        }
716        Object::Dictionary(objects) => {
717            for (_, obj) in objects.iter_mut() {
718                encrypt_object(state, obj_id, obj)?;
719            }
720
721            return Ok(());
722        }
723        // Encryption applies to all strings and streams in the document's PDF file. We return the
724        // crypt filter and the content here.
725        Object::String(content, _) => (state.get_string_filter(), &*content),
726        Object::Stream(stream) => (state.get_stream_filter(), &stream.content),
727        // Encryption is not applied to other object types such as integers and boolean values.
728        _ => {
729            return Ok(());
730        }
731    };
732
733    // If the stream object specifies its own crypt filter, override the default one with the one
734    // from this stream object.
735    if let Some(filter) = override_crypt_filter {
736        crypt_filter = filter;
737    }
738
739    // Compute the key from the original file encryption key and the object identifier to use for
740    // the corresponding object.
741    let key = crypt_filter.compute_key(&state.file_encryption_key, obj_id)?;
742
743    // Encrypt the plaintext.
744    let ciphertext = crypt_filter.encrypt(&key, plaintext)?;
745
746    // Store the ciphertext in the object.
747    match obj {
748        Object::Stream(stream) => stream.set_content(ciphertext),
749        Object::String(content, _) => *content = ciphertext,
750        _ => (),
751    }
752
753    Ok(())
754}
755
756/// Decrypts `obj`.
757pub fn decrypt_object(state: &EncryptionState, obj_id: ObjectId, obj: &mut Object) -> Result<(), DecryptionError> {
758    // The cross-reference stream shall not be encrypted and strings appearing in the
759    // cross-reference stream dictionary shall not be encrypted.
760    let is_xref_stream = obj
761        .as_stream()
762        .map(|stream| stream.dict.has_type(b"XRef"))
763        .unwrap_or(false);
764
765    if is_xref_stream {
766        return Ok(());
767    }
768
769    // The Metadata stream shall only be encrypted if EncryptMetadata is set to true.
770    if obj.type_name().ok() == Some(b"Metadata") && !state.encrypt_metadata {
771        return Ok(());
772    }
773
774    // A stream filter type, the Crypt filter can be specified for any stream in the document to
775    // override the default filter for streams. The stream's DecodeParms entry shall contain a
776    // Crypt filter decode parameters dictionary whose Name entry specifies the particular crypt
777    // filter that shell be used (if missing, Identity is used).
778    let override_crypt_filter = obj
779        .as_stream()
780        .ok()
781        .filter(|stream| {
782            stream
783                .filters()
784                .map(|filters| filters.contains(&&b"Crypt"[..]))
785                .unwrap_or(false)
786        })
787        .and_then(|stream| stream.dict.get(b"DecodeParms").ok())
788        .and_then(|object| object.as_dict().ok())
789        .map(|dict| {
790            dict.get(b"Name")
791                .and_then(|object| object.as_name())
792                .ok()
793                .and_then(|name| state.crypt_filters.get(name).cloned())
794                .unwrap_or(Arc::new(IdentityCryptFilter))
795        });
796
797    // Retrieve the ciphertext and the crypt filter to use to decrypt the ciphertext from the given
798    // object.
799    let (mut crypt_filter, ciphertext) = match obj {
800        // Encryption applies to all strings and streams in the document's PDF file, i.e., we have to
801        // recursively process array and dictionary objects to decrypt any string and stream objects
802        // stored inside of those.
803        Object::Array(objects) => {
804            for obj in objects {
805                decrypt_object(state, obj_id, obj)?;
806            }
807
808            return Ok(());
809        }
810        Object::Dictionary(objects) => {
811            for (_, obj) in objects.iter_mut() {
812                decrypt_object(state, obj_id, obj)?;
813            }
814
815            return Ok(());
816        }
817        // Encryption applies to all strings and streams in the document's PDF file. We return the
818        // crypt filter and the content here.
819        Object::String(content, _) => (state.get_string_filter(), &*content),
820        Object::Stream(stream) => (state.get_stream_filter(), &stream.content),
821        // Encryption is not applied to other object types such as integers and boolean values.
822        _ => {
823            return Ok(());
824        }
825    };
826
827    // If the stream object specifies its own crypt filter, override the default one with the one
828    // from this stream object.
829    if let Some(filter) = override_crypt_filter {
830        crypt_filter = filter;
831    }
832
833    // Compute the key from the original file encryption key and the object identifier to use for
834    // the corresponding object.
835    let key = crypt_filter.compute_key(&state.file_encryption_key, obj_id)?;
836
837    // Decrypt the ciphertext.
838    let plaintext = crypt_filter.decrypt(&key, ciphertext)?;
839
840    // Store the plaintext in the object.
841    match obj {
842        Object::Stream(stream) => stream.set_content(plaintext),
843        Object::String(content, _) => *content = plaintext,
844        _ => (),
845    }
846
847    Ok(())
848}
849
850#[cfg(test)]
851mod tests {
852    use super::rc4::Rc4;
853    use crate::creator::tests::create_document;
854    use crate::encryption::{Aes128CryptFilter, Aes256CryptFilter, CryptFilter};
855    use crate::{EncryptionState, EncryptionVersion, Permissions};
856    use rand::Rng as _;
857    use std::collections::BTreeMap;
858    use std::sync::Arc;
859
860    #[test]
861    fn rc4_works() {
862        let cases = [
863            // Key, Plain, Cipher
864            (
865                String::from("Key"),
866                String::from("Plaintext"),
867                String::from("BBF316E8D940AF0AD3"),
868            ),
869            (String::from("Wiki"), String::from("pedia"), String::from("1021BF0420")),
870        ];
871
872        for (key, plain, cipher) in cases {
873            // Reencode cipher from a hex string to a Vec<u8>
874            let cipher = cipher.as_bytes();
875            let mut cipher_bytes = Vec::with_capacity(cipher.len() / 2);
876            for hex_pair in cipher.chunks_exact(2) {
877                cipher_bytes.push(u8::from_str_radix(std::str::from_utf8(hex_pair).unwrap(), 16).unwrap());
878            }
879
880            let decryptor = Rc4::new(key);
881            let decrypted = decryptor.decrypt(&cipher_bytes);
882            assert_eq!(plain.as_bytes(), &decrypted[..]);
883        }
884    }
885
886    #[test]
887    fn encrypt_v1() {
888        let mut document = create_document();
889
890        let version = EncryptionVersion::V1 {
891            document: &document,
892            owner_password: "owner",
893            user_password: "user",
894            permissions: Permissions::all(),
895        };
896
897        let state = EncryptionState::try_from(version).unwrap();
898
899        assert!(document.encrypt(&state).is_ok());
900        assert!(document.decrypt("user").is_ok());
901    }
902
903    #[test]
904    fn encrypt_v2() {
905        let mut document = create_document();
906
907        let version = EncryptionVersion::V2 {
908            document: &document,
909            owner_password: "owner",
910            user_password: "user",
911            key_length: 40,
912            permissions: Permissions::all(),
913        };
914
915        let state = EncryptionState::try_from(version).unwrap();
916
917        assert!(document.encrypt(&state).is_ok());
918        assert!(document.decrypt("user").is_ok());
919    }
920
921    #[test]
922    fn encrypt_v4() {
923        let mut document = create_document();
924
925        let crypt_filter: Arc<dyn CryptFilter> = Arc::new(Aes128CryptFilter);
926
927        let version = EncryptionVersion::V4 {
928            document: &document,
929            encrypt_metadata: true,
930            crypt_filters: BTreeMap::from([(b"StdCF".to_vec(), crypt_filter)]),
931            stream_filter: b"StdCF".to_vec(),
932            string_filter: b"StdCF".to_vec(),
933            owner_password: "owner",
934            user_password: "user",
935            permissions: Permissions::all(),
936        };
937
938        let state = EncryptionState::try_from(version).unwrap();
939
940        assert!(document.encrypt(&state).is_ok());
941        assert!(document.decrypt("user").is_ok());
942    }
943
944    #[test]
945    fn encrypt_r5() {
946        let mut document = create_document();
947
948        let crypt_filter: Arc<dyn CryptFilter> = Arc::new(Aes256CryptFilter);
949
950        let mut file_encryption_key = [0u8; 32];
951
952        let mut rng = rand::rng();
953        rng.fill(&mut file_encryption_key);
954
955        #[allow(deprecated)]
956        let version = EncryptionVersion::R5 {
957            encrypt_metadata: true,
958            crypt_filters: BTreeMap::from([(b"StdCF".to_vec(), crypt_filter)]),
959            file_encryption_key: &file_encryption_key,
960            stream_filter: b"StdCF".to_vec(),
961            string_filter: b"StdCF".to_vec(),
962            owner_password: "owner",
963            user_password: "user",
964            permissions: Permissions::all(),
965        };
966
967        let state = EncryptionState::try_from(version).unwrap();
968
969        assert!(document.encrypt(&state).is_ok());
970        assert!(document.decrypt("user").is_ok());
971    }
972
973    #[test]
974    fn encrypt_v5() {
975        let mut document = create_document();
976
977        let crypt_filter: Arc<dyn CryptFilter> = Arc::new(Aes256CryptFilter);
978
979        let mut file_encryption_key = [0u8; 32];
980
981        let mut rng = rand::rng();
982        rng.fill(&mut file_encryption_key);
983
984        let version = EncryptionVersion::V5 {
985            encrypt_metadata: true,
986            crypt_filters: BTreeMap::from([(b"StdCF".to_vec(), crypt_filter)]),
987            file_encryption_key: &file_encryption_key,
988            stream_filter: b"StdCF".to_vec(),
989            string_filter: b"StdCF".to_vec(),
990            owner_password: "owner",
991            user_password: "user",
992            permissions: Permissions::all(),
993        };
994
995        let state = EncryptionState::try_from(version).unwrap();
996
997        assert!(document.encrypt(&state).is_ok());
998        assert!(document.decrypt("user").is_ok());
999    }
1000}