【Python】Python 〜 python-gnupg 〜

◾️はじめに

Pythonでのファイル暗号化・復号化のためのライブラリ
python-gnupg について扱う

目次

【1】前提知識:GnuPG
【2】python-gnupg
 1)インストール
【3】サンプル
 例1:キー生成・暗号化・復号化
 例2:署名・検証(sign / verify)
 例3:公開鍵・秘密鍵のエクスポート/インポート
 例4:公開鍵による暗号化・復号化

【1】前提知識:GnuPG

* GnuPG(グヌー・ピー・ジー) = GNU Privacy Guard
* オープンソースの暗号化ツール

【2】python-gnupg

* Pythonから GnuPGを利用するためのラッパーライブラリ

1)インストール

Step1: GnuPG のインストール

# Macの場合
brew install gnupg

gpg --version

Step2: ライブラリのインストール

pip install python-gnupg

【3】サンプル

例1:キー生成・暗号化・復号化

import os
import gnupg


# --- 設定 ---
os.makedirs('./gpg_home', exist_ok=True)
gpg = gnupg.GPG(gnupghome='./gpg_home')


# --- 鍵ペアを作成 ---
input_data = gpg.gen_key_input(
    name_email='test@example.com',
    passphrase='testpass'
)
key = gpg.gen_key(input_data)
print("✅ 鍵ペアを作成しました:", key.fingerprint)

# --- テスト用ファイル作成 ---
with open('secret.txt', 'w') as f:
    f.write('これは秘密のメッセージです!')

# --- ファイルを暗号化 ---
with open('secret.txt', 'rb') as f:
    encrypted_data = gpg.encrypt_file(
        f,
        recipients=['test@example.com'],
        output='secret.txt.gpg'
    )

if encrypted_data.ok:
    print("🔒 暗号化成功: secret.txt.gpg")
else:
    print("❌ 暗号化失敗:", encrypted_data.stderr)

# --- ファイルを復号化 ---
with open('secret.txt.gpg', 'rb') as f:
    decrypted_data = gpg.decrypt_file(
        f,
        passphrase='testpass',
        output='decrypted.txt'
    )

if decrypted_data.ok:
    print("🔓 復号化成功: decrypted.txt")
else:
    print("❌ 復号化失敗:", decrypted_data.stderr)

例2:署名・検証(sign / verify)

import os
import gnupg


# --- 設定 ---
os.makedirs('./gpg_home', exist_ok=True)
gpg = gnupg.GPG(gnupghome='./gpg_home')


# --- 鍵ペアを作成 ---
input_data = gpg.gen_key_input(
    name_email='signer@example.com',
    passphrase='mypassword'
)
key = gpg.gen_key(input_data)
print("✅ 鍵ペアを作成しました:", key.fingerprint)

# --- 署名対象のファイルを作成 ---
message_path = 'message.txt'
with open(message_path, 'w') as f:
    f.write('このメッセージは署名されています。')

# --- ファイルに署名(sign) ---
with open(message_path, 'rb') as f:
    signed_data = gpg.sign_file(
        f,
        keyid=key.fingerprint,
        passphrase='mypassword',
        output='message.txt.asc'   # ASCIIアーマー形式で署名付きファイルを作成
    )

if signed_data:
    print("✍️ 署名完了: message.txt.asc")
else:
    print("❌ 署名失敗")

# --- 署名の検証(verify) ---
with open('message.txt.asc', 'rb') as f:
    verify_result = gpg.verify_file(f)

if verify_result:
    print("✅ 検証成功!")
    print(f"署名者: {verify_result.username}")
    print(f"フィンガープリント: {verify_result.fingerprint}")
else:
    print("❌ 検証失敗!")

例3:公開鍵・秘密鍵のエクスポート/インポート

import os
import gnupg


# --- 設定 ---
os.makedirs('./gpg_home', exist_ok=True)
gpg = gnupg.GPG(gnupghome='./gpg_home')

# --- 鍵ペア作成(送信者側)---
input_data = gpg.gen_key_input(
    name_email='sender@example.com',
    passphrase='mypassword'
)
sender_key = gpg.gen_key(input_data)
print("✅ 送信者の鍵ペアを作成:", sender_key.fingerprint)

# --- 公開鍵をエクスポート ---
public_key_ascii = gpg.export_keys(sender_key.fingerprint)
with open('sender_public.asc', 'w') as f:
    f.write(public_key_ascii)
print("📤 公開鍵を sender_public.asc にエクスポート")

# --- 秘密鍵をエクスポート(※通常は安全な場所にのみ保存)---
private_key_ascii = gpg.export_keys(
    sender_key.fingerprint, secret=True, passphrase='mypassword')
with open('sender_private.asc', 'w') as f:
    f.write(private_key_ascii)
print("🔐 秘密鍵を sender_private.asc にエクスポート")

# --- 別のユーザー環境(受信者側)をシミュレーション ---
gpg_home_receiver = './gpg_home_receiver'
os.makedirs(gpg_home_receiver, exist_ok=True)
gpg_receiver = gnupg.GPG(gnupghome=gpg_home_receiver)

# --- 公開鍵をインポート ---
with open('sender_public.asc', 'r') as f:
    import_result = gpg_receiver.import_keys(f.read())
print("📥 公開鍵をインポート:", import_result.results)

# --- インポートした鍵を確認 ---
print("🔎 受信者側のキー一覧:")
for key in gpg_receiver.list_keys():
    print(f"  - {key['uids']} ({key['fingerprint']})")

例4:公開鍵による暗号化・復号化

import os
import gnupg

def make_home(path):
    os.makedirs(path, exist_ok=True)
    os.chmod(path, 0o700)  # 権限を安全にする(warning 対策)
    return gnupg.GPG(gnupghome=path)

gpg_sender = make_home('./gpg_home_sender')
gpg_receiver = make_home('./gpg_home_receiver')

# --- Step1: 鍵作成 ---
sender_input = gpg_sender.gen_key_input(
    name_email='sender@example.com',
    passphrase='senderpass'
)
sender_key = gpg_sender.gen_key(sender_input)

receiver_input = gpg_receiver.gen_key_input(
    name_email='receiver@example.com',
    passphrase='receiverpass'
)
receiver_key = gpg_receiver.gen_key(receiver_input)

# --- Step2: 公開鍵交換 ---
receiver_pub = gpg_receiver.export_keys(receiver_key.fingerprint)
import_result = gpg_sender.import_keys(receiver_pub)
print("📥 送信者が受信者の公開鍵をインポート:", import_result.count, "件")

# 🔑 信頼レベル設定(重要)
for key in gpg_sender.list_keys():
    if 'receiver@example.com' in key['uids']:
        gpg_sender.trust_keys(key['fingerprint'], 'TRUST_ULTIMATE')
        print(f"✅ 受信者の鍵 {key['fingerprint']} を信頼済みに設定")

# 再読み込み
gpg_sender.list_keys()

# --- Step3: 暗号化 ---
message = "これは受信者への秘密メッセージです。"
encrypted = gpg_sender.encrypt(
    message.encode('utf-8'),
    recipients=['receiver@example.com'],
    output='message.asc',
    always_trust=True  # ← これが重要!
)

if encrypted.ok:
    print("🔒 暗号化完了: message.asc")
else:
    print("❌ 暗号化失敗:", encrypted.stderr)

# --- Step4: 復号化 ---
if os.path.exists('message.asc'):
    with open('message.asc', 'rb') as f:
        decrypted = gpg_receiver.decrypt_file(f, passphrase='receiverpass', output='decrypted.txt')

    if decrypted.ok:
        print("🔓 復号化完了: decrypted.txt")
        print("📨 内容:", open('decrypted.txt').read())
    else:
        print("❌ 復号化失敗:", decrypted.stderr)
else:
    print("⚠️ 暗号化が失敗したため、message.asc が存在しません。")

関連記事

Python ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2014/08/07/231242