してみるテストロゴ
Apache 2.4系でHTTP/2サーバを構築してみるテスト。

暗号スイートの暗号強度と、公開鍵のビット数の設定

見ず知らずの他人同士が、リーズナブルな計算量で、秘密の通信を行うためには、公開鍵暗号と秘密鍵暗号を組み合わせる必要があります。

この暗号の組み合わせのことを「暗号スイート」と呼びます。

OpenSSLには、多くの暗号スイートが用意されています。どの暗号スイートを選べばいいのか、迷ってしまうと思います。

そして、暗号スイート全体としての暗号強度は、公開鍵の強度も関係してきます。

ここでは、総当たり攻撃の耐性を基準に、暗号スイートと公開鍵の決め方を説明していきます。

 

以下、私の独断と偏見ですが、なぜGoogleやFacebookが、ECDHE(256bit)-ECDSA(256bit)-AES(128bit)の暗号スイートを使用するのか、ご理解いただけると思います。

併せて、Apache Webサーバ(httpd)のECDHEのビット数の変更方法(P-256, P-386)も、説明しています。

 

OpenSSLの「暗号スイート」の一覧は、、

# openssl ciphers -v
ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AESGCM(256) Mac=AEAD
ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AESGCM(256) Mac=AEAD
ECDHE-RSA-AES256-SHA384 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AES(256)  Mac=SHA384
ECDHE-ECDSA-AES256-SHA384 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AES(256)  Mac=SHA384
ECDHE-RSA-AES256-SHA    SSLv3 Kx=ECDH     Au=RSA  Enc=AES(256)  Mac=SHA1
ECDHE-ECDSA-AES256-SHA  SSLv3 Kx=ECDH     Au=ECDSA Enc=AES(256)  Mac=SHA1
(…省略…)
AES128-GCM-SHA256       TLSv1.2 Kx=RSA      Au=RSA  Enc=AESGCM(128) Mac=AEAD
AES128-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AES(128) Mac=SHA256
AES128-SHA SSLv3 Kx=RSA Au=RSA Enc=AES(128) Mac=SHA1 (…省略…)

から確認できます。

 

ここで、左はじに、ハイフン区切りを含む文字がありますが、これが「暗号スイート」です。

つまり、ハイフンで区切られて、それぞれの暗号スイートで利用するアルゴリズムが記載されています。

 

たとえば、ECDHE-RSA-AES256-GCM-SHA384は、[鍵交換方式(Kx)]はECDHE、[鍵認証方式(Au)]はRSA、[メッセージ暗号方式(Enc)]はAES256、[ブロック処理]はGCM、[メッセージ署名方式(Mac)]はSHA384、となります。

暗号スイートのアルゴリズム名の省略

このうち、[鍵交換方式(Kx)]と[鍵認証方式(Au)]がともにRSAの場合は、これを単に「RSA]と表記したり、2つとも省略したりします。

たとえば、AES128-GCM-SHA256とあれば、[鍵交換方式(Kx)]はRSA、[鍵認証方式(Au)]はRSA、が省略されています。

同様に、[ブロック処理]がCBC方式の場合、これを省略することがあります。

 

暗号スイートには、大きく分けて、2つの機能があります。

「傍受によって、中身を読まれないようにするための機能」([鍵交換方式(Kx)]、[メッセージ暗号方式(Enc)]、[ブロック処理])と

「通信の乗っ取りを防ぐための機能」([鍵認証方式(Au)]、[メッセージ署名方式(Mac)])の二つです。

 

つまり、SSLとは、鍵交換(Kx)と鍵認証(Au)によって、信頼できる共通鍵を得て、これを、メッセージ暗号方式(Enc)において利用する機能になります。

 

このうち、今回は、「傍受によって、中身を読まれないようにするための機能」、すなわち「傍受に対する暗号強度」に着目して、鍵交換に利用する公開鍵のビット数を検討したいと思います。

共通鍵暗号と公開鍵暗号の暗号強度

公開鍵のビット数を検討する前に、鍵交換や、メッセージ暗号に利用する暗号の特徴について、理解します。

 

まず共通鍵暗号ですが、これは身近なところでは、パスワード(秘密鍵)で、ZIPファイルを暗号化するときに使う暗号です。

コンピュータの得意な処理を利用するため、処理の効率が高いのが特徴になります。

あらかじめ、他人に知られることなく、お互いに暗号を解読するための秘密鍵の交換が済んでいれば、共通鍵暗号と呼ばれる暗号を使うのが、処理の効率が高まります。

 

ただし、自分でZIPファイルを暗号化するのとは違って、通信相手がいる場合は、そのような状況はなかなか作れません。

たとえば、初めて訪れた、Webのショッピングサイトで、共通鍵暗号を利用しようと思ったら、秘密鍵を交換するところから、取引が始まります。

この処理は、鍵交換や鍵認証と呼ばれますが、一般に公開鍵暗号方式に分類される暗号が利用されます。

 

公開鍵暗号は、公開鍵と秘密鍵の2つを使います。実は、公開鍵から、秘密鍵を求めることができます。

ただし、その計算内容が、コンピュータが苦手で、さらに人間が計算するには膨大な桁数のため、現実的に秘密鍵を求めることができないことから、暗号として成立する方式です。

これを使って、「公開鍵で暗号化して、秘密鍵で復号化する」といった暗号に利用できます。これで、さきほのどの共通鍵暗号の秘密鍵の暗号化(鍵交換)に利用できます。

その逆に、「秘密鍵で暗号化(署名)して、公開鍵で復号化(検証)する」といった、鍵認証にも利用できます。

セキュリティービット数

当然ですが、これらの暗号には解読の難しさ、易しさがあります。

これを暗号強度と呼びます。暗号強度の一つの尺度として、セキュリティービット数が用いられます。

脆弱性の知られていない、共通鍵暗号は、攻撃者は全ての鍵を試行する、総当たり攻撃が必要です。

この、試行回数を基準として、2のべき乗として、尺度にしたものが、セキュリティービット数となります。

 

脆弱性が知られていない場合、共通鍵(秘密鍵)のビット数がそのままセキュリティービット数になります。

さきほどのOpenSSLの「暗号スイート」にも、256や384といった数値がありましたが、これが共通鍵暗号方式のビット数です。

 

一方、公開鍵暗号は、その性質から、秘密鍵のビット数で表現できる数値のすべてが、鍵になるわけではありません。

つまり、公開鍵暗号の場合、秘密鍵に一定の条件が付くため、その条件を満たさない鍵は、攻撃者の試行の対象にならないため、その分簡単になります。

そのため、公開鍵暗号では、解読のしにくさを確保するためには、共通鍵暗号以上のビット数の秘密鍵が必要になります。

 

先ほどのOpenSSLの「暗号スイート」には、メッセージ暗号(Enc)に使う共有鍵暗号のビット長(強度)が入っていますが、公開鍵暗号方式の「RSA」や「ECDSA」、「ECDHE」にはビット数の記載がありません。

つまり、「暗号スイート」とは、別のところで、公開鍵暗号のビット数を決めることになります。(Apache Webサーバにおける設定方法は後述します。)

一般にAES、DHE、RSA、ECDSA、ECDHEのセキュリティービットは、以下の表であると言われています。

セキュリティービット数 対称鍵暗号
(共通鍵暗号)
Finite Field Cryptography
(FFC:有限体暗号)
例:DSA/DH/DHE
Integer Factorization Cryptography
(IFC:整数因数分解暗号)
例:RSA
Elliptic Curve Cryptography
(ECC:楕円曲線暗号)
例:ECDSA/ECDH/ECDHE
80 2TDEA
(3DES Keying option 2)
L=1024
N=160
k=1024 f=160~223
112 3TDEA
(3DES Keying option 1)
L=2048
N=224
k=2048 f=224~255
128 AES-128 L=3072
N=256
k=3072 f=256~383
192 AES-192 L=7680
N=384
k=7680 f=384~511
256 AES-256 L=15360
N=512
k=15360 f=512以上

引用元:http://csrc.nist.gov/publications/nistpubs/800-57/sp800-57-Part1-revised2_Mar08-2007.pdfのp.63 Table 2

 

たとえば、2048ビットのRSA暗号は、112セキュリティービットです。

これは、2112回の試行を行うと、解読できることになります。同じ試行回数のECC(楕円曲線暗号)は、224ビットに相当するといった感じです。

ちなみに、3TDEAは、一般に、3DESと知られている暗号です。これは168ビットの共通鍵を利用しますが、試行回数を減らす攻撃方法が知られているため、実際の暗号強度は112セキュリティービットとなっています。

一方、AESはまだ攻撃方法が知られていないため、共通鍵のビット数がそのまま、セキュリティービット数となっています。

試行1回あたりの計算時間

セキュリティービット数は、試行回数の指標なので、実際には、1回の試行にかかる計算時間は無視されています。

基準となるサーバで、復号にかかる計算時間を、1回の試行にかかる時間を、基準の計算時間として、それぞれの暗号の総当たり攻撃の計算時間を求めてみます。

FPGAを使ったり、専用ハードウエアがからむと、違った傾向になるかもしれませんが、誰もが利用できる環境における、コスト当たりの、計算時間で比較しようという試みです。

 

これと、セキュリティービットを組み合わせて、計算時間にかかわる暗号強度を計算してみます。

私の手元にある、2コア4スレッド、2.4GHzのXEONプロセッサを基準となるサーバとして、見てみましょう

まずは、AESの試行時間を計算してみます。

# /usr/local/ssl/bin/openssl speed aes-128-cbc aes-256-cbc
Doing aes-128 cbc for 3s on 16 size blocks: 13855565 aes-128 cbc's in 3.00s
Doing aes-128 cbc for 3s on 64 size blocks: 3935575 aes-128 cbc's in 3.00s
Doing aes-128 cbc for 3s on 256 size blocks: 1013853 aes-128 cbc's in 3.00s
Doing aes-128 cbc for 3s on 1024 size blocks: 256378 aes-128 cbc's in 3.00s
Doing aes-128 cbc for 3s on 8192 size blocks: 32143 aes-128 cbc's in 3.00s
Doing aes-256 cbc for 3s on 16 size blocks: 10459304 aes-256 cbc's in 3.00s
Doing aes-256 cbc for 3s on 64 size blocks: 2780975 aes-256 cbc's in 3.00s
Doing aes-256 cbc for 3s on 256 size blocks: 725050 aes-256 cbc's in 3.00s
Doing aes-256 cbc for 3s on 1024 size blocks: 182705 aes-256 cbc's in 3.00s
Doing aes-256 cbc for 3s on 8192 size blocks: 22876 aes-256 cbc's in 3.00s

The 'numbers' are in 1000s of bytes per second processed.
type             16 bytes     64 bytes    256 bytes   1024 bytes   8192 bytes
aes-128 cbc      73896.35k    83958.93k    86515.46k    87510.36k    87771.82k
aes-256 cbc      55782.95k    59327.47k    61870.93k    62363.31k    62466.73k

64バイトのブロック処理をみると、AES128は1秒当たり、83958.93Kバイト処理しているとでました。

ということは、1ブロック16バイトなので、1秒当たり、5485738.667ブロック分の試行 が行えます。1ブロック当たり19nsです。

同様に計算すると、AES256は1ブロック(32バイト)あたり、54nsです。

 

公開鍵系の暗号もベンチマークをとります。

# /usr/local/ssl/bin/openssl speed ecdhp256  ecdhp384  ecdhp521 rsa1024  rsa2048  rsa4096
Doing 1024 bit private rsa's for 10s: 9586 1024 bit private RSA's in 10.00s
Doing 1024 bit public rsa's for 10s: 186431 1024 bit public RSA's in 10.00s
Doing 2048 bit private rsa's for 10s: 1502 2048 bit private RSA's in 9.99s
Doing 2048 bit public rsa's for 10s: 49241 2048 bit public RSA's in 10.00s
Doing 4096 bit private rsa's for 10s: 191 4096 bit private RSA's in 10.02s
Doing 4096 bit public rsa's for 10s: 13072 4096 bit public RSA's in 10.00s
Doing 256 bit  ecdh's for 10s: 8539 256-bit ECDH ops in 10.00s
Doing 384 bit  ecdh's for 10s: 3684 384-bit ECDH ops in 10.00s
Doing 521 bit  ecdh's for 10s: 1693 521-bit ECDH ops in 10.00s

                  sign    verify    sign/s verify/s
rsa 1024 bits 0.001043s 0.000054s    958.6  18643.1
rsa 2048 bits 0.006651s 0.000203s    150.4   4924.1
rsa 4096 bits 0.052461s 0.000765s     19.1   1307.2
                              op      op/s
 256 bit ecdh (nistp256)   0.0012s    853.9
 384 bit ecdh (nistp384)   0.0027s    368.4
 521 bit ecdh (nistp521)   0.0059s    169.3

RSA暗号のベンチマークは、1024ビットと2048ビットと4096ビットしか計算できないので、3072ビットと7680ビットと15360ビットは、1024ビットを基準とした、近似式から求めました。公開鍵のビット数がn倍となると、

計算時間=n3×0.7971×[1024ビットの処理時間]

としました。(0.7971は1024ビットと2048ビットの計算時間の関係から算出)

暗号 セキュリティービット 1試行あたりの計算時間 AES128を基準とした総当たり攻撃の計算時間
ビット数 試行回数 計算時間[秒] AES128を基準 2のべき乗 セキュリティービットとの積 指数部
AES128 128 2128 0.000000019 1 20 2128×20=2128 128
AES256 256 2256 0.000000054 2.83 21.501 2256×21.5=2271.5 271.5
RSA1024 80 280 0.001043 54730.73 215.74 280×215.74=295.74 95.74
RSA2048 112 2112 0.006651 349006.78 218.41 2112×218.41=2130.41 130.41
RSA3076 128 2128 0.022447125 1177897.87 220.17 2128×220.17=2148.17 148.17
RSA7680 192 2192 0.350736328 18404654.26 224.13 2192×224.13=2216.13 216.13
RSA15360 256 2256 2.805890625 147237234.11 227.13 2256×227.13=2283.13 283.13
ECDH256 128 2128 0.0012 62969.20 215.94 2128×215.94=2143.94 143.94
ECDH384 192 2192 0.0027 141680.69 217.11 2192×217.11=2209.11 209.11
ECDH521 256 2256 0.0059 309598.55 218.24 2256×218.24=2274.24 274.24

まあ、セキュリティービット数が支配的ですね。

なんだか、ここまで計算してから言うのも何ですが、セキュリティービットだけで考えて、いい気がします。

せっかく計算したので、以下、赤字の計算時間の指数部で比較します。

なお、RSA1024(295.7)はそろそろ実用的な攻撃が可能になりつつあると言われていますが、その

 

2128÷295.74=232.26(約43億)倍の試行時間を必要とするAES128や、

2130.41÷295.74=234.67(約273億)倍の試行時間を必要とするRSA2048ビット

 

への総当たり攻撃は、現時点では事実上不可能と考えられます。

以下の選択は、必要以上に無駄な計算をさせないための試算といった感じでしょうか。

RSA暗号の公開鍵長の選択

さて、RSA暗号で鍵交換を行う、暗号スイートについて、見てみましょう。

TLSv1.2で追加された、鍵交換にRSAを使う暗号スイートは4種類あります。(OpenSSLでは、鍵認証・鍵交換ともにRSAを使用する場合、暗号スイート名から省略されています。)

この暗号スイートにおけるRSA暗号の目的は、鍵交換(共通鍵の保護)と鍵認証の2役です。そのため、共通鍵の強度を超える公開鍵長が望ましいと言えます。

つまり、証明書のRSA公開鍵を使って、鍵交換を行いますので、ここで鍵交換の強度も調整します。

AES128-GCM-SHA256とAES128-SHA256 は、共通鍵暗号方式がAESで、共通鍵のサイズが128ビットです。

前述の表から、総当たり攻撃の計算時間の指数部は128です。

これを超える計算時間の指数部を持つRSA暗号は、計算時間の指数部が、130.41の、RSA2048になります。これは、現実的かつ理想的なサイズですね。

 

AES256-GCM-SHA384と AES256-SHA256は、総当たり攻撃の計算時間の指数部は271.5です。

これを超える計算時間の指数部を持つRSA暗号は15360ビットとなります。こちらは、重そうです。

 

ならば、AES256の共通鍵を、RSA2048で暗号化したら、どうでしょう。

RSA2048のほうが、総当たり攻撃の計算が早く終わるので、暗号スイートへの総当たり攻撃の計算時間は、RSA2048の暗号強度に支配されてしまいます。

(とはいえ、RSA2048を総当たり攻撃する計算時間はいまのところ非現実的です。量子コンピュータが実用化されるまでは。)

つまり暗号スイートの暗号強度とは、鍵交換か、共通鍵のいずれか、弱い方になってしまいます。

 

以下の表は、鍵交換のRSAと、共通鍵のAESの弱い方が赤字になっています。

暗号スイート RSA AES
公開鍵長 総当たり攻撃の計算時間 セキュリティービット 総当たり攻撃の計算時間
AES128-SHA256 2048 130.41 128 128
AES256-SHA256 2048 130.41 256 257.1
3072 148.17 256 257.1
7680 216.13 256 257.1
15360 283.13 256 257.1

この表からも、RSA2048の暗号強度は、AES128と大差ないので、このくらい差だったら、AES256ではなく、AES128の暗号スイートがちょうどいいです。

(共通鍵暗号の処理は、AES256より、AES128の方が、40%程度早く処理が終わります。)

Forward Secrecy(前方秘匿性)が無い意外は、特に問題のない構成です。特に、クライアントの処理が軽いのが特徴になります。

 

逆に、AES128の暗号強度では物足りないという場合は、AES256とRSA暗号を組み合わせた暗号スイートを選択することになります。

この場合、RSA暗号の公開鍵を3072ビット以上にしましょう。AES256の暗号強度には及びませんが、暗号スイート全体の強度を稼げます。

Let's Encryptも4096ビットのRSA暗号の証明書に署名してくれます。ただ、AES256に対して、十分な暗号強度かというと、ちょっと自信がありません。

AES256の暗号強度をフルに期待している方は、15360ビットの公開鍵を用意しましょう。(これは、さすがにLet's Encryptでも試したことありません…)

また、鍵交換が証明書の公開鍵に頼っているため、Forward Secrecy(前方秘匿性)がありません。

後述しますが、4096bitのRSA署名の生成に50ms程度かかります。これは、1サーバあたりどんなに頑張っても、毎秒20クライアントの新規接続程度しか性能が出ません。

以上の理由から、RSA-AES256-*の組み合わせは、あまりお勧めはできません。

ECDHEの楕円曲線の選択

ECDHEは鍵交換のみのアルゴリズムですので、鍵認証のアルゴリズムとは独立しています。

そのため、鍵認証は、ECDSAでもRSAでもかまいません。RSAの公開鍵を鍵交換に使うわけではないので、鍵認証に引きずられることもありません。

また、ECDSAを選んだ場合、ECHDEと異なるビット数の楕円曲線を使うことも可能です。

「通信の乗っ取りを防ぐための機能」([鍵認証方式(Au)]のECDSA署名やRSA署名のサーバ証明書の暗号強度について

鍵交換を行うECDHEは、一つの公開鍵だけで成立しますが、鍵認証を行う、ECDSAやRSAは複数の証明書の公開鍵を利用します。

たとえば、Let's Encryptは2つの証明書、つまり中間証明書と、ルート証明書の、2つの公開鍵を使います。

Let's Encryptの中間証明書、ルート証明書ともに、RSA暗号の2048ビットの公開鍵です。

末端のサーバ証明書から、ルート証明書に至る、証明書のチェーンは、いずれかの証明書が破られた時点で、信頼性を失います。

以上の理由から、サーバ証明書としては中間証明書やルート証明書を大幅に超える暗号強度は必要ありません。

Let's Encryptの中間証明書やルート証明書は、いずれも2048ビットのRSA暗号ですので、サーバ証明書の発行を依頼する場合、同等のものであれば、良いことになります。

つまり、ECDSAのCSRは、2048ビットのRSA暗号よりもセキュリティービット数が多い、P-256(prime256v1)で十分です。P-384はオーバースペックです。

ただでさえ、Let's Encryptのサーバ証明書は有効期間が90日と短いので、なおさら、P-256で十分です。

ちなみに、私の知る限り、暗号強度が最も強いルート証明書は、ECDSA(P-384)を使った旧ベリサイン(現シマンテック社)のVeriSign Class 3 Public Primary Certification Authority - G4です。

鍵交換自体は、ECDHEで行いますので、ECDHEで使用する公開鍵長から、暗号スイートに対して、必要となる総当たり攻撃時間が求まります。

以下の表では、暗号スイートの中で、攻撃時間が短い方を、赤字で表示しています。また、ECDHE公開鍵の方が、暗号強度が強い場合、青背景に白抜き文字にしています。

暗号スイート ECDHE AES
公開鍵長 総当たり攻撃の計算時間 セキュリティービット 総当たり攻撃の計算時間
ECDHE-RSA-AES128-SHA256 256 143.94 128 128
ECDHE-ECDSA-AES128-SHA256 256 143.94 128 128
ECDHE-RSA-AES256-SHA384 256 143.94 256 257.1
384 209.11 256 257.1
ECDHE-ECDSA-AES256-SHA384 256 143.94 256 257.1
384 209.11 256 257.1

AES128を含む暗号スイートでは、256ビットの楕円曲線を使えば、AESの共通鍵を十分保護できそうです。

256ビットのAESを含む暗号スイートでは、384ビットの楕円曲線を使うのがよさそうです。

 

521ビットの楕円曲線があれば、AES256の暗号強度をフルに保護できそうですが、いまのところ廃止されているので、選択肢は、384ビットのみです。

まあ、384ビットの楕円曲線で、セキュリティービットが、200ビットに近いので、十分なのでしょう。

となると、AES192を使った暗号スイートが最も効率が良さそうな気もしますが、いまのところ出ていないようです。

(192ビットというブロック単位が処理しにくいのか、それともバイト単位の処理効率がAES256と、さほど変わらないといった理由なのでしょうか?)

 

さきほど、RSA1024はそろそろ実用的な攻撃が可能になりつつあると言われているといいましたが、AES128 は、RSA1024(295.7)の約43億倍の試行時間を必要とすることはご説明したとおりです。

つまり、現時点では、AES128で十分ということでしょう。AES128なら、鍵交換に使うECDHEのビット数は256で十分です。

これは、実行速度と、暗号強度のバランスの取れた暗号スイートと言えます。AESの共通鍵のブロック処理は、できればCBCではなく、GCMを優先しましょう。

 

もし暗号強度に重きを置いて、AES256 を使う場合は、ECDHEは、384ビットにしましょう。

この場合でも、RSA暗号を鍵交換に使用するわけでは無いので、ルート証明書や中間証明書が、RSAの2048ビットの公開鍵なら、鍵認証がECDSAなら、P-256(prime256v1)で十分です。

同じく、鍵認証にRSAを使うなら、2048ビットがいいでしょう。AESのブロック処理にGCMが望ましいのは、一緒です。

 

実際の設定はどうなるのでしょうか。

これまで、紹介してきた、以下の設定は、どの証明書を使っても、「サーバからの提示が、暗号強度の強い順」となる設定です。

/usr/local/apache2/conf/extra/httpd-ssl.confの一部
…(省略)…
SSLProtocol -All +TLSv1 +TLSv1.1 +TLSv1.2
SSLHonorCipherOrder on
SSLCipherSuite ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:DHE-DSS-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-SHA256:DHE-RSA-AES128-SHA256:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK
…(省略)…
[2017年2月24日追記]

SHA-1に署名衝突攻撃の方法が見つかったため、SHA-1を含む暗号スイートの使用を停止することを推奨します。

ただし、Android4.3以前、Safari6以前を搭載した端末のうち、アクセスできなくなる可能性があります。

それでは、サーバ負荷を考えて共通鍵としてAES128を使う場合と、暗号強度を優先してAES256を使う設定について、RSAとECDSAを利用する場合を、それぞれ見てみましょう。

(検索してきたみなさんは、以下の設定が知りたいだけだともうのですが、長い前フリにお付き合いいただきありがとうございます。)

AES128にECDHE-RSAを組み合わせる場合

暗号強度はそこそこで、RSA証明書を利用する場合、以下の設定になります。

鍵認証にしか使わないので、RSA証明書の公開鍵の長さは、2048ビットで十分です。

/usr/local/apache2/conf/extra/httpd-ssl.confの一部
…(省略)…
SSLProtocol -All +TLSv1 +TLSv1.1 +TLSv1.2
SSLHonorCipherOrder on
SSLCipherSuite ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK
…(省略)…

 

ところで、ApacheでECDHEのビット数はどうやって変更するのでしょうか?

Apache 2.4.8以降と、OpenSSL1.0.2以降が、必要(まだの方はこちらを参考にインストール)ですが、以下の方法で、ECDHEで使用する楕円曲線を変更することができます。

/usr/local/apache2/conf/extra/httpd-ssl.confの一部
…(省略)…
#SSLOpenSSLConfCmd ECDHParameters Automatic
SSLOpenSSLConfCmd ECDHParameters prime256v1
SSLOpenSSLConfCmd Curves secp384r1:prime256v1
…(省略)…

ちなみに、何も設定していなければ、256ビットの楕円曲線が使われるようです。

これまで、紹介してきた「サーバからの提示が、暗号強度の強い順となる設定」や、ネットでよく見かける設定では、AES128でもAES256でも、256ビットの楕円曲線で鍵交換していたということですね。

とすると、AES256 を使用する場合に、少し心もとない楕円曲線で鍵交換していたことになります。

つまり、256ビットの楕円曲線の鍵交換の暗号強度を考えれば、AES128が適正であり、AES128を選択して、処理時間を短縮していた方が、処理速度的にも電力的にもよかったということです。

AES256 より、AES128のほうが、40%ほど早いわけですから、もったいないといえます。

 

なお上記設定にコメントアウトされているとおり、ECDHParametersには、Automaticといった設定ができます。

これは、Curvesに記載の中から、ビット数の大きいものを使うようです。

 

この設定では、サーバ負荷は標準的ですが、クライアントの負荷を抑えることができます。

AES128にECDHE-ECDSAを組み合わせる場合

暗号強度はそこそこで、サーバ負荷を抑えるためには、ECDHE-ECDSAに、AES128ビットがいいでしょう。

この場合、以下の感じです。

/usr/local/apache2/conf/extra/httpd-ssl.confの一部
…(省略)…
SSLProtocol -All +TLSv1 +TLSv1.1 +TLSv1.2
SSLHonorCipherOrder on
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK
…(省略)…

続いて、鍵交換に使うECDHEのビット数は256ビットのものを設定します。

/usr/local/apache2/conf/extra/httpd-ssl.confの一部
…(省略)…
#SSLOpenSSLConfCmd ECDHParameters Automatic
SSLOpenSSLConfCmd ECDHParameters prime256v1
SSLOpenSSLConfCmd Curves secp384r1:prime256v1
…(省略)…

サーバ負荷は軽めで、クライアントの負荷は若干増えます

鍵認証に使うECDSAの公開鍵のビット数ですが、これも256ビットのもので十分です。

証明書チェーンを構成するルート証明書や中間証明書が、2048ビットのRSA暗号ならば、これ以上であれば、これを大きく超える強度の暗号である必要はありません。

ルート証明書が、ECDSA 384ビットの公開鍵の場合

ルート証明書が、シマンテック社のVeriSign Class 3 Public Primary Certification Authority - G4の方は、ルート証明書の公開鍵が P-384です。

この場合、サーバ証明書の公開鍵にも、384ビットの楕円曲線を使うことも考えられます。

これでも、ECDSAのサーバ側の処理時間はちょっと増えるだけです。

クライアント側の証明書チェーンの妥当性の検証は、数[ms]の世界ですが、RSAよりは時間がかかります。

AES256にECDHE-RSAを組み合わせる場合

ECDHEと組み合わせて、RSA暗号のサーバ証明書と、AES256を使う場合は、以下の設定となります。

このときでも、鍵認証に使うRSA暗号の公開鍵の長さは2048ビットで十分です。

/usr/local/apache2/conf/extra/httpd-ssl.confの一部
…(省略)…
SSLProtocol -All +TLSv1 +TLSv1.1 +TLSv1.2
SSLHonorCipherOrder on
SSLCipherSuite ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK
…(省略)…

AESが256ビットなので、鍵交換に使うECDHEの楕円曲線として、P-384(secp384r1)を使います。

AES256を生かすも、殺すも、この設定次第といえます。

/usr/local/apache2/conf/extra/httpd-ssl.confの一部
…(省略)…
#SSLOpenSSLConfCmd ECDHParameters Automatic
SSLOpenSSLConfCmd ECDHParameters secp384r1
SSLOpenSSLConfCmd Curves secp384r1:prime256v1
…(省略)…

Curvesにprime256v1を含んでいるのは、ECDSA用の楕円曲線として、利用される可能性があるためです。

RSAの署名処理が重いところに、ECDHEのビット数が増えた分だけ、負荷が増えます。

また,共通鍵暗号のAESが256ビットになったため、128ビットのAES比べて、メッセージ暗号のパフォーマンスが低下します。

今回比較した中で、サーバ負荷は最も大きいです。

AES256にECDHE-ECDSAを組み合わせる場合

ECDHEと組み合わせて、ECDSAのサーバ証明書と、AES256を使う場合は、以下の設定になります。

鍵認証のECDSAは、ルート証明書や中間証明書が、2048ビットのRSA暗号であれば、256ビットのprime256v1で良いでしょう。

/usr/local/apache2/conf/extra/httpd-ssl.confの一部
…(省略)…
SSLProtocol -All +TLSv1 +TLSv1.1 +TLSv1.2
SSLHonorCipherOrder on
SSLCipherSuite ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK
…(省略)…

AESが256ビットなので、鍵交換に使うECDHEの楕円曲線として、P-384(secp384r1)を使います。

/usr/local/apache2/conf/extra/httpd-ssl.confの一部
…(省略)…
#SSLOpenSSLConfCmd ECDHParameters Automatic
SSLOpenSSLConfCmd ECDHParameters secp384r1
SSLOpenSSLConfCmd Curves secp384r1:prime256v1
…(省略)…

RSA暗号の証明書を使わない分、サーバ負荷は軽めですが、クライアントの負荷は最も大きくなります。

先ほどと同様、共通鍵暗号のAESが256ビットになったため、128ビットのAES比べて、メッセージ暗号のパフォーマンスが低下します。

ECDHEにX25519を使う場合

OpenSSL 1.1.1から、ECDHEにX25519を使えるようになります。

いまのところ、Apache Webサーバから、X25519を利用するためには、ECDHParametersにAutomaticを設定するしかないようです。

設定としては、以下のような感じでしょうか。

この場合、ECDHEの楕円曲線を選べませんが、X25519対応ブラウザからのアクセスは、prime256v1よりもサーバ負荷が低いため、ECDHEの負荷を下げられます。

vi /usr/local/apache2/conf/extra/httpd-ssl.conf
SSLOpenSSLConfCmd ECDHParameters Automatic
SSLOpenSSLConfCmd Curves X25519:secp384r1:prime256v1

サーバ負荷の比較

ということで、ここまで紹介した暗号強度的に、意味のある設定について、暗号処理の時間をまとめてみました。

クライアントも、サーバ側と同じCPUとして比較していますので、スマホ相手の場合は、もう少しかかると思います。

そもそも、SSLセッションキャッシュを使うことが多いでしょうから、キャッシュ保持時間にもよりますが、以下のような、鍵交換を含むネゴシエーションの回数は、減ってきているはずです。

今後は、共通鍵暗号のパフォーマンスのウェイトが増えていくのではないでしょうか。

例によって、これまでベンチマークをとってきた、2コア4スレッド、2.4GHzのXEONプロセッサのケースを見てみましょう

(あくまで、処理の断片を切り取った参考値としてご覧ください。実際は、雑多な処理が加わるので、もう少しかかります。)

下の表は、スループットの処理時間の比較です。

暗号スイート 暗号強度
Forward
Security
(前方秘匿性)
サーバ クライアント 処理時間合計 共通鍵暗号の
パフォーマンス
傍受に対する
セキュリティービット
署名に対する
セキュリティービット
鍵認証署名 鍵交換 合計 証明書検証

鍵認証検証

鍵交換 合計
中間(2048bit) サーバ(2048bit)
RSA - AES128 -*
(2048bit)
112bit
RSA 2048bit
× 6.6[ms] 6.6[ms] 0.2[ms] 0.2[ms] 0.2[ms] 0.6[ms] 7.2[ms] 87,510.36 KB/s
RSA - AES256 -*
(4096bit)
144bit
RSA 4096bit
× 52[ms] 52[ms] 0.2[ms] 0.2[ms] 0.7[ms] 1.1[ms] 53.1[ms] 62,363.31KB/s
ECDHE-RSA-AES128-*
(256bit)(2048bit)
128bit
EC 256bit
112bit
RSA 2048bit
6.6[ms] 1.2[ms] 7.8[ms] 0.2[ms] 0.2[ms] 0.2[ms] 1.2[ms] 1.8[ms] 9.6[ms] 87,510.36 KB/s
ECDHE - ECDSA - AES128 -*
(256bit) (256bit)
128bit
EC 256bit
128bit
EC 256bit
0.4[ms] 1.2[ms] 1.6[ms] 0.2[ms] 0.2[ms] 1.4[ms] 1.2[ms] 3.0[ms] 4.6[ms] 87,510.36 KB/s
ECDHE - RSA - AES256 -*
(384bit) (2048bit)
192bit
EC 384bit
112bit
RSA 2048bit
6.6[ms] 2.7[ms] 9.3[ms] 0.2[ms] 0.2[ms] 0.2[ms] 2.7[ms] 3.3[ms] 12.6[ms] 62,363.31KB/s
ECDHE - ECDSA - AES256 -*
(384bit) (256bit)
192bit
EC 384bit
128bit
EC 256bit
0.4[ms] 2.7[ms] 3.1[ms] 0.2[ms] 0.2[ms] 1.4[ms] 2.7[ms] 4.5[ms] 7.6[ms] 62,363.31KB/s

というこで、AES128を使用する場合、ECDHE(256bit)-ECDSA(256bit)-AES128-*のパフォーマンスが、抜き出ています。

サーバ側処理が1.6[ms]で終わり、共通鍵のパフォーマンスは、87,510.36 KB/sです。

そりゃ、超巨大なサイトでは、ECDHE(256bit)-ECDSA(256bit)-AES128-GCM-SHA256あたりが、利用される訳です。

 

AES256を使用する場合、ECDHE(384bit)-ECDSA(256bit)-AES256-*が良いです。

サーバ側処理が3.1[ms]で終わり、共通鍵のパフォーマンスは、62,363.31 KB/sです。

これでも、サーバ側処理は、ECDHE(256bit)-RSA(2048bit)よりも軽いので、暗号強度を高めるなら、こちらが現実的です。

 

OpenSSL 1.1.0系では楕円曲線暗号の処理が改善 しています。
OpenSSL 1.1.0系では楕円曲線暗号、特にprime256v1と呼ばれる公開鍵長が256ビットの処理が改善 しています。どの程度、改善しているかは、以下のページでご確認ください。

 

さて、いかがでしたでしょうか?

みなさんも、適切な暗号強度の、暗号スイートを選択してみてください。

NEXT >> ECDSA対応のCSRを生成して、Let's Encryptをつかう場合

©Copyrights 2015-2018, non-standard programmer

このサイトは、あくまでも私の個人的体験を、綴ったものです。 軽く参考程度にご利用ください。