ぼちぼち日記

おそらくプロトコルネタを書いていることが多いんじゃないかと思います。

新しいTLSの暗号方式ChaCha20-Poly1305

Disclaimer

本エントリは、近々IETFで標準化される予定の新しいTLSの暗号方式 ChaCha20-Poly1305 について解説したものです。

本来なら、新しい暗号方式を紹介するいうことは、その暗号の安全性についてもちゃんと解説しないといけないかもしれません。しかし一般的に暗号の安全性評価はとても難しく、専門家でない者が暗号の安全性について軽々しく書くわけにはいかないなとも思いました。いろいろ悩みましたが、結局無用な誤解を避けるため、本エントリーでは ChaCha20-Poly1305 の安全性に関する記載を最小限に留めています。

今回紹介する ChaCha20-Poly1305 は、これまでも様々な暗号研究者の評価を受けている暗号方式ですが、まだNISTの標準や某国の推奨暗号リストに掲載されるといった、いわゆる特定機関のお墨付きをもった暗号方式ではありません。記載内容が中途半端で申し訳ありませんが、ChaCha20-Poly1305 の暗号利用の安全性について心配な方は、本エントリーをお読みにならないようお願い致します。またこういった内容を留意していただいた上で、本記事をお読みくださるようお願いします。

2016年6月23日追記:
RFC7905「ChaCha20-Poly1305 Cipher Suites for Transport Layer Security (TLS)」 が発行されました。

0. 短いまとめ

記事が長いです。長文を読むのが苦痛な方は、この短いまとめだけ読んでください。

  1. 新しいTLSの暗号方式 ChaCha20-Poly1305 が仕様化されます。
  2. 新仕様版はChrome49/Firefox47/OpenSSL-1.1.0(beta)などで既に利用可能です。
  3. AES-GCMより転送サイズが小さくなり、AES-NIのないARM環境では3倍程度性能が高くなります。
  4. OpenSSLなどでcipher server preferenceと両立して運用するには現時点で課題があります。equal preference cipher groups機能待ちです。

(2016年5月16日 訂正: 記事中 TLSのAES-GCMのタグ長が12バイトと記載されていましたが、16バイトの誤りです。図表と記載を修正しました。id:kazuhooku さんのご指摘ありがとうございました。)

1. TLSに新しい暗号方式が必要となった背景

常時HTTPS化は、これからのWebには避けられない流れです。その中核となる通信プロトコルTLSには、現在いろいろなリスクや課題が存在します。

1.1 AESがTLSのSPOFになっている

その課題一つに現在広く利用されているAESを使った暗号方式に関するものがあります。

  • 現在実用的に広く使えるTLSの対称暗号が実質AESの一択しかない。

AES以外の暗号で普及しているという意味ではまだ3DESも健在ですが、性能がAESに比べて1/4〜1/10に落ちてしまいます。AES/3DES以外にも性能的に見劣りしない対称暗号もありますが、世界的に広く使われているとは言い難いです。

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

1.2 AES-NIのないARM環境でも安全で高速な暗号が欲しい
  • AESはハードウェア処理(AES-NI)が使える環境では非常に高性能だが、ソフトウェア処理だけではそれほど性能がでない。またAESはキャッシュタイミングなどサイドチャネル攻撃を避ける必要がある。そのため実装が複雑になりがちである。

IntelAMDのCPUで実装されているAES-NIは、非常に強力な機能です。AES-NIを使うだけで暗号処理能力は数倍に跳ね上がります。しかしモバイルやIOTの環境でよく利用されるARMにはAES-NIなど入っておらず、非力なCPUの上でソフトウェアで頑張らないといけません。その上、やみくもな最適化はキャッシュタイミングによるサイドチャネル攻撃を受ける可能性があります。

シンプルな実装で、なおかつAES-NIのない環境でも十分に性能が確保できる暗号方式が求められています。

1.3 新しい暗号方式 ChaCha20-Poly1305 の導入

ChaCha20はストリーム暗号、 Poly1305はメッセージ認証(MAC)の機能を実現します。共に著名な D. J. Bernstein (djb)氏が考案しました。djbは当初SalSa20という暗号を公開し、後にChaCha20という改良版を発表しました。いずれもラテンダンスの名前にちなんでいるようですが、はっきりと名付け由来が書いてある記述を探し当てることはできませんでした。どなたか由来を知っている人がいらっしゃいましたら教えて下さい。

4/5追記: id:bottomzlife さんより情報を頂きました。ありがとうございます。

Poly1305に関しては、最初 dbj djb はhash127という2^127-1の素数を使ってMACを計算する方式を発表していましたが、後により計算効率が良い2^130-5の素数を使ったPoly1305を2005年に発表しました。どちらも鍵の生成に対称暗号と組み合わせることが必要で、論文ではAESと組み合わせたPoly1305-AESが使われていました。Poly1305の仕組み上、AES以外の対称暗号とも組み合わせられることが可能です。

RFC7539では、Poly1305がChaCha20と組み合わせた形で仕様化されました。ChaCha20/Poly1305のどちらも知的財産権などの問題もないと言われています。ChaCha20とPoly1305は、ともに非常に簡潔なアルゴリズムで規定されており、ソフトウェア処理に向いています。これを使って先に述べたTLSの課題を解決できるものと期待されています。

1.4 ChaCha20-Poly1305のこれまでの歩み

ChaCha20-Poly1305のこれまでの歩みをざっと表にしました。

TLSに関連する動きが出てきたのが2013年から。このあたりで、Chacha20とSHA1を組み合わせたり、Salsa20とUMAC(RFC4418)と組み合わせたドラフトなどが公開されていました。動きが本格化したのは、2013/09 にGoogleのセキュリティ専門家 Adam Langlay (agl)氏が、ChaCha20とPoly1305を組み合わせた暗号方式のドラフトを提出してからです。

ちょうど2013/06にEdward Snowden事件でNSAによる広範囲の盗聴・改ざん行為が明らかになり、Dual_EC_DRBGのバックドア問題などNSAが関与しているNIST標準の暗号方式に対する疑義が高まった時分でした。過去米国政府と暗号技術に関して何回も法廷闘争を繰り広げたdjbの暗号は、安全性に対する信頼は他とは違うぞと、この時期の新しい暗号方式の提案にはそんな象徴的な意味合いを個人的に感じてしまいます。

早速ChaCha20-Poly1305は、2013/11にChromeに先行実装され、現在まで既にGoogleのサービスで利用されています。この時期の先行実装は、現在のLastCall 版の仕様と若干異なっており、互換性はないものでした(Googleは既に最新仕様に移行しています)。

Google以外の実装では、2014/04に発覚したHeartBleed脆弱性の余波でLibreSSL/BoringSSLがOpenSSLからフォークされたことを受け、これらのフォークが直ちにChaCha20-Poly1305をサポートし始めました。これらの実装の広がりを受け、IETFTLS WGの要請を受けCFRG(Crypto Forum Research Group)で議論が進み、2015/05にChaCha20-Poly1305の仕様がRFC7539として発行されました。

このRFC7539で規定されたChaCha20-Poly1305をTLSで使えるようにするのが、 draft-ietf-tls-chacha20-poly1305-04 です。2016/3/22にIETF Last Callが開始され、ちょうど明日(4/5)に終わります。IESGとIANAのレビューが無事通れば、近いうちに晴れてRFCになる予定です。この仕様はTLS/DTLSの両方の利用を規定していますが、本エントリーはTLS向けの仕様だけを解説します。

1.5 TLSで使えるChaCha20-Poly1305の種類

今回新たにTLS仕様化されるのは以下の7つの CipherSuiteです。いずれもAEAD(認証付き暗号)であるため、AEADの規定がないTLS1.0/1.1では仕様上利用できません。使うにはTLS1.2以上が必要です。

TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 O, F, C
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 O, F, C
TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 O, Fコメント欄参照
TLS_PSK_WITH_CHACHA20_POLY1305_SHA256 O
TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 O
TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 O
TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256 O

(O: OpenSSL-1.1.0, F: Firefox, C: Chrome)

PSK(PreSharedKey)のCipherSuiteが4つ。ECDHEの鍵交換はRSA/ECDSA認証の2つ、残る1つはDHE/RSAのものです。master secretを生成するPRFにはすべてSHA256を利用します。個人的には Chrome49, Firefox47, OpenSSL-1.1.0-beta1 で既に実装されていること確認していますが、LibreSSLやその他のTLS実装はどの程度対応しているのかまで見ていません。各実装がサポートしているCipherSuiteを表の2カラム目(O, F, C)として記載しておきます。

2. ChaCha20とは何か?

先述した通りChaCha20は非常にシンプルなアルゴリズムを使った暗号です。せっかくだからその仕組みを解説したいと思います。まずはAESと比較してみてChaCha20の特徴を見てみます。

2.1 AESとChaCha20の比較


AESはブロック暗号、ChaCha20はストリーム暗号と分類されます。しかしAES-GCMなどカウンターモードでのAESの利用は、実質ストリーム暗号として機能します。AEADの観点から比較するとストリーム/ブロックでの両者の暗号の違いはほとんどありません。ChaCha20は、入力にNonceと初期カウンター値が必要 なのが特徴です。暗号の安全性を確保するため、Nonceは同じ値が使われないことが必要です。Nonceサイズはオリジナルの djb の論文と異なっています。これはAEADの仕様(RFC5116)の推奨サイズに合わせたためです。

暗号実装では両者は大きく違います。AESでは、剰余計算を高速に行うために事前計算テー ブルを作成したり、要素を非線形に変換するSBOX処理が必要ですが、ChaCha20は後述する通り加算剰余、XOR、ビットローテーションという単純な計算処理だけです。ChaCha20は、SIMDを使うとより高速なソフトウェア処理が可能になります。

2.2 ChaCha 1/4ラウンド演算

先程から繰り返し書いている通り、ChaChaの暗号化を担う処理は非常にシンプルなものです。この処理を行う中心的な関数を1/4ラウンド演算(QuarterRound)と呼びます。ChaChaは内部に4バイトx16個の状態を持っています。このQuarterRoundを使って内部状態の中の4つの要素(a, b, c, d)を混ぜあわせ、新しい要素の値に更新します。

QuarterRoundは、上図の通り4つの演算から成り立っています。 x + y は (x+y) mod 2^32, ^ は XOR, <<< n はnビット左ローテションを表します。注目すべきは乗算がないことです。一般的に暗号技術は、乗算処理が含まれることが多いのです。ChaChaは乗算処理がないため、演算中の桁上り伝搬を心配 する必要がほとんどありません。ビットローテーションも固定長なので、容易に Constant Time の演算処理が実現できます。これがサイドチャンネル攻撃を受けにくい理由です。

ChaChaのQuarterRoundは、1回の処理で4つの要素が2回ずつ更新されています。ここはSalsa20から改良された点で、ChaChaがSalsaより安全性が高くなっていると見られている点です。

2.3 2種類のChaChaラウンド

ChaCha20は、4バイトx16個の初期状態をQuaterRoundを使って状態を変えていきます。QuaterRoundを適応させるやり方として、列の要素4つ対する列ラウンドと、対角的に並ぶ要素に対する対角ラウンド、この2種類のChaChaラウンドを規定しています。これを使い16個の要素全部に対して偏りなく演算を行っています。

2.4 ChaCha20 Stream State

ChaChaの初期の状態はどうやって決まるでしょうか? 最初の4バイトx4は定数値です。これは expand 32-byte k という固定文字列が入っています(このmagic wordの由来もわかりませんでした)。

次にChaCha20の鍵データ、32バイトが続きます。その後に通常1から始まるカウンター値、12バイトのNonceが入ります。これを 列ラウンド+対角ラウンドの演算を10回繰り返します。結果1/4ラウンドを20回繰り返すことから ChaCha20 ということになります。20はラウンド数を表しています。

ChaCha20は、20ラウンドの演算を経て最終的に生成した ChaCha20 State を使って平文から暗号文を生成します。

2.5 ChaCha20による平文の暗号化

平文から暗号文の生成は簡単です。平文を64バイトのブロックに分割します。それぞれのブロックに対してカウンター値を上げながら、それぞれのChaCha20 Stateを計算します。出来上がった ChaCha20 State と64バイトブロックの平文との XOR をとり、暗号文を作ります。

暗号文から平文に戻す手順もほぼ 同一手順です。同じ鍵, Nonce, カウンター値からChaCha20 Stateを作り、暗号文とXORを作れば平文が生成できます。このようにChaCha20ではEncrypt/Decrypt が全く同じ処理でできます。これはソフトウェア処理がシンプルになる大きなメリットです。

AES単体のDecryptは、Encryptの逆関数を用意しなければならず、ChaChaほど簡単にいきません。

3. Poly1305とは何か?

次はPoly1305です。まずは AES-GCMで使われているメッセージ認証GHASHと比較してみます。

3.1 GHASHとPoly1305の比較


GHASHとPoly1305のどちらも Wgman-Carter Constructionという方法でメッセージ認証データを生成します。GHASHはガロア拡大体、Poly1305は素体の有限体上で演算を行います。

仕様的にGHASHは明示的な鍵長制限を持ってなさそうですが(間違っていたら誰か教えて下さい)、AESと組み合わせたAES-GCMの場合は、128bitsの鍵を利用 します。Poly1305は、256bit長の鍵を使います。後で説明しますが、256bit長の鍵を2つの鍵に分割して利用します。
GHASHとPoly1305、ともに生成するMACデータ長はどちらも128bitsです。ただしGHASHの方は、用途に合わせて小さく切り詰めて利用され、AES-GCMでは96bit128bit長にしています。GHASHの利用は、セキュリティの観点から64bits以上であることが求められています。

GHASHの特徴はなんとってもハードウェア処理。Intel/AMDが提供するPCLMULQDQ命令セットを使うと非常に高速に演算できます。
Poly1305の方はChaChaと同様、非常にシンプルなアルゴリズムを持ち、ソフトウェア処理が得意です。
しかも2^130-5という128bitsを少し超えた素数上での演算であるため、計算効率が非常に高くなります。また8bitから64bitまでのサイズの変数を使った最適実装を作ることができ、様々なアーキテクチャ上で高速に動作させることができます。さらにPoly1305は、剰余算を高速化させるために通常行う事前計算テーブ ルの作成が不要です。ただし剰余を求める際にタイミング攻撃に合わないよう Constant timeな実装が求められます。

3.2 Polynomial evalation(多項式評価)

Poly1305のPolyは、Polynomialの略です。MACによって任意の長さのメッセージが改ざんされていないか認証するためには、認証するメーッセージを何かの形で評価することが必要です。
Poly1305は、メッセージを128bits長のブロックに分割します。各ブロックを係数とした多項式f(x)を作成し、xの値が鍵データrの時のf(r)の値でメッセージを評価します。この多項式には0次の定数項がないのが特徴です。もし定数項があるとメッセージ評価値の差分を取ることによって鍵情報が部分的に漏洩してしまうからです。多項式評価を使うメリットは、ホーナー法によって高次の乗算計算を減らして加算の再帰として計算できるからです。ホーナー法を 利用することによって高次の事前計算を避けることができ、ソフトウェア実装がし易くなっています。

3.3 Wegman-Carter Construction

GCMとPoly1305、ともにメッセージ認証コードの生成は、Wegman-Carter Constructionという方式を利用します。

Webman-Carter Constructionとはメッセージのユニバーサルハッシュに一時鍵を加えた値をメッセージ認証値とする方法です。数学的に強度が証明できていることが特徴です。なにより高速です。 ユニバーサルハッシュは、暗号だけでなく誤り訂正などにでも利用される高速なデータハッシュ手法ですが、SHA-1/2のような原像攻撃に耐性があるようなわけではなく、暗号ハッシュほどの強度はありません。しかし Wegman-Carter Construction によってメッセージ改ざんを検知するに十分な強度を得ることができるためTLSのAEADでの利用が進んでいます。

3.4 Poly1305のアルゴリズム

Poly1305のアルゴリズムも単純です。tweet(140字以内)で表現可能といわれるぐらいです。

Poly1305のMAC計算は、認証するデータを16バイト長で分割し、頭に0x01を付加して17バイト長のブロックにします。16バイトに満たないブロックは頭に0x01をつけた後0パディングして17バイト長に揃えます。

16バイト長の鍵を2つ r と s を用意し、鍵rの方は128bit全部利用せず、途中のビットを0にして22bit分間引きます(ここがdjbのすごいところです)。
生成したメッセージを多項式評価として鍵rの値で評価し、素数2^130-5の剰余をユニバーサルハッシュを求めます。一時鍵sを加えれば、強度の高いWgman-CarterのMACデータが出来上がりです。しかしこのままだと最大130ビット長となって扱いにくいので、頭の2bit分を取り除き16バイト長のメッセージ認証 データにします。

Poly1350で利用する鍵 r, s は ChaCha20を使って生成します。カウンター0のChaCha20 Stateを求め、上位16バイトをs 下位16バイトをrに割り当てます。

2^130-5という128bitよりちょい大きい絶妙なサイズの素数を利用しているため16バイトという大きいブロックでメッセージ分割した多項式評価が行える。22bit分間引いた鍵rを使用しているため部分剰余のサイズが一定の範囲に納まり、ホーナー法を使いながら各ブロック毎に逐次計算がしやすくなります。

4. ChaCha20-Poly1305とは何か?

これまでChaCha20とPoly1305を別々に見てきましたが、TLSではChaCha20とPoly1305を組み合わせてAEAD(認証つき暗号)として利用します。従来のMac-then-Encrypt(平文のMACを取ってから暗号化を行う方法)では過去いろいろな脆弱性の影響を受ける可能性があるため、ChaCha20-Poly1305はAEAD一択です。

AES-GCMとChaCha20-Poly1305を比較してみます。

4.1 AES-GCMとChaCha20-Poly1305の比較


AES-GCMとChaCha20-Poly1305の大きな違いは、ChaCha20-Poly1305の鍵交換はECDHE/DHEだけしかサポートしないことです。TLS1.2といえでも、もはやForward Securecyのない鍵交換はサポートしません。

またChaCha20-Poly1305では明示的なIV(Nonce)データを必要としません。明示的IVは、TLS1.0でBEAST攻撃に対応するためTLS1.1に導入された項目ですが、次期TLS1.3では廃止される予定です。ChaCha20-Poly1305は、そのTLS1.3仕様を部分的に先取りしたものになっています。

ChaCha20-Poly1305はTLSの暗号化通信を行う際に双方で持つシーケンス番号(8バイト)のデータをNonceに利用します。シーケンス番号を0でパディングし、master secret から生成される12バイト分のWriteIVとXORを取ってNonceとして利用します。こうすることによって、わざわざ8 バイトのIVを明示的に送信することがなくなり、その分通信データ量を削減することができます。またバグなどでIVが再利用されてしまうといった間違いも避けることができるので、より安全な実装になることが期待されています。

4.2 ChaCha20-Poly1305のAEAD処理フロー

AES-GCM仕様のフローに似せてChaCha20-Poly1305によるAEAD生成(暗号化)のフローを書くとこのようになります。

初期カウンター0でPoly1305用の鍵(r,s)を作り、初期カウンター1に増加させてChaCha20 Key Streamを生成し、平文から暗号文に変換させます。
認証を行うデータと暗号文それぞれを0でパディングして16バイト長に揃えます。平文(8バイト長)と暗号文の長さ(8バイト長)を結合して、全体のデ ータのMACをPoly1305で計算し、128bitのMACデータ(認証タグ)を取得します。TLS1.2では認証を行うデータは、TLSレコード層のデータとシーケンス番号を合わせたデータです。最後に暗号文に認証タグをつけて暗号化されたTLSのアプリケーションデータとして相手に送信します。

4.3 ChaCha20-Poly1305とAES-GCMのサイズ

AES-GCMとChaCha20-Poly1305で1バイトの平文をAEADで暗号化した場合の比較をしてみましょう。

どちらもストリーム暗号として機能するので暗号文は1バイトです。タグのサイズはChaCha20-Poly1305が16バイト、AES-GCMが12バイトです。 タグのサイズはChaCha20-Poly1305とAES-GCMともに16バイトです。
ただAES-GCMは明示的IVの8バイト分先頭に必要です。レコード層の5バイト分は共通ですからChaCha20-Poly1305は22バイト、AES-GCMは26バイト30バイト。TLS1.2ではChaCha20-Poly1305の方が、AES-GCMより小さいサイズに収まります。

5. ChaCha20-Poly1305 vs AES-GCMの性能比較

本当に ChaCha20-Poly1305 は、ARM環境では速いのか? AES-GCMと性能比較してみます。

EC2 c3.large (Intel Xeon E5-2666 Haswell)とRaspberry Pi2 (ARM Cortex-A7)上で openssl speed コマンドによるベンチマークを行いました。ベンチを行った時期がちょっと前だったのでOpenSSLは 3/1 時点での master head( OpenSSL-1.1.0-pre4-dev master HEAD on 2016/03/01)を使っています。その後ChaCha20-Poly1305のアセンブラ関連のバグ修正などされていますが、性能自体はそれほど変わっていないはずです。

Haswellを搭載するc3.largeは、現時点でのEC2の最速CPUで、AES-NI/AVX/AVX2とハードウェアの力で暗号処理を高速化させる機能が満載です。OpenSSLもAES-NI/AVX/AVX2に対応するようビルドしています 。Raspberry Pi2 の ARM の Cortex-A7 には、 NEON によるベクトル処理がサポートされています。しかし2016/04/04時点でまだopenssl-1.1.0にバグが残っており、正常に Raspi でビルドできませんので、実際にベンチを試される方は注意して下さい。

グラフでは 8Kバイトのスループットを比較してみます。

まずは Intel Haswell上での比較から。

うん、AES-GCMはやっぱり速いです。3.1Gbpsのスループットを叩き出しています。ChaCha20-Poly1305はAES-GCMのおよそ半分 1.6Gbpsのスループットがでます。逆にいうとAES-NIという強力なハード処理の助けがなくてもここまで性能が出せるのは健闘でしょう。

ARM上ではどうなる?

おぉ! 確かに ChaCha20-Poly1305の方がAES-GCMより3倍程度速いです。絶対的なスループット性能は Intel Haswellには全くかないませんが、AES-NIのないARM環境では AES-GCMより ChaCha20-Poly1305 の暗号方式を利用するのが性能的に良いことが明らかです。

6. TLSの運用はどうなる? 現状の問題点とは。

6.1 ブラウザは ChaCha20-Poly1305 をどう使う?

TLSで利用する CipherSuite は、TLSのハンドシェイクで決まります。クライアントがハンドシェイクの最初に送信する ClientHello に CipherSuite リストが含まれ、そのリストからサーバが暗号方式を決定し ServerHello で返します。ClientHelloのCipherSuiteのリストは、クライアントが優先して欲しい順番で記載されています。実は ChaCha20-Poly1305の導入に合わせ、Chromeは動作環境によってサーバに送信するCipherSuiteリストを変えるように機能が追加されています。。

Chrome は、端末がAES-NIとAVXをサポートしている時のみChaCha20-Poly1305よりAES-GCMを優先します。

Issue 91913002: net: boost AES-GCM ciphers if the machine has AES-NI.

つまりdefaultは、ChaCha20-Poly1305が最優先で、AES-GCMの性能が高いと判断できるときのみAES-GCMをCipherSuiteのリストの先頭に持ってきています。

Firefoxは、ARM環境の場合の時のみ AES-GCMより ChaCha20-Poly1305を優先させる予定です。

Bug 1126830 - Prioritize ChaCha20/Poly1305 ciphers over AES-GCM for ARM builds

ただこのパッチ、一度 Land されてましたがリリース直前だったため差し戻しを受け、2016/04/04時点でまだ未適応です。

6.2 サーバ側の暗号選択の難しさ

このようにブラウザ側がクライアントの環境に合わせて ChaCha20-Poly1305と AES-GCM のCipherSuiteリストの優先度を変えてTLSのハンドシェイクを開始してくれます。サーバ側はクライアントの環境を直接わからないのでこれは嬉しいことです。

サーバ側はクライアントから送られてくるCipherSuiteリストの順番を見て、単純に優先しているのを決めれば良いかというとそう単純ではありません。通常サーバは、サーバ側のセキュリティポリシーに従い、優先度付きのCipherSuiteリストを保持しています。これと相性が悪いのです。

先ほど述べた通り、TLSのハンドシェイクではサーバはクライアントから送られたCipherSuiteとリストとサーバ側が決めているリストとを比べ、1つの暗 号方式を選択します。サーバ・クライアントともに独立して優先度付きリストを持っているので、選択する方法はクライアントの優先度に従うか、サーバ の優先度に従うか2通りしかありません。クライアントが常にサーバ側のポリシーにあった正しい優先リストで送られてくるのかわかりません 。

一般的なTLSサーバの推奨設定では、サーバ側でセキュリティポリシーで暗号選択を行う設定(Cipher Server Preference)を入れる場合が多いです。

nginxでは、 ssl_prefer_server_ciphers on 、 apacheでは、 SSLHonorCipherOrder on といった設定に該当します。しかしこの場合、 ChaCha20-Poly1305とAES-GCMの選択に問題が生じます。 サーバ側の優先度だけで判断してしまうので、せっかくブラウザがクライアント側の環境に応じて変えた暗号方式の優先度情報が生かされなくなってしまいます。 サーバが ChaCha20-Poly1305の方を優先する設定にすると、ARMやAES-NIのどちらのクライアントも ChaCha20-Poly1305を選択してしまいます。

6.3 OpenSSL-1.1.0に足りないequal preference cipher groups機能

ではGoogleはどうしているのでしょうか? 実は、ChaCha20-Poly1305を実装する際 BoringSSLには equal preference cipher groups機能を実装していました。

Equal preference cipher groups

これは、[]で複数のCipherSuiteをグループ化し、この中の CipherSuiteはクライアントからの優先順に従うというものです。

Googleのサービス GFE(Google Front End)に対して cipher1:cipher2 の2つのリストでどちらが選択されるのか、試してみました。

結果からGoogleは、

[ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-CHACHA20-POLY1305]:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256

なリストで運用しているのではないかと予想が付きます。

この equal preference cipher groups機能は便利ですし、是非ChaCha20-Poly1305の導入と共に使いたいところです。

実は、OpenSSLでは今年の1月ぐらいに同様のリクエストが issue で登録されていました。

Support bracketed equal-preference groups in SSL_CTX_set_cipher_list

今回もうすぐOpenSSL-1.1.0がリリースされるので、どうなんだろうと要望を書き加えたところ、OpenSSLチームの一人から「私も欲しいけど、もう時間切れ」とのこと。あぁ OpenSSL-1.1.0はもう feature freeze に入っています。時すでに遅し。パッチ出したとしても1.1.1 以降まで待たないといけないでしょう。

結局今のところ OpenSSLで ChaCha20-Poly1305 をAES-NI/ARMのクライアント環境で共に最適に利用するには Cipher Server Preference を利用しないようにするしかないです。この設定が受け入れられないところも多いでしょうね。うぅ、なんともったいない・・・

ということで、今後普及が見込まれるTLSの新しい暗号方式 ChaCha20-Poly1305 について解説しました。まだまだ課題はありますが、次期TLS1.3では AES-GCMとChaCha20-Poly1305 がMTI(Must To Implement)として規定されています。この2つのデファクトはこれからしばらく続く可能性が高いので、きちんとした理解を持ってより安全なTLSの運用を目指しましょう。