Cifrar y descifrar PDFs en Python, Rust, Go
Cobertura por binding. El descifrado (abrir con contraseña) está disponible en los cinco bindings. Guardar un PDF nuevo ya cifrado se soporta en Python, Rust, Go (
DocumentEditor.SaveEncrypted) y WASM (saveEncryptedToBytes). La API pública de C# expone la apertura con contraseña mediantePdfDocument.OpenWithPassword, pero todavía no hay un wrapperSaveEncryptedpúblico — si necesitas generar PDFs cifrados desde una pipeline de C#, usa la CLI de Rust o los bindings de Go/Python.
Cifra un PDF con contraseña:
Python
from pdf_oxide import PdfDocument
doc = PdfDocument("report.pdf")
doc.save_encrypted("protected.pdf", "userpass", "ownerpass")
WASM
import { WasmPdfDocument } from "pdf-oxide-wasm";
const doc = new WasmPdfDocument(bytes);
const encrypted = doc.saveEncryptedToBytes("userpass", "ownerpass", true, true, true, true);
// encrypted is a Uint8Array
doc.free();
Rust
use pdf_oxide::api::Pdf;
let mut doc = Pdf::open("report.pdf")?;
doc.save_encrypted("protected.pdf", "userpass", "ownerpass")?;
Go
package main
import (
"log"
pdfoxide "github.com/yfedoseev/pdf_oxide/go"
)
func main() {
editor, err := pdfoxide.OpenEditor("report.pdf")
if err != nil { log.Fatal(err) }
defer editor.Close()
if err := editor.SaveEncrypted("protected.pdf", "userpass", "ownerpass"); err != nil {
log.Fatal(err)
}
}
C++
#include <pdf_oxide/pdf_oxide.hpp>
auto editor = pdf_oxide::DocumentEditor::open("report.pdf");
editor.save_encrypted("protected.pdf", "userpass", "ownerpass");
Swift
import PdfOxide
let editor = try DocumentEditor.open("report.pdf")
try editor.saveEncrypted("protected.pdf", userPassword: "userpass", ownerPassword: "ownerpass")
Dart
import 'package:pdf_oxide/pdf_oxide.dart';
final editor = DocumentEditor.open('report.pdf');
editor.saveEncrypted('protected.pdf', 'userpass', 'ownerpass');
editor.close();
R
library(pdfoxide)
editor <- pdf_editor_open("report.pdf")
pdf_editor_save_encrypted(editor, "protected.pdf", "userpass", "ownerpass")
pdf_editor_close(editor)
Julia
using PdfOxide
editor = open_editor("report.pdf")
save_encrypted(editor, "protected.pdf", "userpass", "ownerpass")
Zig
const pdf_oxide = @import("pdf_oxide");
var editor = try pdf_oxide.DocumentEditor.open("report.pdf");
defer editor.deinit();
try editor.saveEncrypted("protected.pdf", "userpass", "ownerpass");
Objective-C
#import "POXPdfOxide.h"
NSError *err = nil;
POXDocumentEditor *editor = [POXDocumentEditor openEditor:@"report.pdf" error:&err];
[editor saveEncryptedToPath:@"protected.pdf"
userPassword:@"userpass"
ownerPassword:@"ownerpass"
error:&err];
Elixir
{:ok, editor} = PdfOxide.open_editor("report.pdf")
:ok = PdfOxide.editor_save_encrypted(editor, "protected.pdf", "userpass", "ownerpass")
Abre un PDF cifrado:
Python
from pdf_oxide import PdfDocument
doc = PdfDocument("protected.pdf", password="userpass")
text = doc.extract_text(0)
print(text)
WASM
const doc = new WasmPdfDocument(encryptedBytes);
doc.authenticate("userpass");
const text = doc.extractText(0);
console.log(text);
doc.free();
Rust
let mut doc = Pdf::open_with_password("protected.pdf", "userpass")?;
let text = doc.extract_text(0)?;
println!("{}", text);
Go
doc, _ := pdfoxide.Open("protected.pdf")
defer doc.Close()
if _, err := doc.Authenticate("userpass"); err != nil { log.Fatal(err) }
text, _ := doc.ExtractText(0)
fmt.Println(text)
C#
using PdfOxide;
using var doc = PdfDocument.OpenWithPassword("protected.pdf", "userpass");
Console.WriteLine(doc.ExtractText(0));
C++
auto doc = pdf_oxide::Document::open_with_password("protected.pdf", "userpass");
auto text = doc.extract_text(0);
std::cout << text << "\n";
Swift
let doc = try Document.openWithPassword("protected.pdf", password: "userpass")
let text = try doc.extractText(0)
print(text)
Dart
final doc = PdfDocument.openWithPassword('protected.pdf', 'userpass');
final text = doc.extractText(0);
print(text);
R
doc <- pdf_open_with_password("protected.pdf", "userpass")
text <- pdf_extract_text(doc, 0)
cat(text)
Julia
doc = open_with_password("protected.pdf", "userpass")
text = extract_text(doc, 0)
println(text)
Zig
var doc = try pdf_oxide.Document.openWithPassword("protected.pdf", "userpass");
defer doc.deinit();
const text = try doc.extractText(a, 0);
defer a.free(text);
Objective-C
POXDocument *doc = [POXDocument openWithPassword:@"protected.pdf" password:@"userpass" error:&err];
NSString *text = [doc extractText:0 error:&err];
NSLog(@"%@", text);
Elixir
{:ok, doc} = PdfOxide.open_with_password("protected.pdf", "userpass")
{:ok, text} = PdfOxide.extract_text(doc, 0)
IO.puts(text)
PDF Oxide usa cifrado AES-256 de forma predeterminada. Licencia MIT, sin restricciones AGPL.
Instalación
pip install pdf_oxide
Cifrar PDFs
Cifrado básico
Python
from pdf_oxide import PdfDocument
doc = PdfDocument("input.pdf")
doc.save_encrypted("output.pdf", "user123", "owner456")
WASM
const doc = new WasmPdfDocument(bytes);
const encrypted = doc.saveEncryptedToBytes("user123", "owner456", true, true, true, true);
doc.free();
Rust
let mut doc = Pdf::open("input.pdf")?;
doc.save_encrypted("output.pdf", "user123", "owner456")?;
C++
auto editor = pdf_oxide::DocumentEditor::open("input.pdf");
editor.save_encrypted("output.pdf", "user123", "owner456");
Swift
let editor = try DocumentEditor.open("input.pdf")
try editor.saveEncrypted("output.pdf", userPassword: "user123", ownerPassword: "owner456")
Dart
final editor = DocumentEditor.open('input.pdf');
editor.saveEncrypted('output.pdf', 'user123', 'owner456');
editor.close();
R
editor <- pdf_editor_open("input.pdf")
pdf_editor_save_encrypted(editor, "output.pdf", "user123", "owner456")
pdf_editor_close(editor)
Julia
editor = open_editor("input.pdf")
save_encrypted(editor, "output.pdf", "user123", "owner456")
Zig
var editor = try pdf_oxide.DocumentEditor.open("input.pdf");
defer editor.deinit();
try editor.saveEncrypted("output.pdf", "user123", "owner456");
Objective-C
POXDocumentEditor *editor = [POXDocumentEditor openEditor:@"input.pdf" error:&err];
[editor saveEncryptedToPath:@"output.pdf"
userPassword:@"user123"
ownerPassword:@"owner456"
error:&err];
Elixir
{:ok, editor} = PdfOxide.open_editor("input.pdf")
:ok = PdfOxide.editor_save_encrypted(editor, "output.pdf", "user123", "owner456")
- Contraseña de usuario — requerida para abrir y ver el documento
- Contraseña de propietario — requerida para acceso completo (imprimir, copiar, modificar)
Solo contraseña de apertura
Define una contraseña de usuario sin restricciones adicionales:
doc = PdfDocument("input.pdf")
doc.save_encrypted("locked.pdf", "viewpass", "adminpass")
Sin contraseña de apertura, restringe acciones
Deja que cualquiera abra el documento, pero restringe la impresión y la copia:
Python
doc = PdfDocument("input.pdf")
doc.save_encrypted(
"restricted.pdf",
"", # No password to open
"adminpass", # Owner password for full access
allow_print=False,
allow_copy=False,
allow_modify=False,
allow_annotate=False,
)
WASM
const doc = new WasmPdfDocument(bytes);
const restricted = doc.saveEncryptedToBytes(
"", // No password to open
"adminpass", // Owner password for full access
false, // allowPrint
false, // allowCopy
false, // allowModify
false // allowAnnotate
);
doc.free();
Rust
let config = EncryptionConfig::new("", "adminpass")
.with_permissions(Permissions::none());
doc.save_with_encryption("restricted.pdf", config)?;
Solo impresión
Permite ver e imprimir, pero no copiar ni modificar:
Python
doc = PdfDocument("input.pdf")
doc.save_encrypted(
"print-only.pdf",
"",
"adminpass",
allow_print=True,
allow_copy=False,
allow_modify=False,
)
WASM
const doc = new WasmPdfDocument(bytes);
const printOnly = doc.saveEncryptedToBytes(
"", // No password to open
"adminpass",
true, // allowPrint
false, // allowCopy
false, // allowModify
true // allowAnnotate
);
doc.free();
Rust
let config = EncryptionConfig::new("", "adminpass")
.with_permissions(Permissions::print_only());
doc.save_with_encryption("print-only.pdf", config)?;
Opciones de permisos
| Parámetro | Predeterminado | Descripción |
|---|---|---|
allow_print |
True |
Permite imprimir el documento |
allow_copy |
True |
Permite copiar texto y gráficos |
allow_modify |
True |
Permite modificar el contenido |
allow_annotate |
True |
Permite agregar anotaciones |
Descifrar PDFs
Abrir con contraseña
Python
from pdf_oxide import PdfDocument
doc = PdfDocument("encrypted.pdf", password="secret")
text = doc.extract_text(0)
print(f"Pages: {doc.page_count()}")
WASM
const doc = new WasmPdfDocument(encryptedBytes);
doc.authenticate("secret");
const text = doc.extractText(0);
console.log(`Pages: ${doc.pageCount()}`);
doc.free();
Rust
let mut doc = Pdf::open_with_password("encrypted.pdf", "secret")?;
let text = doc.extract_text(0)?;
println!("Pages: {}", doc.page_count()?);
C++
auto doc = pdf_oxide::Document::open_with_password("encrypted.pdf", "secret");
auto text = doc.extract_text(0);
std::cout << "Pages: " << doc.page_count() << "\n";
Swift
let doc = try Document.openWithPassword("encrypted.pdf", password: "secret")
let text = try doc.extractText(0)
print("Pages: \(try doc.pageCount())")
Dart
final doc = PdfDocument.openWithPassword('encrypted.pdf', 'secret');
final text = doc.extractText(0);
print('Pages: ${doc.pageCount}');
R
doc <- pdf_open_with_password("encrypted.pdf", "secret")
text <- pdf_extract_text(doc, 0)
cat("Pages:", pdf_page_count(doc), "\n")
Julia
doc = open_with_password("encrypted.pdf", "secret")
text = extract_text(doc, 0)
println("Pages: ", page_count(doc))
Zig
var doc = try pdf_oxide.Document.openWithPassword("encrypted.pdf", "secret");
defer doc.deinit();
const text = try doc.extractText(a, 0);
defer a.free(text);
std.debug.print("Pages: {d}\n", .{try doc.pageCount()});
Objective-C
POXDocument *doc = [POXDocument openWithPassword:@"encrypted.pdf" password:@"secret" error:&err];
NSString *text = [doc extractText:0 error:&err];
NSLog(@"Pages: %ld", (long)[doc pageCountError:&err]);
Elixir
{:ok, doc} = PdfOxide.open_with_password("encrypted.pdf", "secret")
{:ok, text} = PdfOxide.extract_text(doc, 0)
{:ok, pages} = PdfOxide.page_count(doc)
IO.puts("Pages: #{pages}")
Guardar sin cifrado
Abre un PDF cifrado y guarda una copia sin cifrado:
Python
from pdf_oxide import PdfDocument
doc = PdfDocument("encrypted.pdf", password="secret")
doc.save("decrypted.pdf")
WASM
const doc = new WasmPdfDocument(encryptedBytes);
doc.authenticate("secret");
const decrypted = doc.save();
// decrypted is an unencrypted Uint8Array
doc.free();
Rust
let mut doc = Pdf::open_with_password("encrypted.pdf", "secret")?;
doc.save("decrypted.pdf")?;
Volver a cifrar con otra contraseña
Python
from pdf_oxide import PdfDocument
doc = PdfDocument("old-protected.pdf", password="oldpass")
doc.save_encrypted("new-protected.pdf", "newuser", "newowner")
WASM
const doc = new WasmPdfDocument(encryptedBytes);
doc.authenticate("oldpass");
const reEncrypted = doc.saveEncryptedToBytes("newuser", "newowner", true, true, true, true);
doc.free();
Rust
let mut doc = Pdf::open_with_password("old-protected.pdf", "oldpass")?;
doc.save_encrypted("new-protected.pdf", "newuser", "newowner")?;
Cifrado por lotes
Cifra todos los PDFs de un directorio:
from pdf_oxide import PdfDocument, PdfError
from pathlib import Path
input_dir = Path("reports/")
output_dir = Path("protected/")
output_dir.mkdir(exist_ok=True)
for pdf_path in input_dir.glob("*.pdf"):
try:
doc = PdfDocument(str(pdf_path))
out_path = output_dir / pdf_path.name
doc.save_encrypted(
str(out_path),
"company2025",
"admin2025",
allow_print=True,
allow_copy=False,
)
print(f"Encrypted: {pdf_path.name}")
except PdfError as e:
print(f"Failed: {pdf_path.name}: {e}")
Descifrado por lotes
Descifra todos los PDFs con una contraseña conocida:
from pdf_oxide import PdfDocument, PdfError
from pathlib import Path
input_dir = Path("protected/")
output_dir = Path("decrypted/")
output_dir.mkdir(exist_ok=True)
for pdf_path in input_dir.glob("*.pdf"):
try:
doc = PdfDocument(str(pdf_path), password="company2025")
out_path = output_dir / pdf_path.name
doc.save(str(out_path))
print(f"Decrypted: {pdf_path.name}")
except PdfError as e:
print(f"Failed: {pdf_path.name}: {e}")
Algoritmos compatibles
PDF Oxide admite todos los algoritmos estándar de cifrado de PDF:
| Algoritmo | Longitud de clave | Seguridad |
|---|---|---|
| AES-256 | 256 bits | La más fuerte (predeterminada) |
| AES-128 | 128 bits | Fuerte |
| RC4-128 | 128 bits | Heredado |
| RC4-40 | 40 bits | Débil (solo compatibilidad) |
save_encrypted() usa AES-256 de forma predeterminada. Si quieres elegir explícitamente el algoritmo, usa la API de Rust con EncryptionConfig.
¿Por qué no pdfplumber o pdfminer?
Ni pdfplumber ni pdfminer saben trabajar con PDFs cifrados:
- pdfplumber — lanza error con PDFs protegidos por contraseña. Sin soporte de descifrado.
- pdfminer — soporte de cifrado limitado; falla con archivos cifrados con AES-256.
- pypdf — permite descifrar, pero es 15× más lento que PDF Oxide para extraer texto después de descifrar.
Si necesitas procesar PDFs cifrados a gran escala, PDF Oxide cubre descifrado y cifrado de forma nativa con AES-128 y AES-256.
Páginas relacionadas
- API de cifrado y seguridad — referencia completa de la API de cifrado
- Procesamiento por lotes — patrones de procesamiento paralelo
- Primeros pasos con Python — instalación y conceptos básicos