シーザー暗号・XOR暗号を解く
文字を「ずらす」最古の暗号と、ビット単位で「反転」させる現代的な暗号。2つの古典的暗号の仕組みと、CTFで実際に使われる解読テクニック「総当たり攻撃」「既知平文攻撃」を体験します。
📋 目次
🏰 シーザー暗号とは何か|文字を「ずらす」最古の暗号
2000年以上前から使われる、もっとも単純な暗号
ローマ帝国の軍事暗号
シーザー暗号は、古代ローマの将軍ユリウス・カエサルが軍事連絡に使ったとされる暗号です。仕組みは驚くほど単純で、アルファベットを一定の数だけずらして置き換えるだけ。例えば「shift(シフト)3」なら、A→D、B→E、C→Fのように3文字後ろの文字に変換します。アルファベットの最後(Z)まで来たら先頭(A)に戻ります。
シーザー暗号は「シフト数」が鍵(パスワード)の役割を果たします。送信者と受信者がシフト数を共有していれば、受信者は逆方向にずらすだけで元の文章を復元できます。仕組みは単純ですが、これが暗号の最も基本的な考え方「鍵を使って情報を変換し、鍵を持つ者だけが元に戻せる」を体現しています。
🔍 シーザー暗号を解読する(総当たり攻撃)
鍵の候補がたった25個しかない、という致命的な弱点
シーザー暗号には決定的な弱点があります。アルファベットは26文字なので、シフト数の候補は1〜25の25パターンしかありません。鍵を知らなくても、全パターンを順番に試して「意味の通る文章」が出てきたところで解読完了です。これを総当たり攻撃(ブルートフォース攻撃)と呼びます。
Consoleで25パターンを一瞬で試す
第2話で学んだConsoleタブを使えば、25回のループであっという間に全パターンを表示できます。長い文章であれば、目で見て英語(または日本語ローマ字)として読める結果を見つけるだけです。
ROT13という有名な特殊ケース
シフト数が13の場合をROT13と呼びます。26文字の半分なので、同じ変換をもう一度行うと元の文章に戻る(自己逆変換)という面白い特徴があります。暗号強度はゼロですが、フォーラムやネタバレ防止のテキスト隠しとして今でも使われています。
⚡ XOR暗号とは何か|ビット単位の排他的論理和
「同じなら0、違うなら1」というシンプルな演算が生む強力な性質
XOR(排他的論理和、記号は^)は、2つのビットを比較し「両方が同じなら0、違うなら1」を返す論理演算です。JavaScriptでは5 ^ 3のように書きます。一見地味な演算ですが、暗号の世界では非常に重要な性質を持っています。
暗号化と復号がまったく同じ演算でできるのがXOR暗号の特徴です。平文をキーでXORすれば暗号文になり、暗号文を同じキーでXORすればまた平文に戻ります。さらに重要なのは、暗号文と平文が分かれば鍵が計算できるという点です。これが次のセクションで使う攻撃の核心になります。
🗝️ XOR暗号を解読する(既知平文攻撃)
「答えの一部を知っている」ことが最大の武器になる
既知平文攻撃(Known-Plaintext Attack)とは
暗号文の一部分が何を意味するか、あらかじめ分かっている状況での攻撃手法です。CTFでは「フラグは必ずCTF{から始まる」という形式が決まっているため、この4文字が常に「既知の平文」として使えます。これは現実のセキュリティ診断でも実際に使われる、由緒正しい攻撃手法です。
単一バイトの鍵で暗号化されたXOR暗号なら、攻撃はとても簡単です。暗号文の最初の1バイトと、知っている平文(Cの文字コード)をXORするだけで鍵が判明します。鍵が分かれば、暗号文全体に同じ鍵をXORして残りをすべて復号できます。
| 暗号方式 | 単位 | 鍵の候補数 | 解読の弱点 |
|---|---|---|---|
| シーザー暗号 | 文字 | 25パターン | 総当たりで一瞬 |
| XOR暗号(単一バイト鍵) | バイト | 256パターン | 既知平文があれば鍵が即座に判明 |
| XOR暗号(複数バイト鍵) | バイト(繰り返し) | 256鍵の長さ | 鍵の長さ分の既知平文が必要 |
本物のセキュリティでも教訓になる話
「形式が決まっているデータ」をXORだけで保護するのは危険です。JSONなら必ず{で始まる、PDFなら必ず%PDFで始まる……このような既知のヘッダーがあるだけで、単純なXOR暗号は簡単に破られます。本物の暗号化にはAESなど検証済みのアルゴリズムを使うべき理由がここにあります。
🧩 5分CTFチャレンジ:XOR暗号の鍵を見破れ!
「CTF{」が常に先頭にあることを利用する
下の通信ログは、単一バイトのXOR鍵で暗号化されています。鍵は不明ですが、フラグは必ずCTF{から始まることが分かっています。この事実を使って鍵を導き出し、暗号文全体を復号してください。
チャレンジの手順
① 下の16進数の暗号文をコピーする → ② F12 → Consoleタブを開く → ③ 16進数を1バイトずつの数値配列に変換する → ④ 配列の最初の値と'C'.charCodeAt(0)をXORして鍵を求める → ⑤ 求めた鍵を配列全体にXORして文字列に戻す → ⑥ 完成したフラグを入力!
ENCRYPTED (HEX):
190e1c21026a080511146a0d14050a166e6b140e69020e27
Consoleにそのまま貼り付けられるコード例
var hex="(上の暗号文)";
var b=hex.match(/../g).map(function(h){return parseInt(h,16);});
var key=b[0]^'C'.charCodeAt(0);
var plain=b.map(function(x){return String.fromCharCode(x^key);}).join('');
console.log(plain);
既知平文攻撃で鍵を導き、復号して得られたフラグを入力してください。
暗号文は16進数なので、2文字ずつ区切って数値(0〜255)に変換します。JavaScriptならhex.match(/../g).map(h=>parseInt(h,16))で配列にできます。
配列の0番目の値は「平文の’C’(文字コード67)をXORした結果」です。つまり鍵 = 配列[0] ^ 67で求まります。求めた鍵を配列の全要素にXORし、String.fromCharCodeで文字列に戻すとフラグが完成します。
📝 まとめ+FAQ+次回予告
今回のポイントを振り返ろう
第11話では、2000年前から使われるシーザー暗号と、ビット演算によるXOR暗号という2つの古典的暗号を学びました。シーザー暗号は鍵の候補が少なすぎる弱点があり、XOR暗号は既知平文攻撃という実践的な手法で鍵そのものを暴くことができます。どちらも「暗号の歴史」と「攻撃者の思考プロセス」を理解する上で欠かせない基礎知識です。
・シーザー暗号はアルファベットをシフトする文字単位の暗号
・シフト数は25パターンしかないため総当たり攻撃で一瞬で解ける
・XOR暗号は同じ演算で暗号化も復号もできる(自己逆変換)
・暗号文 ^ 既知の平文 = 鍵、という既知平文攻撃が成立する
・CTFのフラグは必ずCTF{で始まるため、それ自体が既知平文として使える
Q. ROT13は誰でも解読できますか?
はい、ROT13は暗号強度がゼロで、シフト数が13と分かっている(あるいは推測できる)ため、誰でも一瞬で解読できます。実用上はネタバレ防止のような「うっかり読んでしまわないようにする」程度の役割しかありません。
Q. XOR暗号の鍵が複数バイトだったらどうなりますか?
鍵の長さ分の既知平文が必要になります。例えば鍵が3バイトなら、最初の3バイトの平文が分かれば鍵全体が判明します。鍵の長さが分からない場合は、暗号文の繰り返しパターンを統計的に分析する「カシスキー検査」のような手法が使われますが、これは中級編で扱うトピックです。
Q. シーザー暗号やXOR暗号は今でも実際に使われていますか?
セキュリティ目的としてはまったく使われません。現代の暗号化にはAES(共通鍵暗号)やRSA(公開鍵暗号)など、数学的に解読困難であることが証明されたアルゴリズムが使われます。シーザー暗号やXOR暗号は、暗号の基本概念を学ぶ教材として、またCTFの入門問題として今も活躍しています。
Q. なぜCTFの問題でXORがよく出題されるのですか?
実装が簡単でビット演算の基礎を試せること、既知平文攻撃のような実践的な攻撃手法を体験できること、そして本物のマルウェアや難読化ツールでも実際にXORが「簡易な隠蔽」として使われることがあるためです。XORを見たら「既知平文攻撃が効くかもしれない」と考えるのがCTFプレイヤーの基本姿勢です。
ハッシュ関数とパスワードクラック
これまでフラグ判定に使ってきたSHA-256の正体に迫り、ハッシュの「不可逆性」とパスワードクラックの基本(辞書攻撃・レインボーテーブル)を体験します。
📚 参考情報
- IPA「暗号技術解説」(情報処理推進機構)
- MDN Web Docs「ビット単位演算子」(Mozilla)
- NIST FIPS 197 — Advanced Encryption Standard(AES仕様書)


コメント