Python, pypdfでPDFのパスワードを設定・解除(暗号化・復号)
Pythonのサードパーティライブラリpypdf(旧PyPDF2)を使うと、PDFファイルのパスワードの設定・解除(暗号化・復号)ができる。
- py-pdf/pypdf: A pure-python PDF library capable of splitting, merging, cropping, and transforming the pages of PDF files
- Encryption and Decryption of PDFs — pypdf 5.5.0 documentation
既存のPDFファイルにパスワードを設定したり、暗号化されたPDFファイルをパスワードなしで保存したりできる。あくまでも既知のパスワードを使って解除するだけで、パスワードが分からない場合は解除できない。
サンプルで使用しているPDFファイルは以下のリンクから。暗号化されているファイルのパスワードはすべてpassword
。
すべてのPDFファイルに対して動作を保証するものではない。
pypdfのインストール
pypdfは外部ライブラリに依存しておらず、pip
(pip3
)でインストール可能。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にパスワードを設定して保存できる。
- 元のPDFファイルから
PdfReader
オブジェクトを生成 - 中身をコピーした
PdfWriter
オブジェクトを生成(clone_from
引数を使用) PdfWriter
オブジェクトにパスワードを設定PdfWriter
オブジェクトをPDFファイルとして保存
PdfReader
とPdfWriter
をそれぞれ生成する。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 usingAES-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')