ヘロログ
暗号

単一換字式暗号(Monoalphabetic Substitution Cipher)

シーザー暗号(シフト暗号)では、すべての文字を同じ数だけずらすため、鍵は25通りしかなく容易に総当たりで解読できる。では、ずらし方を統一せず、各文字を自由に別の文字に割り当てるとどうなるか? これが単一換字式暗号(Monoalphabetic Substitution Cipher)である。

単一換字式暗号の鍵空間は26! \approx 4.03 \times 10^{26}通りという天文学的な数になり、総当たり攻撃はまったく現実的でない。しかし、この膨大な鍵空間にもかかわらず、頻度分析という手法によって解読されてしまう。その構造と弱点を理解することは、暗号の安全性とは何かを考える上で重要である。

アルベルティと暗号円盤

単一換字式暗号は古くから用いられていたが、その運用を効率化する道具として、1467年頃にイタリアのレオン・バッティスタ・アルベルティ(Leon Battista Alberti)が暗号円盤(Cipher Disk)を考案した。大小2枚の同心円盤の外側に平文アルファベット、内側に暗号アルファベットを配置し、内側を回転させることで換字表を素早く設定できる。アルベルティは「西洋暗号学の父」とも呼ばれている。

アルゴリズム

変換規則

単一換字式暗号の鍵は、26文字のアルファベットをどのように並び替えるかという変換規則\sigmaである。例えば、次のような対応表が一つの鍵となる。

平文abcdefghijklmnopqrstuvwxyz
暗号文DICOXYUZPJKWLHBGSNRFTMLQAE

シーザー暗号では「3文字ずらす」という一つのルールで全文字の対応が決まるが、単一換字式暗号では各文字が独立に任意の文字に対応する。この対応は重複なし(1対1対応、すなわち置換)でなければならない。

暗号化

平文の各文字を、変換規則\sigmaに従って対応する暗号文字に置き換える。

単一換字式暗号の暗号化・復号
\begin{aligned} \text{暗号化:} \quad c_i &= \sigma(p_i) \\ \text{復号:} \quad p_i &= \sigma^{-1}(c_i) \end{aligned}
計算例:「attackatdawn」を暗号化

上の変換規則\sigmaを用いると:

平文attackatdawn
暗号文DFFDCKDFODLH

平文の「a」は常に「D」に、「t」は常に「F」に変換される。この「同じ文字は常に同じ暗号文字になる」という性質こそが、頻度分析に対する脆弱性の原因である。

鍵空間の大きさ

26文字のアルファベットの並び替え(置換)の総数は26!(26の階乗)である。

26! = 26 \times 25 \times 24 \times \cdots \times 2 \times 1 \approx 4.03 \times 10^{26}
鍵空間の比較

シーザー暗号(シフト暗号)の鍵空間はわずか25通りだが、単一換字式暗号は約4×1026通りである。これは地球上の海岸の砂粒の数(約1023個)の1000倍以上に相当し、1秒間に10億個の鍵を試しても、全探索に約128億年かかる計算になる。

安全性と弱点

鍵空間が巨大であるにもかかわらず、単一換字式暗号は頻度分析により解読できる。その理由は、暗号化が「文字の1対1置換」に過ぎないため、平文の統計的特徴がそのまま暗号文に反映されるからである。

英語では「E」が約12.7%の頻度で出現する。単一換字式暗号で「E→X」と変換していれば、暗号文中の「X」もやはり約12.7%の頻度で出現する。つまり、暗号文の頻度分布を英語の標準頻度と比較するだけで、文字の対応関係を推測できてしまう。

鍵空間の大きさ ≠ 安全性

単一換字式暗号は、鍵空間が大きくても安全とは限らないことを示す好例である。暗号の安全性は鍵空間の大きさだけでなく、暗号文から平文に関する情報がどれだけ漏れるかによって決まる。

まとめ

項目内容
分類換字式暗号(単一換字)
26文字の置換規則 \sigma
暗号化c_i = \sigma(p_i)
復号p_i = \sigma^{-1}(c_i)
鍵空間26! \approx 4.03 \times 10^{26}
安全性総当たりには耐えるが、頻度分析で解読可能

単一換字式暗号の弱点は、同じ平文の文字が常に同じ暗号文字に変換される点にある。この問題を根本的に解決するために、位置ごとに異なる換字表を適用するヴィジュネル暗号(多表式暗号)が考案された。

実践

下のウィジェットで単一換字式暗号を体験できる。暗号鍵(26文字の並び)を設定して暗号化・復号を試そう。「ランダム鍵」ボタンでランダムな換字表を生成できる。

単一換字式暗号エンコーダー / デコーダー

Python実装

substitution_cipher.py
import string, random

def generate_key():
    alpha = list(string.ascii_uppercase)
    random.shuffle(alpha)
    return ''.join(alpha)

def substitution_encrypt(plaintext, key):
    table = str.maketrans(
        string.ascii_lowercase + string.ascii_uppercase,
        key.lower() + key.upper()
    )
    return plaintext.translate(table)

def substitution_decrypt(ciphertext, key):
    table = str.maketrans(
        key.lower() + key.upper(),
        string.ascii_lowercase + string.ascii_uppercase
    )
    return ciphertext.translate(table)

実行例
key = "DICOXYUZPJKWLHBGSNRFTMLQAE"
ct = substitution_encrypt("attackatdawn", key)
print(f"暗号化: attackatdawn -> {ct}")

pt = substitution_decrypt(ct, key)
print(f"復号:   {ct} -> {pt}")

import math
print(f"\n鍵空間: 26! = {math.factorial(26):,}")
暗号化: attackatdawn -> dffdckdfodlh 復号: dffdckdfodlh -> attackatdawn 鍵空間: 26! = 403,291,461,126,605,635,584,000,000