kenmaro です。
秘密計算、特に準同型暗号のことについて記事を書いています。
秘密計算エンジニアとして得た全ての知見をまとめた記事はこちら。
https://qiita.com/kenmaro/items/74c3147ccb8c7ce7c60c
これから準同型暗号について勉強したいリサーチャー、エンジニアの方へのロードマップはこちら。
https://qiita.com/kenmaro/items/f2d4fb84833c308a4d29
今話題のゼロ知識証明について解説した記事はこちら。
https://qiita.com/kenmaro/items/d968375793fe754575fe
概要
今回は、データ通信の安全性を守る暗号技術ということで、
今一度TLSに登場するバージョンやそれに関わる暗号スイート、
そしてHTTPのバージョン、QUICの話などまで再勉強してみたので、その時に得られた事柄について備忘録的にまとめていきたいと思います。
TLS のバージョンと暗号スイート
TLS1.1から1.3にかけて、
- 鍵交換(Kx)
- サーバ認証(Au)
- 通信の暗号化(Enc)
- データが改竄されていないことを保証するための補助データ(Mac)
MacはMessage Authentication Code の略であり、データが改竄されていないことを保証するための補助データのことです。
を行う機能に使われる暗号技術やハッシュ関数は変遷してきました。
図でまとめると以下のようになります。
バージョン | 鍵交換 | サーバ認証 | 通信の暗号化 | MACを生成する関数 |
---|---|---|---|---|
TLS1.1(RFC5246) | RSA | RSA | AES-CBC | SHA1 |
TLS 1.2 (RFC 7525) | ECDHE(Ephemeral) | RSA | AES128(GCM) | SHA256 |
TLS 1.3 | ECDHE(Ephemeral) | ECDSA | AES128(GCM) | SHA256 |
この中で、鍵交換やサーバ認証を行うのが、TLSが定義するハンドシェイクです。
ハンドシェイク
こちらの記事を眺めてもらうと図解がしてあってとてもわかりやすいです。
また、各フローの詳細についてもまとめられています。
このハンドシェイクは、
- サーバの認証(サーバが信頼できるサーバかどうか)
- マスターシークレットの共有(Macや通信データを暗号化する共通鍵を作る素となるもの)
を実行するためのものです。
図を見て理解したことを言葉で書き下すと以下のようになります。
ハンドシェイク | タイプ(例) | RTT(Round Trip Time) | 詳細 |
---|---|---|---|
TLS1.2 | TLS_RSA_WITH_AES_128_CBC_SHA | 3 | 最初はClientHello メッセージにより、クライアント(端末)が対応しているTLSのバージョンや暗号スイートの情報が含まれる。サーバはClientHelloを受け取り、サーバが対応しているものとマッチさせどれを使うか判断、判断後ServerHelloDoneを送信 |
バージョン | タイプ(例) | RTT(Round Trip Time) | 詳細 |
---|---|---|---|
TLS1.2 | TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 | 3 | |
TLS1.3 | TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 | 2 | 通信路は3つの暗号化が実行。1つ目はイニシャル鍵(クライアントが乱数的に作ったサーバのコネクションIDから生成)。2つ目の暗号化はより安全性の高い、ハンドシェイク鍵(ECDHで交換された鍵)イニシャル鍵、ハンドシェイク鍵の生成には事前共有鍵(PSK:Pre Shared Key)が必要。3つ目はアプリケーションデータ鍵(同様にECDHで交換された鍵、事前共有鍵から計算された鍵)を使用。最初は事前共有鍵はないため、0のバイト列が使用。2回目以降はハンドシェイク鍵と、以前の事前共有鍵(セッションIDもしくはセッションチケットによってサーバ側が取得)を使用して今回の事前共有鍵を生成 |
セッション
時間のかかるハンドシェイクを何回も実行しなくていいように、セッションという技術が用いられています。
バージョン | キーワード | 詳細① | 詳細② |
---|---|---|---|
TLS1.2 | セッションをもちいて( サーバ名、共通鍵の種類、鍵交換の種類、ハッシュ関数の種類、ALPNの値(httpか、httpsか)、事前共有鍵)を使い回す。 | セッションによりフルハンドシェイク(鍵交換)を行うことなく通信を再開できる。サーバが各クライアントに対してセッションを保持するのは高負担。セッションID方式の利点:セッションデータを1回しか使われないように制限し、リプレイ攻撃を防止(DBから取り出す時に削除するように実装)。欠点:サーバへの高負荷(クライアントの増加によりリソースを多く使用) | RFC 5077でセッションチケットが定義された。サーバがサーバの秘密鍵で復号できる暗号化されたセッション情報をクライアントが保持する。利点と欠点は、セッションID方式のほぼ真逆 |
TLS1.3 | 0-RTT | 0-RTTは、PSKのみを使用してアプリケーションデータを暗号化し送信する機能のこと。冒頭のハンドシェイクによる通信の遅延を解決するために導入(つまり1RTT節約)。しかし、完全前方秘匿性(将来にわたって過去の通信内容の秘匿性が失われないようにする)が失われることと、リプレイ攻撃が可能なこと(ハンドシェイク毎リプレイ可能)が問題。 | リプレイされてもいいデータを0-RTTで送信する。冪等性があるデータはリトライしていい、なければリトライしてはいけない(POST)。ChromeはQUICで0-RTT+POSTリトライしている |
通信の暗号化
通信の暗号化は暗号化する鍵と復号する鍵が共通である、共通鍵方式の暗号を用いることが一般的です。
理由は公開鍵方式の暗号よりも、暗号時や復号時の計算量が少なく処理が高速に実行可能だからです。
バージョン | 共通鍵プロトコル |
---|---|
TLS1.1 | ストリーム暗号、CBCモードのブロック暗号 |
TLS1.2 | AEADの追加, ストリーム暗号、ブロック暗号 |
TLS1.3 | AEADのみ |
TLS1.1ではストリーム暗号、CBCモードのブロック暗号などが採用されていましたが、
ストリーム暗号(RC4)にはさまざまな攻撃手法があり、RFC7465で使用が禁止されました。
また、CBCに対してもBEASTと呼ばれる攻撃手法が有効とされました。
TLS1.2ではAEADが追加され、TLS1.3ではAEADのみ採用、というように、
暗号の秘匿性のみではなく、完全性や認証性も考慮したプロトコルが現在は使われています。
TLSにおけるプライバシーの保護
バージョン | プライバシーの保護 |
---|---|
TLS1.2 | 証明書が平文で流れるため、誰が通信しているのかがわかる。セッションチケットが同一のまま複数回平文で流れる。 |
TLS1.3 | 証明書も暗号化。セッションチケットは使い捨て |
TLSにおける圧縮技術
バージョン | 圧縮 |
---|---|
TLS1.2 | 圧縮機能を使用すると、CRIMEやBREACHという攻撃手法に脆弱性を持つ。TLS1.2で圧縮は使ってはいけない |
TLS1.3 | 圧縮機能は削除 |
攻撃手法
攻撃手法はたくさんありますが、一部だけまとめています。
攻撃手法 | 説明 | 事例(インシデント) | 解決策 |
---|---|---|---|
リプレイ攻撃 | 暗号化されているデータをそのまま送ることでログインできてしまう | 2016年DAOから65億円分不正送金 | ワンタイムパスワード |
CHAP(チャレンジハンドシェイク認証プロトコル)を使用 | |||
中間者攻撃(MITM) | 送信者と受信者の間でデータを改竄してなりすます攻撃。署名鍵によって解決 | ||
CRIME | secret cookie を、インジェクトしたデータに対して送られる圧縮されたpayloadがどう小さくなるかから割り出す方法。 | ||
BREACH | CRIMEの亜種 | ||
Racoon Attack | TLS1.2 及びそれ以前のDHに対する攻撃手法 | https://jvn.jp/ta/JVNTA95716145/ |
ブロック暗号とモード
ブロック暗号とは、平文を一定の長さ(DESでは64ビット、AESでは128ビットなど)で区切り、
それぞれのブロックを暗号化していくためそう呼ばれています。
このとき、もちろん暗号化したいデータはそれらの長さより長いことがほとんどですので、
たくさんのブロックを暗号化して送ることになります。
このとき、この暗号化のサイクルにいろいろな手法があり、それを「モード」と呼びます。
このモードについてはWikipediaの資料を読めば理解できると思います。
ECBと呼ばれるモードでは、複数のブロックに同じ平文が暗号化されることになると、出てくる暗号文が同じになってしまうため、暗号文にパターンが存在することになり、安全でないとされました。
これを受け、CBCモードやCFB、OFB、CTRモードなど様々なモードはイニシャルベクトルやノンスなどを用いて暗号文にパターンが出ないような工夫がなされています。
共通鍵暗号を通信で互いに使うためには、両者間で共通となる鍵を共有することが必要になります。
もちろん、共通鍵を共有するための通信はまだ暗号化されていないため、どうやって送れば安全に共通鍵を共有できるのかを考える必要が出てきます。
そこで使われるのが、鍵交換という暗号技術を用いた手法です。
鍵交換について
鍵交換でよく使われるものは以下のアルゴリズムです。
鍵交換 | 相互の認証 | 前方秘匿性 | セッションごとに鍵を交換 | 推奨される鍵長 |
---|---|---|---|---|
RSA | 可 | 不可 | 不可 | 2048 |
DH | 不可 | 可 | 可 | 2048 |
ECDHE | 可 | 可 | 可 | 224 |
相互の認証
相互の認証、というキーワードについて見てみましょう。
相互というは「送信者」と「受信者」が互いに正当なパーティであるかの検証、ということです。
したがって、相互の認証がなければ攻撃者が仮に両者の間に割り込んだ場合、「中間者攻撃」を受けやすくなります。
前方秘匿性
前方秘匿性というキーワードについてもみていきます。
例えば攻撃者が、攻撃対象の通信路で流れたデータを全て保存しておき、サーバの改修などの時に秘密鍵を盗むことができれば、
今までの全ての通信を復元できることになります。
一方でDH使い捨ての暗号になります。
使い捨てという意味は、DHではセッションごとに共通鍵を変更することから、
仮に共通鍵と通信の内容が傍受されたとしても
データ漏洩の被害をそのセッションの間だけに止めることができます。
したがって、セッションごとに公開鍵と秘密鍵をその都度生成するため、前述の攻撃に対して耐性があります。
楕円暗号と鍵長
最後にDHとECDHEの違いですが、「EC」というキーワードは「Eliptic Curve (楕円曲線)」という意味であり、
有限体上の離散対数問題を考える際の代数体を整数で考えるか、楕円曲線上で考えるか、という違いになります。
表の「推奨される鍵長」からもみてとれるように、楕円ベースの暗号は短い鍵長で高いセキュリティを実現することができます。
つまり、楕円を用いた時はやり取りするデータ量が少なく高速だという利点があります。
また、楕円曲線の研究は進んでおり、楕円を構成するパラメータについては、RFC4492で厳選されたパラメータが存在しています。
TLS1.2 で追加された楕円
IFTFやNISTはセキュリティの基準を取り決めているそれぞれ欧州とアメリカの研究所であり、
多くの権威たちが様々なセキュリティ分析を行い、世の中で使われる暗号技術の標準化をおこなっています。
TLS1.2では、それまでにNISTというアメリカの専門機関が国際標準として選んでいた
- NIST P-256
- NIST P-384
- NIST P-521
と呼ばれる楕円に加えて、
- Curve25519
- Curve448
というNIST由来ではない楕円が選定されました。
これは、NISTが選出した楕円に対して(正確に言えば楕円を用いた乱数生成器に)バックドア(裏口)を設けて暗号通信をNSAが秘密裏に解読していたのではないか、という疑念が
スノーデン氏の告発により明らかになったからです。
この告発があった2013年以降、Curve25519は注目を集めることになりました。
その後、2018年にTLS1.3が公開されてから、鍵交換アルゴリズムはCurve25519を用いたx25519が推奨されています。
このあたりは読んでいくと面白いので、興味のある方は
や
を読んでいただければと思います。
MACについて
MACは暗号文と共に送られる認証タグです。
この認証タグを用いることで、暗号を受信した人はその暗号が途中で改竄されていないかを検証し、その暗号の「完全性」を検証することができます。
MACを搭載した暗号は
AEAD: Authenticated Encryption with Associated Data
日本語では認証付き暗号と呼ばれます。
暗号が改竄されていないかのチェック
Wikipediaの解説がとてもわかりやすいので参照していただきたいです。
https://ja.wikipedia.org/wiki/%E8%AA%8D%E8%A8%BC%E4%BB%98%E3%81%8D%E6%9A%97%E5%8F%B7
認証付き暗号の種類として、ウィキペディアの中でも3つ例が出されていますが、
やっていることの違いはMACをどのタイミングで作って暗号文に埋め込むか、というところです。
MACはハッシュ関数を用いて平文(もしくは暗号文)から一意につくられ、暗号文にパディングされるなどして受信者へと送信されます。
受信者はその暗号文とそのパディングされたMACを再度計算して検証することで、暗号文が途中で改竄されていないかどうかをチェックできます。
また、MAC後暗号化にはバインディングオラクル攻撃という手法が見つかっています。
ここでなるほどと思ったのは、AEADは平文既知性があるということ。
つまり平文からハッシュ関数を生成するため、暗号を作る人は平文を知っていなければAEADを構成することができません。
したがって、平文選択攻撃(CCA)を防ぐことができます。
どういうことかと言うと、平文選択攻撃では、攻撃者は復号オラクル(復号をしてくれる人)に対して、どんな暗号文も復号をお願いすることができ、それは自分で作った任意の暗号文でも良いのですが、
AEADを制約とした場合、復号オラクルは、認証できない暗号(つまり暗号送信者が暗号化プロトコルに沿わずに任意に生成した暗号)に対しては復号を拒否することができるからです。
暗号が本物の送信者によるものかのチェック
暗号文が本当に「本物の送信者」から送られてきたかどうかも、MACの一部である署名情報を用いて検証できます。
MITM(Man in the middle)攻撃、日本語だと中間者攻撃と呼ばれる攻撃では、
送信者と受信者の間に入った攻撃者があたかも送信者であるようになりすまして暗号文を受信者に送りつける攻撃です。
この攻撃にに対して、TLSでは署名を使って対処します。
データから署名鍵を使って(データ、署名)のペアを作り、
受信者は検証鍵を使ってそのペアが正しいかを判断します。
このペアを作ることができるのは署名鍵を持っている人だけ(つまり送信者しかこの鍵を持っていないので)なので、
この暗号が送信者から送られてきた(途中で誰かがなりすまして送ってはいない)ことがわかります。
RSAを使うかDHを使うか、またはECDHEを使うかというのは下の表からもわかるように一長一短あり、使い分けが必要です。
HTTPの各バージョン
HTTPはTCPを用いてデータの送信者と受信者の間でどのように認証を行いデータの送信を行うか
を取り決めたプロトコルです。
通信を始める際のハンドシェイクということばを聞いたことがある方も多いかもしれませんが、ハンドシェイクの内容を取り決めているのもHTTPプロトコルです。
HTTPには様々なバージョンがありますが、1,2,3について詳しくまとめられている資料では
こちらが大変詳しくわかりやすかったです。時間があればこちらを一度読み通してみることをお勧めします。
まずは階層モデルのおさらい
HTTPプロトコルは、その一つ下の層であるトランスポート層に位置するTCPプロトコルを利用して成り立っています。
TCP/IPの4階層モデルのおさらい | プロトコル | 詳細 |
---|---|---|
アプリケーション層 | HTTP, SMTP(メール) | |
トランスポート層 | TCP, UDP, QUIC | TCPはパケットロスや、順番の入れ替わりに対して対処してアプリケーション層に送るのに対して、UDPはそこをアプリケーション層に任せる。信頼性の有る無しと呼んだりするが、QUICは最下層としてUDPを使いつつも信頼性を確保している |
インターネット層 | IP | パケットを届ける通信ルール |
ネットワークインターネット層 | MAC、イーサネット | 隣接したパソコンがデータをやりとりするための通信ルール(MACやイーサネット) |
HTTPはTCP/IPの4階層モデルでのアプリケーション層の実装であり、
HTTP/1.1 1.2, 1.3というようにバージョンが進化しています。
成り立ち(前身) | 課題点① | 課題点② | |
---|---|---|---|
HTTP/1 | Head of Blocking 問題 | ||
HTTP/2 | Google SPDY | 圧縮機能に脆弱性が発見 | パケットロス時のストリーム間の影響 |
HTTP/3 | Google QUIC |
HTTP/1 のHead of Blocking 問題
http/1.1 が持っていた、1つの接続で複数のリクエストを送るkeep alive と呼ばれる機能で、
1, 2, 3, 4というふうに送ると、例えば2のレスポンスに時間がたくさんかかる場合、3,4は待たなければいけませんでした。
keep alive を使わずにTCPレイヤでコネクションを複数張ってもいいのですが、それだとコネクションの確率に時間がかかるのと、帯域の使い方としても非効率であり、問題となっていました。
HTTP/2で実装されたストリーム通信
head of blocking 問題への解決策として、HTTP/2ではバイナリ形式のフレームと呼ばれる単位にリクエストを区切り、
1つのTCPコネクションでリクエストを並列的に多重化しました(実際にはデータ自体は直列で送られており、並列で送ることはできません)
リクエストとレスポンスのペアは、ストリームと呼ばれる単位で管理されます。
http/2は、他にも
- ウィンドウ制御(受信側のバッファを溢れさせないように送信データ量を管理する仕組み)
- ヘッダ圧縮
- サーバープッシュ
- 優先度制御
- エラーハンドリング
といった機能を持っています。
HTTP/1.3, QUIC
- IFTFによるHTTP over QUIC の標準化(2016~18)
- IFTFによるhttp/3 としての標準化(2018~)
- RFC9114 HTTP/3標準化
- RFC9204 QPACK 標準化
ここで、HTTP/1.3におけるQUICと呼ばれるプロトコルには、以下のような特徴があります。
観点 | TCPの特徴 | QUICの特徴 |
---|---|---|
パケットロス | TCPではパケットロスが起きると、その後のパケットが受信できていたとしてもアプリケーションには送らない。 | QUICではパケットロスが発生したとしても、後続のパケットが受信できていればそれをアプリケーション層に送る |
パケット番号 | パケットに番号をつけ、パケットロスしたものに対しても送信側が番号をつけるので、受信側はロスしたことなども含めて理解できる | |
コネクションID | TCPは5タプル(受信者IP、送信者IP、受信者ポート、送信者ポート、IPヘッダのプロトコルが1つでも変わるとコネクションを継続できない。 | QUICはIDを使うため変化があってもコネクションを継続できる |
トランスポート層の制御情報も暗号化 | http/2まではTCPの制御に関する情報(再送、切断など)については暗号化されていなかった。また、http/2以前では暗号化はオプションだった。 | TCPの制御に関する情報(再送、切断など)についても暗号化、暗号化は必須。 |
アプデが早い | TCPはOSで処理される。 | QUICはブラウザなどのアプリケーションで処理されるので、更新の反映がとても早い。 |
パケット | 1UPDパケットに、1つ以上のQUICパケットが入る | |
フレーム | 1QUICパケットには、1つ以上のフレームが入るフレームの種類は20種類 | |
ストリーム | HTTP/2ではストリームの管理はhttp/2、パケットの管理はTCPと別れていたので、ストリーム単位では信頼性がない。 | QUICはそれらの管理を一括で行うため、アプリケーションプロトコルに対してストリーム単位での信頼性を確保可能 |
暗号化 | 暗号化は、暗号が改竄されていないことがわかる認証つき暗号で構成 |
HTTP/2, HTTP/3 で用いられるヘッダ圧縮技術
圧縮対象 | 名称 | 使用技術 | 注釈 | |
---|---|---|---|---|
HTTP/2 | ヘッダ | HPACK | ハフマン符号、辞書データ | ハフマン符号は、頻出文字をその他の文字より小さいビットで表すような符号化のこと |
HTTP/3 | ヘッダ | QPACK | ハフマン符号、辞書データ | 辞書データは、キーワードに対してインデックスを振り、キーワードの代わりに数字だけを送ること |
QUICの今後
圧縮対象 | 名称 | 使用技術 | 注釈 | |
---|---|---|---|---|
HTTP/2 | ヘッダ | HPACK | ハフマン符号、辞書データ | ハフマン符号は、頻出文字をその他の文字より小さいビットで表すような符号化のこと |
HTTP/3 | ヘッダ | QPACK | ハフマン符号、辞書データ | 辞書データは、キーワードに対してインデックスを振り、キーワードの代わりに数字だけを送ること |
最後に
今回は、データ通信の安全性を守る暗号技術まとめということでなるべく網羅的に勉強したことを備忘録的に書こうと思いましたが、
情報量が多く散らかってしまいました。
何気なく普段使っているウェブブラウザ一つにしても、裏ではいろいろなプロトコルにより私たちのセキュリティが守られているということはすごいことですね。
GoogleがHTTP/2やHTTP/3の前身を作っているということは初めて知り、自社で開発したものを最終的に社会インフラに還元しているのがやはり偉大だなと思わされました。
今後も勉強するたびにこちらの記事はアップデートしていけるように頑張りたいと思います。
今回はこの辺で。