pythonの暗号化/復号化をファイルで行う。(格納した暗号ファイルを復号しデータを取得)

  • 投稿日2019.08.23、更新日2019.10.29
  • IT
pythonの暗号化/復号化をファイルで行う。(格納した暗号ファイルを復号しデータを取得)
pythonの暗号化/復号化をファイルで行う処理をご紹介します。

ファイルで行う理由としては、
サーバに平文のパスワードを置くなという、
セキュリティ要件があったので、
暗号化しようということになり、簡単なロジックを作成しましたので、
参考になれば幸いです。

ロジックが簡単すぎやしますが、
平文で置くなとしか要件なかったし、
データファイルとキーファイルの置き場を違うところにして、
若干複合しにくくしてとりあえず良しとするか・・・。

暗号化/復号化処理関数

暗号化復号化の関数は以下の通りです。
ファイル名はcrypto_util.pyとします。
# -*- coding: utf-8 -*-
from Crypto.Cipher import AES
key_size = 32
iv = '1234567890123456'.encode('utf-8')

def create_key(p_key):
    """
    キーデータ(bytes)を作成する。
    長さが32でない場合は、0埋め、もしくはtrimする。
    :param p_key:
    :return:
    """
    key_size_fill = p_key.zfill(key_size)
    key = key_size_fill[:key_size].encode('utf-8')
    return key


def encrypt(data, p_key, output_file=None):
    """
    暗号化
    :param data: 暗号化対象データ
    :param p_key: 暗号キー
    :param output_file: 暗号化結果の出力先ファイル
    :return:
    """
    key = create_key(p_key)
    obj = AES.new(key, AES.MODE_CFB, iv)

    ret_bytes = obj.encrypt(data)

    if output_file is not None:
        with open(output_file, "wb") as fout:
            fout.write(ret_bytes)

    return ret_bytes


def decrypt(data, p_key):
    """
    復号化
    :param data:復号化データ
    :param p_key:暗号キー
    :return:
    """
    key = create_key(p_key)
    obj = AES.new(key, AES.MODE_CFB, iv)
    return obj.decrypt(data)


def encrypt_from_file(input_data_file_name, output_data_file_name, key_file_path):
    """
    データを暗号化しファイルに出力する。
    :param input_data_file_name: 暗号化したい文字列を含むファイル(パスを含む)
    :param output_data_file_name: 暗号化ファイル(パスを含む)
    :param key_file_path: 暗号キーファイル(パスを含む)
    :return:
    """
    with open(input_data_file_name, "r", encoding="utf-8") as df:
        str_file_data = df.read()

    with open(key_file_path, "r") as kf:
        key = kf.read()

    return encrypt(str_file_data, key, output_file=output_data_file_name)


def decrypt_from_file(data_file_path, key_file_path):
    """
    暗号化されたファイルを復号化する。
    :param data_file_path: 暗号化されたファイル(パスを含む)
    :param key_file_path: 暗号キーファイル(パスを含む)
    :return:
    """
    with open(data_file_path, "rb") as df:
        byte = df.read()

    with open(key_file_path, "r") as kf:
        key = kf.read()

    return decrypt(byte, key).decode('utf-8')

関数説明

encryptで暗号化、decryptで復号化をしています。
後はそれを呼ぶ際にファイルを経由する処理、
encrypt_from_file、decrypt_from_fileがあります。

AES暗号化ではパラメータに
データ、キー、ベクトル(iv)となっているもの)が必要となります。

データは暗号化・復号化したいデータ

キーは暗号化・復号化で利用するキーです。これもバイト長指定がありますが、
関数で0埋め、trimするようにしています。

ベクトルは暗号化がかぶらないようにする付属文字で、
16バイト長であればなんでもいい文字列です。なので任意に指定可能です。

wikiの説明では以下となっていました。
「初期化ベクトル(英: initialization vector、IV)はビット列であり、
ストリーム暗号またはブロック暗号を任意の暗号利用モードで実行するとき、
同じ暗号鍵でストリームを生成しても毎回異なるストリームを生成するのに必要とされる。
これにより、毎回暗号鍵を替えるといった時間のかかる作業を省くことができる。

IVの大きさは使用する暗号化アルゴリズムと暗号プロトコルに依存し、
通常は暗号のブロックサイズと同じか暗号鍵と同じサイズである。
IVは受信者がその暗号を解読する際に必須である。」

呼出元関数

呼出元の関数は以下の通り。
input_fileに暗号化したい文字列を設定し、
key_file_nameに暗号化と復号化で使用するキーを設定します。
input_fileはUTF-8を想定していますが、
暗号化/復号化処理関数のencodingを
変えればそれぞれの文字コードに対応可能です。
# これが暗号化/復号化処理関数のファイルです。
import crypto_util

input_file_name = "input_file"
output_data_file_name = "output_data_file"
key_file_name = "key_file"

# 暗号化
crypto_util.encrypt_from_file(input_file_name, output_data_file_name, key_file_name)

# 復号化
decrypto_data = crypto_util.decrypt_from_file(output_data_file_name, key_file_name)

print(decrypto_data)

必要なライブラリ

暗号化で必要なライブラリがありますので、
そちらをインストールしてください。
anacondaを利用されている場合は、
不要と思われます。

pycryptodomeというライブラリが必要でした。
(pycryptoというライブラリは更新終了で移行推奨されている模様)
pip install pycryptodome
でインストールしてください。

https://qiita.com/muramasawani/items/24f91d8137972091b914
を参考させてもらいました。

更にここでインストール失敗する場合があります。
私の場合、dockerにインストールする際、
下記ライブラリが不足していたためインストール失敗しました。
その際は下記のページを参考にインストールを進めてみてください。
https://stackoverflow.com/questions/22073516/failed-to-install-python-cryptography-package-with-pip-and-setup-py

補足

暗号化する際にバイトデータで渡していますが、
これは暗号化ライブラリで pycryptodome を使用したためです。
pycryptodome だと文字列渡したら、
例外発生したので、一旦バイトに変換して暗号化/復号化しています。

ITカテゴリの最新記事