どうも、nippa です。
python で暗号化をできないかと思い、ライブラリを調べていました。
暗号化のライブラリとしては
があるようです。
PyCryptodome は pycrypto からフォークされたライブラリになります。
今回は後者の pyca/cryptography ついてまとめておきます。
PyCryptodome についても追々まとめたいと思います。
環境
cryptography の動作環境
で動作します。
cryptography の特徴
high-level、low-level の暗号化機能が利用可能です。
low-level の暗号機能に関しては、セキュリティリスクになる場合があります。
そのため暗号機能の十分な知識がない場合は、high-level の暗号機能を使うことが強く推奨されています。
潜在的なセキュリティリスクを伴うものをhazardous materials(hazmat)
として、cryptography.hazmat
のパッケージにまとめられています。
また、共通鍵暗号に Fernet を採用しています。Fernet ではキーに加え、バージョン、タイムスタンプなどを追加した上で暗号化されます。
cryptography のインストール
pip install cryptography
暗号化と復号の手順
大きな流れとしては、以下になります。
- 暗号化するキーを作成
- 暗号化
- 復号する
基本的には暗号化の際にどのような方式で暗号化するかの違いになります。
hazmat を利用すれば暗号化の方式などを細かく設定することも可能です。
暗号化・復号化のサンプルコード
せっかくなので、暗号化・復号化の練習してみたいと思います。
サンプル1: high-level の暗号化(cryptography 任せ)
key の生成をライブラリに任せて暗号化します。
token を保存し、利用する際に復号化すれば暗号化前の文字列が復号できます。
from cryptography.fernet import Fernet key = Fernet.generate_key() f = Fernet(key) token = f.encrypt(b"Secret!") print(token) print(f.decrypt(token))
ファイルに保存する場合、key を使って token を復号できます。
簡単にコードにすると
from cryptography.fernet import Fernet f = Fernet(b"keyの値") token = b"tokenの値" print(f.decrypt(token))
で復号されます。
サンプル 2: high-level の暗号化(現在時刻を使った暗号化)
上でも書きましたが Fernet では時刻を暗号化の際に利用します。
時刻を指定することも可能です。
パラメータとしては、引数で指定した値 - 現在時刻
として時刻を扱う内容になります。
from cryptography.fernet import Fernet import time key = Fernet.generate_key() f = Fernet(key) now = time.time() token = f.encrypt_at_time(b"Secret!", int(now)) print(token) print(f.decrypt(token))
サンプル 1 同様に、key を使って復号可能です。
from cryptography.fernet import Fernet f = Fernet(b"keyの値") token = b"tokenの値" print(f.decrypt(token))
で復号されます。
サンプル 3: low-level の暗号化(パスワードを利用した鍵の作成・暗号化)
以下の方法でパスワードを指定して鍵を生成することができます。
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import base64 import os from cryptography.fernet import Fernet from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC password = b"password" salt = os.urandom(16) kdf = PBKDF2HMAC( algorithm=hashes.SHA256(), length=32, salt=salt, iterations=100000, ) key = base64.urlsafe_b64encode(kdf.derive(password)) f = Fernet(key) token = f.encrypt(b"Secret!") print(key) print(token) print(f.decrypt(token))
桁数が少ないのでハッシュ化に SHA256 を利用しています。またにソルトを urandom で指定してます。
これまで同様に、以下の方法でデコード可能です。
from cryptography.fernet import Fernet f = Fernet(b"keyの値") token = b"tokenの値" print(f.decrypt(token))
感想
cryptography 大まかな使い方は、 理解できました。
ライブラリお任せで利用する場合は、特に考えることはないと思います。
個人情報などのセンシティブ情報の暗号化などに使えるかと思います。
ではでは、また次回。