Encryption
Sign a password-protected PDF, protect the signed output, and produce AES-256 (V5/R6) encrypted output
Two independent concerns: the input's open password travels with the document via PdfReader,
while output protection is a signing decision on SignConfig — the document is re-encrypted
before signing, so the signature covers the encrypted bytes. Every recipe is a self-contained snippet
for your own project; see Cookbook for how they're written.
Recipes
| Recipe | What it shows | Feature |
|---|---|---|
sign_protected | Sign a password-protected input (PdfReader::open(…).password(…)) | pfx |
encrypt_output | Protect the output: new / owner / keep_password | pfx |
aes256_demo | AES-256 (V5/R6) encrypted signed output | pfx |
Protected → protected
A protected document should stay protected after signing. The open password rides on the input via
PdfReader; .keep_password() re-encrypts the signed output with that same password and cipher.
use mudrit::prelude::*;
let signer = PfxSigner::from_file("signer.pfx", "password")?;
let cfg = SignConfig::builder()
.place("F", [350, 60, 560, 160])?
.timestamp(Timestamp::url(mudrit::DEFAULT_TSA_URL))
.ltv(true)
.keep_password() // re-protect the output with the SAME password (AES-128)
.build();
let input = PdfReader::open("locked.pdf")?.password("open-password");
let signed = sign_pdf(input, &signer, &cfg)?;
// `signed` is both digitally signed AND still opens with the same passwordRepo example:
sign_protected— ships with the licensed source bundle.
Protect the output
Three ways to protect a signed output, all offline:
use mudrit::prelude::*;
let cfg = SignConfig::builder()
.place("F", [350, 60, 560, 160])?
// new user (open) password, AES-128 by default
.encrypt("user-secret")
// …or a distinct owner (permissions) password, separate from the open password:
// .encrypt(OutputEncryption::password("user-pw").owner_password("owner-pw"))
// …or re-use the input's own open password + cipher (protected in → protected out):
// .keep_password()
.build();
let signed = sign_pdf(&pdf, &signer, &cfg)?;Restrict what a viewer may do by pairing a distinct owner password with Permissions — the
restrictions are only enforced when the owner password differs from the open password:
.encrypt(
OutputEncryption::password("user")
.owner_password("owner")
.permissions(Permissions::all().copy(false).modify(false)),
)Repo example:
encrypt_output(source bundle). See the Encryption guide.
AES-256 output
Output defaults to AES-128 (AESV2); opt into AES-256 (AESV3 / V5 / R6) with .cipher(...):
use mudrit::prelude::*;
let cfg = SignConfig::builder()
.place("F", [350, 60, 560, 160])?
.encrypt(OutputEncryption::password("secret").cipher(Cipher::Aes256))
.build();
let signed = sign_pdf(&pdf, &signer, &cfg)?;Both ciphers open correctly in Adobe Acrobat / Reader. Encryption works with every Method,
including MultiChained — every chained revision is encrypted with the same file key, so the whole
multi-signature document stays protected, and certify + encrypt stays DocMDP-valid.
Repo example:
aes256_demo(source bundle).
Test cert; PDF/A conflict; when the network is used
The source-bundle programs use the bundled samples/test_protected.pdf (open password asd) and
samples/ABC12.pfx test certificate — supply your own protected input and DSC in your project.
aes256_demo is fully offline; the .timestamp(...) / .ltv(true) variants above need outbound
network for the TSA / CRL fetch. Output encryption cannot be combined with
PDF/A — the standard forbids encryption, so .pdfa(…) and .encrypt(…) together
are rejected.