TLS 1.3 学習ノート

(※この記事は 別媒体に投稿した記事 のバックアップです。canonical も設定しています)

はじめに

これは筆者が TLS 1.3 を学習した時のメモを記事にしたものです。
内容の正確性は担保できませんので、あらかじめご了承ください。

参考にした書籍

参考にしたウェブサイト

TLS とは?

TLS は Transport Layer Security の略で、インターネット上で安全に通信を行うためのプロトコルです。

インターネット上で安全に通信を行う必要性

前提として、インターネットはセキュリティが考慮されていません。
もともとインターネットは、大学間で少数のノードでネットワークが構成されたためです。
当初はそれで特に問題ありませんでした。

しかし現在は数多くの人々が、機密情報を含む様々な情報をやり取りしています。
そうした状況で、通信内容が容易に盗聴されたり改ざんされてしまっては、安心して使うことができなくなります。
そのため TLS のように安全な通信を行うためのプロトコルが必要になりました。

TLS が提供している機能

以下の3つの機能を提供しています。

認証

公開鍵証明書を使用し、正当な通信相手であることを検証できます。

暗号化

公開鍵暗号と共通鍵暗号を併用し、通信内容を暗号化して安全に通信できます。

改竄検知

ハッシュ関数(認証付きの共通鍵暗号)を使い、通信内容の改竄を検知できます。

TLSが提供しているセキュリティ要素

以下の3つのセキュリティ要素を提供しています。

機密性

通信の内容が通信相手以外に漏れず、秘密が守られることです。

真正性

正しい相手と通信していることが検証できることです。

完全性

通信内容が改ざんされることなく、正確に通信できることです。

TLS/SSL の歴史

概要

TLS の前身となった SSL は、当時高いシェアを誇る Netscape Navigator を提供していた Netscape 社で開発されました。
その後、IETF に移管され TLS に名称が変更されました。

SSL と TLS の違い

SSL (Secure Socket Layer) は TLS の前身となるプロトコルで、合わせて SSL/TLS などと表記されることもあります。
以下の通り Netscape 社から IETF に移管され、Microsoft の意向により名称が TLS に変更されました。

SSL 1.0

1994年に Netscape 社によって開発されました。
しかし公開前に問題が発覚したため、実装されることなく破棄されました。

SSL 2.0

SSL 1.0 と同じく1994年に Netscape 社によって開発されました。
現在は RFC 6176 により廃止されています。

SSL 3.0

1995年に SSL 2.0 のいくつかの重大な脆弱性に対応しました。
根本から設計し直し、現在の TLS プロトコルの基本設計になっています。
現在は RFC 7568 により廃止されています。

TLS 1.0 (RFC 2246)

SSL を Netscape 社から IETF に移管するために、1996年に TLS ワーキンググループに移管されました。
Netscape 社と Microsoft 社の政治的抗争により標準化作業が遅れ、1999年にようやくリリースされました。

SSL 3.0 との違いはわずかですが、互換性はありません。
また Microsoft 社の意向により TLS に名称が変更されました。
現在は RFC 8996 により廃止されています。

TLS 1.1 (RFC 4346)

基本的なセキュリティに関する修正がメインで、2006年に公開されました。
現在は RFC 8996 により廃止されています。

TLS 1.2 (RFC 5246)

アルゴリズムの追加や、AEAD(認証付き暗号)に対応し、2008年にリリースされました。
また、ハードコードされていたセキュリティ技術が取り除かれ、柔軟なプロトコルに変更されました。

TLS 1.3 (RFC 8446)

2018年にリリースされた、最も新しいバージョンです。

TLS 1.3 の改善点

TLS 1.3 は2018年にリリースされた比較的新しい暗号プロトコルです。
番号はマイナーバージョンアップですが、事実上新しいプロトコルと言えるほどの変更があります。

現在有効な前バージョン (TLS 1.2) と比較して、何が改善されたのかをピックアップしていきます。

ハンドシェイクの暗号化範囲の拡大

ハンドシェイク中の Client Hello, Server Hello 以外が暗号化されるようになりました。
TLS 1.2 では合意前のハンドシェイクの内容は全て平文でやりとりしていました。

これは、ディフィー・ヘルマン系の鍵交換方式に統一されたことによる改善です。
(ディフィー・ヘルマン鍵交換については「公開鍵暗号」の章を参照してください)

暗号スイートの削減

TLS 1.2 に存在する数百の暗号スイートに比べ、大幅に削減されました。
特に、古く安全でない暗号が削減されたので、安全性が高まりました。

TLS 1.3 では、現在5つの暗号スイートが定義されています。

This specification defines the following cipher suites for use with TLS 1.3.

           +------------------------------+-------------+
           | Description                  | Value       |
           +------------------------------+-------------+
           | TLS_AES_128_GCM_SHA256       | {0x13,0x01} |
           |                              |             |
           | TLS_AES_256_GCM_SHA384       | {0x13,0x02} |
           |                              |             |
           | TLS_CHACHA20_POLY1305_SHA256 | {0x13,0x03} |
           |                              |             |
           | TLS_AES_128_CCM_SHA256       | {0x13,0x04} |
           |                              |             |
           | TLS_AES_128_CCM_8_SHA256     | {0x13,0x05} |
           +------------------------------+-------------+

https://datatracker.ietf.org/doc/html/rfc8446#appendix-B.4

認証付きの共通鍵暗号アルゴリズムに統一

AES-GCM などの認証付きの共通鍵暗号アルゴリズムを使うように統一されました。
認証付きの共通鍵暗号アルゴリズムは、改ざん防止の (H)MAC がついているようなモードです。

これにより、なりすましや改ざんを防ぎつつ MAC による真正性検証が不要になりました。
(MAC については「ハッシュ関数」の章を参照)

PFS(Perfect Forward Security)

PFS (Perfect Forward Secrecy)とは、暗号化された通信と秘密鍵の両方漏洩しても複合できない、という鍵交換に関する概念です。
セッションごとに別の秘密鍵を使うことで、秘密鍵が漏洩しても復号されてしまう範囲を最小限に留めることができます。
また秘密鍵自体をセッション終了後に破棄することで、漏洩の可能性も最小限にします。
(PFS はいくつかの解説を読んでも定義や何を持って PFS とするかがマチマチなので、一旦自分の分かった範囲でまとめています。以下のウェブサイトが参考になりました)

例えば、通信の暗号化に毎回同じ秘密鍵を暗号通信に使用しても、その時点では復号されません。
しかし将来的に何らかの方法で秘密鍵が漏洩し、過去の暗号化された通信内容が保存されていた場合、その内容が容易に復号できてしまう問題があります。

これは、スノーデン氏によるNSAの諜報活動のリークで話題になりました。
NSA は通信内容が暗号化されていてもとにかく保管しておき、後から鍵を入手したら解読するという手法をとっているとのことです。

このことから、毎回同じ秘密鍵を使うよりも、PFS をサポートした方式を使うようになっています。
TLS 1.3 では、ディフィー・ヘルマン鍵交換を使うことで PFS を実現しています。
(ディフィー・ヘルマン鍵交換については「公開鍵暗号」の章を参照してください)

RTT (Round Trip Time) の改善

TLS 1.3 は 1-RTT でハンドシェイクが完了ができ、データのやり取り開始までの時間が短縮されました。
TLS 1.2 は 2-RTT が必要でしたので、速度の観点で大きな改善です。

これは、鍵交換の方式がディフィー・ヘルマン系のみになったことが大きく影響しています。
(ディフィー・ヘルマン鍵交換については「公開鍵暗号」の章を参照)

0-RTT (セッション再開)

更に RTT を削減して、いきなりデータを送信することも仕様上可能になっています。
いきなりデータを (暗号化して) 送信できるということからわかるように、事前に共有 (交換) した秘密鍵を使用しています。

事前に共有 (交換) した秘密鍵を使用するので、鍵の使い回しにより前方秘匿性 (PFS) がなくなります。
キュリティを低下させるがパフォーマンスは向上する、というトレードオフの機能になっています。
0-RTT はオプション扱いなので、使わないことももちろん可能です。

前方秘匿性 (PFS) はなくても良いから、可能な限りパフォーマンスを上げたいという場合に使えるかもしれません。

参考: 走り出した TLS 1.3(2):0-RTTでいきなり暗号化メッセージ - wolfSSL

ハンドシェイク

ハンドシェイクとは、暗号化された通信を行うために必要な情報を交換し、暗号化通信を確立するための一連の処理です。
TLS 1.3 では、フルハンドシェイクと事前共有鍵 (PSK: Pre-Shared Key) 接続の2種類があります。

ハンドシェイクの目的

ハンドシェイクでは、以下の4つを達成する必要があります。

達成すべきことは4つあります。

  1. 接続で使いたいパラメータを双方が提示し、一般的なセキュリティパラメータについて双方で合意する
  2. サーバの真正性を検証する(必要であればクライアントの真正性も検証する)
  3. 暗号鍵をいくつか生成する
  4. ハンドシェイクメッセージが能動的ネットワーク攻撃者によって書き換えられていないことを検証する

プロフェッショナルSSL/TLS 特別版PDF P495

フルハンドシェイク

以下の流れで行われます。

  1. [Client --> Server] Client Hello
    • TLS 接続の要求
    • 接続したい TLS のバージョン
    • クライアントが使用できる暗号スイート一覧
    • (TLS 1.3 のみ) 鍵合意のパラメーター一式
  2. [Client <-- Server] Server Hello
    • サーバー側が選択した暗号スイート
  3. [Client <-- Server] Encrypted Extensions
    • 補足情報(※実際にどう使われているのかはまだ分かってない)
  4. [Client <-- Server] Certificate
    • サーバー証明書
  5. [Client <-- Server] Certificate Verify
    • ハンドシェイク内容の署名情報など
  6. [Client <-- Server] Finished
    • ハンドシェイク完了のメッセージ
  7. [Client <-- Server] Finished (この時点でハンドシェイク完了)
    • ハンドシェイク完了のメッセージ
  8. [Client <-> Server] Application Data
    • 双方向にアプリケーションデータをやり取りする
  9. [Client <-- Server] Alert (Close Notify)
    • TLS の接続終了メッセージ
  10. [Client --> Server] Alert (Close Notify) (この時点で TLS の接続が終了)
    • TLS の接続終了メッセージ

参考: TLS 1.3の性能 その2 – フルハンドシェイク - wolfSSL

事前共有鍵 (PSK: Pre-Shared Key) 接続

その名の通り、事前に共有した鍵 (PSK) を使用して暗号通信を開始する方式です。

PSK をそのまま秘密鍵として使用することも可能です。
しかし前方秘匿性 (PFS) がなくなるため、PSK を使ってさらにディフィー・ヘルマン鍵交換を実行することが推奨されています。

参考: TLS 1.3の性能 その3 - 事前共有鍵(Pre-Shared Key: PSK) - wolfSSL

セッション再開

TLS 1.3 では、セッション再開は PSK の拡張として整理されており、再開時のプロトコルは PSK プロトコル利用の一方法として位置づけられています。

徹底解剖 TLS 1.3 P33

セッションを再開する場合、前回の通信でサーバーから発行されたセッションチケットを送付することで開始します。

TLS 1.2 ではセッションIDを使った方式も存在しましたが、TLS 1.3 では廃止されました。
また TLS 1.2 ではクライアント側からセッションチケットの発行を要求できたが、TLS 1.3 ではサーバー側の判断になった。

Early Data

PSK (そのまま鍵として使用する場合) やセッション再開の場合、開始時点で暗号に必要な鍵が確定しているため、最初のメッセージに暗号化したデータを含めて送信することが可能になっています。
ただし、その場合前方秘匿性 (PFS) が失われる点に注意してください。

乱数

乱数はランダムな数列のことで、生成された乱数は秘密鍵などで使用します。
秘密鍵に使われるので、セキュリティの全ては乱数生成器の品質にかかっています。

周期性や統計的な偏りがなく、予測不可能であることが理想な乱数です。

乱数生成器の種類

本当の意味で、全く予測が不可能なランダムな数列を生成する乱数生成器を「真正乱数生成器」と言います。
真性乱数生成器では、ランダムな物理現象を観測した結果を用いることが多いようです。

真性乱数を生成させる場合には、コンピューターは、アルゴリズムではなく、同位体の放射性崩壊や電波静的など、予測できない外部の物理変数を使用する必要があります。 量子レベルでは、亜原子粒子は完全にランダムな振る舞いをしており、予測不可能なシステムの理想的な変数になっています。

https://www.wolfssl.jp/wolfblog/2021/08/16/true-random-vs-pseudorandom-number-generation/

真性乱数発生器の例: 量子理論を基にした真性乱数発生器 AR-QUANTIS IDQ | 乱数発生器 | 株式会社アルゴ

真正乱数生成器は理想ではあるがコストや品質の課題があるため、実際には疑似乱数生成器 (PRNG) を組み合わせて使う場合が多いようです。
真正乱数生成器から得られる少量のデータ (シード) から疑似乱数を生成しています。
暗号学的な疑似乱数生正規 (CSPRNG) には予測不可能であることも必要になります。

/dev/random と /dev/urandom

よく使われている2つの乱数生成器で、以下の記事が詳しかったので一部引用します。

エントロピープールが枯渇すると、/dev/random は乱数を生成できなくなりエントロピープールが貯まるまで処理を停止します。
/dev/urandom は、エントロピープールが枯渇すると、内部プールを再利用して乱数を生成し、処理が停止することがありません。

エントロピープールが貯まるまで乱数生成の処理を停止することをブロックといい、urandom は "unlocked" random source の略です。

内部プールを再利用すると、同じ乱数を生成してしまうような乱数の衝突が発生しやすくなります。
このため/dev/random を『真の乱数』、/dev/urandom を『疑似乱数』と呼ぶことがあります。

エントロピープールは、キーボードやマウスなどの入力デバイスによるイベントやハードディスクの読み込み時間、ネットワークトラフィックなどの環境ノイズから生成されます。

https://pentan.info/server/dev_random_urandom.html

乱数生成における欠陥の事例

乱数生成はセキュリティ上非常に重要な役割を持っているため、欠陥がそのまま重大なセキュリティ上の脅威になります。

「プロフェッショナルSSL/TLS」から一部の事例の概要を紹介します。
詳細は書籍を確認してください。

Netscape Navigator における RNG の欠陥 (1994年)

「プロフェッショナルSSL/TLS P156」より

Debian における RNG の欠陥 (2006年)

「プロフェッショナルSSL/TLS P157」より

ハッシュ関数

ハッシュ関数は任意のデータから、固定長の出力を出力するアルゴリズムのことを指します。

例えば以下のような文章のハッシュ値を例に考えてみます。

あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。

この文章を MD5 というアルゴリズムで計算すると、以下のような出力が得られます。

7863f16deea16ea0425275938f0f3d32

次に、上記の文章の最後に改行コード(ASCIIコード値: 10)を追加すると以下のような出力が得られます。

547a91535b80f8782ec24617cea09ecb

データの長さに関わらず一定の長さの値が得られ、内容のごく一部が変わるだけでも値が大きく変わるのが特徴です。

ハッシュ関数に求められる性質

以下の3つがあります。

現像計算困難性 (Preimage resistance)

ハッシュ関数を通じて得られた値から、元のデータを特定することが困難である性質を指します。

第2現像計算困難性 (Second preimage resistance)

あるデータからハッシュ関数を通じて出力される値があり、それと同じ値が出力されるデータを特定することが困難である性質を指します。

ハッシュ関数はデータの改ざんの検出にも使われるため、同一のハッシュ値になるデータが容易に特定されると、改ざん検知に使うことが難しくなります。

衝突耐性 (Collision resistance)

同じハッシュ値が得られる2つの異なるデータを特定することが困難である性質を指します。

ハッシュ関数の代表例

解説は、Wikipedia にかかれている説明だけで十分わかりやすかったので、Wikipedia の内容を引用します。

MD5

1991年に考案されたアルゴリズムで、IETFによってRFC 1321として標準化された。近年では同一のハッシュ値を持つ異なる原文のペアを効率よく探索することなどができるようになり、セキュリティ用途でMD5を使用するのは十分安全とは言えなくなっている。
https://e-words.jp/w/MD5.html

SHA-1

SHA-1はNSA(米国家安全保障局)が考案し、1995年にNIST(米国標準技術局)によって連邦情報処理標準の一つ(FIPS 180-1)として標準化された。2005年頃から効率的に攻撃する手法がいくつか発見され十分な安全性が保たれなくなったため、近年では2001年に制定された後継のSHA-2規格への移行が進んでいる。
https://e-words.jp/w/SHA-1.html

余談ですが Git では SHA-1 が使われています。

SHA-2

SHA-2はNSA(米国家安全保障局)が考案し、2001年にNIST(米国標準技術局)によって連邦情報処理標準の一つ(FIPS 180-4)として標準化された。SHA-224、SHA-256、SHA-384、SHA-512の4つをまとめた総称で、これらの末尾の数字がそれぞれのハッシュ値のビット長を表している。最長のSHA-512が最も安全性が高く、一般的にはSHA-256が最もよく利用されている。
https://e-words.jp/w/SHA-2.html

SHA-3

SHA-3はSHA-2の後継規格を定めるべくNIST(米国標準技術局)が暗号学者らに公募したもので、応募された方式の中から「Keccak」(キャチャックあるいはケチャックと読む)が選ばれ、2015年に連邦情報処理標準「FIPS 202」として公式に発表された。

2020年代初頭の状況ではSHA-1に対する現実的な攻撃手法が考案され、SHA-1の廃止とSHA-2への移行が急がれている。SHA-2に対する効率的な攻撃手法は未だ報告されておらず、SHA-3への移行を急ぐ必要は無いが、主要な暗号通信ソフトウェアや通信プロトコル規格などがSHA-3対応仕様の追加などを進めており、使用可能な環境が整いつつある。

https://e-words.jp/w/SHA-3.html

MAC (Message Authentication Code, メッセージ認証コード)

MAC はメッセージを認証するためのコード(短い情報)を生成するためのアルゴリズム、またはそのアルゴリズムを使用して生成されたコードを指します。
任意のメッセージと共通鍵から生成します。

MAC では共通の鍵が使われるため、事前に鍵交換が必要になります。
また、共通鍵が使われているため、偽造されたメッセージであるかどうかは検証できません。
(メッセージが完全なものであることは検証できるが、共通鍵を手に入れれば誰でもMACを生成できるため)

HMAC (Hash-based Message Authentication Code)

ハッシュ関数には反復型の暗号学的ハッシュ関数ならば任意のものを利用できる。MD5を用いたものを「HMAC-MD5」、SHA-1を用いたものを「HMAC-SHA1」、SHA-2のSHA-256を用いたものを「HMAC-SHA256」というように呼ぶ。
https://e-words.jp/w/HMAC.html

ハッシュ関数を使用して MAC の生成を行う方式です。
RFC 2104 として公開されています。

余談

1. Bitcoin の論文内での記載

ビットコインのいわゆるマイニングも、ハッシュ関数の性質が使われています。
"4. Proof-of-Work" の章で書かれています。

bitcoin.pdf

現像計算困難性を逆に活用し、先頭のnビット (参加しているノードの計算力よって変動するらしい) が 0 になるように nonce を探すことから、マイニング (採掘) と呼ばれています。

2. JWT での活用例

JWT の署名で HMAC が使用されることもあります。

JWTs can be signed using a secret (with the HMAC algorithm) or ...
https://jwt.io/introduction

共通鍵暗号

共通鍵暗号(または秘密鍵暗号、対象鍵暗号とも)方式とは、通信相手と 事前に共有した 秘密鍵を用いて暗号化・複合を行う暗号方式です。
公開鍵暗号に比べて高速に暗号化・複合が行えるが、秘密鍵の交換を安全に行う方法が課題です。
そのため共通鍵暗号で使う秘密鍵を公開鍵暗号方式で交換し、実際のデータはその秘密鍵を使用して暗号化するというように、両方を組み合わせて使う場合もあります。

暗号化の方式としては、ストリーム暗号化方式とブロック暗号化方式の2種類があります。
また、ブロック暗号化方式は暗号利用モードも選択する必要があります。

ストリーム暗号化方式

ストリーム暗号(ストリームあんごう、stream cipher)とは、平文をビット単位あるいはバイト単位などで逐次、暗号化する暗号です。

https://ja.wikipedia.org/wiki/ストリーム暗号

しかし、暗号利用モードのOFB, CFB, CTRなどでブロック暗号を利用するとストリーム暗号が構成できるので、ストリーム暗号専用アルゴリズムは、ブロック暗号と比べて何かしらの点で特長(メリット)がなければ存在する意味がない。たとえば、近年(AESの採択以降)はAESを利用するより高速であることをアピールすることが多い。

https://ja.wikipedia.org/wiki/ストリーム暗号

RC4

高速で仕組みがシンプルなストリーム暗号化方式です。
しかし、現在では既に安全ではないとされ、RFC 7465 により禁止されました。

ChaCha20

RFC 7539 で定義されています。
Salsa20 というストリーム暗号の変種のようです。

Salsa20 - Wikipedia

TLS 1.3 で唯一定義されているストリーム暗号であり、暗号としてもある程度普及しているようです。

現在実用的に広く使えるTLSの対称暗号が実質AESの一択しかない。
(略)
こんな状況でもし今、AESに重大な問題が見つかったらとしたらどうなるか? TLSの運用者は非常に厳しい選択に迫られます。対称暗号以外ではTLS1.2において、認証は RSA/ECDSA, 鍵交換は DHE/ECDHEと2つ以上の仕組みが存在します。リスク管理の観点から、現実的に代用できるAESのバックアップを持つことが今のTLSに必要です。
https://jovi0608.hatenablog.com/entry/20160404/1459748671

こういった意味合いも大きそうです。

ブロック暗号化方式

ブロック暗号化方式は、データを一定の長さ(ブロック)ごとに暗号化処理する方式です。
ブロックの大きさは、128bit (16bytes) が多く使われています。

DES

DESとは、1977年にアメリカ連邦政府標準の暗号方式として採用された、共通鍵(秘密鍵)暗号方式の一つ。

(中略)

1990年代になりコンピュータの処理性能が向上すると56ビットという鍵長では解読が容易になってしまい、また、暗号研究の進展により差分解読法や線形解読法などの効率的な攻撃法が見出されたため、現代では安全な暗号方式ではないとされている。

https://e-words.jp/w/DES.html

現在ではあまり使われることのないブロック暗号方式です。

AES

AESとは、2000年にアメリカ連邦政府標準の暗号方式として採用された、共通鍵(秘密鍵)暗号方式の一つ。
https://e-words.jp/w/AES.html

現在、世界で最も広く利用されているブロック暗号方式です。

暗号利用モード

暗号利用モード(あんごうりようモード、Block cipher modes of operation)とは、ブロック暗号を利用して、ブロック長よりも長いメッセージを暗号化するメカニズムのことです。

https://ja.wikipedia.org/wiki/暗号利用モード

ブロック暗号方式で、暗号化したいデータが鍵長よりも長い場合、繰り返し暗号を適用する必要があります。
最初に紹介する ECB モードのように単純な繰り返しだと問題が生じる場合があるため、他のモードが作られました。

ECB (Electronic Codebook Mode)

単純にブロックごとに同じ秘密鍵で暗号化する方式です。
同じ内容のブロックを暗号した場合、同じ暗号データが出力されるためパターンを隠すことができず推奨されません。

以下の Wikipedia で紹介されていた図が分かりやすいです。
(注釈も書かれていますが、画像がランダムなノイズのように変換されても安全ではないことに注意してください)

ECBモードで画像を暗号化した場合の例 (Wikipedia より)

https://ja.wikipedia.org/wiki/暗号利用モード#Electronic_Codebook_(ECB)

CBC (Cipher Block Chaining)

CBC は IV (Initial Vector) と前のブロックの暗号化の結果を使用して、同じ内容のブロックを暗号した場合でも別の暗号データを出力できるようにしたモードです。

CBCモードでの暗号化 (Wikipedia より)

https://ja.wikipedia.org/wiki/暗号利用モード#Cipher_Block_Chaining_(CBC)

欠点としては、前のブロックの暗号化の結果がないと次のブロックが暗号化できないので、暗号化処理を並列化することができません。

CTR (Counter)

CTRモード (Counter Mode) は、ブロック暗号を同期型のストリーム暗号として扱うものです。integer counter mode (ICM) あるいは segmented integer counter mode (SIC) とも呼ばれる。

https://ja.wikipedia.org/wiki/暗号利用モード#Counter_(CTR)

各ブロックと単調増加するカウンターを組み合わせて暗号化する方式です。
前後に関連がないため、暗号化・復号ともに並列化することが可能です。

CTRモードでの暗号化 (Wikipedia より)

https://ja.wikipedia.org/wiki/暗号利用モード#Counter_(CTR)

CBC-MAC (Cipher Block Chaining Message Authentication Code)

CBCモードを使い、MACを生成する方式です。
(MAC については「ハッシュ関数」の章を参照)

暗号化を行うものではないようです。
また CBC を使うため、並列計算はできません。

CBC-MACモードでの暗号化 (Wikipedia より)

https://ja.wikipedia.org/wiki/CBC-MAC

CCM (Counter with CBC-MAC)

CTR (Counter) と CBC-MAC を組み合わせた方式です。
CTR を使い暗号化を行いつつ、CBC-MAC を使い認証を行います。

GCM (Galois/Counter Mode)

名称が示すように、GCMは暗号化としてCTRモードを、認証として新しいGalois modeを組み合わせたものです。
https://ja.wikipedia.org/wiki/Galois/Counter_Mode

CCM に似て CTR (Counter) モードを利用した暗号化と、と認証 (Galois) を組み合わせた方式です。
認証タグと呼ばれるハッシュ値のような値により、暗号化された内容を検証することが可能です。
CTR (Counter) モードを使用するため、並列計算が可能です。

GCMモードでの暗号化 (Wikipedia より)

https://ja.wikipedia.org/wiki/Galois/Counter_Mode

[筆者感想]
並列計算が可能でパフォーマンスが良く、特許による妨げもない ため、現状では GCM が最も使いやすい暗号モードかな、と思いました。

公開鍵暗号

公開鍵暗号は、秘密鍵と公開鍵という対になる2つの鍵を使い、どちらかの鍵で暗号化したデータは対になる鍵でしか複合できないという特性を持つ暗号方式です。
名前が示す通り、秘密鍵は所有者のみが保有しなければならないことに対し、公開鍵は広く公開することが可能です。

例えば、公開鍵で暗号化したデータは秘密鍵でしか複合できません。
これにより安全でない通信経路であっても、秘密鍵の所有者に安全にデータを受け渡すことができます。

逆に、秘密鍵で暗号化したデータは、公開鍵でしか複合できません。
これにより受信したデータが、たしかに秘密鍵の所有者が送信した (=改ざんされていない) 内容であることを確認できる。

欠点としては、共通鍵暗号に比べて暗号化・復号の速度が遅いです。
そのため共通鍵暗号で使う秘密鍵を公開鍵暗号方式で交換し、実際のデータはその秘密鍵を使用して暗号化するというように、両方を組み合わせて使う場合もあります。

公開鍵暗号の方式は様々あり、代表的なものとしては RSA や楕円曲線暗号等があります。
また公開鍵暗号を使用して鍵交換を行うディフィー・ヘルマン鍵交換などもあります。

RSA

RSA暗号(RSAあんごう)とは、桁数が大きい合成数の素因数分解が現実的な時間内で困難であることを安全性の根拠とした公開鍵暗号の一つです。

https://ja.wikipedia.org/wiki/RSA暗号

現在広く普及している公開鍵暗号の方式です。

楕円曲線 (ECC)

楕円曲線上の離散対数問題 (EC-DLP) の困難性を安全性の根拠とする暗号。

https://ja.wikipedia.org/wiki/楕円曲線暗号

楕円曲線を利用した暗号方式の総称で、具体的な暗号方式としてはDSAを楕円曲線上で定義した楕円曲線DSA (ECDSA) などがあります。

ディフィー・ヘルマン鍵交換

事前の秘密の共有無しに、盗聴の可能性のある通信路を使って、暗号鍵の共有を可能にする、公開鍵暗号方式の暗号プロトコルです。この鍵は、共通鍵暗号の鍵として使用可能です。

https://ja.wikipedia.org/wiki/ディフィー・ヘルマン鍵共有

「徹底解剖 TLS 1.3 P62」にあるこの図が分かりやすい。

ディフィー・ヘルマン鍵交換の流れ

ディフィー・ヘルマン鍵交換のサンプルプログラム

上記の図を元に (大きな桁の数を扱いやすい) Ruby で簡単なサンプルプログラムを作ってみた。
最終的に、やり取りしていない 30 という数値が双方で算出できることがわかる。

## dh.rb
puts "G: #{G = 39}"
puts "P: #{P = 51}"
puts "A: #{A = 43}"
puts "B: #{B = 76}"
puts ""

puts "Pa: (G[#{G}] ** A[#{A}]) % P[#{P}] = #{Pa = (G ** A) % P}"
puts "Pb: (G[#{G}] ** B[#{B}]) % P[#{P}] = #{Pb = (G ** B) % P}"
puts ""

puts "(Pb[#{Pb}] ** A[#{A}]) % P[#{P}] = #{(Pb ** A) % P}"
puts "(Pa[#{Pa}] ** B[#{B}]) % P[#{P}] = #{(Pa ** B) % P}"
$ ruby dh.rb 
G: 39
P: 51
A: 43
B: 76

Pa: (G[39] ** A[43]) % P[51] = 45
Pb: (G[39] ** B[76]) % P[51] = 21

(Pb[21] ** A[43]) % P[51] = 30
(Pa[45] ** B[76]) % P[51] = 30

公開鍵基盤 (PKI)

公開鍵暗号を利用した証明書を使い、通信相手の認証を行い、通信における信頼を成り立たせる仕組みです。
正当な通信相手であることを認証するために、認証局 (CA) から発行された証明書を使用します。
認証局 (CA) が PKI における重要な役割を果たしています。

例として https://example.com にアクセスした場合、通信相手が確かに https://example.com であることを認証できます。
(https://example.com にアクセスしているつもりが、実は https://evil.example にアクセスしていた、ということにはならない)

あくまで通信相手が想定している相手であることが確認できるだけで、例にあげた https://example.com が悪意のないサイトであるか、といったことは確認できません。

証明書

証明書には、認証のレベルに応じた以下の3種類があります。

EV 証明書 (Extended validation)

サイトを運営する組織が実在し、申請していることが確認できた場合に発行される証明書です。
従来は、アドレスバーが緑色になり企業名などが表示されるといったメリットが存在したが、現在はなくなっています。

OV 証明書 (Organization validation)

DV証明書と同様に、サイトを運営する組織が実在し、申請していることが確認できた場合に発行される証明書です。
DV証明書に比べ、手続きや検証が簡略化されており、標準化されていません。
というよりも、OV証明書が先に存在し、その標準化されていない状況に対してより厳格で一貫性のある方法を求められて、EV証明書が作られたようです。

DV 証明書 (Domain Validation)

ドメインを保有していることが確認できた場合に発行される証明書です。
3種類の中で最も簡素な方法で、手続きも自動化されています。

証明書の形式

証明書では「X.509 デジタル公開鍵証明書形式」という形式が使用されており、これが標準になっています。
X.500 ディレクトリシリーズ の一つで、ISO/IEC の国際標準として規定されています。

フィールド

証明書には以下の情報が含まれています。

上記の他に拡張したフィールドを使用することも可能になっています。

ルート証明書

信頼できる通信相手であるかどうかは、証明書に署名しているCAの証明書をたどり、最終的にルート証明書に到達するかどうかで検証しています。

ルート証明書は、信頼できるCAが署名した証明書である前提で登録されています。
そのため、悪意のある証明書をルート証明書に登録すると、悪意ある相手を信頼してしまうため、ルート証明書を自分で登録は注意が必要です。

CA (Certification Authority, 認証局)

CAは、証明書を発行する機関です。

その中でも、特に他の認証局から認証を受けず、自分で自分を認証する認証局をルート認証局と呼び、ルート認証局が発行する自らの証明書をルート証明書と呼びます。
ルート認証局以外の認証局は中間認証局と呼びます。

CAが侵略された場合、公開鍵基盤全体のセキュリティが失われてしまいます。
そのため、認証局は特に高いセキュリティを求められています。
証明書の発行・管理に関する基本要件をまとめた Baseline Requirement というものが存在します。

証明書は、有料で発行するケースが多かったのですが、現在は Let's Encrypt などの無料で(DV)証明書が発行できる CA も存在します。

証明書の失効

証明書が何らかの侵害を受けた場合に、失効するための手段が用意されています。
失効の方法は、以下の2つの標準があります。

CRL (Certificate Revocation List)

失効した証明書のシリアル番号を全て一覧にしたものです。
欠点としては、リストが肥大化することで配布や検索が重くなってしまいます。

OCSP (Online Certificate Status Protocol)

単一の証明書の失効状態を証明書利用者が取得できるようにするプロトコルです。
証明書のシリアル番号などで、都度オンラインで問い合わせることで失効状態を取得できます。

PKI の弱点

PKI は完璧なシステムではなく、いくつもの弱点を抱えています。
ここでは「プロフェッショナルSSL/TLS 第3章 公開鍵基盤」の見出し部分だけ抜粋してみます。
(詳細は書籍を確認してください)

余談

ロシアが自国のウェブサイトの信頼を独自に担保するTLS認証局を設置 - GIGAZINE