自分だけのクイズ作成 - Quipha公開中

【Python】AES暗号・復号【PyCryptodome】

Python
スポンサーリンク

はじめに

今回はPythonを使って、AESで暗号化・復号を行います。
AESキーは、任意のパスフレーズをもとに生成します。

パスフレーズで暗号・復号を行うことにより、実戦的に使えると思います。
是非、参考にしてみてください。

使用するバージョンなど
  • Python
  • PyCryptodome 3.16.0

Evernoteのテキスト暗号化

Evernoteにはテキスト暗号化機能があり、AESで暗号化を行っています。
その仕組みや実際のソースコードについては、以下の記事で解説していますので参考にしてみてください。

VS Codeインストール

Pythonで実装を行うにあたって、VS Codeのインストール方法は、以下の記事にまとめましたのでご覧ください。

VS Codeのオススメ設定や拡張機能などは、以下の記事にまとめました。

スポンサーリンク

暗号化の仕組み

今回はAES暗号化します。

Advanced Encryption Standard (AES) は、アメリカが2001年に標準暗号として定めた共通鍵暗号アルゴリズムである。アメリカ国立標準技術研究所(NIST)が公募し、Rijndael(ラインダール)がAESとして採用された。

https://ja.wikipedia.org/wiki/Advanced_Encryption_Standard

Evernoteの仕組みも同じですが、今回は以下のように暗号化・復号を行う実装をします。

  • 任意のパスフレーズをもとに、PBKDF2を利用しAESキーを生成します。
  • ソルトとHMAC/SHA-256 ハッシュ関数を 50,000 回通して生成します。(反復回数)
  • AESキーを使い、AESで暗号化・復号を行います。

反復回数は多い方が暗号化に時間がかかりますが、復号にも時間がかかりブルートフォース攻撃の対策にもなります。
また、PBKDF2は並列処理に弱いとされていますが、対策としてArgon2などがあり、必要に応じて選択しましょう。

また暗号化を行う際に、毎回同じ値にならないように対応します。
(ソルト・初期ベクトル)

安全でない暗号化の修正 - Google ヘルプ
この情報は、安全でない暗号化パターンが含まれているアプリのデベロッパーを対象としています。該当するアプリは、暗号テキストの生成に使わ

実装

PyCryptodome

Pythonで暗号・復号しますが、ライブラリにPyCryptodomeを使用します。

Welcome to PyCryptodome’s documentation — PyCryptodome 3.15.0 documentation

pipコマンドでインストールします。

pip install pycryptodome

暗号化

ソルトと初期ベクトルをランダムに生成します。

from Crypto.Random import get_random_bytes

salt = get_random_bytes(16)
iv = get_random_bytes(16)

PBKDF2を使用して、AESキーを生成します。

passPhrase = "password123"
...
# AESキーの生成(128bit、5万回)
key = pbkdf2_hmac('sha256', bytes(passPhrase, encoding='utf-8'), salt, 50000, int(128 / 8))

ソルトとパスフレーズをもとに、AESキーを生成します。
ソルトを使用することにより、毎回違う値を生成することができます。
反復回数は5万回に設定しましたが、任意です。

生成したAESキーを使い、AES(128bit)で暗号化します。

# 暗号
aes = AES.new(key, AES.MODE_CBC, iv)
data = Padding.pad(targetText.encode('utf-8'), AES.block_size, 'pkcs7')
encrypted = aes.encrypt(data)
print(encrypted)

暗号化されたテキストは以下のように表示されました。

b'_[\x87\x89\xfd(\xb4\xe5q\x10@\x18\xa8\x9fU\xd7\xb4\x89 \xffVVFN\xed\xf9\x7f+Fc\x16\x17'

実行する度に値が変わることを確認しましょう。

復号

今度は復号を行います。
復号するためには、暗号化する際に使用した以下の情報が必要です。

  • パスフレーズ
  • ソルト
  • 初期ベクトル
  • 反復回数
  • 暗号化された情報

パスフレーズは非公開である必要があります。

AESキーの生成は暗号化と同じで、パスフレーズをもとに行います。

passPhrase = "password123"
...
# AESキーの生成(128bit、5万回)
key = pbkdf2_hmac('sha256', bytes(passPhrase, encoding='utf-8'), salt, 50000, int(128 / 8))

AESキーと初期ベクトルを使い、復号できます。

# 復号
aes = AES.new(key, AES.MODE_CBC, iv)
plaintext = aes.decrypt(encrypted)
print(plaintext.decode(encoding='utf-8'))

全容

暗号と復号の処理を分けて実装しました。
ポイントなのは、暗号化に使用した情報をもとに復号する必要があります。

from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
from Crypto.Util import Padding
from hashlib import pbkdf2_hmac

# 暗号
def encrypt(text, passPhrase):

    salt = get_random_bytes(16)
    iv = get_random_bytes(16)

    # AESキーの生成(128bit、5万回)
    key = pbkdf2_hmac('sha256', bytes(passPhrase, encoding='utf-8'), salt, 50000, int(128 / 8))

    # 暗号
    aes = AES.new(key, AES.MODE_CBC, iv)
    data = Padding.pad(text.encode('utf-8'), AES.block_size, 'pkcs7')
    encrypted = aes.encrypt(data)

    return {
        'salt': salt,
        'iv': iv,
        'encrypted': encrypted
    }

# 復号
def decrypt(encryptedData, passPhrase):

    # AESキーの生成(128bit、5万回)
    key = pbkdf2_hmac('sha256', bytes(passPhrase, encoding='utf-8'), encryptedData['salt'], 50000, int(128 / 8))

    # 復号
    aes = AES.new(key, AES.MODE_CBC, encryptedData['iv'])
    plaintext = aes.decrypt(encryptedData['encrypted'])

    return plaintext.decode(encoding='utf-8')


targetText = "暗号化したいテキスト"
passPhrase = "password123"

# 暗号化
encryptedData = encrypt(targetText, passPhrase)

# 復号
decrypted = decrypt(encryptedData, passPhrase)

print(decrypted)

テキストをパスフレーズで暗号化しています。
また、暗号化された情報とパスフレーズで復号しています。

TXT-Crypter

今回解説した仕組みと同じですが、暗号・復号を簡単に行うことができるサービスを作成しました。

TXT-Crypter
簡単にテキストを暗号・復号でき、秘密情報を守ります

パスワードなど、見られたくない情報を手軽に暗号・復号することができます。
パスフレーズをもとに暗号化し、URLを生成します。
そのURLにアクセスし、パスフレーズを入力することによりいつでも復号できます。

Notionを使ってパスワード管理を行う例は、以下の記事を参考にしてください。

さいごに

今回はPythonを使って、AESで暗号化・復号を行いました。
暗号・復号の仕組みについて参考にしてみてください。

\オススメ/

コメント

タイトルとURLをコピーしました