はじめに
少し前の私は、HTTPS や SSH を毎日使いながら、その中身を自分の言葉で説明できませんでした。AES、RSA、HMAC という単語は知っています。ところが「共通鍵と公開鍵はどういう関係なのか」「署名とハッシュは何が違うのか」と聞かれると、答えに詰まる状態でした。部品の名前は知っているのに、部品どうしのつながり(体系)を一度も整理したことがなかったのです。
この記事は、CySec(東京電機大学が提供する社会人向けのサイバーセキュリティ教育プログラム「国際化サイバーセキュリティ学特別コース」)で学んだ内容を、自分の言葉で再構成した復習ログです。本シリーズの通し番号では #5 にあたります。想定読者は、少し前の私と同じく「実務で TLS や暗号ライブラリを使ってはいるが、共通鍵・公開鍵・署名・ハッシュがどうつながる体系なのかを整理したことがないエンジニア」です。
この記事の軸になる見方を、先に1行で書いておきます。
暗号の歴史は、「秘密にするもの」を小さくしてきた歴史である。
最初は、暗号の仕組み(アルゴリズム)全体が秘密でした。やがて秘密は「鍵」だけに絞られ、さらに「鍵を相手と共有すること」すらやめてしまいます。そして最後に、秘密鍵の使い方を逆転させると「署名」が生まれます。この一本線を図にすると、次のようになります。
読み終えたとき、AES・RSA・HMAC といった単語が「バラバラの名前」ではなく「この一本線のどこかにいる部品」として見えるようになれば成功です。なお私自身まだ学習中なので、間違いがあれば指摘していただけると助かります。
コード例は Python 3.11 で動作確認しています(標準ライブラリのみ使用。pow(e, -1, phi) を使うため Python 3.8 以降が必要です)。
暗号の部品は2つしかない ── 換字と転置
まず用語をそろえます。元のメッセージを 平文、平文を読めない形に変換することを 暗号化、その結果を 暗号文、暗号文を平文に戻すことを 復号 と呼びます。講義で強調されていた小ネタですが、「復号化」とは言いません。「暗号化」の対は「復号」です。
そして、暗号がメッセージに加える操作は、突き詰めると2つしかありません。
-
換字(かえじ、substitution): 文字をほかの文字に入れ替える操作です。たとえば
TDUの各文字を1つ前の文字に置き換えるとSCTになります。 -
転置(transposition): 文字の順序を入れ替える操作です。たとえば
TDUを逆順に並べ替えるとUDTになります。
この2つの部品は、紀元前から使われていました。
- スキュタレー暗号(紀元前5世紀): パピルスの帯を決まった太さの木片に巻きつけて横向きに文字を書き、ほどくと文字の順序がバラバラになる、という仕組みです。「正しい太さの木片」を持つ人だけが読めます。転置の例です。
-
シーザー暗号(紀元前1世紀): アルファベットを
k文字分ずらします。k = 3ならA → D、B → Eと対応させます。換字の例です。
先に伏線を張っておきます。実は、現代の標準暗号である AES の内部も、この「換字」と「転置」の組み合わせでできています。部品そのものは2500年前から変わっていません。変わってきたのは「何を秘密にするか」です。
古典暗号はなぜ敗れたか ── 鍵空間と頻度攻撃
古典暗号の敗北の歴史を、駆け足でたどります。ここで得られる教訓が、現代暗号の設計思想に直結するからです。
シーザー暗号 ── 鍵が26通りしかない
シーザー暗号を Python で書くと、次のようになります。
def caesar_encrypt(plaintext: str, key: int) -> str:
result = []
for ch in plaintext.upper():
if ch.isalpha():
result.append(chr((ord(ch) - ord("A") + key) % 26 + ord("A")))
else:
result.append(ch)
return "".join(result)
print(caesar_encrypt("ATTACK AT DAWN", 3))
実行結果です。
DWWDFN DW GDZQ
シーザー暗号の鍵は「何文字ずらすか」で、選べる値は実質26通りしかありません。鍵の候補全体を 鍵空間 と呼びますが、鍵空間が26なら、全部試せばよいだけです。復号は「逆向きにずらす」操作なので、同じ関数に負の鍵を渡せば総当たりできます。
ciphertext = "DWWDFN DW GDZQ"
for key in range(26):
print(f"key={key:2d}: {caesar_encrypt(ciphertext, -key)}")
実行結果(抜粋)です。key=3 の行に平文が現れています。
key= 0: DWWDFN DW GDZQ
key= 1: CVVCEM CV FCYP
key= 2: BUUBDL BU EBXO
key= 3: ATTACK AT DAWN
(以下略)
アフィン暗号と一般の換字暗号 ── 鍵空間を広げても破れる
ずらすだけでは弱いので、鍵を複雑にする方向の改良が生まれます。アフィン暗号 は、各文字(を数値化した m)を c = (a * m + b) mod 26 で変換します。鍵は (a, b) の組です。ただし a は 26 と互いに素でなければなりません(たとえば a = 2 だと複数の文字が同じ文字に潰れて復号できません)。使える a は12通りで、鍵空間は 12 × 26 = 312 通りです。シーザー暗号(a = 1 の特殊ケース)より広がりますが、総当たりできる規模であることに変わりはありません。
では、思い切って「26文字の置換表そのもの」を鍵にしたらどうでしょうか。これが 一般の単一アルファベット換字暗号 です。置換表の総数は 26!(約4 × 10^26)で、総当たりは現実的に不可能になります。
ところが、これも破られます。英文ではアルファベットの出現頻度に大きな偏りがあるからです。e が最も多く、t や s も多く出ます。暗号文の文字の出現頻度を数えれば、置換表の対応をかなりの精度で推測できます。これが 頻度攻撃 です。さらに、推測した断片から辞書で単語を当てにいく 辞書攻撃 も併用できます。
ここで最初の重要な教訓が得られます。
鍵空間の大きさは、安全性を保証しない。
26! という天文学的な鍵空間を持っていても、平文の統計的な性質が暗号文に漏れていれば破られます。
ヴィジュネル暗号と Enigma ── 機械化の到達点へ
頻度攻撃への対策として、「1つの文字を複数の文字に化けさせる」複数アルファベット換字暗号 が生まれます。16世紀に登場した ヴィジュネル暗号 は、シーザー暗号の「ずらす数」を周期 l の鍵文字列で切り替えていく方式です。同じ e でも位置によって違う文字になるので、単純な頻度の偏りは消えます。それでも、周期 l を推定されると「l 個のシーザー暗号の束」に分解され、頻度攻撃に帰着されてしまいます。
この発想を機械で極限まで進めたのが rotor machine です。単一アルファベット換字を行う歯車(rotor)を複数連結し、1文字暗号化するごとに rotor が回転して置換表が変わります。第二次世界大戦でドイツが使った Enigma が代表例です。
古典暗号の敗北を表にまとめます。
| 方式 | 秘密(鍵) | 破られ方 |
|---|---|---|
| シーザー暗号 | ずらす数(26通り) | 総当たり |
| アフィン暗号 |
(a, b) の組 |
総当たり |
| 単一アルファベット換字 | 置換表(26! 通り) | 頻度攻撃・辞書攻撃 |
| ヴィジュネル暗号 | 周期 l の鍵文字列 |
周期の推定 + 頻度攻撃 |
| Enigma | rotor の構成と初期設定 | 実機・運用情報の流出と解析 |
転換点 ── ケルクホフの原理「秘密は鍵だけにせよ」
ここで歴史の転換点が来ます。実は Enigma より60年も前、1883年に、オランダ生まれの言語学者・暗号学者ケルクホフ(Auguste Kerckhoffs)が論文『La Cryptographie militaire(軍事暗号)』で、軍用暗号が満たすべき原則を示していました。その第2原則が、のちに ケルクホフの原理 と呼ばれるものです。
暗号系は、秘密であることを要求してはならない。敵の手に落ちても不都合がないものでなければならない。
言い換えると、暗号の安全性は、メカニズム(アルゴリズム)の秘密に依存するべきではなく、鍵の秘密だけに依存するべきということです。
Enigma は、この原理の正しさを裏側から証明してしまいました。講義では、U ボートから Enigma の実機が連合国側に渡り、チューリングらによって解析・解読された経緯が紹介されました。メカニズムを秘密にする戦略は、機械が1台流出した時点で崩れます。しかも、流出したことに気づけるとは限りません。一方、秘密が「鍵」だけなら、漏れた鍵を交換すれば仕組み全体は使い続けられます。
現代暗号は、この原理の上に立っています。記法もここで導入しておきます。暗号化アルゴリズムを E、復号アルゴリズムを D、鍵を k, k' として、
c = E(k, m) # 平文 m を鍵 k で暗号化し、暗号文 c を得る
m = D(k', c) # 暗号文 c を鍵 k' で復号し、平文 m を得る
と書きます。E と D は公開されており、秘密は鍵だけです。そして、この k と k' の関係で、現代暗号は2つの世界に分岐します。
アルゴリズムを公開することには、副次効果もあります。世界中の研究者が攻撃を試みることができ、それでも生き残った方式だけを安心して使えるのです。この効果は、のちほど AES の公募の話で再登場します。
共通鍵暗号 ── 秘密は「共有する鍵」だけ
まず k = k' の世界、つまり暗号化と復号で同じ鍵を使う 共通鍵暗号(対称暗号、秘密鍵暗号とも呼びます)です。送信者と受信者が同じ鍵を秘密に共有します。
ストリーム暗号 ── 完全だが使えない OTP と、その妥協
ワンタイムパッド(OTP) は、1917年に Vernam が考案した方式で、平文とまったく同じ長さのランダムなビット列を鍵とし、ビットごとに XOR します。
c = k XOR m # 暗号化
m = k XOR c # 復号(同じ鍵でもう一度 XOR すると戻る)
OTP は 完全秘匿性(perfect secrecy) を持つことが証明されています(Shannon, 1949)。完全秘匿性とは、「暗号文 c を手に入れても、それが平文 m0 の暗号文である確率と m1 の暗号文である確率が等しい」という性質です。直感的に言えば、暗号文から平文の情報が1ビットも漏れません。総当たりすら無意味です。すべての鍵を試すと「すべてのあり得る平文」が等しく出てきてしまい、どれが正解か原理的に判別できないからです。
しかし OTP には致命的な弱点があります。平文と同じ長さの鍵を、安全に、毎回使い捨てで共有しなければならないのです。1GB のファイルを送るのに 1GB の鍵を安全に届けられるなら、最初からファイルを届ければよい、という本末転倒に陥ります。
そこで現実的な妥協として、疑似乱数生成器(PRG) を使います。短い seed(たとえば 128 bit)を入力として長い疑似乱数列を生成し、OTP の「真の乱数」の代わりに使う方式です。共有する秘密は短い seed だけで済みます。完全秘匿性は失われますが、実用的になります。これが ストリーム暗号 です。
ただし、PRG の品質がそのまま安全性になります。代表例の RC4(1987年)は WEP(無線LAN)や HTTPS で広く使われましたが、脆弱性が積み重なり、TLS では RFC 7465(2015年2月)で全バージョンにおいて使用が禁止されました。講義では、LFSR(線形フィードバックシフトレジスタ)ベースの方式にも、DVD の CSS や GSM 携帯電話の A5/1, A5/2 など脆弱なものがあったと紹介されていました。
ブロック暗号 ── DES から AES へ
ストリーム暗号と並ぶもう1つの系統が ブロック暗号 です。固定長のデータブロック(64 bit や 128 bit)を単位として暗号化・復号を行います。内部構造は「初期変換 → 繰り返し関数(段数分くりかえす)→ 最終変換」という形で、繰り返しの段数が堅牢性に効いてきます。
DES(Data Encryption Standard) は、1977年に米国の連邦標準として制定されたブロック暗号です。IBM が開発し、NIST(当時は NBS)が標準化しました。64 bit ブロック、56 bit 鍵、繰り返し部は Feistel 構造です。
DES の最期は、この記事の軸から見ると示唆的です。
- 1993〜1994年: 三菱電機の松井充氏がブロック暗号への線形解読法を提案し、実際に DES の解読実験に成功しました。
- 1998年: EFF(電子フロンティア財団)が製作費25万ドル未満の専用ハードウェア Deep Crack で、DES の鍵を約56時間(3日弱)の総当たりで発見しました(EFF のプレスリリース)。
- 2006年: FPGA を並べた COPACOBANA が、約1万ドルの費用で約7日という水準まで総当たりを「安く」しました(講義資料より)。
注目したいのは、DES が破られた主因はアルゴリズムの構造的欠陥というより、56 bit という鍵空間が計算機の進歩に追い越されたことだという点です。古典暗号の節で「鍵空間の大きさは安全性を保証しない」と書きましたが、逆に「鍵空間が小さすぎれば確実に破られる」のもまた真です。鍵空間は安全性の必要条件であって、十分条件ではないわけです。
後継の AES(Advanced Encryption Standard) は、NIST が1997年に公募し、世界中から提案された候補を公開の場で評価したうえで、2001年に Daemen と Rijmen の Rijndael を選定・標準化したものです(FIPS 197)。128 bit ブロック、鍵は 128/192/256 bit、繰り返し部は SPN 構造 です。
ここで冒頭の伏線を回収します。SPN は Substitution-Permutation Network の略で、S-box による換字(Substitution)とビットの並べ替え(Permutation = 転置)を何段も繰り返す構造です。シーザーとスキュタレーの時代の2つの部品が、形を変えて、いまも世界標準の暗号の中で現役なのです。そして「公開コンペで世界中の攻撃に耐えた方式を標準にする」という AES の選定プロセスそのものが、ケルクホフの原理の体現になっています。
利用モード ── 正しい部品も、使い方を間違えると漏れる
ブロック暗号は固定長のブロックしか暗号化できません。任意の長さのメッセージを暗号化するには、ブロックをどうつないでいくかという 利用モード が必要です。そして、ここに有名な落とし穴があります。
最も素朴な ECB モード は、メッセージをブロックに区切って、それぞれを独立に暗号化します。一見問題なさそうですが、同じ平文ブロックが必ず同じ暗号文ブロックになるため、平文のパターンが暗号文に残ります。これを視覚的に示すのが「ECB ペンギン」として知られる実験です。Linux のマスコット Tux のビットマップ画像を ECB モードで暗号化すると、各ピクセルブロックの色は変わるのに、同じ色の領域は同じ暗号文になるため、ペンギンの輪郭がはっきり見えたままになります。講義資料でも紹介されていた比較画像が、Wikipedia の Block cipher mode of operation のページに掲載されています。
主な利用モードを表で整理します(IV は initialization vector = 初期ベクトルで、ランダムに選びます)。
| モード | 仕組みの概要 | 特徴 |
|---|---|---|
| ECB | 各ブロックを独立に暗号化する | 同一平文ブロックが同一暗号文ブロックになり、パターンが漏れる |
| CBC | 前の暗号文ブロックと XOR してから暗号化する | 同じ平文でもブロックごとに違う暗号文になる。IV が必要 |
| OFB | IV を繰り返し暗号化して鍵ストリームを作り、平文と XOR する | ブロック暗号をストリーム暗号のように使える |
| CTR | IV にブロックごとに +1 した値を暗号化し、平文と XOR する | 各ブロックを独立に計算でき、並列処理しやすい |
ここで2つ目の教訓です。
正しい部品を選んでも、使い方(モード)を誤れば守れない。
AES 自体がどれだけ堅牢でも、ECB で画像を暗号化すれば輪郭は漏れます。暗号は「正しい部品 × 正しい使い方」がそろって初めて機能します。
公開鍵暗号 ── 「鍵を共有する」ことすらやめる
共通鍵暗号は、秘密を「共有する鍵」1つまで小さくしました。しかし、最後の問題が残っています。その鍵を、どうやって相手に安全に渡すのかという鍵配送問題です。安全な通信のために鍵が必要なのに、鍵を渡すための安全な通信路がない。しかも n 人が相互に通信するなら n(n-1)/2 個の鍵を管理することになります。
この問題に正面から答えたのが、1976年の Diffie と Hellman の論文 New Directions in Cryptography です。この論文は公開鍵暗号とディジタル署名の概念を提示しました(具体的な暗号方式はまだありませんでした)。そして1978年、Rivest・Shamir・Adleman の3人が初の具体的な方式を提案します。3人の頭文字を取った RSA暗号 です。
公開鍵暗号の発想はこうです。暗号化に使う鍵(公開鍵)は、いっそ公開してしまう。復号に使う鍵(秘密鍵)だけを手元に置く。 誰でも公開鍵でメッセージを暗号化して送れますが、復号できるのは秘密鍵を持つ本人だけです。これが成立するために必要な性質はただ1つ、「公開鍵から秘密鍵を求めることが困難である」ことです。
この記事の軸で言えば、秘密はついに「自分しか持たない秘密鍵」1つまで縮みました。もう誰とも秘密を共有しません。
公開鍵暗号の構造と、支える数学
公開鍵暗号は、3つのアルゴリズムで構成されます。
-
鍵生成
G: セキュリティパラメータk(鍵長のようなもの)を入力に、公開鍵と秘密鍵のペアを出力します。Gは確率的アルゴリズムでなければなりません(毎回同じ鍵ペアが出てきたら困ります)。 -
暗号化
E: 公開鍵と平文から暗号文を作ります。Eが確率的アルゴリズムであるものを 確率暗号 と呼び、安全のためには確率暗号であるべきとされます(理由は後述します)。 -
復号
D: 秘密鍵と暗号文から平文を返します。Dは確定的アルゴリズムでなければなりません。
「公開鍵から秘密鍵を求めるのが困難」という性質は、数学の「一方向には簡単だが、逆向きは困難」な問題で実現されます。代表は次の2つです。
-
素因数分解問題: 大きな素数
p,qを掛けてn = pqを作るのは一瞬ですが、nからp,qを求めるのは(nが十分大きければ)困難と予想されています。 -
離散対数問題:
y = g^x mod pをxから計算するのは一瞬ですが、yからxを求めるのは困難と予想されています。
教科書RSA を動かしてみる
RSA 暗号(素因数分解問題ベース)の骨格は、驚くほど短く書けます。
-
鍵生成: 異なる素数
p,qを選び、n = pqとします。ed ≡ 1 mod (p-1)(q-1)となるe,dを求めます。(n, e)が公開鍵、dが秘密鍵です。 -
暗号化:
c = m^e mod n -
復号:
m = c^d mod n
小さな数で実際に動かしてみます。
p, q = 61, 53
n = p * q # 3233
phi = (p - 1) * (q - 1) # 3120
# (p-1)(q-1) と互いに素な値を選ぶ
e = 17
d = pow(e, -1, phi) # e * d ≡ 1 mod phi となる d(Python 3.8+)
# 平文(n より小さい数として表現したメッセージ)
m = 65
c = pow(m, e, n) # 暗号化: c = m^e mod n
m2 = pow(c, d, n) # 復号: m = c^d mod n
print(f"公開鍵 (n, e) = ({n}, {e}) / 秘密鍵 d = {d}")
print(f"暗号化: m = {m} -> c = {c}")
print(f"復号: c = {c} -> m = {m2}")
実行結果です。
公開鍵 (n, e) = (3233, 17) / 秘密鍵 d = 2753
暗号化: m = 65 -> c = 2790
復号: c = 2790 -> m = 65
e 乗して d 乗すると元に戻る、という対称性のきれいな仕組みです。
このコードは絶対に実用に使わないでください。 これは仕組みを理解するための「教科書RSA(Textbook RSA)」です。鍵が小さすぎて一瞬で素因数分解できるのはもちろん、たとえ鍵を大きくしても、このままの素朴な RSA は同じ平文から常に同じ暗号文ができる(確率暗号ではない)など、さまざまな攻撃が可能なことが知られています。実務では必ず実績のある暗号ライブラリを使ってください。
素朴なRSA が確率暗号になるまで ── PKCS #1 と OAEP
「教科書RSA はそのままでは危ない」という話には、具体的な歴史があります。実用の RSA では平文にパディング(詰め物)を施してから暗号化します。PKCS #1 v1.5 というパディング規格である程度の安全性が確保されると期待されていましたが、1998年に Bleichenbacher が、PKCS #1 v1.5 パディングは選択暗号文攻撃に対して秘密鍵の情報を漏らすことを示しました。
その後、Bellare と Rogaway が提案した OAEP(Optimal Asymmetric Encryption Padding) を RSA と組み合わせる方式(RSA-OAEP)が登場し、Fujisaki・Okamoto・Pointcheval・Stern によって、選択暗号文攻撃に対して安全であることが証明されました(内部のハッシュ関数をランダム関数とみなすモデルでの証明です)。OAEP は乱数を混ぜ込むので、同じ平文でも毎回違う暗号文になります。つまり RSA を 確率暗号 にする仕掛けでもあります。現行の RSA 仕様である RFC 8017(PKCS #1 v2.2)でも、新規のアプリケーションには RSAES-OAEP の採用が推奨されています。
「暗号を自作するな」「ライブラリの低レベル API を生で叩くな」とよく言われる理由が、この歴史に詰まっています。式としては正しい RSA でも、周辺の設計(パディング)が一段甘いだけで秘密鍵が漏れるのです。
離散対数の世界 ── DH 鍵交換と ElGamal
公開鍵の世界を支えるもう1つの土台、離散対数問題の側も見ておきます。まず Diffie-Hellman 鍵交換 です。これは「暗号化」ではなく「鍵の合意」の仕組みです。お互いに乱数 a, b を秘密に持ち、g^a mod p と g^b mod p を公開で交換すると、双方が同じ値 g^ab mod p を計算できます。盗聴者は g^a と g^b を見ても、離散対数問題が解けない限り g^ab を求められません。TLS 1.3 の鍵交換 (EC)DHE は、この仕組みを毎回使い捨ての値で行うもので、実用上は楕円曲線版(ECDHE)が主流です。
離散対数問題ベースの公開鍵暗号としては ElGamal暗号 があります。Diffie-Hellman の鍵配送方式を変形したもので、暗号化のたびに乱数 r を選び、c = (g^r mod p, m * y^r mod p) という2要素の暗号文を作ります。乱数 r のおかげで、同じ平文でも毎回違う暗号文になる、確率暗号のわかりやすい実例です。
秘密鍵の使い方を逆にすると「署名」になる
ここまでで、秘密は「自分しか持たない秘密鍵」まで縮みました。最後の一歩は、秘密を小さくする話ではなく、秘密鍵の使い方を逆転させる話です。
RSA の暗号化では「公開鍵で暗号化し、秘密鍵で復号」しました。これを逆にして、秘密鍵で変換し、公開鍵で確認するとどうなるでしょうか。
-
署名:
σ = m^d mod n(秘密鍵dで署名σを作る) -
検証:
m ≡ σ^e mod nが成立するか確認する(公開鍵eで誰でも検証できる)
秘密鍵 d を持つのは本人だけなので、検証が通る σ を作れたのは本人だけのはずです。これが ディジタル署名 です。先ほどの数値例の続きで確認できます。
sigma = pow(m, d, n) # 署名: σ = m^d mod n
print(f"署名: σ = {sigma}")
print(f"検証: σ^e mod n == m -> {pow(sigma, e, n) == m}")
実行結果です。
署名: σ = 588
検証: σ^e mod n == m -> True
ディジタル署名も、鍵生成(G)・署名(Sign)・検証(Vrfy)の3アルゴリズムで構成されます。署名に使う秘密鍵を 署名鍵、検証に使う公開鍵を 検証鍵 と呼びます。
これも「教科書RSA署名」です。講義でも、復号アルゴリズムをそのまま署名生成に流用するだけでは安全なディジタル署名にはならない、と補足されていました。実際の RSA 署名は、メッセージそのものではなくメッセージのハッシュ値にパディングを施してから署名します(RFC 8017 の RSASSA-PSS など)。
MAC とハッシュ関数 ── 体系の残りのピースを埋める
署名が出てきたところで、体系の地図を完成させます。暗号技術が守るものは「機密性(盗み見させない)」だけではありません。「完全性・認証(改ざんやなりすましを検出する)」も守ります。そして、共通鍵系と公開鍵系のそれぞれに、機密性の道具と完全性の道具があります。
| 守りたい性質 | 共通鍵系 | 公開鍵系 |
|---|---|---|
| 機密性(盗み見させない) | 共通鍵暗号(AES など) | 公開鍵暗号(RSA-OAEP など) |
| 完全性・認証(改ざん・なりすましの検出) | MAC(HMAC など) | ディジタル署名 |
MAC(Message Authentication Code) は、送信者と受信者が秘密鍵を共有し、その鍵でメッセージから短い tag を計算する仕組みです。受信者は同じ鍵で tag を検証し、改ざんの有無を判定します。「共通鍵版の署名」と捉えると、表の対応がきれいに見えます。
ハッシュ関数 は、任意長のデータを固定長(256 bit など)のハッシュ値に圧縮する関数です。セキュリティ用途では、次の2つの性質が要求されます。
-
一方向性:
y = H(x)を満たすxを、yから求めるのが困難であること。 -
耐衝突性:
H(a) = H(b)となる異なるa,bを見つけるのが困難であること。
ハッシュ関数自体は鍵を持たない「圧縮の道具」ですが、ほかの部品の材料として体系のあちこちに顔を出します。ハッシュ関数から MAC を構成したものが HMAC ですし、ディジタル署名が「ハッシュ値に署名する」のは先ほど見たとおりです。もし耐衝突性が破れて同じハッシュ値を持つ2つの文書を作れるなら、片方への署名がもう片方への署名としても通ってしまいます。ハッシュの性質が、署名の安全性を直接支えているわけです。
全部 TLS に入っている
ここまでに登場した部品を、1か所で全部使っているシステムがあります。あなたが今この記事を読むのに使った TLS(https:// の s)です。現行の TLS 1.3(RFC 8446)の構成要素を、この記事の登場人物と対応させてみます。
| TLS 1.3 がやること | 使われる部品 | この記事での登場箇所 |
|---|---|---|
| 鍵交換((EC)DHE)で共通鍵の材料を共有する | 離散対数問題系の公開鍵技術 | DH 鍵交換 |
| サーバ証明書で通信相手を認証する | ディジタル署名(RSA, ECDSA) | ディジタル署名 |
| アプリケーションデータを暗号化する | AEAD(AES-GCM, ChaCha20-Poly1305)= 共通鍵暗号 + 改ざん検出 | 共通鍵暗号・MAC |
| セッション鍵を導出する(HKDF) | HMAC ベースの鍵導出 = ハッシュ関数 | ハッシュ関数・MAC |
なぜ全部入りなのかには、明確な理由があります。公開鍵暗号は共通鍵暗号に比べてはるかに低速なので、大量のデータを公開鍵暗号で直接暗号化するのは現実的ではありません。そこで「鍵の共有は公開鍵系で行い、本文の暗号化は高速な共通鍵系で行う」という分業(ハイブリッド構成)になっています。Diffie と Hellman が1976年に提起した鍵配送問題の答えが、毎日のハンドシェイクの最初の一往復で動いているのです。
紀元前の換字・転置から数えておよそ2500年。「秘密を小さくする」進化の到達点を、私たちは https:// の一文字として毎日使っています。
まとめ
この記事では、CySec 第4回「暗号学」の内容を、「暗号の歴史は『秘密にするもの』を小さくしてきた歴史である」という一本線で再構成しました。
- 暗号の部品は 換字と転置 の2つだけです。この2部品は、AES の SPN 構造の中でいまも現役です。
- 古典暗号の敗北からの教訓は2つです。鍵空間の大きさは安全性を保証しない(頻度攻撃)、そしてメカニズムの秘密は守りきれない(Enigma)。
- 転換点は ケルクホフの原理(1883年)です。アルゴリズムは公開し、秘密は鍵だけに依存させる。これが現代暗号の出発点です。
- 共通鍵暗号 は秘密を「共有する鍵」まで、公開鍵暗号 は「誰とも共有しない秘密鍵」まで縮めました。ただし教科書RSA と OAEP の歴史が示すとおり、正しい部品も使い方(パディング・モード)を誤れば破られます。
- 秘密鍵の使い方を逆転させると ディジタル署名 になります。MAC とハッシュ関数を加えると、TLS 1.3 を構成する部品が全部そろいます。
講義の後半は、安全性の定義(攻撃モデルと攻撃目標の組み合わせ)の話でした。「選択暗号文攻撃」という言葉がこの記事にも出てきましたが、攻撃の強さをどう定義し、何をもって「安全」と言うのかは、それ自体が大きなテーマです。この記事の範囲を超えるので、稿を改めて整理する予定です(近日公開予定)。
最後まで読んでいただき、ありがとうございました。AES・RSA・HMAC が「一本線の上の部品」として見えるようになっていれば、これ以上うれしいことはありません。
参考資料
- Kerckhoffs, "La Cryptographie militaire" (1883) 原文アーカイブ
- RFC 7465: Prohibiting RC4 Cipher Suites
- EFF DES Cracker Press Release (1998年7月)
- FIPS 197: Advanced Encryption Standard (AES)
- RFC 8017: PKCS #1: RSA Cryptography Specifications Version 2.2
- RFC 8446: The Transport Layer Security (TLS) Protocol Version 1.3
- Diffie & Hellman, "New Directions in Cryptography" (1976)
- Block cipher mode of operation(Wikipedia、ECB ペンギンの比較画像)
あわせて読みたい
CySec 復習ログシリーズです。
- なぜ情報セキュリティは標準化されるのか ── ISO/IEC とマネジメントシステムの基礎【CySec復習ログ#1】
- ISMSの歴史と2022年大改定 ── BS7799からリスクマネジメント(ISO 31000)まで【CySec復習ログ#2】
- 内部統制を「リスク(脆弱性)に打つ実装戦略」として理解し直す【CySec復習ログ#3】
- 「ルールを守っているか」では、セキュリティは守れない ── 準拠性監査から有効性監査へ【CySec復習ログ#4】
- その多要素認証、どの攻撃に効いてますか? ── 脅威で認証を整理し直す【CySec復習ログ#6】
- 数学的に安全な暗号が寿命を迎える2つの理由【CySec復習ログ#7】
- ランサム攻撃は「単発事件」ではなく「分業された産業」── MITRE ATT&CKで攻撃の連鎖を読む【CySec復習ログ#8】
同じ「復習ログ」シリーズ(セキュリティ資格の学習ログ):