Skip to content

Python, Rust, Go에서 PDF 암호화 및 복호화하기

바인딩 지원 현황. 암호화된 PDF 열기(복호화)는 다섯 개 바인딩 모두에서 지원합니다. 새 PDF를 암호화해 저장하는 기능은 Python, Rust, Go(DocumentEditor.SaveEncrypted), WASM(saveEncryptedToBytes)에서 사용할 수 있습니다. C# 공개 API는 PdfDocument.OpenWithPassword로 비밀번호 기반 열기를 제공하지만, SaveEncrypted 공개 래퍼는 아직 노출되지 않았습니다. C# 파이프라인에서 암호화된 결과를 만들어야 한다면 Rust CLI나 Go/Python 바인딩을 사용하세요.

비밀번호로 PDF를 암호화합니다:

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")

암호화된 PDF를 엽니다:

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는 기본적으로 AES-256 암호화를 사용합니다. MIT 라이선스이며 AGPL 제약이 없습니다.

설치

pip install pdf_oxide

PDF 암호화

기본 암호화

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")
  • 사용자 비밀번호 — 문서를 열고 보는 데 필요
  • 소유자 비밀번호 — 전체 권한(인쇄, 복사, 수정)에 필요

열기 비밀번호만 설정

제한 없이 사용자 비밀번호만 설정합니다:

doc = PdfDocument("input.pdf")
doc.save_encrypted("locked.pdf", "viewpass", "adminpass")

열기 비밀번호 없이 동작 제한

누구나 열어볼 수는 있지만 인쇄와 복사를 제한합니다:

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)?;

인쇄만 허용

열람과 인쇄는 허용하되 복사와 수정은 막습니다:

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)?;

권한 옵션

매개변수 기본값 설명
allow_print True 문서 인쇄 허용
allow_copy True 텍스트·그래픽 복사 허용
allow_modify True 콘텐츠 수정 허용
allow_annotate True 주석 추가 허용

PDF 복호화

비밀번호로 열기

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}")

암호화 없이 저장

암호화된 PDF를 열어 암호화되지 않은 사본으로 저장합니다:

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")?;

다른 비밀번호로 재암호화

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")?;

일괄 암호화

디렉터리 내의 모든 PDF를 암호화합니다:

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}")

일괄 복호화

알고 있는 비밀번호로 모든 PDF를 복호화합니다:

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}")

지원 알고리즘

PDF Oxide는 모든 표준 PDF 암호화 알고리즘을 지원합니다:

알고리즘 키 길이 보안 수준
AES-256 256비트 가장 강력(기본값)
AES-128 128비트 강력
RC4-128 128비트 레거시
RC4-40 40비트 약함(호환 목적만 권장)

save_encrypted()는 기본적으로 AES-256을 사용합니다. 알고리즘을 명시적으로 지정하려면 Rust API의 EncryptionConfig를 사용하세요.

pdfplumber나 pdfminer가 안 되는 이유

pdfplumber와 pdfminer는 암호화된 PDF를 처리하지 못합니다:

  • pdfplumber — 비밀번호가 걸린 PDF에서 에러를 냅니다. 복호화 기능이 없습니다.
  • pdfminer — 암호화 지원이 제한적이며 AES-256 파일에서는 실패합니다.
  • pypdf — 복호화는 지원하지만, 복호화 후 텍스트 추출이 PDF Oxide보다 15배 느립니다.

대규모로 암호화된 PDF를 처리해야 한다면, PDF Oxide는 AES-128과 AES-256에서 복호화와 암호화를 네이티브로 모두 처리합니다.

관련 페이지