暗号利用モード(CBC/CTR/GCM)とビット単位の動作原理
なぜ AES だけでは暗号化できないのか腑に落ちる。ブロック暗号を任意長データに広げるモードの内部動作を、ECB の弱点から GCM の認証タグまでビット単位で読み解く。
- 1.AES などのブロック暗号は固定長(128ビット)しか扱えない。任意長データへ広げる手順が利用モードで、ECB/CBC/CTR/GCM はこの広げ方の違い。
- 2.ECB はブロックごとに同じ鍵で独立変換するため平文のパターンが暗号文に透ける。CBC は前ブロックを連鎖させ IV で初期化、CTR はカウンタを暗号化してストリーム化する。
- 3.CBC/CTR は秘匿だけで改ざんを検知できない。GCM は CTR の秘匿に GHASH ベースの認証タグを足した AEAD で、暗号化と完全性を同時に保証する。
ブロック暗号は「固定長の置換」でしかない
AES のようなブロック暗号は、本質的には鍵で選ばれた1つの全単射(置換)です。AES なら入力も出力もちょうど128ビット(16バイト)で固定で、鍵を1本決めると「128ビットの平文ブロック → 128ビットの暗号文ブロック」という対応が1つ決まります。鍵が同じなら、同じ平文ブロックは必ず同じ暗号文ブロックになります。
ここに任意長データを暗号化するうえでの根本問題があります。現実のデータは128ビットちょうどではありません。**「固定長の置換器をどう繰り返し適用し、ブロックをどう繋ぐか」を決める手順が暗号利用モード(mode of operation)**です。AES そのものの強度ではなく、このモードの選び方・使い方こそが事故の温床になります。
ブロック暗号をブロック単位で適用する ECB/CBC は、平文がブロック長の倍数でないと処理できません。そこで末尾を埋めるのがパディング(PKCS#7 など)です。一方、後述の CTR/GCM は平文をキーストリームと XOR するストリーム的な使い方なので、パディングが不要で平文の長さがそのまま暗号文長になります。
ECB:独立変換ゆえにパターンが透ける
最も素朴なモードが **ECB(Electronic Codebook)**です。平文を16バイトごとに区切り、各ブロックを独立に、同じ鍵で暗号化するだけ。連鎖も乱数もありません。
C[i] = E(K, P[i]) # 各ブロックは互いに独立。前後関係なし
この独立性が致命的です。前述のとおり「同じ平文ブロック → 同じ暗号文ブロック」なので、平文に繰り返しパターンがあると、そのパターンが暗号文にそのまま残ります。ビットマップ画像を ECB で暗号化すると元絵の輪郭が透けて見える、という有名な例はこれが原因です。中身は読めなくても、どこが同じデータかという構造情報が漏れます。
ECB は「平文の等値関係が暗号文に保存される」ため、機密性を満たしません。さらに改ざん検知もなく、ブロックの並べ替え・削除・複製にも気づけません。NIST も推奨せず、実務での選択肢から外してください。ECB を避ける理由を理解することが、以降のモードを学ぶ動機です。
CBC:前ブロックを連鎖させ IV で初期化する
**CBC(Cipher Block Chaining)は ECB の弱点を「連鎖」で潰します。各平文ブロックを暗号化する前に、直前の暗号文ブロックと XOR してから暗号化します。先頭ブロックには直前が無いので、代わりにIV(初期化ベクトル)**を XOR します。
C[0] = E(K, P[0] XOR IV) # 先頭は IV で初期化
C[i] = E(K, P[i] XOR C[i-1]) # 以降は直前の暗号文を連鎖
XOR によって、同じ平文ブロックでも直前の暗号文が違えば暗号化への入力が変わるため、ECB のようなパターン漏れが消えます。IV を毎回ランダムに変えれば、同じ平文を同じ鍵で暗号化しても毎回違う暗号文になります。これが CBC の肝です。
CBC の IV は**暗号論的に安全な乱数(CSPRNG)**で生成し、鍵ごとに使い回さないこと。IV を固定・予測可能にすると、先頭ブロックで同一平文が同一暗号文に戻り、ECB と同じ漏洩が起きます。IV は秘密である必要はなく、暗号文に添えて送ってよい値です。なお復号は P[i] = D(K, C[i]) XOR C[i-1] で、復号には逆置換 D を使う点に注意してください。
CBC には2つの実務的な弱点があります。第一に逐次依存で、C[i] は C[i-1] に依存するため暗号化を並列化できません(復号は各ブロックに C[i-1] が揃うので並列可能)。第二に、CBC 自体は改ざんを検知しません。パディング検証のエラー有無を観測するパディングオラクル攻撃が成立し得るため、CBC を使うなら別途 MAC を付ける(Encrypt-then-MAC)か、後述の AEAD を選びます。
CTR:ブロック暗号を「ストリーム暗号」に変える
**CTR(Counter)**は発想を変えます。平文を直接暗号化するのではなく、カウンタ値を暗号化して鍵ストリーム(キーストリーム)を作り、それを平文と XOR します。
S[i] = E(K, nonce || counter+i) # カウンタを暗号化して鍵ストリーム生成
C[i] = P[i] XOR S[i] # 平文と XOR するだけ
注目すべきは、ブロック暗号 E を暗号化方向にしか使わない点です。復号も P[i] = C[i] XOR S[i] と全く同じ S[i] を作って XOR するだけなので、逆置換 D が不要になります。さらに各ブロックの S[i] は他ブロックに依存しないため、暗号化も復号も完全に並列化でき、任意位置からのランダムアクセス復号もできます。CBC の逐次依存という弱点をここで解消しています。
CTR は同じ (鍵, カウンタ) の組から必ず同じ鍵ストリームを生みます。同じ鍵ストリームで2つの平文を暗号化すると、暗号文同士の XOR が平文同士の XORに等しくなり(C1 XOR C2 = P1 XOR P2)、秘匿が崩れます。ノンスとカウンタ空間が重ならない設計が絶対条件で、これは後述の GCM にもそのまま当てはまります。
CTR も秘匿のみで、単体では改ざんを検知しません。XOR ベースゆえ、攻撃者が暗号文の特定ビットを反転すると復号後の平文の同じ位置のビットが反転します(ビット反転攻撃)。CTR を安全に使うには認証が要る――その答えが GCM です。
GCM:CTR の秘匿に GHASH の認証タグを足す
**GCM(Galois/Counter Mode)**は AEAD(Authenticated Encryption with Associated Data)の代表です。一度の処理で機密性(暗号化)と完全性・真正性(認証タグ)を同時に実現します。中身は2段構成です。
- 暗号化:本体は CTR そのもの。ノンスから初期カウンタ
J0を作り、J0+1, J0+2, …を暗号化した鍵ストリームと平文を XOR して暗号文を得る。 - 認証:暗号文と AAD(暗号化しないが改ざん検知したいヘッダ等)を GHASH で畳み込み、最後に
E(K, J0)と XOR して認証タグ(通常128ビット)を生成する。
GHASH は、ガロア体 GF(2^128) 上の乗算を使ったユニバーサルハッシュです。鍵から導出した H = E(K, 0^128) を係数に、各データブロック X[i] を多項式の係数とみなして次の漸化式で畳み込みます(すべて GF(2^128) 上の演算)。
H = E(K, 0…0) # ハッシュ用サブキー(鍵から導出)
Y[0] = 0
Y[i] = (Y[i-1] XOR X[i]) ⊗ H # ⊗ は GF(2^128) の乗算
tag = Y[last] XOR E(K, J0) # 最後に J0 の暗号化値で“鍵付き”にする
ポイントは、GHASH 単体は鍵 H を知れば誰でも計算できるただのハッシュだという点です。最後に E(K, J0)(攻撃者には予測不能)と XOR することで初めて鍵付きの認証タグになり、偽造を防ぎます。復号側は同じ手順でタグを再計算し、一致しなければ平文を一切返さず復号を失敗させます。これにより CTR のビット反転攻撃やパディングオラクルが封じられます。
| 観点 | ECB | CBC | CTR | GCM |
|---|---|---|---|---|
| 連鎖/初期化 | なし(独立) | 前暗号文を連鎖+IV | カウンタを暗号化 | CTR+GHASH |
| パディング | 必要 | 必要 | 不要(ストリーム) | 不要(ストリーム) |
| 並列化 | 可 | 暗号化は不可/復号は可 | 暗号化・復号とも可 | 暗号化・復号とも可 |
| 改ざん検知 | なし | なし(要MAC) | なし | あり(認証タグ) |
| 逆置換 D | 復号で必要 | 復号で必要 | 不要 | 不要 |
| 実務評価 | 使用禁止 | MAC併用が前提 | 単体は不可・要認証 | 推奨(AEAD) |
「AES-GCM が安全なのはなぜか」は、(1) CTR による秘匿、(2) GHASH+E(K,J0) による鍵付き認証タグ、(3) 復号時のタグ検証失敗で平文を返さない、の3点で答えられます。逆に「同じノンスを2回使うと何が起きるか」は、CTR 部での鍵ストリーム再利用に加え、GCM では認証鍵 H の推定→タグ偽造まで波及する、と一段深く押さえると差がつきます。
実装で踏み外さないための原則
モードの理論を理解しても、運用での落とし穴は別にあります。最後に実務原則を整理します。
- モードを自作・選定で凝らない:標準ライブラリの AES-GCM(または ChaCha20-Poly1305)を既定にする。CBC を新規採用する理由は通常ありません。秘匿と改ざん検知を分けて考える基礎は 暗号の基礎 を参照。
- ノンス/IV は CSPRNG で生成し再利用しない:GCM のノンスは96ビット推奨。乱数で衝突が怖い高頻度用途では、鍵ごとのカウンタ方式で一意性を担保します。
- タグは必ず検証する:GCM の復号は「復号してからタグ照合」ではなく、タグ検証に失敗したら平文を一切利用しない実装を使うこと。タグ長を短縮しない(128ビットを使う)。
- 暗号化はハッシュ・署名と役割が違う:暗号化は秘匿、改ざん検知は AEAD のタグや署名の仕事です。両者の違いは ハッシュ化と暗号化の違い、鍵の真正性を保証する基盤は PKI と証明書 を参照してください。
ブロック暗号は固定長の置換にすぎず、それを任意長データに広げ・安全に繋ぐのがモードの役割。ECB(独立→パターン漏れ)、CBC(連鎖+IV→逐次依存・要MAC)、CTR(ストリーム化→並列可・要認証)、GCM(CTR+GHASH→AEAD)という改良の流れを押さえれば、迷ったときの結論は明確です――新規実装は AES-GCM などの AEAD を、ノンス一意・タグ検証必須で使う。
セキュリティ Article
暗号利用モード(CBC/CTR/GCM)とビット単位の動作原理を実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
暗号
比較で見る軸
難易度: advanced / カテゴリ: セキュリティ / タグ数: 5
導入後に効く点
ECB はブロックごとに同じ鍵で独立変換するため平文のパターンが暗号文に透ける。CBC は前ブロックを連鎖させ IV で初期化、CTR はカウンタを暗号化してストリーム化する。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- セキュリティ
- タグ数
- 5
判断チェックリスト
- 自社の用途が「暗号 / AES」に近いか確認する。
- 強みである「AES などのブロック暗号は固定長(128ビット)しか扱えない。任意長データへ広げる手順が利用モードで、ECB/CBC/CTR/GCM はこの広げ方の違い。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。