Python, pypdfでPDFのパスワードを設定・解除(暗号化・復号)

Modified: | Tags: Python, PDF

Pythonのサードパーティライブラリpypdf(旧PyPDF2)を使うと、PDFファイルのパスワードの設定・解除(暗号化・復号)ができる。

既存のPDFファイルにパスワードを設定したり、暗号化されたPDFファイルをパスワードなしで保存したりできる。あくまでも既知のパスワードを使って解除するだけで、パスワードが分からない場合は解除できない。

サンプルで使用しているPDFファイルは以下のリンクから。暗号化されているファイルのパスワードはすべてpassword

すべてのPDFファイルに対して動作を保証するものではない。

pypdfのインストール

pypdfは外部ライブラリに依存しておらず、pippip3)でインストール可能。AES方式の暗号化・復号を利用する場合はpypdf[crypto]とする。

$ pip install pypdf
$ pip install pypdf[crypto]

以下のサンプルコードで使用しているpypdfのバージョンは5.5.0

以前はPyPDF2という名前だったが、2023年にpypdfに改められた。

pypdfが対応する暗号化アルゴリズム

Adobe AcrobatでPDFファイルにパスワードを設定する場合、以下の暗号化アルゴリズム(暗号化レベル)を選択できる。

Acrobat 6.0 およびそれ以降」(PDF 1.5)を選択すると、128-bit RC4 を使用して文書が暗号化されます。
Acrobat 7.0 およびそれ以降」(PDF 1.6)を選択すると、128-bit キーサイズの AES 暗号化アルゴリズムを使用して文書が暗号化されます。
Acrobat X およびそれ以降」(PDF 1.7)を選択すると、256-bit AES を使用して文書が暗号化されます。Acrobat 8 および 9 で作成した文書に 256-bit AES 暗号化を適用するには、「Acrobat X およびそれ以降」を選択します。
パスワードによる PDF の保護 - Adobe Acrobat

pypdfではバージョン5.5.0時点でRC4およびAESでの暗号化・復号に対応している。

PDF encryption makes use of RC4 and AES algorithms with different key length. pypdf supports all of them until PDF-2.0, which is the latest PDF standard. Encryption and Decryption of PDFs — pypdf 5.5.0 documentation

PDFファイルが暗号化されているか確認

PdfReaderオブジェクトのis_encrypted属性で、PDFファイルが暗号化されているかどうかを確認できる。

import pypdf

print(pypdf.__version__)
# 5.5.0

pdf = pypdf.PdfReader('data/src/pdf/sample1.pdf')
print(pdf.is_encrypted)
# False

PDFファイルにパスワードを設定して保存

以下の手順でパスワードなしのPDFにパスワードを設定して保存できる。

  1. 元のPDFファイルからPdfReaderオブジェクトを生成
  2. 中身をコピーしたPdfWriterオブジェクトを生成(clone_from引数を使用)
  3. PdfWriterオブジェクトにパスワードを設定
  4. PdfWriterオブジェクトをPDFファイルとして保存

PdfReaderPdfWriterをそれぞれ生成する。PdfWriter()clone_from引数を使用するとドキュメントの内容をコピーできる。

src_pdf = pypdf.PdfReader('data/src/pdf/sample1.pdf')
dst_pdf = pypdf.PdfWriter(clone_from=src_pdf)

encrypt()メソッドで暗号化する。

第一引数user_pwdでユーザーパスワード、第二引数owner_pwdでオーナーパスワード(権限パスワード)を設定する。第二引数を省略するとオーナーパスワードも第一引数のユーザーパスワードと同じになる。

さらにalgorithm引数で暗号化アルゴリズムを指定できる。バージョン5.5.0時点ではAES-256-R5が推奨されている。

The algorithm can be one of RC4-40, RC4-128, AES-128, AES-256-R5, AES-256. We recommend using AES-256-R5. Encryption and Decryption of PDFs — pypdf 5.5.0 documentation

最後にwrite()メソッドでPdfWriterオブジェクトをpdfファイルとして保存する。

dst_pdf.encrypt('pass_user', 'pass_owner', algorithm='AES-256-R5')
dst_pdf.write('data/temp/sample1_pass.pdf')

PDFファイルのパスワードを解除(削除・変更)して保存

パスワード付きのPDFファイルのパスワードを削除したり変更したりして保存するのも、上述のパスワードの設定とほぼ同じ手順。パスワードを解除するステップが増える。

暗号化されたPDFファイルから生成したPdfReaderオブジェクトをPdfWriter()clone_from引数に指定するとエラーになる。

pdf_pass = pypdf.PdfReader('data/temp/sample1_pass.pdf')
print(pdf_pass.is_encrypted)
# True

# dst_pdf = pypdf.PdfWriter(clone_from=pdf_pass)
# FileNotDecryptedError: File has not been decrypted

パスワードの解除にはdecrypt()メソッドを使う。パスワードが一致しない場合は0、ユーザーパスワードに一致した場合は1、オーナーパスワードに一致した場合は2を返す。

print(pdf_pass.decrypt('wrong-password'))
# 0

print(pdf_pass.decrypt('pass_user'))
# 1

print(pdf_pass.decrypt('pass_owner'))
# 2

パスワードを解除した後は、clone_from引数に指定でき、write()で保存すればパスワードなしのPDFファイルになる。

dst_pdf = pypdf.PdfWriter(clone_from=pdf_pass)
dst_pdf.write('data/temp/sample1_no_pass.pdf')

パスワードを変更したい場合はencrypt()で新たなパスワードを設定してから保存する。

dst_pdf = pypdf.PdfWriter(clone_from=pdf_pass)
dst_pdf.encrypt('new_pass_user', 'new_pass_owner', algorithm='AES-256-R5')
dst_pdf.write('data/temp/sample1_new_pass.pdf')

関連カテゴリー

関連記事