Mudrit
Cookbook

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

RecipeWhat it showsFeature
sign_protectedSign a password-protected input (PdfReader::open(…).password(…))pfx
encrypt_outputProtect the output: new / owner / keep_passwordpfx
aes256_demoAES-256 (V5/R6) encrypted signed outputpfx

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 password

Repo 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.

Next

On this page