🔐

イラストで正しく理解するTLS 1.3の暗号技術

2022/03/15に公開

イラストで正しく理解するTLS 1.3の暗号技術

初めに

ここではTLS 1.3(以下TLSと略記)で使われている暗号技術を解説します。
主眼はTLSのプロトコルではなく、「暗号技術」の用語の挙動(何を入力して何を出力するのか)と目的の理解です。

実際にどのような方式なのかといった、より詳しい説明は拙著『図解即戦力 暗号と認証のしくみと理論がこれ1冊でしっかりわかる教科書』(暗認本)や『暗認本』の内容を紹介したスライドや動画などの資料集をごらんください。
なお表題の「イラストで」は数式を使わないという程度の意味です。

TLSで守りたいもの

TLSはコンピュータ同士が安全に通信するための規格です。
主に人がブラウザを介して「https://」で始まるWebサイトにアクセスするときに利用されます。

安全に通信するためには、通信内容が盗聴されても情報が漏れない機密性が必要です。
それから通信が改竄されていないことを示す完全性や通信相手が本物であることを示す真正性も必要です。

機密性と完全性
機密性と完全性

TLSの全体像

TLSのクライアントとサーバの大まかなやりとりは次の通りです。

TLSのプロトコル(『暗認本』p.218)
TLSのプロトコル(『暗認本』p.218)

暗号技術に関わるところを見ていきましょう。

  1. まずクライアントからサーバにClientHelloでECDH鍵共有を開始します。
  2. サーバのServerHelloで鍵共有が完了します。そしてサーバの公開鍵証明書と署名を送付します(Certificate/Verify)。
  3. クライアントは証明書と署名の検証をします。

鍵共有が終わったときからAEADによる暗号化が始まります。
それでは個々の用語の説明を始めましょう。

暗号化と復号

機密性で必要になるのが暗号化(encryption)です。
守りたい情報である平文を暗号鍵と呼ばれる情報で暗号化して、元の平文が分からない暗号文にします。
暗号文は復号鍵と呼ばれる情報で復号して元の平文に戻します。
復号鍵が無いと暗号文から元の平文の情報は何も得られません。
これを秘匿性といいます。

暗号化と復号
暗号化と復号

暗号鍵と復号鍵は同じ方式もあれば異なる方式もあります。
「暗号鍵=復号鍵」のときを共通鍵暗号、「暗号鍵≠復号鍵」のときを公開鍵暗号PKE(Public Key Encryption)といいます。
復号鍵は他人に見せてはいけないので秘密鍵ともいいます。
共通鍵暗号では「暗号鍵=復号鍵=秘密鍵」です。

PKEでは暗号鍵は他人に見せてもよいので公開鍵ともいいます。
ただしTLSでは共通鍵暗号しか使いません。PKEは忘れてもらってよいです。
繰り返します。TLS 1.3ではPKEを使いません。

「あれ、公開鍵暗号を使うと書いてあった・習ったよ」という方がいらっしゃるかもしれません。
それは、その情報が古いか、間違っているか、あるいは公開鍵暗号がPKC(Public Key Cryptography)の意味で使われているかです。
PKEとPKCの違いについては『あなたの「公開鍵暗号」はPKE? それともPKC?』をどうぞ。

ECDH鍵共有

共通鍵暗号を使うには二者間(アリスとボブ)でこっそり秘密鍵を共有しなければなりません。
そのためにTLSではECDH鍵共有を使います。
EC(Elliptic Curve)とは楕円曲線という数学用語、DHはDiffieとHellmanという人の名前を示します。

楕円曲線は、イメージ的には浮輪の表面に糸が巻きついたものです。
数学的な話は上記書籍や、『Software Design2022年3月号』
「第4章:電子署名のプロセスを体験 Pythonによる楕円曲線暗号の実装」をごらんください。

(注)楕円曲線暗号のPythonによる実装その1(有限体とECDH鍵共有)で記事を公開しています。

ECDH鍵共有では次のことをします。
まずアリスは10進数で77桁ぐらいの大きな数aをランダムに選び秘密にしておきます。
そしてそれを楕円曲線の点と呼ばれるものに変換します。
イメージ的には中が全く見えないカプセルAにaを入れるようなものです。
カプセルは中に入れた数値に対応した模様が現れます。
模様から中身aを取り出したり、推測したりは誰にもできません(図では便宜上aを見せてますが実際には分かりません)。

(注意)この操作は暗号化とはいいません。aを知らない人は誰も「復号」できないからです。

カプセルに入れる
カプセルに入れる

このカプセルAは特殊な性質を持っていて、別の数bとくっつけると
数abを入れたカプセルABになります。
新しくできたカプセルの模様を見ても、やはり中身の数字は分かりません。

カプセルAと数bをくっつける
カプセルAと数bをくっつける

このような特殊な性質を使ってECDH鍵共有を行います。

  1. アリスは秘密の値aを選び、それをカプセルに入れたAをボブに送ります。
  2. ボブは秘密の値bを選び、それをカプセルに入れたBをアリスに送ります。
  3. アリスは自分のaとボブのBからabが入ったカプセルABを作ります。
  4. ボブは自分のbとアリスのAからabが入ったカプセルABを作ります。

アリスとボブはお互い、中身の値abは分からないのですが、それが入った同じカプセルを入手しました。
通信を盗聴してカプセルAやカプセルBを入手してもカプセルABを作れないことが知られています。

ECDH鍵共有
ECDH鍵共有

「TLSの全体像」におけるクライアントとサーバがClientHello, ServerHelloをするところでECDH鍵共有をします。
ECDH鍵共有によって共有されたカプセルABからAEAD用の秘密鍵sを作ります。
作り方は鍵導出関数HKDF(HMAC-based Key Derivation Function)という方法を利用します。
HKDFの詳細は上記書籍をごらんください。イメージとしてはぐしゃっとつぶす感じです。

(注意)公開鍵暗号PKEを使って共通鍵暗号の秘密鍵を暗号化する静的RSA(ハイブリッド暗号)はTLS 1.3で廃止されました。

認証付き暗号AEAD

ECDH鍵共有で秘密の値を共有できたのでそれを用いてデータを暗号化して送り合います。
その際、TLSでは認証付き暗号AEAD(Authenticated Encryption with Associated Data)を使います。
AEADは暗号化による秘匿性と、データが改竄されていないことを保証する完全性を同時に満たす暗号方式です。

(注意)AESのCBCモードはTLS 1.3で廃止されました。

TLSでは主にAES-GCMやChaCha20-Poly1305という方式が広く使われます。

暗号化

これらの暗号化方式(AES-CTRやChaCha20)をイメージで表現します。

平文(入力データ)をオセロの白黒列で表現します。白は1で黒は0とします。

AES-CTRやChaCha20
AES-CTRやChaCha20

暗号化は次のようにします。
秘密鍵を擬似乱数生成器と呼ばれるところに入力すると白黒をひっくり返すか返さないかという操作の列が生成されます。
この列は秘密鍵を知らない人には予測不可能です。
そして、この操作に従って平文の白黒をひっくり返したり、そのままにして暗号文を作ります。
秘密鍵を知らないと暗号文から元の平文を推測できません。

復号は暗号化と同じです。
秘密鍵を擬似乱数生成器にいれて、全く同じひっくり返す操作の列を生成し、それを暗号文に対して行います。
暗号化でひっくり返した部分だけがもう一度ひっくり返されて元の平文に戻ります。

完全性

通信途中で暗号文の白黒を勝手にひっくり返される(改竄される)と平文が壊れてしまいます。
それを防ぐためにデータの正しさも同時に検証します。AEADにはメッセージ認証符号MAC(Message Authentication Code)という技術が組み込まれています。
これはデータと秘密鍵を一緒にスクラップして認証タグと呼ばれる小さな値を出力します。

MAC
MAC

認証タグは元のデータや秘密鍵が1ビットでも異なると違う値になり、意図した形につぶすことは不可能です。
AEADでは平文を暗号化すると同時に暗号文から認証タグを作り、暗号文と認証タグを相手に送ります。

受け手は復号と同時に認証タグを計算し、同じ値になれば正しさが保証されます。
また、同時に相手が同じ秘密鍵で暗号化したことも分かります。

AEAD(『暗認本』p.225)
AEAD(『暗認本』p.225)

署名

ECDH鍵共有とAEADにより機密性と完全性が達成できるように見えます。
しかし、実はこれだけではまだ不十分です。
通信相手が本当にその人であることを示す真正性が必要です。
ECDH鍵共有は、単に盗聴するだけの受動的な攻撃者に対しては安全ですが、通信経路を改竄する能動的な攻撃者に対しては安全ではないからです。
そのような攻撃を中間者攻撃MITM(Man-In-The-Middle)といいます。

中間者攻撃
中間者攻撃

TLSではMITMを防ぐために署名を使います。
署名は次の3ステップからなります。

  1. アリスは署名鍵sと検証鍵Sのペアを作り、検証鍵Sをボブに渡します。
  2. アリスは署名鍵sを使ってデータmから署名σと呼ばれるデータを作り、データと署名の組(m, σ)をボブに渡します。
  3. ボブは検証鍵を使ってデータと署名の組(m, σ)を検証し、正しければ受理、そうでなければ拒否します。

署名
署名

署名σはメッセージ認証符号MACの認証タグと同じく、署名鍵sとデータmが1ビットでも異なると違う値になります。
MACと違う点は、受けて側がデータの正しさを確認するときに署名鍵sとは異なる検証鍵Sを使う点にあります。
検証鍵Sは署名鍵sをカプセルに入れたものに相当し、検証鍵から署名鍵を求めることはできません。
検証鍵は誰に見せても良いので公開鍵、署名鍵は誰にも見せてはいけないので秘密鍵ともいいます。

検証鍵で受理される署名を作れるのは署名鍵を持つ人だけです。

(注意)署名の公開鍵は公開鍵暗号PKEの公開鍵と異なり「暗号化」に使うのではありません。
同じ「秘密鍵」「公開鍵」という用語が使われるので混乱しやすいのですが用途が異なります。

サーバを運営するボブは、自分のドメインと自分が使う署名の検証鍵のペアを第三者である認証局に署名してもらいます。これを公開鍵証明書といいます。
認証局の検証鍵で公開鍵証明書を検証すれば、ドメインとドメインの検証鍵のペアの正しさが保証されます。

公開鍵証明書
公開鍵証明書

TLSでサーバがクライアントに返答するときは、公開鍵証明書と通信全体の署名を送ります。

クライアントは公開鍵証明書の正しさを認証局の検証鍵で確認し、それからデータの正しさをサーバの検証鍵で検証するとデータが改竄されていないと判断できます。

認証局の検証鍵の入手方法は公開鍵基盤PKI(Public Key Infrastructure)の枠組みで行いますが、その説明は今はしません。

まとめ

以上の説明をまとめると、TLS 1.3では

  1. ECDH鍵共有によって秘密鍵を共有し、
  2. AEADで秘匿性と完全性を備えた暗号化を行い、
  3. 公開鍵証明書と署名の正しさで中間者攻撃MITMを防ぎ、相手を認証する。

となります。これらの用語の意味を理解できたでしょうか。

資料(再掲)

GitHubで編集を提案

Discussion