How to Protect PDFs with Passwords and Encryption in Python
Encrypting PDF files with a password ensures that only authorized people can read or modify them. Python provides three main tools: pypdf (native, no external dependencies), pikepdf (binding for qpdf, more powerful), and the command-line tool qpdf. This guide covers AES-256 encryption, permission control, and password removal.
Types of PDF Protection
| Type | Description |
|---|---|
| User password | Required to open the PDF |
| Owner password | Controls permissions: print, copy, edit |
| RC4-128 | Obsolete, Acrobat 5+ compatible |
| AES-128 | Acrobat 7+, acceptable |
| AES-256 | Acrobat X+, recommended standard |
Installation
pip install pypdf pikepdf
# On Linux, pikepdf requires:
apt-get install libqpdf-dev
Encrypting PDFs with pypdf
from pypdf import PdfReader, PdfWriter
def encrypt_pdf(input_path, output_path, user_password, owner_password=None):
"""
Add password protection to a PDF.
owner_password: if None, uses the same as user_password
"""
reader = PdfReader(input_path)
writer = PdfWriter()
for page in reader.pages:
writer.add_page(page)
if reader.metadata:
writer.add_metadata(reader.metadata)
owner = owner_password or user_password
writer.encrypt(
user_password=user_password,
owner_password=owner,
use_128bit=False, # False = AES-256 in pypdf >= 3.x
permissions_flag=0
)
with open(output_path, "wb") as f:
writer.write(f)
print(f"Encrypted PDF saved: {output_path}")
encrypt_pdf(
"confidential_report.pdf",
"protected_report.pdf",
user_password="read_only_123",
owner_password="owner_master_XYZ"
)
Permission Control with pypdf
from pypdf import PdfReader, PdfWriter
from pypdf.constants import UserAccessPermissions
def encrypt_with_permissions(input_path, output_path,
user_pwd, owner_pwd,
allow_print=True,
allow_copy=False,
allow_edit=False,
allow_annotate=True):
reader = PdfReader(input_path)
writer = PdfWriter()
for page in reader.pages:
writer.add_page(page)
perms = 0
if allow_print:
perms |= UserAccessPermissions.PRINT
perms |= UserAccessPermissions.PRINT_HIGH_QUALITY
if allow_copy:
perms |= UserAccessPermissions.EXTRACT
perms |= UserAccessPermissions.EXTRACT_TEXT_AND_GRAPHICS
if allow_edit:
perms |= UserAccessPermissions.MODIFY
if allow_annotate:
perms |= UserAccessPermissions.ADD_OR_MODIFY
writer.encrypt(
user_password=user_pwd,
owner_password=owner_pwd,
permissions_flag=perms
)
with open(output_path, "wb") as f:
writer.write(f)
print(f"Protected: print={allow_print}, copy={allow_copy}, edit={allow_edit}")
encrypt_with_permissions(
"contract.pdf",
"contract_protected.pdf",
user_pwd="view_contract",
owner_pwd="admin_owner_2026",
allow_print=True,
allow_copy=False,
allow_edit=False
)
Encrypting with pikepdf (Native AES-256)
import pikepdf
def encrypt_pdf_pikepdf(input_path, output_path, user_pwd, owner_pwd=None):
"""Encrypt with AES-256 using pikepdf."""
owner = owner_pwd or user_pwd
with pikepdf.open(input_path) as pdf:
perms = pikepdf.Permissions(
accessibility=True,
extract=False,
modify_annotation=True,
modify_assembly=False,
modify_form=False,
modify_other=False,
print_lowres=True,
print_highres=True,
)
encryption = pikepdf.Encryption(
owner=owner,
user=user_pwd,
R=6, # R=6 → AES-256 (PDF 2.0)
allow=perms
)
pdf.save(output_path, encryption=encryption)
print(f"Saved with AES-256: {output_path}")
encrypt_pdf_pikepdf(
"document.pdf",
"document_aes256.pdf",
user_pwd="secure_access_2026",
owner_pwd="master_owner_XYZ"
)
Removing PDF Password
If you know the password, create an unencrypted version:
from pypdf import PdfReader, PdfWriter
def remove_password(input_path, password, output_path):
reader = PdfReader(input_path)
if reader.is_encrypted:
result = reader.decrypt(password)
if result == 0:
print("ERROR: Incorrect password")
return False
print(f"PDF unlocked (permissions level: {result})")
else:
print("PDF is not encrypted")
writer = PdfWriter()
for page in reader.pages:
writer.add_page(page)
with open(output_path, "wb") as f:
writer.write(f)
print(f"Password-free PDF: {output_path}")
return True
remove_password("protected_doc.pdf", "my_password", "unlocked_doc.pdf")
Using pikepdf to Decrypt
import pikepdf
def decrypt_pdf_pikepdf(input_path, password, output_path):
try:
with pikepdf.open(input_path, password=password) as pdf:
pdf.save(output_path)
print(f"Decrypted: {output_path}")
return True
except pikepdf.PasswordError:
print("ERROR: Incorrect password")
return False
Checking Encryption Status
from pypdf import PdfReader
def inspect_pdf(path):
reader = PdfReader(path)
print(f"File: {path}")
print(f"Encrypted: {reader.is_encrypted}")
if reader.is_encrypted:
level = reader.decrypt("")
if level > 0:
print(f" Accessible without user password (level: {level})")
else:
print(f" Requires user password")
meta = reader.metadata
if meta and not reader.is_encrypted:
print(f"Pages: {len(reader.pages)}")
print(f"Title: {meta.get('/Title', 'N/A')}")
print(f"Author: {meta.get('/Author', 'N/A')}")
print(f"Creator: {meta.get('/Creator', 'N/A')}")
inspect_pdf("mystery_document.pdf")
Batch Encryption
from pypdf import PdfReader, PdfWriter
from pathlib import Path
import json
def batch_encrypt(input_folder, output_folder, user_password, owner_password=None):
input_folder = Path(input_folder)
output_folder = Path(output_folder)
output_folder.mkdir(exist_ok=True)
pdfs = list(input_folder.glob("*.pdf"))
print(f"Encrypting {len(pdfs)} PDFs...")
log = {}
for pdf_path in pdfs:
out = output_folder / pdf_path.name
try:
reader = PdfReader(str(pdf_path))
writer = PdfWriter()
for page in reader.pages:
writer.add_page(page)
writer.encrypt(user_password, owner_password)
with open(out, "wb") as f:
writer.write(f)
log[pdf_path.name] = "OK"
print(f" ✓ {pdf_path.name}")
except Exception as e:
log[pdf_path.name] = f"ERROR: {e}"
print(f" ✗ {pdf_path.name}: {e}")
with open(output_folder / "encryption_log.json", "w") as f:
json.dump(log, f, indent=2)
success = sum(1 for v in log.values() if v == "OK")
print(f"\nDone: {success}/{len(pdfs)} PDFs encrypted")
batch_encrypt("documents/", "encrypted_documents/", "company_password_2026")
Adding a Security Watermark
from pypdf import PdfReader, PdfWriter
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter
import io
def create_watermark(text="CONFIDENTIAL", opacity=0.15):
packet = io.BytesIO()
c = canvas.Canvas(packet, pagesize=letter)
width, height = letter
c.saveState()
c.setFillColorRGB(0.8, 0, 0, opacity)
c.setFont("Helvetica-Bold", 60)
c.translate(width / 2, height / 2)
c.rotate(45)
text_width = c.stringWidth(text, "Helvetica-Bold", 60)
c.drawString(-text_width / 2, 0, text)
c.restoreState()
c.save()
packet.seek(0)
return PdfReader(packet)
def apply_watermark(input_path, output_path, text="CONFIDENTIAL"):
watermark = create_watermark(text)
reader = PdfReader(input_path)
writer = PdfWriter()
for page in reader.pages:
page.merge_page(watermark.pages[0])
writer.add_page(page)
# Also encrypt
writer.encrypt("view_only", "admin_owner")
with open(output_path, "wb") as f:
writer.write(f)
print(f"Watermarked and encrypted: {output_path}")
apply_watermark("report.pdf", "confidential_report.pdf", "READ ONLY")
Additional Resource
For converting PDFs to Word, images, text and other formats without any coding, use KaijuConverter — free and no registration required.
Related conversions
Document conversions that follow this topic naturally: