はじめに
前回、AESで暗号化する実装をしてみた際、知らない暗号モードが増えたなと思いました。
なので、どの暗号モードを使用すべきかの、判定材料の一つとして、代表的な暗号モードの処理速度を簡単に計ってみようと思いました。
測定する暗号モード
測定する暗号モードは以下にしました。
- CTR
- GCM
- OCB
選んだ理由を以下に説明します。
CTR
暗号のみを行う暗号モードで、一番取り回しが効いて、使いやすいと思ったため選びました。
GCM
暗号/認証を行う暗号モードです。SSL/TLSの暗号化にも、使われる暗号モードなので、比較的メジャーだと思います。
OCB
これも暗号/認証を行う暗号モードです。ただ、これの特許はアメリカが持っているそうです。
ただし、フリーソフトとして使用できるオープンライセンス、だそうですので、サンプルを作るのはいいですが、ちょっと仕事では使いにくいかなと思います。
GCMと明瞭な速度の違いとかがあるのか?という興味の元、測定してみます。
測定に使用したサンプルコード
サンプルコード
- 各処理を1000000回回した処理時間を計測しています。
- VM上で動作させたため、絶対的な処理時間そのものは、あまり意味がありません。あくまで相対的な処理時間として見てください。
- 動作環境は前回と同じです。
from Cryptodome.Cipher import AES from hashlib import sha256 import random import time def start_time(): return time.time() def end_time(start_time, message): end_time = time.time() # 経過時間を表示 elapsed_time = end_time - start_time print("{} 経過時間(s):{}".format(message, elapsed_time)) def generate_random_secret_key(algorithm_func=sha256): return algorithm_func(str(random.random).encode('utf-8')).digest() # CTR def ctr_encrypt(secret_key, raw_data): crypto = AES.new(secret_key, AES.MODE_CTR) return dict(content=crypto.encrypt(raw_data), nonce=crypto.nonce) def ctr_decrypt(secret_key, encrypted_data): """ encrypted_data = dict(content, nonce) """ crypto = AES.new(secret_key, AES.MODE_CTR, nonce=encrypted_data['nonce']) return crypto.decrypt(encrypted_data['content']) def ctr_encrypt_and_decrypt(secret_key, raw_data): encrypted_data = ctr_encrypt(secret_key, raw_data.encode()) return ctr_decrypt(secret_key, encrypted_data) # GCM def gcm_encrypt(secret_key, raw_data): crypto = AES.new(secret_key, AES.MODE_GCM) content, tag = crypto.encrypt_and_digest(raw_data) return dict(content=content, nonce=crypto.nonce, tag=tag) def gcm_decrypt(secret_key, encrypted_data): crypto = AES.new(secret_key, AES.MODE_GCM, nonce=encrypted_data['nonce']) return crypto.decrypt_and_verify(encrypted_data['content'], encrypted_data['tag']) def gcm_encrypt_and_decrypt(secret_key, raw_data): encrypted_data = gcm_encrypt(secret_key, raw_data.encode()) return gcm_decrypt(secret_key, encrypted_data) # OCB def ocb_encrypt(secret_key, raw_data): crypto = AES.new(secret_key, AES.MODE_OCB) content, tag = crypto.encrypt_and_digest(raw_data) return dict(content=content, nonce=crypto.nonce, tag=tag) def ocb_decrypt(secret_key, encrypted_data): crypto = AES.new(secret_key, AES.MODE_OCB, nonce=encrypted_data['nonce']) return crypto.decrypt_and_verify(encrypted_data['content'], encrypted_data['tag']) def ocb_encrypt_and_decrypt(secret_key, raw_data): encrypted_data = ocb_encrypt(secret_key, raw_data.encode()) return ocb_decrypt(secret_key, encrypted_data) if __name__ == "__main__": key = generate_random_secret_key() raw_data = 'raw_test_data' t = start_time() for i in range(100000): decrypted_data = ctr_encrypt_and_decrypt(key, raw_data) end_time(t, 'MODE_CTR') print(decrypted_data) t = start_time() for i in range(100000): decrypted_data = gcm_encrypt_and_decrypt(key, raw_data) end_time(t, 'MODE_GCM') print(decrypted_data) t = start_time() for i in range(100000): decrypted_data = ocb_encrypt_and_decrypt(key, raw_data) end_time(t, 'MODE_OCB') print(decrypted_data)
測定結果
モード | 平均[s] |
CTR | 4.29 |
GCM | 24.92 |
OCB | 14.92 |
ということで、暗号+認証モードは、暗号のみのモードに比べて、5倍ほど処理時間がかかるようです。
OCBとGCMではOCBのほうが早いようです。
測定時出力
以下が測定時の出力です。なんとなく3回行ってみました。
$ python3 aes_encrypt_mode.py MODE_CTR 経過時間(s):4.257887125015259 b'raw_test_data' MODE_GCM 経過時間(s):23.77862286567688 b'raw_test_data' MODE_OCB 経過時間(s):15.00019884109497 b'raw_test_data' $ python3 aes_encrypt_mode.py ODE_CTR 経過時間(s):4.250228404998779 b'raw_test_data' MODE_GCM 経過時間(s):26.86670160293579 b'raw_test_data' MODE_OCB 経過時間(s):15.084097862243652 b'raw_test_data' $ python3 aes_encrypt_mode.py MODE_CTR 経過時間(s):4.365018606185913 b'raw_test_data' MODE_GCM 経過時間(s):24.15635585784912 b'raw_test_data' MODE_OCB 経過時間(s):14.68250060081482 b'raw_test_data'
サンプルソース
ここに、上記のソース、及び関連のソースを置いてあります。
おわりに
思ったより暗号+認証モードは処理時間がかかるのが分かりました。
何かの参考にしてください。