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_passwordin Rust,authenticate()in WASM,Authenticateon Go/C#PdfDocument,OpenWithPasswordin C#). Producing encrypted output (save_encrypted/saveEncryptedToBytes) is exposed in Python, Rust, WASM, and Go (DocumentEditor.SaveEncrypted). The C#DocumentEditordoes not currently exposeSaveEncrypted— 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 |
Related Pages
- Editing Overview – opening, metadata, and save workflow
- Form Field Editing – restrict form editing with permissions
- Redaction – redact content before encrypting
- Page Operations – prepare pages before final encryption