Encrypt, decrypt, and set PDF permissions

This guide shows you how to manage PDF passwords and access controls using the PDFluent SDK. It is for Rust developers who need to secure or modify existing PDF documents.

Add PDFluent to Cargo.toml

Encryption removal is part of the encryption feature.

toml
# Cargo.toml
[dependencies]
pdfluent = "1.0.0"

Encrypt a PDF with a password in Rust

Protect a PDF with a user password and an owner password. Choose AES-256 and configure fine-grained permission flags.

rust
use pdfluent::{PdfDocument, EncryptOptions};

fn main() -> pdfluent::Result<()> {
    let mut doc = PdfDocument::open("report.pdf")?;
    let opts = EncryptOptions::aes256()
        .with_user_password("open-sesame")
        .with_owner_password("owner-secret");
    doc.encrypt(opts)?;
    doc.save("report-encrypted.pdf")?;
    Ok(())
}

Complete program, compiled against the published crate: Code on GitHub →

The same code, typed and run on screen. Watch on YouTube

  1. Open the PDF

    Open the document you want to protect. Use a mutable binding.

    rust
    use pdfluent::prelude::*;
    
    let mut doc = PdfDocument::open("report.pdf")?;
  2. Choose the encryption algorithm

    EncryptOptions::aes256() uses AES-256, which is the current best practice. EncryptOptions::aes128() is accepted but the 1.0 backend currently always emits AES-256 state; if strict 128-bit output matters for interop, track this as a known deviation.

    rust
    let opts = EncryptOptions::aes256();
  3. Set user and owner passwords

    The user password is required to open the document. The owner password unlocks all permissions. If you omit with_user_password, the document opens without a password but still enforces permission flags.

    rust
    let opts = opts
        .with_user_password("open_document_2025")
        .with_owner_password("full_access_secret");
  4. Configure permissions

    Start from a preset (Permissions::full_access, print_only, read_only, or annotate) and opt out of individual rights with the with_*(false) builders: with_print, with_modify, with_copy, with_annotate, with_fill_forms, with_extract_accessibility, with_assemble, with_print_high_quality.

    rust
    let perms = Permissions::full_access()
        .with_modify(false)
        .with_copy(false);
    
    let opts = opts.with_permissions(perms);
  5. Encrypt and save

    Call encrypt() then save() to write the protected file. encrypt takes EncryptOptions by value (no reference).

    rust
    doc.encrypt(opts)?;
    doc.save("report_protected.pdf")?;
  • AES-256 requires PDF 1.7 or later. If you need compatibility with older readers, use EncryptOptions::aes128() — note that the 1.0 SDK currently emits AES-256 state regardless of the algorithm tag; strict AES-128 is tracked as a 1.1 follow-up.
  • The owner password controls the permission flags. Without it, even the software that created the PDF cannot bypass the restrictions.
  • Encryption does not compress the document. The file size stays roughly the same.
  • PDF/A documents must not be encrypted. Remove encryption before validating for PDF/A compliance.

Decrypt a password-protected PDF in Rust

Open an encrypted PDF with the user or owner password and save an unprotected copy. Works with RC4-128 and AES-128/256 encrypted files.

rust
use pdfluent::{PdfDocument, OpenOptions};

fn main() -> pdfluent::Result<()> {
    let mut doc = PdfDocument::open_with(
        "locked.pdf",
        OpenOptions::new().with_password("s3cret"),
    )?;
    doc.decrypt("s3cret")?;
    doc.save("decrypted.pdf")?;
    Ok(())
}
  1. Open the encrypted PDF

    Use PdfDocument::open_with() and provide the user or owner password. The method returns an error if the password is wrong.

    rust
    use pdfluent::{PdfDocument, OpenOptions};
    
    let mut doc = PdfDocument::open_with("protected.pdf", OpenOptions::new().with_password("open123"))?;
  2. Handle a wrong password

    Match on Error::WrongPassword to give the user a clear error instead of a generic failure.

    rust
    use pdfluent::{PdfDocument, OpenOptions};
    
    let result = PdfDocument::open_with("protected.pdf", OpenOptions::new().with_password("guess"));
    match result {
        Ok(doc) => { /* proceed */ }
        Err(_) => eprintln!("Could not open - wrong or missing password."),
    }
  3. Check the encryption details

    After opening, inspect the encryption type and permission flags that were set by the document author.

    rust
    // Strip the encryption so the saved copy opens without a password
    doc.decrypt("open123")?;
  4. Remove encryption

    Call decrypt(password) to strip all password protection and permission flags from the document in memory.

    rust
    doc.save("decrypted.pdf")?;
  5. Save the unprotected document

    Save to a new path. The saved file will open in any PDF reader without a password.

    rust
    // Verify by re-opening without a password
    let check = PdfDocument::open("decrypted.pdf")?;
    println!("Re-opened without a password: {} pages", check.page_count());
  • You can use the owner password to open the document even when the user password is different. The owner password grants full access regardless of permission flags.
  • After calling open_with(), all normal PDFluent operations work on the document. You do not need to remove encryption to extract text or render pages.
  • Some PDFs are encrypted but have no user password. They open without a password in readers but still have permission flags. open_with() with an empty string handles this case.

Add a user or owner password to a PDF in Rust

Protect a PDF with a password so readers must enter it to open the file, or set an owner password to restrict editing.

rust
use pdfluent::{PdfDocument, EncryptOptions};

fn main() -> pdfluent::Result<()> {
    let mut doc = PdfDocument::open("invoice.pdf")?;
    doc.encrypt(EncryptOptions::aes256().with_user_password("s3cret"))?;
    doc.save("invoice-protected.pdf")?;
    Ok(())
}
  1. Add PDFluent with encryption support

    The encryption feature includes AES-128 and AES-256 support.

    rust
    # Cargo.toml
    [dependencies]
    pdfluent = "1.0.0"
  2. Open the source document

    Open the PDF you want to protect. If it is already encrypted, open it with the current owner password first.

    rust
    use pdfluent::PdfDocument;
    
    let mut doc = PdfDocument::open("report.pdf")?;
  3. Configure AES-256 encryption

    The first argument to aes256() is the owner password. The second is the user password. Set the user password to an empty string to allow opening without a password while still restricting permissions.

    rust
    use pdfluent::EncryptOptions;
    
    // Both passwords set - readers must enter user-pw to open
    let opts = EncryptOptions::aes256().with_owner_password("owner-pw-123").with_user_password("user-pw-456");
    
    // Owner password only - file opens without a password, but editing is restricted
    let opts = EncryptOptions::aes256().with_owner_password("owner-pw-123").with_user_password("");
  4. Apply the encryption and save

    doc.encrypt() modifies the in-memory document. The protection is written to disk on save.

    rust
    doc.encrypt(opts)?;
    doc.save("report-protected.pdf")?;
    println!("Saved report-protected.pdf");
  5. Verify the password is set

    Re-open the saved file and confirm it requires a password.

    rust
    let result = PdfDocument::open("report-protected.pdf");
    match result {
        Err(_) => println!("Correct: file requires a password to open."),
        Ok(_) => println!("Warning: file opened without a password."),
    }
  • AES-256 is supported by all PDF readers released after 2010. For maximum compatibility with very old readers, use EncryptOptions::aes128 instead.
  • An empty user password means the PDF opens without a password prompt but is still encrypted. Permission flags are enforced by compliant readers.
  • Store the owner password securely. Without it, you cannot change or remove the encryption later. PDFluent cannot crack or bypass PDF encryption.
  • Password strength matters. A PDF with a short or common user password provides minimal protection against brute-force attacks.

Remove the password from a PDF you own in Rust

Decrypt a password-protected PDF and save a clean, unencrypted copy. Requires the owner password.

rust
use pdfluent::{PdfDocument, OpenOptions};

fn main() -> pdfluent::Result<()> {
    let mut doc = PdfDocument::open_with(
        "locked.pdf",
        OpenOptions::new().with_password("s3cret"),
    )?;
    doc.decrypt("s3cret")?;
    doc.save("unlocked.pdf")?;
    Ok(())
}
  1. Open the PDF with the owner password

    You need the owner password to remove encryption. The user password only grants read access. If you only have the user password, you cannot remove or modify the encryption.

    rust
    use pdfluent::{PdfDocument, OpenOptions};
    
    let mut doc = PdfDocument::open_with(
        "protected.pdf",
        OpenOptions::new().with_password("owner-pw-123"),
    )?;
  2. Handle the wrong password case

    open_with() returns Error::WrongPassword if the password is incorrect. Handle this in a pipeline to log failures without crashing.

    rust
    use pdfluent::{PdfDocument, OpenOptions};
    
    match PdfDocument::open_with("protected.pdf", OpenOptions::new().with_password("owner-pw-123")) {
        Ok(doc) => println!("Opened successfully"),
        Err(_) => eprintln!("Wrong or missing password."),
    }
  3. Remove encryption and save

    decrypt(password) strips all encryption dictionaries from the document. The saved file is a plain PDF with no password required.

    rust
    doc.decrypt("owner-pw-123")?;
    doc.save("unprotected.pdf")?;
    
    // Verify by opening without a password
    let _check = PdfDocument::open("unprotected.pdf")?;
    println!("Saved an unprotected copy.");
  4. Batch remove passwords from multiple PDFs

    Combine with a directory scan to decrypt a folder of PDFs at once.

    rust
    use std::fs;
    use pdfluent::{PdfDocument, OpenOptions};
    
    let password = "owner-pw-123";
    
    for entry in fs::read_dir("./encrypted")?.filter_map(|e| e.ok()) {
        let path = entry.path();
        if path.extension().map_or(false, |e| e == "pdf") {
            match PdfDocument::open_with(&path, OpenOptions::new().with_password(password)) {
                Ok(mut doc) => {
                    doc.decrypt(password)?;
                    let out = std::path::Path::new("./decrypted").join(path.file_name().unwrap());
                    doc.save(out)?;
                    println!("Decrypted: {}", path.display());
                }
                Err(_) => eprintln!("Could not open: {}", path.display()),
            }
        }
    }
  • You must have the owner password to remove encryption. PDFluent does not brute-force or crack passwords.
  • If a PDF only has an owner password (empty user password), the file opens without a password but is still encrypted. You still need the owner password to call decrypt(password).
  • Saving to the same file path as the input overwrites the original. Keep a backup of the original before running this operation.

Open a password-protected PDF in Rust

Pass a user or owner password through OpenOptions to decrypt a PDF at load time, then work with it like any other document.

rust
use pdfluent::{PdfDocument, OpenOptions};

fn main() -> pdfluent::Result<()> {
    let doc = PdfDocument::open_with(
        "locked.pdf",
        OpenOptions::new().with_password("s3cret"),
    )?;
    println!("{} pages", doc.page_count());
    Ok(())
}

Complete program, compiled against the published crate: Code on GitHub →

The same code, typed and run on screen. Watch on YouTube

  1. Provide the password via OpenOptions

    PdfDocument::open_with takes a path and an OpenOptions. Chain .with_password(...) to pre-provision the user or owner password. Owner passwords grant full access regardless of permissions.

    rust
    use pdfluent::prelude::*;
    
    let opts = OpenOptions::new().with_password("s3cret");
    let doc = PdfDocument::open_with("locked.pdf", opts)?;
  2. Handle a wrong password cleanly

    A wrong password returns Error::DecryptionFailed with reason WrongPassword. Match on the stable error code to prompt the user or fall back to a password-recovery flow.

    rust
    use pdfluent::prelude::*;
    
    match PdfDocument::open_with(
        "locked.pdf",
        OpenOptions::new().with_password("maybe_wrong"),
    ) {
        Ok(doc) => println!("opened with {} pages", doc.page_count()),
        Err(e) if e.code() == "E-SECURITY-DECRYPTION-FAILED" => {
            eprintln!("wrong password — try again");
        }
        Err(e) => return Err(e),
    }
  3. Read the password from a secret store

    Don't hard-code secrets. Read the password from your runtime's secret manager — environment variable, vault, or a config file loaded through your existing secret-management layer.

    rust
    use pdfluent::prelude::*;
    
    let pw = std::env::var("PDF_OPEN_PASSWORD")
        .expect("PDF_OPEN_PASSWORD env var not set");
    
    let doc = PdfDocument::open_with(
        "locked.pdf",
        OpenOptions::new().with_password(pw),
    )?;
  4. Open from bytes with a password

    If the PDF is already in memory (blob from a database, response from an API), use from_bytes_with with the same OpenOptions. No filesystem roundtrip required.

    rust
    use pdfluent::prelude::*;
    
    let bytes: Vec<u8> = fetch_from_backend()?;
    let doc = PdfDocument::from_bytes_with(
        &bytes,
        OpenOptions::new().with_password("s3cret"),
    )?;
  • The user password lets you view the document; the owner password additionally unlocks all permissions. PDFluent accepts either — the correct password opens the file.
  • A wrong password returns Error::DecryptionFailed { reason: DecryptionFailureReason::WrongPassword }. Match on .code() == "E-SECURITY-DECRYPTION-FAILED" for a stable check.
  • After opening, the document is fully decrypted in memory. Subsequent operations (text extraction, form fills, save) work normally. The saved output is unencrypted unless you re-encrypt with doc.encrypt(...).
  • PDFluent supports RC4-128, AES-128, and AES-256 encrypted files. Some older or very permissive documents have no password at all — opening them without OpenOptions works as usual.

Check whether a PDF is protected in Rust

1.0 does not report a document's permission bits. It answers whether the file is protected and whether your password opens it -- and it sets permissions when you write one.

rust
use pdfluent::error::DecryptionFailureReason;
use pdfluent::{Error, OpenOptions, PdfDocument};

fn main() -> pdfluent::Result<()> {
    // 1.0 does not report the permission bits of a document it opened. What it
    // does answer is whether the file is protected at all, and whether the
    // password you have is the one it wants.
    match PdfDocument::open("document.pdf") {
        Ok(doc) => println!("no password needed: {} pages", doc.page_count()),
        Err(Error::DecryptionFailed { reason, .. }) => {
            // Without a password there is only one answer worth giving, and the
            // library gives that one: PasswordRequired. WrongPassword can only
            // come back from an open that carried a password.
            println!("protected ({reason:?}); trying the one we have");
            match PdfDocument::open_with(
                "document.pdf",
                OpenOptions::new().with_password("user-password"),
            ) {
                Ok(doc) => println!("opened: {} pages", doc.page_count()),
                Err(Error::DecryptionFailed { reason, .. }) => match reason {
                    DecryptionFailureReason::WrongPassword => println!("that is not the password"),
                    other => println!("cannot open it: {other:?}"),
                },
                Err(e) => return Err(e),
            }
        }
        Err(e) => return Err(e),
    }

    Ok(())
}
  1. Find out whether the document is protected

    An encrypted document opened without a password fails with Error::DecryptionFailed and the reason PasswordRequired. That is deliberate: an open that offered no password has no typo to report, so the library does not say WrongPassword to someone who never gave one.

    rust
    use pdfluent::error::DecryptionFailureReason;
    use pdfluent::{Error, PdfDocument};
    
    match PdfDocument::open("document.pdf") {
        Ok(doc) => println!("open: {} pages", doc.page_count()),
        Err(Error::DecryptionFailed { reason, .. }) => match reason {
            DecryptionFailureReason::PasswordRequired => println!("a password is required"),
            other => println!("cannot decrypt: {other:?}"),
        },
        Err(e) => return Err(e),
    }
  2. Try the password you have, and read the answer

    Supply it through OpenOptions. This is the only shape in which WrongPassword can come back, so it is where a wrong candidate is told apart from a file that simply needs one. The user password is enough to read the document; the owner password is what you need to change how it is protected.

    rust
    use pdfluent::error::DecryptionFailureReason;
    use pdfluent::{Error, OpenOptions, PdfDocument};
    
    match PdfDocument::open_with(
        "protected.pdf",
        OpenOptions::new().with_password("user-password"),
    ) {
        Ok(doc) => println!("{} pages", doc.page_count()),
        Err(Error::DecryptionFailed { reason, .. }) => match reason {
            DecryptionFailureReason::WrongPassword => println!("wrong password"),
            other => println!("cannot open it: {other:?}"),
        },
        Err(e) => return Err(e),
    }
  3. Set the permissions you want on the way out

    Permissions are something you write, not something you read back: build them and hand them to encrypt(). Permissions::print_only, read_only, annotate and full_access are the presets, with_print and friends the fine control.

    rust
    use pdfluent::{EncryptOptions, Permissions};
    
    let mut doc = PdfDocument::open("document.pdf")?;
    doc.encrypt(
        EncryptOptions::aes256()
            .with_user_password("user-password")
            .with_owner_password("owner-password")
            .with_permissions(Permissions::print_only()),
    )?;
    doc.save("restricted.pdf")?;
  • There is no doc.with_permissions() reader in 1.0, and no permission flags on an opened document. with_permissions is a builder method on EncryptOptions -- it sets what a document allows, and this page shows it in that position.
  • PasswordRequired and WrongPassword ask different things of a caller, so the library keeps them apart: an open that carried no password can only produce the first, whatever the engine underneath reported.
  • Permission bits are a request to the viewer, not enforcement. Any tool with the file can ignore them; encryption is what actually keeps a reader out.
  • Accessibility extraction stays enabled in every preset, per ISO 32000-2: a spec-compliant reader gives assistive technology access whatever the bits say.
  • Some producers set permission bits without encrypting the file at all. Those bits are unprotected metadata; nothing about them is binding.

Set print, copy, and edit permissions on a PDF in Rust

Lock down what readers can do with your PDF. Restrict printing, copying text, editing, and form filling using the PDFluent SDK.

rust
use pdfluent::{PdfDocument, EncryptOptions, Permissions};

fn main() -> pdfluent::Result<()> {
    let mut doc = PdfDocument::open("report.pdf")?;
    let opts = EncryptOptions::aes256()
        .with_owner_password("owner-secret")
        .with_permissions(Permissions::print_only());
    doc.encrypt(opts)?;
    doc.save("report-restricted.pdf")?;
    Ok(())
}
  1. Open the source document

    Open the PDF you want to restrict. If it is already encrypted you must supply the owner password.

    rust
    let mut doc = PdfDocument::open("input.pdf")?;
    // Or, if already encrypted:
    // let mut doc = PdfDocument::open_with("input.pdf", OpenOptions::new().with_password("current-owner-pw"))?;
  2. Define the permission set

    Use the Permissions builder to choose what is allowed. All operations default to denied when you use the builder.

    rust
    use pdfluent::Permissions;
    
    let permissions = Permissions::full_access()
        .with_print(false)       // block all printing
        .with_print_high_quality(false)
        .with_copy(false)        // block text/image copying
        .with_modify(false)      // block page editing
        .with_annotate(false)    // block adding comments
        .with_fill_forms(true);  // allow form data entry
  3. Apply AES-256 encryption with the permissions

    Pair the permission set with an encryption config. The owner password lets you change permissions later. The user password is what readers enter to open the file.

    rust
    use pdfluent::EncryptOptions;
    
    let opts = EncryptOptions::aes256().with_owner_password("owner-secret").with_user_password("user-secret")
        .with_permissions(permissions);
    
    doc.encrypt(opts)?;
  4. Save the output file

    Write the encrypted PDF to disk. The original file is not modified.

    rust
    doc.save("locked.pdf")?;
    println!("Saved locked.pdf");
  • AES-256 encryption requires PDF 1.7 or higher. PDFluent upgrades the PDF version automatically if needed.
  • The owner password must differ from the user password, otherwise most PDF readers ignore the permission flags.
  • Permissions without encryption have no effect. PDF readers only enforce flags when the file is encrypted.
  • To remove permissions later, open the file with the owner password and call doc.decrypt(password).