Skip to content

Encryption & Security

PDF Oxide supports encrypting PDFs with passwords and permissions using industry-standard algorithms. You can set a user password (required to open the document), an owner password (required for full access), and fine-grained permissions controlling printing, copying, and modification.

Binding coverage. Opening encrypted PDFs works across all bindings (password= in Python, PdfDocument.open_with_password in Rust, authenticate() in WASM, Authenticate on Go/C# PdfDocument, OpenWithPassword in C#). Producing encrypted output (save_encrypted / saveEncryptedToBytes) is exposed in Python, Rust, WASM, and Go (DocumentEditor.SaveEncrypted). The C# DocumentEditor does not currently expose SaveEncrypted — use the Rust CLI (pdf-oxide encrypt) or a Go/Python step to produce encrypted output from a C# workflow.

Algorithm support

Algorithm Read Write Notes
RC4 (40/128-bit) Yes Yes Legacy; use only for compatibility
AES-128 (V=4, R=4) Yes Yes PDF 1.6+ default
AES-256 (V=5, R=6) Yes Yes PDF 2.0; includes uncompressed-object string decryption, push-button widget /MK /CA captions, and correct Algorithm 2.B termination

AES-256 coverage is full end-to-end: opening, authenticating, reading form values, and saving encrypted output. ObjStm / XRef streams are not encrypted per ISO 32000-2 §7.6.3. The object cache is correctly invalidated after a late authenticate() call so any content read before authentication is re-parsed with the right key.

Quick Start: Save with Encryption

Python

from pdf_oxide import PdfDocument

doc = PdfDocument("input.pdf")
doc.set_title("Confidential Report")

# Encrypt with user and owner passwords
doc.save_encrypted("protected.pdf", "user123", "owner456")

WASM

import { WasmPdfDocument } from "pdf-oxide-wasm";

const doc = new WasmPdfDocument(bytes);
doc.setTitle("Confidential Report");

// Encrypt with user and owner passwords (all permissions enabled)
const output = doc.saveEncryptedToBytes(
  "user123", "owner456", true, true, true, true
);
doc.free();

Rust

use pdf_oxide::api::Pdf;

let mut doc = Pdf::open("input.pdf")?;

// Simple encryption with user and owner passwords
doc.save_encrypted("protected.pdf", "user123", "owner456")?;

Go

package main

import (
    "log"
    pdfoxide "github.com/yfedoseev/pdf_oxide/go"
)

func main() {
    editor, err := pdfoxide.OpenEditor("input.pdf")
    if err != nil { log.Fatal(err) }
    defer editor.Close()

    _ = editor.SetTitle("Confidential Report")

    // Encrypt with user and owner passwords (AES-256)
    if err := editor.SaveEncrypted("protected.pdf", "user123", "owner456"); err != nil {
        log.Fatal(err)
    }
}

Encryption with Custom Permissions

Python

The save_encrypted method accepts permission flags as keyword arguments.

from pdf_oxide import PdfDocument

doc = PdfDocument("input.pdf")

# View-only: no printing, copying, or modifying
doc.save_encrypted(
    "readonly.pdf",
    "viewpass",
    "adminpass",
    allow_print=False,
    allow_copy=False,
    allow_modify=False,
    allow_annotate=False,
)

# Allow only printing
doc.save_encrypted(
    "print-only.pdf",
    "",            # No open password required
    "adminpass",
    allow_print=True,
    allow_copy=False,
    allow_modify=False,
    allow_annotate=False,
)

Python save_encrypted Parameters

Parameter Type Default Description
path str required Output file path
user_password str required Password to open (empty = no open password)
owner_password str None Full-access password (defaults to user password)
allow_print bool True Allow printing
allow_copy bool True Allow copying text/graphics
allow_modify bool True Allow modifying the document
allow_annotate bool True Allow adding annotations

WASM

import { WasmPdfDocument } from "pdf-oxide-wasm";

const doc = new WasmPdfDocument(bytes);

// View-only: no printing, copying, or modifying
const readonly = doc.saveEncryptedToBytes(
  "viewpass", "adminpass", false, false, false, false
);

// Allow only printing (empty user password = no open password)
const printOnly = doc.saveEncryptedToBytes(
  "", "adminpass", true, false, false, false
);
doc.free();

Rust

For complete control over encryption settings, use EncryptionConfig and SaveOptions.

use pdf_oxide::api::Pdf;
use pdf_oxide::editor::{
    EncryptionConfig, EncryptionAlgorithm, Permissions, SaveOptions,
};

let mut doc = Pdf::open("input.pdf")?;

// Build permissions
let mut perms = Permissions::read_only();
perms.print = true;  // Allow printing only

// Build encryption config
let config = EncryptionConfig::new("user123", "owner456")
    .with_algorithm(EncryptionAlgorithm::Aes256)
    .with_permissions(perms);

// Save with encryption
doc.save_with_encryption("protected.pdf", config)?;

EncryptionConfig

The EncryptionConfig struct controls all encryption parameters.

use pdf_oxide::editor::{EncryptionConfig, EncryptionAlgorithm, Permissions};

let config = EncryptionConfig {
    user_password: "user123".to_string(),
    owner_password: "owner456".to_string(),
    algorithm: EncryptionAlgorithm::Aes256,
    permissions: Permissions::all(),
};

Or use the builder pattern:

let config = EncryptionConfig::new("user123", "owner456")
    .with_algorithm(EncryptionAlgorithm::Aes128)
    .with_permissions(Permissions::read_only());

EncryptionConfig Fields

Field Type Description
user_password String Password required to open the document
owner_password String Password for full access and changing security
algorithm EncryptionAlgorithm Encryption algorithm to use
permissions Permissions Access control flags

Encryption Algorithms

Algorithm Description
EncryptionAlgorithm::Aes256 AES-256 (strongest, recommended)
EncryptionAlgorithm::Aes128 AES-128
EncryptionAlgorithm::Rc4_128 RC4 128-bit (legacy compatibility)
EncryptionAlgorithm::Rc4_40 RC4 40-bit (legacy, weak)

AES-256 is the default when using save_encrypted() in Python or the Pdf API.

Permissions

The Permissions struct controls what operations are allowed when a document is opened with the user password.

use pdf_oxide::editor::Permissions;

// Allow everything
let all = Permissions::all();

// Restrict everything
let readonly = Permissions::read_only();

Permissions Fields

Field Type Default (all) Default (read_only) Description
print bool true false Allow printing
print_high_quality bool true false Allow high-quality printing
modify bool true false Allow modifying content
copy bool true false Allow copying text/graphics
annotate bool true false Allow adding annotations
fill_forms bool true false Allow filling form fields
accessibility bool true true Allow accessibility extraction
assemble bool true false Allow page assembly operations

Custom Permissions

let mut perms = Permissions::read_only();
perms.print = true;          // Allow printing
perms.fill_forms = true;     // Allow filling forms
perms.accessibility = true;  // Always allow for compliance

SaveOptions

Use SaveOptions for full control over how the document is written.

use pdf_oxide::editor::{SaveOptions, EncryptionConfig};

// Full rewrite (default)
let opts = SaveOptions::full_rewrite();

// Incremental update (faster, preserves structure)
let opts = SaveOptions::incremental();

// With encryption
let config = EncryptionConfig::new("user", "owner");
let opts = SaveOptions::with_encryption(config);

Opening Encrypted PDFs

Python

Pass the password when opening the document.

from pdf_oxide import PdfDocument

doc = PdfDocument("protected.pdf", password="user123")
text = doc.extract_text(0)
print(text)

Rust

use pdf_oxide::PdfDocument;

let doc = PdfDocument::open_with_password("protected.pdf", "user123")?;
let text = doc.extract_text(0)?;
println!("{}", text);

Go

doc, _ := pdfoxide.Open("protected.pdf")
defer doc.Close()
if _, err := doc.Authenticate("user123"); err != nil { log.Fatal(err) }
text, _ := doc.ExtractText(0)
fmt.Println(text)

C#

using var doc = PdfDocument.OpenWithPassword("protected.pdf", "user123");
Console.WriteLine(doc.ExtractText(0));

Complete Encryption Workflow

Python

from pdf_oxide import PdfDocument

# Open and modify
doc = PdfDocument("report.pdf")
doc.set_title("Confidential Report")
doc.set_author("Finance Team")

# Save with view-only restrictions
doc.save_encrypted(
    "report-protected.pdf",
    "",            # No password to open
    "admin2025",   # Owner password for full access
    allow_print=True,
    allow_copy=False,
    allow_modify=False,
)

WASM

import { WasmPdfDocument } from "pdf-oxide-wasm";

const doc = new WasmPdfDocument(bytes);
doc.setTitle("Confidential Report");
doc.setAuthor("Finance Team");

// Save with view-only restrictions (no open password, print allowed)
const output = doc.saveEncryptedToBytes(
  "", "admin2025", true, false, false, false
);
doc.free();

Rust

use pdf_oxide::api::Pdf;
use pdf_oxide::editor::{
    DocumentEditor, EditableDocument,
    EncryptionConfig, EncryptionAlgorithm, Permissions, SaveOptions,
};

// Open and modify
let mut doc = Pdf::open("report.pdf")?;
{
    let editor = doc.editor().unwrap();
    editor.set_title("Confidential Report");
    editor.set_author("Finance Team");
}

// Configure encryption
let permissions = Permissions {
    print: true,
    print_high_quality: true,
    modify: false,
    copy: false,
    annotate: false,
    fill_forms: true,
    accessibility: true,
    assemble: false,
};

let config = EncryptionConfig::new("", "admin2025")
    .with_algorithm(EncryptionAlgorithm::Aes256)
    .with_permissions(permissions);

doc.save_with_encryption("report-protected.pdf", config)?;

Re-encrypt with Different Settings

Rust

use pdf_oxide::editor::{DocumentEditor, EditableDocument, EncryptionConfig, SaveOptions};

// Open with current password
let mut editor = DocumentEditor::open("old-protected.pdf")?;

// Save with new encryption
let config = EncryptionConfig::new("newuser", "newowner");
let options = SaveOptions::with_encryption(config);
editor.save_with_options("re-encrypted.pdf", options)?;

Full API Reference

Pdf Methods

Method Returns Description
save_encrypted(path, user_pw, owner_pw) Result<()> Save with AES-256 and full permissions
save_with_encryption(path, config) Result<()> Save with custom encryption config

DocumentEditor / EditableDocument Methods

Method Returns Description
save(path) Result<()> Save with full rewrite (no encryption)
save_with_options(path, options) Result<()> Save with custom options

Configuration Types

Type Description
EncryptionConfig User/owner passwords, algorithm, permissions
EncryptionAlgorithm Aes256, Aes128, Rc4_128, Rc4_40
Permissions Fine-grained access control flags
SaveOptions Full rewrite, incremental, or encrypted save