共通鍵暗号
このレッスンでは、その効率性によって保存中および転送中のデータの多くを保護する共通鍵暗号について学びます。
レッスンの終わりまでに、以下の内容を網羅します:
- 共通鍵暗号とは何か
- 共通鍵暗号の使用方法を示す Python コード例
- 共通鍵暗号の応用例の概観
- 共通鍵暗号のアプリケーション
- 共通鍵暗号のセキュリティ
- 古典コンピュータおよび量子コンピュータからのこれらのアルゴリズムへの脅威
共通鍵暗号の概要
共通鍵暗号(SKC) は、最も古く、最も直感的な暗号化の形式です。SKC では、機密情報は共通鍵暗号化(SKE)によって保護されます。すなわち、暗号化と復号の両方に 単一の秘密鍵 を用います。
SKC には以下が含まれます:
- 秘密鍵を使用して与えられた平文を 暗号文 に変換する暗号化関数
- 同じ秘密鍵を使用して暗号文を平文に戻すことで、その操作を逆にする復号関数
平文とは、自然言語テキストやバイナリコードなど、情報の内容に原則として直接アクセスできる、暗号化されていないあらゆる種類のデータを意味します。一方、暗号文 とは、復号前にその情報の内容へのアクセスが意図的に不可能にされている暗号化済みデータを指します。
共有秘密鍵を使用した暗号化・復号操作を記述するアルゴリズムは、対称暗号とも呼ばれます。
図1. 同じ鍵を使用して与えられた平文を暗号文に共通鍵暗号化し、平文に復号する様子。
共通鍵暗号システムの性質
共通鍵暗号システムは、静的に保存されたデータや何らかの伝送チャネルを通じた通信の両方において、メッセージを保護するために以下の性質を確保する必要がありま す:
- 機密性(Confidentiality): 暗号化されたメッセージの情報の内容が、無断アクセスから保護されているという性質を指します。
- 完全性(Integrity): 保存または転送中に暗号化されたメッセージへの改ざんを検出できるという性質を指します。
- 真正性(Authenticity): メッセージの受信者が送信者の身元を確認し、権限のない第三者によるなりすましを検出できるという性質を指します。
さらに、これらの性質は、暗号化・復号に使用されるアルゴリズムや暗号が公開されている場合でも、暗号化されたメッセージの情報の内容へのアクセスが秘密鍵へのアクセスのみを通じて独占的に制御される設定で実現される必要があります。
したがって、安全な共通鍵暗号システムを実装するには、主に2つのタスクが必要です:
- 暗号解読攻撃に対して耐性のある堅牢な共通鍵暗号アルゴリズムを採用すること。
- 秘密鍵の配布と管理における機密性を確保すること。
このレッスンでは、SKC 技術の主な関心事である最初のタスクに関連する側面について説明します。ただし、2番目のタスクは SKC 自体の範囲外の解決策を必要とするため、後ほど紹介します。
Python を用いた共通鍵暗号化の実例
古典的な シーザーシフト暗号 と、2001年から共通鍵暗号の標準となっている現代の Advanced Encryption System(AES)を使用した暗号化・復号操作の簡単な例を示します。 まず、必要な共通鍵暗号化アルゴリズムを提供する Python ライブラリをセットアップし、暗号化したい平文を定義します。
# Added by doQumentation — required packages for this notebook
!pip install -q cryptography numpy secretpy
# Install the library if needed
# %pip install secretpy
# import the required crypto functions which will be demonstrated later
from secretpy import Caesar
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from functools import reduce
import numpy as np
# Set the plaintext we want to encrypt
plaintext = "this is a strict top secret message for intended recipients only"
print(f"\nGiven plaintext: {plaintext}")
2つの異なる共通鍵暗号化方式を使用して暗号化・復号する方法を示します:
- 古典的なシーザーシフト暗号
- 現代のAdvanced Encryption Standard AES-256 プロトコル
シーザーシフト暗号
シーザーシフト暗号化では以下を定義します:
- エンコードする可能な文字のアルファベット
- 0(暗号化なし)からアルファベットの長さまでのシフト値。これを鍵とみなします。
平文の各文字が暗号文中の別の文字に置換されるため、単一換字式暗号と呼ばれます。
この例では、アルファベットの小文字を使用します。
まずセットアップを行いましょう。
# initialize the required python object for doing Caesar shift encryption
caesar_cipher = Caesar()
# Define the shift, ie the key
caesar_key = 5
print(f"Caesar shift secret key: {caesar_key}")
# Define the alphabet
alphabet = (
"a",
"b",
"c",
"d",
"e",
"f",
"g",
"h",
"i",
"j",
"k",
"l",
"m",
"n",
"o",
"p",
"q",
"r",
"s",
"t",
"u",
"v",
"w",
"x",
"y",
"z",
" ",
)
print(f"alphabet: {alphabet}")
平文を暗号化して、シーザー暗号の暗号文を得ます。
caeser_ciphertext = caesar_cipher.encrypt(plaintext, caesar_key, alphabet)
print(f"Encrypted caeser shift ciphertext: {caeser_ciphertext}")
暗号化に使用した同じ鍵を使用して、暗号文を元の平文に復号します。
caeser_plaintext = caesar_cipher.decrypt(caeser_ciphertext, caesar_key, alphabet)
print(f"Decrypted caeser shift plaintext: {caeser_plaintext}\n")
Advanced Encryption Standard(AES)暗号
次に、一般的な共通鍵暗号化アルゴリズムである AES を使用して平文を暗号化します。
まず、鍵を作成します。この場合はランダムな16文字の文字列です。
# lambda defines an inline function in this case that takes two values a,b with the resulting expression of a+b
# reduce uses a two-argument function(above), and applies this to all the entries in the list (random alphabet characters) cumulatively
aes_key = reduce(lambda a, b: a + b, [np.random.choice(alphabet) for i in range(16)])
print(f"AES secret key: {aes_key}")
AES は複数の動作モードをサポートしており、どれを使用するかを指定する必要があります。
cryptography ライブラリの modes.CBC クラスが提供する暗号ブロック連鎖(CBC)モードを選択します。AES の CBC モードは、追加のセキュリティのために乱数を使用します。これには、ランダムな初期化ベクトル(IV)、または ノンス とも呼ばれるものを指定する必要があります。鍵と同様に、ランダムな文字列を使用します。
aes_initialization_vector = reduce(
lambda a, b: a + b, [np.random.choice(alphabet) for i in range(16)]
)
print(f"AES initialization vector: {aes_initialization_vector}")
秘密メッセージの送信者のために AES 暗号を初期化できます。初期化ベクトルが CBC 動作モードのセットアップのために modes.CBC クラスに渡されていることに注目してください。
その後、送信する平文を暗号化します。
# The encryptor is setup using the key and CBC. In both cases we need to convert the string (utf-8) into bytes
sender_aes_cipher = Cipher(
algorithms.AES(bytes(aes_key, "utf-8")),
modes.CBC(bytes(aes_initialization_vector, "utf-8")),
)
aes_encryptor = sender_aes_cipher.encryptor()
# update can add text to encypt in chunks, and then finalize is needed to complete the encryption process
aes_ciphertext = (
aes_encryptor.update(bytes(plaintext, "utf-8")) + aes_encryptor.finalize()
)
# Note the output is a string of bytes
print(f"Encrypted AES ciphertext: {aes_ciphertext}")
復号するために、受信者のために AES 暗号を初期化します。意図された受信者は秘密鍵と初期化ベクトルの両方にアクセスできますが、後者は秘密にする必要はありません。
# Similar setup of AES to what we did for encryption, but this time, for decryption
receiver_aes_cipher = Cipher(
algorithms.AES(bytes(aes_key, "utf-8")),
modes.CBC(bytes(aes_initialization_vector, "utf-8")),
)
aes_decryptor = receiver_aes_cipher.decryptor()
# Do the decryption
aes_plaintext_bytes = aes_decryptor.update(aes_ciphertext) + aes_decryptor.finalize()
# convert back to a character string (we assume utf-8)
aes_plaintext = aes_plaintext_bytes.decode("utf-8")
print(f"Decrypted AES plaintext: {aes_plaintext}")
共通鍵暗号の応用
シーザー暗号 などの古典暗号はずいぶん前に廃れましたが、AES などの現代の共通暗号システムは、以下を含む幅広い応用分野で展開されています:
-
データの暗号化と復号: SKC は、デバイスに静的に保存されているか、ネットワーク上で転送されているかにかかわらず、機密データを保護するために広く使用されています。例としては、ユーザー認証情報の保護、メールメッセージの暗号化、金融取引のセキュリティ確保などがあります。
-
安全な通信: SSL/TLS などの一般的な通信プロトコルは、共通鍵暗号と公開鍵暗号の組み合わせを使用して、2者間で交換されるデータの機密性と完全性を確保します。これらのメッセージは、共有鍵を使用する共通鍵暗号化によって暗号化・復号されます。共通鍵暗号化に使用される鍵は、公開鍵と秘密鍵のペアを使用する公開鍵暗号化を使用して安全に交換されます。共通鍵暗号化はより高速であるため、大きなサイズのメッセージの暗号化に使用できます。
-
真正性の検証: 一部の設定では、SKC はメッセージ認証コード(MAC)や鍵付きハッシュ MAC(HMAC)などの技術を通じて採用され、メッセージの 真正性 と