Pythonで暗号化・復号化を実装する(Cryptography)

プログラミング

PythonにおけるCryptographyライブラリを用いた暗号化・復号化の実装

Pythonで安全な暗号化・復号化処理を実装する上で、cryptographyライブラリは非常に強力で柔軟な選択肢となります。このライブラリは、現代的な暗号化アルゴリズム、ハッシュ関数、デジタル署名などを包括的にサポートしており、セキュアなアプリケーション開発に不可欠なツールです。

cryptographyライブラリの概要

cryptographyライブラリは、Pythonの標準ライブラリではありませんが、非常に広く利用されており、インストールも容易です。pip install cryptographyコマンドでインストールできます。このライブラリは、低レベルの暗号 primitives(基本的な暗号要素)と、それらを組み合わせてより高レベルな暗号化スキームを構築するための抽象化を提供します。

主な機能

  • 対称暗号化 (Symmetric Encryption): 同じ鍵で暗号化と復号化を行う方式。高速ですが、鍵の安全な共有が課題となります。
  • 非対称暗号化 (Asymmetric Encryption): 公開鍵と秘密鍵のペアを使用する方式。鍵の共有が不要ですが、対称暗号化に比べて処理速度は遅くなります。
  • ハッシュ関数 (Hash Functions): 任意のデータを固定長のハッシュ値に変換する関数。データの改ざん検出などに利用されます。
  • デジタル署名 (Digital Signatures): メッセージの認証と完全性を保証するための技術。
  • 鍵交換 (Key Exchange): 安全に共有鍵を生成するためのプロトコル。

対称暗号化の実装例

対称暗号化では、Fernetという使いやすいインターフェースが提供されています。Fernetは、AES (Advanced Encryption Standard) という実績のある暗号化アルゴリズムを基盤としており、認証付き暗号化 (Authenticated Encryption with Associated Data: AEAD) を実現しています。

鍵の生成

まず、暗号化・復号化に使用する鍵を生成します。

from cryptography.fernet import Fernet

# 鍵の生成
key = Fernet.generate_key()
print(f"生成された鍵: {key.decode()}")

暗号化

生成した鍵を使用して、メッセージを暗号化します。

# Fernetインスタンスの作成
f = Fernet(key)

# 暗号化したいメッセージ (バイト列である必要がある)
message = b"This is a secret message."

# メッセージの暗号化
encrypted_message = f.encrypt(message)
print(f"暗号化されたメッセージ: {encrypted_message.decode()}")

復号化

暗号化されたメッセージと、同じ鍵を使用して復号化します。

# メッセージの復号化
decrypted_message = f.decrypt(encrypted_message)
print(f"復号化されたメッセージ: {decrypted_message.decode()}")

Fernetは、暗号化と同時にメッセージの改ざんを検出する機能も内蔵しているため、安全にデータを保護できます。

非対称暗号化の実装例 (RSA)

非対称暗号化では、公開鍵と秘密鍵のペアが使用されます。cryptographyライブラリは、RSAアルゴリズムの実装を提供しています。

鍵ペアの生成

まず、公開鍵と秘密鍵のペアを生成します。

from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import serialization

# 鍵ペアの生成
private_key = rsa.generate_private_key(
    public_exponent=65537,
    key_size=2048
)

# 公開鍵の取得
public_key = private_key.public_key()

鍵の保存 (オプション)

生成した鍵は、ファイルなどに保存しておくと再利用できます。ここでは、PEM形式で保存する例を示します。

# 秘密鍵の保存
pem_private_key = private_key.private_bytes(
    encoding=serialization.Encoding.PEM,
    format=serialization.PrivateFormat.PKCS8,
    encryption_algorithm=serialization.NoEncryption() # パスワードなしで保存
)
with open("private_key.pem", "wb") as f:
    f.write(pem_private_key)

# 公開鍵の保存
pem_public_key = public_key.public_bytes(
    encoding=serialization.Encoding.PEM,
    format=serialization.PublicFormat.SubjectPublicKeyInfo
)
with open("public_key.pem", "wb") as f:
    f.write(pem_public_key)

暗号化 (公開鍵を使用)

メッセージを暗号化するには、受信者の公開鍵を使用します。

from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import hashes

# 暗号化したいメッセージ (バイト列)
message = b"This is a secret message for asymmetric encryption."

# 公開鍵での暗号化
encrypted_message = public_key.encrypt(
    message,
    padding.OAEP( # OAEP padding scheme
        mgf=padding.MGF1(algorithm=hashes.SHA256()),
        algorithm=hashes.SHA256(),
        label=None
    )
)
print(f"非対称暗号化されたメッセージ: {encrypted_message.hex()}") # 16進数で表示

復号化 (秘密鍵を使用)

暗号化されたメッセージを復号化するには、対応する秘密鍵を使用します。

# 秘密鍵での復号化
decrypted_message = private_key.decrypt(
    encrypted_message,
    padding.OAEP( # OAEP padding scheme
        mgf=padding.MGF1(algorithm=hashes.SHA256()),
        algorithm=hashes.SHA256(),
        label=None
    )
)
print(f"非対称復号化されたメッセージ: {decrypted_message.decode()}")

非対称暗号化は、公開鍵と秘密鍵のペアを適切に管理することが重要です。秘密鍵は絶対に漏洩させてはなりません。

ハッシュ関数

ハッシュ関数は、データの完全性を検証するために広く利用されます。cryptographyライブラリでは、SHA-256などの主要なハッシュアルゴリズムをサポートしています。

SHA-256ハッシュの計算

from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.hashes import HashAlgorithm # HashAlgorithm は実際には不要

# ハッシュ化したいデータ (バイト列)
data_to_hash = b"Some data to be hashed."

# ハッシュオブジェクトの作成 (SHA-256)
hasher = hashes.Hash(hashes.SHA256())

# データの追加
hasher.update(data_to_hash)

# ハッシュ値の取得
digest = hasher.finalize()
print(f"SHA-256 ハッシュ値: {digest.hex()}")

ハッシュ値は、元のデータが少しでも変更されると大きく変化するため、データの整合性チェックに役立ちます。

デジタル署名

デジタル署名は、メッセージの送信元を認証し、メッセージが改ざんされていないことを保証します。非対称暗号化の技術を利用して実装されます。

署名の生成 (秘密鍵を使用)

from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import hashes

# 署名したいメッセージ (バイト列)
message_to_sign = b"This message needs to be signed."

# 秘密鍵による署名
signature = private_key.sign(
    message_to_sign,
    padding.PSS( # PSS padding scheme
        mgf=padding.MGF1(hashes.SHA256()),
        salt_length=padding.PSS.MAX_LENGTH
    ),
    hashes.SHA256()
)
print(f"生成された署名: {signature.hex()}")

署名の検証 (公開鍵を使用)

受信者は、送信者の公開鍵を使用して署名を検証します。

try:
    public_key.verify(
        signature,
        message_to_sign,
        padding.PSS( # PSS padding scheme
            mgf=padding.MGF1(hashes.SHA256()),
            salt_length=padding.PSS.MAX_LENGTH
        ),
        hashes.SHA256()
    )
    print("署名は有効です。メッセージは改ざんされていません。")
except Exception as e:
    print(f"署名は無効です: {e}")

署名の検証に失敗した場合、メッセージが改ざんされたか、署名が不正である可能性が示唆されます。

まとめ

cryptographyライブラリは、Pythonで堅牢な暗号化・復号化機能を実装するための強力なツールキットです。対称暗号化、非対称暗号化、ハッシュ関数、デジタル署名など、幅広い機能を提供しており、開発者はこれらの機能を組み合わせて、データの機密性、完全性、認証を確保するアプリケーションを構築できます。各暗号化手法にはそれぞれの利点と注意点があり、アプリケーションの要件に応じて適切な方法を選択し、安全に実装することが重要です。特に、鍵の管理はセキュリティの根幹をなすため、慎重な取り扱いが求められます。