はじめに
基本情報・応用情報試験などで必ず出てくる「共通鍵暗号方式」「公開鍵暗号方式」。
正直、試験のために暗記してた頃(この記事を書く前)は「暗号化に使うのは公開鍵と秘密鍵どっちだっけ?」と迷うことがあったのですが、仕組みを理解するとこんな迷いはまずなくなります。
今回は、暗記レベルから一歩解像度を上げて理解することが目的です。
概要
記事の流れはこんな感じです。章ごとに順に読み進めると、技術同士のつながりが見えてきます。
「共通鍵暗号方式」で暗号文のやり取りができる!
→ 「鍵配送問題」のジレンマ
→ 解決策として「公開鍵暗号方式」(けど処理は遅い...)
→ 両者のいいとこ取りの「ハイブリッド暗号方式」登場
→ 公開鍵をすり替えられたらお終い...(中間者攻撃)
→ 対策の土台となる「デジタル署名」(改ざん・なりすましを検知!)
→ でも、署名の検証に使う公開鍵もすり替えられたらお終い...
→ 認証局が公開鍵の持ち主を保証する「電子証明書」で対策!
→ まとめ:これら全部を組み合わせた実例「TLS」
登場する技術と、それぞれで達成したいことを整理するとこうなります。
- 暗号化 → 機密性(第三者に見られても読めない)
- デジタル署名 → 完全性・真正性・否認防止(改ざんされていない、本人が作った、送った本人が言い逃れできない)
- 電子証明書 → 公開鍵の真正性(その公開鍵が確かに本人のもの)
共通鍵暗号方式
第三者には読めない形でメッセージをやり取りしたい2人がいるとします。両者は事前に同じ鍵を共有しておきます。
メッセージはこの鍵で暗号化することができ、同じ鍵を使って復号することができます。
同じ鍵を持っていれば復号できてしまうので、第三者には絶対に秘密です。
図の通り暗号文のやり取りはシンプルです。
ただ、
「そもそも共通鍵をどうやって第三者にバレず安全に共有するの?」
「もともと安全な経路なら暗号化する必要もないし、安全じゃない経路で鍵交換したら鍵を盗まれるんじゃ?」
という疑問が出てくると思います。これは「鍵配送問題」と呼ばれています。
まさにこの問題を解決するために考案されたのが、次の章で解説する「公開鍵暗号方式」です。
ちなみに、鍵配送問題の解決策には「Diffie-Hellman(ディフィー・ヘルマン)鍵共有」という方法もあります。これは公開鍵暗号の考え方を使った手法で、共通鍵そのものは送らずに、公開された通信路で情報を交換し、通信相手と同じ秘密の値をそれぞれ計算します。詳細には触れませんが、とにかく「素晴らしいアイディアによって安全に共通鍵を作れる」ということです。
公開鍵暗号方式
共通鍵暗号方式では「鍵をどうやって安全に共有するか」が問題でした。
公開鍵暗号方式は、そもそも暗号化と復号で別々の鍵を使うことでこの問題を回避します。
受信者は「公開鍵」と「秘密鍵」の2つで1組の鍵(鍵ペア)を作ります。
公開鍵で暗号化したものは、ペアになっている秘密鍵でしか復号できません。
公開鍵は名前の通り誰に見られても構わないものです。秘密鍵は受信者だけが持ち、誰にも渡しません。
この仕組みを使って共通鍵を安全に交換することができるのですが、それは後で「ハイブリッド暗号方式」の章で説明します。
実際に暗号化、復号を体感
ちょっとここで、実際に暗号化と復号を試してみます。
macOSに標準で入っているopensslコマンドを使います。
# 秘密鍵を作る
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out private.pem
# 秘密鍵から公開鍵を取り出す
openssl pkey -in private.pem -pubout -out public.pem
# 公開鍵で暗号化する
echo "私の暗証番号はXXXXです。" > msg.txt
openssl pkeyutl -encrypt -pubin -inkey public.pem -in msg.txt -out msg.enc
# 暗号文は読めない
cat msg.enc
# 秘密鍵で復号する
openssl pkeyutl -decrypt -inkey private.pem -in msg.enc
ここでは一人二役やりましたが、公開鍵 public.pem を相手に渡し、相手が暗号化した msg.enc を送り返してもらうことで、秘密鍵 private.pem を持っている自分しか復号できないということになります。
ちなみに、手順に「秘密鍵から公開鍵を取り出す」とありますが、
- 秘密鍵 → 公開鍵:簡単に計算できる
- 公開鍵 → 秘密鍵:現実的な時間では計算できない
という一方通行の性質があるため公開鍵は公開しても大丈夫なのです。
比較
共通鍵暗号と公開鍵暗号の仕組みをざっくり理解したところで、それぞれの方式の特徴を比較しながら理解していきたいと思います。
アルゴリズム
代表的なアルゴリズムをまとめました。
【共通鍵暗号方式】
共通鍵暗号のアルゴリズムは、時代とともに「解読される → より強いものに置き換わる」という世代交代を繰り返してきました。現在の主流はAESです。
| アルゴリズム | ポイント |
|---|---|
| DES / 3DES | 旧米国標準のブロック暗号。DESは鍵が短く解読可能、3DESはDESを3回かけた延命策。 現在は非推奨。 |
| RC4 | WEPやSSL/TLSで普及したストリーム暗号。 脆弱性が見つかり、TLSでの使用は禁止。 |
| AES | DESの後継で現在の標準。TLSや無線LANで使用される。 |
【公開鍵暗号方式】
公開鍵暗号のアルゴリズムは、「計算するのは簡単だが、逆算するのは非常に難しい」数学の問題を安全性の根拠にしています。長く主流だったのはRSAですが、近年はより短い鍵で同じ強さを実現できる楕円曲線暗号が広く使われているようです。
| アルゴリズム | ポイント |
|---|---|
| RSA | 最も代表的な公開鍵暗号。大きな数の素因数分解が難しいことを安全性の根拠にしている。 名前は考案者3人の頭文字(Rivest-Shamir-Adleman)。 |
| 楕円曲線暗号 | 楕円曲線上の離散対数問題の難しさを利用。 RSAより短い鍵長で同等の安全性を確保できる。 |
処理の速さ
暗号化・復号の処理の速さを比較すると、
共通鍵暗号:速い
公開鍵暗号:遅い
となります。
【共通鍵暗号が速い理由】
共通鍵暗号の鍵は、送信者と受信者の2人だけが知る秘密です。鍵そのものが秘密なので、暗号化の仕組みに求められるのは「鍵を知らない人には元のデータが推測できないほど、データをかき混ぜること」だけです。
かき混ぜるだけなら、ビットを入れ替えたり置き換えたりといった、コンピュータが大得意な単純作業の繰り返しで十分。だから速い。
【公開鍵暗号が遅い理由】
一方、公開鍵暗号では暗号化に使う公開鍵を誰でも知ることができます。それでも安全であるためには、「公開鍵から秘密鍵を計算で求めることが事実上不可能」である必要があります。
「それってどうやるの?」って話ですが、「一方向には簡単でも、逆方向には極めて難しい」という数学的な関係を利用しています。
例えば、2つの素数を掛けるのは簡単だけど、その結果から元の素数を求める(素因数分解)のは難しい、という関係です。
例)61 × 53 = 3233(掛け算は一発で終わる)
「じゃあ 3233 は何と何の掛け算?」→ 2で割れる?3で割れる?5は?7は?……と小さい素数から順に試していく
この程度の桁数なら十数回で辿り着けますが、実際に使われているのは数百桁(RSAだと約617桁)で、こうなるとコンピュータでも現実的な時間では逆算できません。
数学的に複雑な計算をするため、正規の利用者が行う暗号化・復号の計算も重くなってしまいます。これが公開鍵暗号が遅い理由です。
【まとめ】
| 方式 | 処理の速さ | 理由 |
|---|---|---|
| 共通鍵暗号 | 速い | 鍵自体が秘密だから、単純なビット演算でかき混ぜるだけで済む |
| 公開鍵暗号 | 遅い | 公開鍵から秘密鍵を逆算されないように、巨大な数で重い計算をする |
必要な鍵の数
【共通鍵暗号方式:多い】
共通鍵暗号方式では、通信する2者の組ごとに別の鍵が必要です。
例えば、3人が互いに秘密の通信をする場合、ペアごとに1本ずつ共通鍵が必要です。
3人から2人を選ぶ組み合わせなので 3C2 = 3×2/2 = 3本 です。
つまり、n人なら nC2 で n(n−1)/2 が必要な数です。
100人なら4,950本必要になり、人数が増えるほど膨大な数の鍵が必要になります。
【公開鍵暗号方式:少ない】
公開鍵暗号方式では、例えば3人が互いに秘密の通信をする場合、各人が自分専用の鍵ペア(公開鍵と秘密鍵)を1組ずつ持ちます。
Aさん: 公開鍵A / 秘密鍵A
Bさん: 公開鍵B / 秘密鍵B
Cさん: 公開鍵C / 秘密鍵C
鍵の総数は 3人× 2本(公開鍵1+秘密鍵1) = 6本(3組)です。
実際の通信では、公開鍵を相手に渡して使います。例えばBさんとCさんがAさんに送る場合は次のようになります。
鍵が「人」に紐づくので、相手の人数に関係なく1人あたり2本(1組)で済みます。
つまり、n人 × 2本(公開鍵1+秘密鍵1) = 2n が必要な数になります。
100人なら200本になり、「共通鍵暗号方式」と比べて圧倒的に少なく済みます。
【まとめ】
| 方式 | 必要な鍵の数 | 計算式 |
|---|---|---|
| 共通鍵暗号 | 多い | n(n−1)/2 |
| 公開鍵暗号 | 少ない | 2n |
(補足)
3人の例では、実は公開鍵暗号方式の方が鍵の数は多くなります(共通鍵3本、公開鍵6本)。両者が並ぶのは5人(どちらも10本)で、それより人数が増えるほど公開鍵暗号の方が圧倒的に少なくなる、という意味での多い・少ないです。
共通鍵暗号と公開鍵暗号のまとめ
| 項目 | 共通鍵暗号 | 公開鍵暗号 |
|---|---|---|
| 暗号化と復号の鍵 | 同じ鍵 | 別の鍵(公開鍵と秘密鍵) |
| 必要な鍵の数 | 多い n(n−1)/2
|
少ない 2n
|
| 処理の速さ | 速い | 遅い |
| 鍵の受け渡し | 安全な手段が必要(鍵配送問題) | 公開鍵は誰に渡してもよい |
| 代表例 | AES | RSA、楕円曲線暗号 |
| 主な用途 | データ本体の暗号化 | 鍵の共有、デジタル署名(※後述) |
ハイブリッド暗号方式
ここまでで、共通鍵暗号と公開鍵暗号にはそれぞれ得意・不得意があることが分かりました。
共通鍵暗号:処理は速いけど、鍵を安全に渡せない(鍵配送問題)
公開鍵暗号:鍵は安全に渡せるけど、処理が遅い
この両者のいいとこ取りをして、鍵配送問題の解決と処理の速さを両立したのが「ハイブリッド暗号方式」です。
仕組み
処理の流れはこんな感じです。
ポイントは役割分担です。
公開鍵暗号 → 共通鍵を安全に共有するためだけに使う
共通鍵暗号 → データ本体の暗号化に使う
「これで完璧じゃん!」と思いきや、まだ問題が...
その公開鍵は本物?
「公開鍵が本物かどうか分からなくない?」
もし攻撃者に公開鍵をすり替えられたら、送信者は攻撃者の公開鍵で共通鍵を暗号化してしまい、攻撃者はそれを自分の秘密鍵で復号して共通鍵を盗めます。受信者には暗号化し直して転送すれば、誰も気づきません。(中間者攻撃)こうなったら後は中身筒抜けです。
これを防ぐには、「この公開鍵は確かに受信者本人のもの」と証明する仕組みが必要で、その仕組みの土台になるのが「デジタル署名」です。(※あくまで土台でありデジタル署名のみで解決するわけではない)
デジタル署名
前の章では、公開鍵をすり替えられると中間者攻撃を受けてしまう、という問題が出てきました。
要するに「受け取ったものが本物かどうか分からない」のが問題です。
これは公開鍵に限った話ではありません。暗号化は「中身を隠す」技術なので、届いたデータについても次のことまでは分かりません。
- 途中で書き換えられていないか(改ざん)
- 本当にその人が送ったものか(なりすまし)
- 送った本人が「そんなの送ってない」と言い逃れしないか(否認)
この「本物かどうか」を確かめられるようにするのがデジタル署名です。
まずはデータが本物かどうかを確かめる仕組みから見ていきます。
本物か確かめる仕組み
デジタル署名は、「秘密鍵で署名を作って、公開鍵で検証する」という手順です。
秘密鍵は本人しか持っていないので、署名を作れるのは本人だけ。一方、公開鍵は誰でも持てるので、検証は誰でもできます。つまり「本人にしか作れないけど、誰でも確かめられる」ということです。
細かい説明の前に、まずは処理の流れです。
実際の署名では、データそのものではなく、データのハッシュ値に対して署名を作ります。
ハッシュ値は、データから計算される固定長の短い値で、次の性質があります。
- 同じデータからは必ず同じハッシュ値になる
- データが1文字でも違えば、まったく違うハッシュ値になる ※
- ハッシュ値から元のデータを復元することはできない
※ 注意: 同じハッシュ値になる別のデータは存在するが、異なるデータから同じハッシュ値になる組み合わせを見つけることは事実上不可能
公開鍵暗号の処理は遅いので、大きなデータに直接署名するのは大変です。そこで短いハッシュ値に署名します。データが改ざんされればハッシュ値も変わるので、ハッシュ値に署名すればデータ全体に署名したのと同じ効果が得られます。
照合が成功すれば、次のことが確かめられます。
- 完全性:データが改ざんされていない(改ざんされていればハッシュ値が一致しない)
- 真正性:送信者本人が作った(署名を作れるのは秘密鍵を持つ本人だけ)
- 否認防止:送信者は「送っていない」と言い逃れできない(本人にしか作れない署名があるから)※ 秘密鍵は本人だけが適切に管理しているという前提
暗号化の時とは鍵ペアを作る人が逆になっていますが、目的を考えれば当然です。
暗号化:受信者が鍵ペアを作り、「この公開鍵を渡すからメッセージは暗号化して僕に送ってね」
署名:送信者が鍵ペアを作り、「今から送るデータに署名しといたから、公開鍵で本物かどうか確かめてね」
まだ残っている問題...
データの改ざんもなりすましも見抜ける方法「デジタル署名」を理解しました。
「公開鍵にデジタル署名して本物だと証明すれば『公開鍵が本物かどうか問題』を解決できるじゃん、今度こそ完璧」...とはならず、まだ問題が。(どんだけあんねん)
本人が自分の公開鍵に署名しても、その署名を検証するには本人の公開鍵が必要です。
「その公開鍵が本物か分からない」から困っていたので堂々巡りです。
当然、自分で「本物です」と言っても証明になりません。
必要なのは、みんなが信頼できる第三者に「この公開鍵は確かにこの人のもの」と署名してもらうこと。
それを実現するのが「電子証明書」です!!次章に続く...
電子証明書
前の章で出てきた「みんなが信頼できる第三者」が「認証局(CA)」、認証局が署名して発行する証明書が「電子証明書」です。
電子証明書の中身
電子証明書には、主に次の情報が入っています。
- 公開鍵
- 公開鍵の持ち主の情報(Webサイトならドメイン名など)
- 有効期限
- 発行した認証局の情報
- 認証局のデジタル署名
つまり「この公開鍵の持ち主はこの人です」という内容に、認証局がデジタル署名したもの。前の章で学んだデジタル署名が、そのまま使われています。
証明書の発行
まずは、公開鍵の持ち主が認証局から証明書を発行してもらう流れです。
認証局は、提出された公開鍵が本当にその人のものかを審査したうえで、自分の秘密鍵で署名します。これで「認証局のお墨付き」が付いた公開鍵ができあがります。
発行は最初に一度行えばOKで、持ち主は以降、この証明書を使い回します(有効期限が切れたら更新します)。
証明書の検証
次に、証明書を受け取った相手が、中の公開鍵を本物かどうか確かめる流れです。こちらは通信のたびに行います。
公開鍵を「むき出し」で送るのではなく、認証局のお墨付き(証明書)に入れて送るのがポイントです。
また、図に認証局が登場していないことにも注目です。検証のたびに認証局へ問い合わせる必要はなく、手元にある認証局の公開鍵だけで確かめられます。
では、攻撃者がすり替えようとするとどうなるでしょう。
- 証明書の中の公開鍵を自分のものに書き換える → 中身が変わるので署名の検証に失敗する
- 自分で証明書を作る → 認証局の秘密鍵を持っていないので、正しい署名を付けられない
- 自分のドメインの正規の証明書を送る → 持ち主(ドメイン名)が通信したい相手と一致しないのでバレる
電子証明書を使えば、どのパターンでもすり替えはバレます。これで中間者攻撃を防げるようになりました!
認証局の公開鍵は本物?
「証明書の検証に使う認証局の公開鍵、それ自体は本物なの?」(疑いの無限ループ)
認証局の公開鍵もネットワークで受け取っていたら、すり替えられる可能性があります。
このループを断ち切るのが「ルート認証局」です。
信頼の起点となる最上位の認証局(ルート認証局)の証明書は、OSやブラウザにあらかじめ組み込まれています。ネットワーク経由で受け取らないので、すり替えられにくいのです。
ちなみにルート証明書は、ルート認証局が自分の公開鍵に自分で署名したものです。
自己署名なのに信頼できるのは、署名があるからではなく、OSやブラウザの開発元が審査したうえで組み込んでいるからです。
証明書チェーン
実際には、ルート認証局が直接Webサイトに証明書を発行することは少なく、間に「中間認証局」が入ります(ルート認証局 → 中間認証局 → Webサイト)。
中間認証局の証明書(中間証明書)は、Webサイトが自分の証明書と一緒に送ってきます。
このように、Webサイトの証明書からルート証明書まで連なったものを「証明書チェーン」と呼びます。
検証するときは、「1つ上の証明書に入っている公開鍵で、1つ下の証明書の署名を検証する」をくり返します。
サーバー証明書の署名は中間証明書の公開鍵で、中間証明書の署名はルート証明書の公開鍵で検証し、手元のルート証明書までたどり着ければOKです。
中間証明書はネットワーク経由で受け取りますが、組み込み済みのルート証明書で検証できるので問題ありません。
つまり、事前に持っている必要があるのはルート証明書だけで、そこから署名をたどることで信頼を広げていく仕組みです。
PKI(公開鍵基盤)
ここまで見てきた、認証局・電子証明書・ルート証明書を組み合わせて「この公開鍵は確かにこの人のもの」を保証する仕組み全体を「PKI(Public Key Infrastructure:公開鍵基盤)」と呼びます。
次の章で見るHTTPS(TLS)も、このPKIの上に成り立っています。
TLS(HTTPS)は暗号技術の結集だった!
ここまで、共通鍵暗号から電子証明書まで、問題を1つずつ解決してきました。
最後に、これらが実際にどう組み合わさって使われているのかを、普段使っているHTTPS(TLS)で見てみます。
ちなみに、Webサイトが使う電子証明書は「サーバー証明書(SSL/TLS証明書)」と呼ばれます。仕組みは前の章で説明した電子証明書そのものです。
仕組み
現在主流のTLS 1.3の流れを、ポイントに絞って簡略化して見ていきます。
前提として、Webサーバーはあらかじめ認証局からサーバー証明書を発行してもらっていて、ブラウザ(OS)にはルート証明書が組み込まれています。どちらも電子証明書の章で見た状態です。(以下、Webサーバーを単に「サーバー」と呼びます)
TLSの通信は、大きく「鍵共有」「サーバーの検証」「データのやり取り」の3段階に分かれます。
※ 実際のやり取りはもっと細かいですが、この図ではポイントに絞って省略しています。
【1】鍵共有(①〜④)
最初に、ブラウザとサーバーで共通鍵を共有します。ここで使われているのが「Diffie-Hellman鍵共有」です。
ブラウザとサーバーはお互いに鍵共有用の値を送り合い、自分の値と相手から届いた値を使って、それぞれ手元で共通鍵を計算します。別々に計算しているのに、両者は同じ共通鍵にたどり着きます。共通鍵そのものはネットワークに一度も流れないので、鍵配送問題はここで解決します。
ここから先の通信は、この共通鍵で暗号化されます。ただし、Diffie-Hellman鍵共有だけでは相手が誰かまでは分かりません。攻撃者と鍵を共有してしまっている可能性もあるので、大事なデータを送る前に、相手が本物かを確かめる必要があります。
ハイブリッド暗号方式の章で紹介した「共通鍵を公開鍵で暗号化して送る」方法は、TLS 1.3では廃止されています。この方法では、サーバーの秘密鍵が漏れると過去の通信まで復号されてしまうためです。TLS 1.3のDiffie-Hellman鍵共有では接続ごとに使い捨ての値を使うので、秘密鍵が漏れても過去の通信は守られます(前方秘匿性)。
【2】サーバーの検証(⑤〜⑧)
相手が本物のサーバーかどうかを、2つのステップで確かめます。
⑤⑥ 公開鍵が本物かを確かめる(電子証明書)
まず、サーバーが自分の証明書を中間証明書と一緒に送ります。ブラウザは受け取った証明書チェーンを、中間証明書、ルート証明書とたどって署名を検証します。さらに、ドメイン名が今アクセスしているサイトと一致するか、有効期限内かも確認します。
これで、証明書の中の公開鍵が本当にそのサイトのものだと分かります。
⑦⑧ 相手が公開鍵の持ち主本人かを確かめる(デジタル署名)
とはいえ、証明書は公開情報なので誰でも入手できます。攻撃者が本物のサイトの証明書をコピーして送ってくることもできてしまいます。
そこでサーバーは、ここまでのやり取りに自分の秘密鍵で署名して送ります。ブラウザがこの署名を証明書の中の公開鍵で検証し、成功すれば、相手は秘密鍵を持つ本物のサーバーだと分かります。
しかも署名の対象は「ここまでのやり取り」なので、鍵共有のときに送り合った値がすり替えられていないことも同時に確認できます。中間者攻撃は、ここで防がれているわけです。
【3】データのやり取り(⑨⑩)
こうして、本物のサーバーとだけ同じ共通鍵を共有できたことが確認できました。
最後に、速い共通鍵暗号を使ってリクエストとレスポンス、つまりデータ本体をやり取りします。
まとめ
TLSの中で、これまでの章で見てきた技術がそれぞれの役割を果たしています。
| 段階 | 使われている技術 | 解決していること |
|---|---|---|
| 【1】鍵共有 | Diffie-Hellman鍵共有 | 鍵配送問題 |
| 【2】サーバーの検証(証明書) | 電子証明書(証明書チェーン) | 公開鍵のすり替え |
| 【2】サーバーの検証(署名) | デジタル署名 | なりすまし・鍵共有用の値の改ざん |
| 【3】データのやり取り | 共通鍵暗号 | 機密性と処理の速さの両立 |
おわりに
共通鍵暗号方式と公開鍵暗号方式を理解するつもりが、デジタル署名や電子証明書、TLSまで調べるハメになりました。暗号技術は、1つの技術ですべてを解決しているわけではないということが、今回調べてみてよくわかりました。
技術の繋がりや発明された背景なんかが分かるとより理解しやすいですね。
というわけで今回は以上です。