Skip to main content

Crate pdfrum_crypt

Crate pdfrum_crypt 

Source
Expand description

§pdfrum-crypt

The standard security handler (ISO 32000-1 §7.6), revisions 2 through 6: an /Encrypt dictionary plus a password produce a SecurityHandler, and every string and stream in the file decrypts through it, keyed by the indirect object it belongs to.

use pdfrum_crypt::{CryptClass, SecurityHandler};
use pdfrum_object::ObjRef;

let handler = SecurityHandler::Identity;
assert_eq!(handler.decrypt(ObjRef::new(1, 0), CryptClass::Stream, b"raw"), b"raw");

The object reference is not optional context — it is part of the key. Revisions 2 to 4 derive an RC4 or AES-128 key by an MD5 ladder over the padded password and the object’s number and generation, so the same bytes at a different object number decrypt to something else. Revisions 5 and 6 verify a SHA-2 hash and unwrap a 32-byte AES-256 key the file stores directly, and only there is the key object-independent. CryptClass distinguishes strings from streams because /StmF and /StrF can name different crypt filters.

The AES-CBC initialisation vector is an argument rather than something this crate mints, because a decrypting caller reads it off the ciphertext and only an encrypting one has to produce it. pdfrum-edit draws file keys and vectors from the operating system for every encrypted save; a fixed seed still pins /ID bytes, not the secrets.

Two things are deliberately out of scope. Building a new /Encrypt dictionary is revision 6 only (standard_r6), because /O, /U, /OE, /UE and /Perms are written by whoever chose the passwords. And graph walks stay in the caller — whether a signature’s /Contents is exempt, or /EncryptMetadata applies, is a question about the document, not about a cipher.

Public-key handlers (Adobe.PubSec) are not implemented.

Part of pdfrum. #![forbid(unsafe_code)].

MIT OR Apache-2.0

Structs§

EncryptParams
The /Encrypt dictionary as a record of what the file said.
Iv
One AES initialisation vector, supplied by the caller of crate::SecurityHandler::encrypt.
KeyMaterial
The secret bytes behind one encrypted file: the AES-256 file key, the four revision-6 salts (ISO 32000-2 §7.6.4.4.7, algorithms 8 and 9), and four random bytes for /Perms (Algorithm 10).
Permissions
What a document’s security handler permits.
SmallKey
A file encryption key of at most 32 bytes.

Enums§

Cipher
The cipher a document’s crypt filter resolves to.
CryptClass
Which crypt filter class a payload belongs to.
Error
What went wrong building a security handler.
PasswordEncoding
Which spelling of a password unlocked a document.
SecurityHandler
A document’s decryption state: which cipher, which key, and what the password unlocked.

Constants§

ENTROPY_LEN
The bytes of a new file’s secrets: the 32-byte file key, then the user validation salt, user key salt, owner validation salt and owner key salt, 8 bytes each, then four random bytes for /Perms (ISO 32000-2 Algorithm 10).
PAD
The 32-byte padding string every revision 2 to 4 password is padded with (ISO 32000 §7.6.3.3, “Algorithm 2” step a).

Functions§

is_signature_dict
Whether dict is a signature dictionary, whose /Contents must stay undecrypted.
md5
MD5 of one buffer (RFC 1321).
parse_encrypt_dict
Read an /Encrypt dictionary into an EncryptParams.
rc4
Crypt data under key, returning a fresh buffer.
sha1
SHA-1 of one buffer (FIPS 180-2).
standard_r6
The /Encrypt dictionary and the handler that enciphers under it, for a document protected by user (opens with reading rights) and owner (opens with every right). An empty user password means anyone can open the file; an empty owner password is replaced by the user password, as Acrobat does, so there is always a way to unlock it.