Skip to main content

pdfluent_lopdf/
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 = algorithm
247                    .compute_hashed_owner_password_r4(Some(&owner_password), &user_password)?;
248
249                algorithm.user_value =
250                    algorithm.compute_hashed_user_password_r2(document, &user_password)?;
251
252                let file_encryption_key =
253                    algorithm.compute_file_encryption_key_r4(document, &user_password)?;
254
255                Ok(Self {
256                    version: algorithm.version,
257                    revision: algorithm.revision,
258                    key_length: algorithm.length,
259                    encrypt_metadata: algorithm.encrypt_metadata,
260                    file_encryption_key,
261                    owner_value: algorithm.owner_value,
262                    user_value: algorithm.user_value,
263                    permissions: algorithm.permissions,
264                    ..Default::default()
265                })
266            }
267            EncryptionVersion::V2 {
268                document,
269                owner_password,
270                user_password,
271                key_length,
272                permissions,
273            } => {
274                let permissions = permissions.correct_bits();
275
276                let mut algorithm = PasswordAlgorithm {
277                    encrypt_metadata: true,
278                    length: Some(key_length),
279                    version: 2,
280                    revision: 3,
281                    permissions,
282                    ..Default::default()
283                };
284
285                let owner_password = algorithm.sanitize_password_r4(owner_password)?;
286                let user_password = algorithm.sanitize_password_r4(user_password)?;
287
288                algorithm.owner_value = algorithm
289                    .compute_hashed_owner_password_r4(Some(&owner_password), &user_password)?;
290
291                algorithm.user_value =
292                    algorithm.compute_hashed_user_password_r3_r4(document, &user_password)?;
293
294                let file_encryption_key =
295                    algorithm.compute_file_encryption_key_r4(document, &user_password)?;
296
297                Ok(Self {
298                    version: algorithm.version,
299                    revision: algorithm.revision,
300                    key_length: algorithm.length,
301                    encrypt_metadata: algorithm.encrypt_metadata,
302                    file_encryption_key,
303                    owner_value: algorithm.owner_value,
304                    user_value: algorithm.user_value,
305                    permissions,
306                    ..Default::default()
307                })
308            }
309            EncryptionVersion::V4 {
310                document,
311                encrypt_metadata,
312                crypt_filters,
313                stream_filter,
314                string_filter,
315                owner_password,
316                user_password,
317                permissions,
318            } => {
319                let permissions = permissions.correct_bits();
320
321                let mut algorithm = PasswordAlgorithm {
322                    encrypt_metadata,
323                    length: Some(128),
324                    version: 4,
325                    revision: 4,
326                    permissions,
327                    ..Default::default()
328                };
329
330                let owner_password = algorithm.sanitize_password_r4(owner_password)?;
331                let user_password = algorithm.sanitize_password_r4(user_password)?;
332
333                algorithm.owner_value = algorithm
334                    .compute_hashed_owner_password_r4(Some(&owner_password), &user_password)?;
335
336                algorithm.user_value =
337                    algorithm.compute_hashed_user_password_r3_r4(document, &user_password)?;
338
339                let file_encryption_key =
340                    algorithm.compute_file_encryption_key_r4(document, &user_password)?;
341
342                Ok(Self {
343                    version: algorithm.version,
344                    revision: algorithm.revision,
345                    key_length: algorithm.length,
346                    encrypt_metadata: algorithm.encrypt_metadata,
347                    file_encryption_key,
348                    crypt_filters,
349                    stream_filter,
350                    string_filter,
351                    owner_value: algorithm.owner_value,
352                    user_value: algorithm.user_value,
353                    permissions: algorithm.permissions,
354                    ..Default::default()
355                })
356            }
357            #[allow(deprecated)]
358            EncryptionVersion::R5 {
359                encrypt_metadata,
360                crypt_filters,
361                file_encryption_key,
362                stream_filter,
363                string_filter,
364                owner_password,
365                user_password,
366                permissions,
367            } => {
368                if file_encryption_key.len() != 32 {
369                    return Err(DecryptionError::InvalidKeyLength)?;
370                }
371
372                let permissions = permissions.correct_bits();
373
374                let mut algorithm = PasswordAlgorithm {
375                    encrypt_metadata,
376                    version: 5,
377                    revision: 5,
378                    permissions,
379                    ..Default::default()
380                };
381
382                let owner_password = algorithm.sanitize_password_r6(owner_password)?;
383                let user_password = algorithm.sanitize_password_r6(user_password)?;
384
385                let (user_value, user_encrypted) = algorithm
386                    .compute_hashed_user_password_r6(file_encryption_key, user_password)?;
387
388                algorithm.user_value = user_value;
389                algorithm.user_encrypted = user_encrypted;
390
391                let (owner_value, owner_encrypted) = algorithm
392                    .compute_hashed_owner_password_r6(file_encryption_key, owner_password)?;
393
394                algorithm.owner_value = owner_value;
395                algorithm.owner_encrypted = owner_encrypted;
396
397                algorithm.permission_encrypted =
398                    algorithm.compute_permissions(file_encryption_key)?;
399
400                Ok(Self {
401                    version: algorithm.version,
402                    revision: algorithm.revision,
403                    key_length: algorithm.length,
404                    encrypt_metadata: algorithm.encrypt_metadata,
405                    crypt_filters,
406                    file_encryption_key: file_encryption_key.to_vec(),
407                    stream_filter,
408                    string_filter,
409                    owner_value: algorithm.owner_value,
410                    owner_encrypted: algorithm.owner_encrypted,
411                    user_value: algorithm.user_value,
412                    user_encrypted: algorithm.user_encrypted,
413                    permissions: algorithm.permissions,
414                    permission_encrypted: algorithm.permission_encrypted,
415                })
416            }
417            EncryptionVersion::V5 {
418                encrypt_metadata,
419                crypt_filters,
420                file_encryption_key,
421                stream_filter,
422                string_filter,
423                owner_password,
424                user_password,
425                permissions,
426            } => {
427                if file_encryption_key.len() != 32 {
428                    return Err(DecryptionError::InvalidKeyLength)?;
429                }
430
431                let permissions = permissions.correct_bits();
432
433                let mut algorithm = PasswordAlgorithm {
434                    encrypt_metadata,
435                    version: 5,
436                    revision: 6,
437                    permissions,
438                    ..Default::default()
439                };
440
441                let owner_password = algorithm.sanitize_password_r6(owner_password)?;
442                let user_password = algorithm.sanitize_password_r6(user_password)?;
443
444                let (user_value, user_encrypted) = algorithm
445                    .compute_hashed_user_password_r6(file_encryption_key, user_password)?;
446
447                algorithm.user_value = user_value;
448                algorithm.user_encrypted = user_encrypted;
449
450                let (owner_value, owner_encrypted) = algorithm
451                    .compute_hashed_owner_password_r6(file_encryption_key, owner_password)?;
452
453                algorithm.owner_value = owner_value;
454                algorithm.owner_encrypted = owner_encrypted;
455
456                algorithm.permission_encrypted =
457                    algorithm.compute_permissions(file_encryption_key)?;
458
459                Ok(Self {
460                    version: algorithm.version,
461                    revision: algorithm.revision,
462                    key_length: algorithm.length,
463                    encrypt_metadata: algorithm.encrypt_metadata,
464                    crypt_filters,
465                    file_encryption_key: file_encryption_key.to_vec(),
466                    stream_filter,
467                    string_filter,
468                    owner_value: algorithm.owner_value,
469                    owner_encrypted: algorithm.owner_encrypted,
470                    user_value: algorithm.user_value,
471                    user_encrypted: algorithm.user_encrypted,
472                    permissions: algorithm.permissions,
473                    permission_encrypted: algorithm.permission_encrypted,
474                })
475            }
476        }
477    }
478}
479
480impl EncryptionState {
481    pub fn version(&self) -> i64 {
482        self.version
483    }
484
485    pub fn revision(&self) -> i64 {
486        self.revision
487    }
488
489    pub fn key_length(&self) -> Option<usize> {
490        self.key_length
491    }
492
493    pub fn encrypt_metadata(&self) -> bool {
494        self.encrypt_metadata
495    }
496
497    pub fn crypt_filters(&self) -> &BTreeMap<Vec<u8>, Arc<dyn CryptFilter>> {
498        &self.crypt_filters
499    }
500
501    pub fn file_encryption_key(&self) -> &[u8] {
502        self.file_encryption_key.as_ref()
503    }
504
505    pub fn default_stream_filter(&self) -> &[u8] {
506        self.stream_filter.as_ref()
507    }
508
509    pub fn default_string_filter(&self) -> &[u8] {
510        self.string_filter.as_ref()
511    }
512
513    pub fn owner_value(&self) -> &[u8] {
514        self.owner_value.as_ref()
515    }
516
517    pub fn owner_encrypted(&self) -> &[u8] {
518        self.owner_encrypted.as_ref()
519    }
520
521    pub fn user_value(&self) -> &[u8] {
522        self.user_value.as_ref()
523    }
524
525    pub fn user_encrypted(&self) -> &[u8] {
526        self.user_encrypted.as_ref()
527    }
528
529    pub fn permissions(&self) -> Permissions {
530        self.permissions
531    }
532
533    pub fn permission_encrypted(&self) -> &[u8] {
534        self.permission_encrypted.as_ref()
535    }
536
537    pub fn decode<P>(document: &Document, password: P) -> Result<Self, Error>
538    where
539        P: AsRef<[u8]>,
540    {
541        if !document.is_encrypted() {
542            return Err(Error::NotEncrypted);
543        }
544
545        // The name of the preferred security handler for this document. It shall be the name of
546        // the security handler that was used to encrypt the document.
547        //
548        // Standard shall be the name of the built-in password-based security handler.
549        let filter = document
550            .get_encrypted()
551            .and_then(|dict| dict.get(b"Filter"))
552            .and_then(|object| object.as_name())
553            .map_err(|_| Error::DictKey("Filter".to_string()))?;
554
555        if filter != b"Standard" {
556            return Err(Error::UnsupportedSecurityHandler(filter.to_vec()));
557        }
558
559        let algorithm = PasswordAlgorithm::try_from(document)?;
560        let file_encryption_key = algorithm.compute_file_encryption_key(document, password)?;
561
562        let mut crypt_filters = document.get_crypt_filters();
563
564        // CF is meaningful only when the value of V is 4 (PDF 1.5) or 5 (PDF 2.0).
565        if algorithm.version < 4 {
566            crypt_filters.clear();
567        }
568
569        let mut state = Self {
570            version: algorithm.version,
571            revision: algorithm.revision,
572            key_length: algorithm.length,
573            encrypt_metadata: algorithm.encrypt_metadata,
574            crypt_filters,
575            file_encryption_key,
576            owner_value: algorithm.owner_value,
577            owner_encrypted: algorithm.owner_encrypted,
578            user_value: algorithm.user_value,
579            user_encrypted: algorithm.user_encrypted,
580            permissions: algorithm.permissions,
581            permission_encrypted: algorithm.permission_encrypted,
582            ..Default::default()
583        };
584
585        // StmF and StrF are meaningful only when the value of V is 4 (PDF 1.5) or 5 (PDF 2.0).
586        if algorithm.version == 4 || algorithm.version == 5 {
587            if let Ok(stream_filter) = document
588                .get_encrypted()
589                .and_then(|dict| dict.get(b"StmF"))
590                .and_then(|object| object.as_name())
591            {
592                state.stream_filter = stream_filter.to_vec();
593            }
594
595            if let Ok(string_filter) = document
596                .get_encrypted()
597                .and_then(|dict| dict.get(b"StrF"))
598                .and_then(|object| object.as_name())
599            {
600                state.string_filter = string_filter.to_vec();
601            }
602        }
603
604        Ok(state)
605    }
606
607    pub fn encode(&self) -> Result<Dictionary, DecryptionError> {
608        let mut encrypted = Dictionary::new();
609
610        encrypted.set(b"Filter", Object::Name(b"Standard".to_vec()));
611
612        encrypted.set(b"V", Object::Integer(self.version));
613        encrypted.set(b"R", Object::Integer(self.revision));
614
615        if let Some(key_length) = self.key_length {
616            encrypted.set(b"Length", Object::Integer(key_length as i64));
617        }
618
619        // Optional; meaningful only when the value of V is 4 (PDF 1.5) or 5 (PDF 2.0)). Indicates
620        // whether the document-level metadata stream shall be encrypted. Default value: true.
621        if self.version >= 4 {
622            encrypted.set(b"EncryptMetadata", Object::Boolean(self.encrypt_metadata));
623        }
624
625        encrypted.set(b"O", Object::string_literal(self.owner_value.clone()));
626        encrypted.set(b"U", Object::string_literal(self.user_value.clone()));
627        encrypted.set(b"P", Object::Integer(self.permissions.bits() as i64));
628
629        if self.revision >= 4 {
630            let mut filters = Dictionary::new();
631
632            for (name, crypt_filter) in &self.crypt_filters {
633                let mut filter = Dictionary::new();
634
635                filter.set(b"Type", Object::Name(b"CryptFilter".to_vec()));
636                filter.set(b"CFM", Object::Name(crypt_filter.method().to_vec()));
637
638                filters.set(name.to_vec(), Object::Dictionary(filter));
639            }
640
641            encrypted.set(b"CF", Object::Dictionary(filters));
642            encrypted.set(b"StmF", Object::Name(self.stream_filter.clone()));
643            encrypted.set(b"StrF", Object::Name(self.string_filter.clone()));
644        }
645
646        if self.revision >= 5 {
647            encrypted.set(b"OE", Object::string_literal(self.owner_encrypted.clone()));
648            encrypted.set(b"UE", Object::string_literal(self.user_encrypted.clone()));
649            encrypted.set(
650                b"Perms",
651                Object::string_literal(self.permission_encrypted.clone()),
652            );
653        }
654
655        Ok(encrypted)
656    }
657
658    pub fn get_stream_filter(&self) -> Arc<dyn CryptFilter> {
659        self.crypt_filters
660            .get(&self.stream_filter)
661            .cloned()
662            .unwrap_or(Arc::new(Rc4CryptFilter))
663    }
664
665    pub fn get_string_filter(&self) -> Arc<dyn CryptFilter> {
666        self.crypt_filters
667            .get(&self.string_filter)
668            .cloned()
669            .unwrap_or(Arc::new(Rc4CryptFilter))
670    }
671}
672
673/// Create an AES-256 (PDF 2.0, V=5, R=6) [`EncryptionState`] for a document.
674///
675/// Generates a cryptographically random 32-byte file encryption key internally.
676/// The returned state can be passed directly to [`Document::encrypt`].
677pub fn aes256_encryption_state(
678    owner_password: &str,
679    user_password: &str,
680    permissions: Permissions,
681) -> crate::Result<EncryptionState> {
682    use rand::Rng as _;
683    let mut file_key = [0u8; 32];
684    rand::rng().fill(&mut file_key);
685    let crypt_filter: Arc<dyn CryptFilter> = Arc::new(Aes256CryptFilter);
686    EncryptionState::try_from(EncryptionVersion::V5 {
687        encrypt_metadata: true,
688        crypt_filters: BTreeMap::from([(b"StdCF".to_vec(), crypt_filter)]),
689        file_encryption_key: &file_key,
690        stream_filter: b"StdCF".to_vec(),
691        string_filter: b"StdCF".to_vec(),
692        owner_password,
693        user_password,
694        permissions,
695    })
696}
697
698/// Encrypts `obj`.
699pub fn encrypt_object(
700    state: &EncryptionState,
701    obj_id: ObjectId,
702    obj: &mut Object,
703) -> Result<(), DecryptionError> {
704    // The cross-reference stream shall not be encrypted and strings appearing in the
705    // cross-reference stream dictionary shall not be encrypted.
706    let is_xref_stream = obj
707        .as_stream()
708        .map(|stream| stream.dict.has_type(b"XRef"))
709        .unwrap_or(false);
710
711    if is_xref_stream {
712        return Ok(());
713    }
714
715    // The Metadata stream shall only be encrypted if EncryptMetadata is set to true.
716    if obj.type_name().ok() == Some(b"Metadata") && !state.encrypt_metadata {
717        return Ok(());
718    }
719
720    // A stream filter type, the Crypt filter can be specified for any stream in the document to
721    // override the default filter for streams. The stream's DecodeParms entry shall contain a
722    // Crypt filter decode parameters dictionary whose Name entry specifies the particular crypt
723    // filter that shell be used (if missing, Identity is used).
724    let override_crypt_filter = obj
725        .as_stream()
726        .ok()
727        .filter(|stream| {
728            stream
729                .filters()
730                .map(|filters| filters.contains(&&b"Crypt"[..]))
731                .unwrap_or(false)
732        })
733        .and_then(|stream| stream.dict.get(b"DecodeParms").ok())
734        .and_then(|object| object.as_dict().ok())
735        .map(|dict| {
736            dict.get(b"Name")
737                .and_then(|object| object.as_name())
738                .ok()
739                .and_then(|name| state.crypt_filters.get(name).cloned())
740                .unwrap_or(Arc::new(IdentityCryptFilter))
741        });
742
743    // Retrieve the plaintext and the crypt filter to use to decrypt the ciphertext from the given
744    // object.
745    let (mut crypt_filter, plaintext) = match obj {
746        // Encryption applies to all strings and streams in the document's PDF file, i.e., we have to
747        // recursively process array and dictionary objects to decrypt any string and stream objects
748        // stored inside of those.
749        Object::Array(objects) => {
750            for obj in objects {
751                encrypt_object(state, obj_id, obj)?;
752            }
753
754            return Ok(());
755        }
756        Object::Dictionary(objects) => {
757            for (_, obj) in objects.iter_mut() {
758                encrypt_object(state, obj_id, obj)?;
759            }
760
761            return Ok(());
762        }
763        // Encryption applies to all strings and streams in the document's PDF file. We return the
764        // crypt filter and the content here.
765        Object::String(content, _) => (state.get_string_filter(), &*content),
766        Object::Stream(stream) => (state.get_stream_filter(), &stream.content),
767        // Encryption is not applied to other object types such as integers and boolean values.
768        _ => {
769            return Ok(());
770        }
771    };
772
773    // If the stream object specifies its own crypt filter, override the default one with the one
774    // from this stream object.
775    if let Some(filter) = override_crypt_filter {
776        crypt_filter = filter;
777    }
778
779    // Compute the key from the original file encryption key and the object identifier to use for
780    // the corresponding object.
781    let key = crypt_filter.compute_key(&state.file_encryption_key, obj_id)?;
782
783    // Encrypt the plaintext.
784    let ciphertext = crypt_filter.encrypt(&key, plaintext)?;
785
786    // Store the ciphertext in the object.
787    match obj {
788        Object::Stream(stream) => stream.set_content(ciphertext),
789        Object::String(content, _) => *content = ciphertext,
790        _ => (),
791    }
792
793    Ok(())
794}
795
796/// Decrypts `obj`.
797pub fn decrypt_object(
798    state: &EncryptionState,
799    obj_id: ObjectId,
800    obj: &mut Object,
801) -> Result<(), DecryptionError> {
802    // The cross-reference stream shall not be encrypted and strings appearing in the
803    // cross-reference stream dictionary shall not be encrypted.
804    let is_xref_stream = obj
805        .as_stream()
806        .map(|stream| stream.dict.has_type(b"XRef"))
807        .unwrap_or(false);
808
809    if is_xref_stream {
810        return Ok(());
811    }
812
813    // The Metadata stream shall only be encrypted if EncryptMetadata is set to true.
814    if obj.type_name().ok() == Some(b"Metadata") && !state.encrypt_metadata {
815        return Ok(());
816    }
817
818    // A stream filter type, the Crypt filter can be specified for any stream in the document to
819    // override the default filter for streams. The stream's DecodeParms entry shall contain a
820    // Crypt filter decode parameters dictionary whose Name entry specifies the particular crypt
821    // filter that shell be used (if missing, Identity is used).
822    let override_crypt_filter = obj
823        .as_stream()
824        .ok()
825        .filter(|stream| {
826            stream
827                .filters()
828                .map(|filters| filters.contains(&&b"Crypt"[..]))
829                .unwrap_or(false)
830        })
831        .and_then(|stream| stream.dict.get(b"DecodeParms").ok())
832        .and_then(|object| object.as_dict().ok())
833        .map(|dict| {
834            dict.get(b"Name")
835                .and_then(|object| object.as_name())
836                .ok()
837                .and_then(|name| state.crypt_filters.get(name).cloned())
838                .unwrap_or(Arc::new(IdentityCryptFilter))
839        });
840
841    // Retrieve the ciphertext and the crypt filter to use to decrypt the ciphertext from the given
842    // object.
843    let (mut crypt_filter, ciphertext) = match obj {
844        // Encryption applies to all strings and streams in the document's PDF file, i.e., we have to
845        // recursively process array and dictionary objects to decrypt any string and stream objects
846        // stored inside of those.
847        Object::Array(objects) => {
848            for obj in objects {
849                decrypt_object(state, obj_id, obj)?;
850            }
851
852            return Ok(());
853        }
854        Object::Dictionary(objects) => {
855            for (_, obj) in objects.iter_mut() {
856                decrypt_object(state, obj_id, obj)?;
857            }
858
859            return Ok(());
860        }
861        // Encryption applies to all strings and streams in the document's PDF file. We return the
862        // crypt filter and the content here.
863        Object::String(content, _) => (state.get_string_filter(), &*content),
864        Object::Stream(stream) => (state.get_stream_filter(), &stream.content),
865        // Encryption is not applied to other object types such as integers and boolean values.
866        _ => {
867            return Ok(());
868        }
869    };
870
871    // If the stream object specifies its own crypt filter, override the default one with the one
872    // from this stream object.
873    if let Some(filter) = override_crypt_filter {
874        crypt_filter = filter;
875    }
876
877    // Compute the key from the original file encryption key and the object identifier to use for
878    // the corresponding object.
879    let key = crypt_filter.compute_key(&state.file_encryption_key, obj_id)?;
880
881    // Decrypt the ciphertext.
882    let plaintext = crypt_filter.decrypt(&key, ciphertext)?;
883
884    // Store the plaintext in the object.
885    match obj {
886        Object::Stream(stream) => stream.set_content(plaintext),
887        Object::String(content, _) => *content = plaintext,
888        _ => (),
889    }
890
891    Ok(())
892}
893
894#[cfg(test)]
895mod tests {
896    use super::rc4::Rc4;
897    use crate::creator::tests::create_document;
898    use crate::encryption::{Aes128CryptFilter, Aes256CryptFilter, CryptFilter};
899    use crate::{EncryptionState, EncryptionVersion, Permissions};
900    use rand::Rng as _;
901    use std::collections::BTreeMap;
902    use std::sync::Arc;
903
904    #[test]
905    fn rc4_works() {
906        let cases = [
907            // Key, Plain, Cipher
908            (
909                String::from("Key"),
910                String::from("Plaintext"),
911                String::from("BBF316E8D940AF0AD3"),
912            ),
913            (
914                String::from("Wiki"),
915                String::from("pedia"),
916                String::from("1021BF0420"),
917            ),
918        ];
919
920        for (key, plain, cipher) in cases {
921            // Reencode cipher from a hex string to a Vec<u8>
922            let cipher = cipher.as_bytes();
923            let mut cipher_bytes = Vec::with_capacity(cipher.len() / 2);
924            for hex_pair in cipher.chunks_exact(2) {
925                cipher_bytes
926                    .push(u8::from_str_radix(std::str::from_utf8(hex_pair).unwrap(), 16).unwrap());
927            }
928
929            let decryptor = Rc4::new(key);
930            let decrypted = decryptor.decrypt(&cipher_bytes);
931            assert_eq!(plain.as_bytes(), &decrypted[..]);
932        }
933    }
934
935    #[test]
936    fn encrypt_v1() {
937        let mut document = create_document();
938
939        let version = EncryptionVersion::V1 {
940            document: &document,
941            owner_password: "owner",
942            user_password: "user",
943            permissions: Permissions::all(),
944        };
945
946        let state = EncryptionState::try_from(version).unwrap();
947
948        assert!(document.encrypt(&state).is_ok());
949        assert!(document.decrypt("user").is_ok());
950    }
951
952    #[test]
953    fn encrypt_v2() {
954        let mut document = create_document();
955
956        let version = EncryptionVersion::V2 {
957            document: &document,
958            owner_password: "owner",
959            user_password: "user",
960            key_length: 40,
961            permissions: Permissions::all(),
962        };
963
964        let state = EncryptionState::try_from(version).unwrap();
965
966        assert!(document.encrypt(&state).is_ok());
967        assert!(document.decrypt("user").is_ok());
968    }
969
970    #[test]
971    fn encrypt_v4() {
972        let mut document = create_document();
973
974        let crypt_filter: Arc<dyn CryptFilter> = Arc::new(Aes128CryptFilter);
975
976        let version = EncryptionVersion::V4 {
977            document: &document,
978            encrypt_metadata: true,
979            crypt_filters: BTreeMap::from([(b"StdCF".to_vec(), crypt_filter)]),
980            stream_filter: b"StdCF".to_vec(),
981            string_filter: b"StdCF".to_vec(),
982            owner_password: "owner",
983            user_password: "user",
984            permissions: Permissions::all(),
985        };
986
987        let state = EncryptionState::try_from(version).unwrap();
988
989        assert!(document.encrypt(&state).is_ok());
990        assert!(document.decrypt("user").is_ok());
991    }
992
993    #[test]
994    fn encrypt_r5() {
995        let mut document = create_document();
996
997        let crypt_filter: Arc<dyn CryptFilter> = Arc::new(Aes256CryptFilter);
998
999        let mut file_encryption_key = [0u8; 32];
1000
1001        let mut rng = rand::rng();
1002        rng.fill(&mut file_encryption_key);
1003
1004        #[allow(deprecated)]
1005        let version = EncryptionVersion::R5 {
1006            encrypt_metadata: true,
1007            crypt_filters: BTreeMap::from([(b"StdCF".to_vec(), crypt_filter)]),
1008            file_encryption_key: &file_encryption_key,
1009            stream_filter: b"StdCF".to_vec(),
1010            string_filter: b"StdCF".to_vec(),
1011            owner_password: "owner",
1012            user_password: "user",
1013            permissions: Permissions::all(),
1014        };
1015
1016        let state = EncryptionState::try_from(version).unwrap();
1017
1018        assert!(document.encrypt(&state).is_ok());
1019        assert!(document.decrypt("user").is_ok());
1020    }
1021
1022    #[test]
1023    fn encrypt_v5() {
1024        let mut document = create_document();
1025
1026        let crypt_filter: Arc<dyn CryptFilter> = Arc::new(Aes256CryptFilter);
1027
1028        let mut file_encryption_key = [0u8; 32];
1029
1030        let mut rng = rand::rng();
1031        rng.fill(&mut file_encryption_key);
1032
1033        let version = EncryptionVersion::V5 {
1034            encrypt_metadata: true,
1035            crypt_filters: BTreeMap::from([(b"StdCF".to_vec(), crypt_filter)]),
1036            file_encryption_key: &file_encryption_key,
1037            stream_filter: b"StdCF".to_vec(),
1038            string_filter: b"StdCF".to_vec(),
1039            owner_password: "owner",
1040            user_password: "user",
1041            permissions: Permissions::all(),
1042        };
1043
1044        let state = EncryptionState::try_from(version).unwrap();
1045
1046        assert!(document.encrypt(&state).is_ok());
1047        assert!(document.decrypt("user").is_ok());
1048    }
1049}