AES-NIという加速装置のお話

今回は、暗号の話をしましょう。といっても、難しい数学の話をするわけではありませんよ。ただ、数個のコマンドをたたくだけです。

インターネットという開かれた空間の中であんまり収集されると困る情報をやりとりするのに暗号は重要です。弊社では広告配信のステータスをユーザのブラウザを介して送受信するので、そこで最も暗号化処理が活躍します。

私の勝手なイメージですが、ブロック暗号の中ではBlowfishが処理速度が速いと思っていました。他にも3DESやAESといったよく使われる暗号方式はありますが、それらはBlowfishと比べて暗号強度は強いが処理は遅いものだと思っていました。しかし、世の中にはAES-NIという加速装置があるではありませんか! この加速装置がどのくらいの性能であるのかみてみましょう。

AES-NIは、AES (Advanced Encryption Standard)専用のCPU命令群です。AESのために専用の回路がCPUの中にあるわけです。CPUに足し算やかけ算をさせるのと同じように、AES(の処理の1ステップ)をやれ、と命令できるわけです。さすが暗号標準と言われるだけありますね。すさまじい優遇措置です。

速度比較

opensslコマンドを使ってベンチマークをします。コマンドは次の通り。

openssl speed blowfish camellia-256-cbc des-ede3 aes-256-cbc

これで、Blowfish, Camellia, 3DES, AESのベンチマークができます。使用マシンのCPUは、AMD Opteron(R) 6276 2.3GHz。opensslのバージョンなどは結果を参照ください。

結果は次のようになりました。

OpenSSL 1.0.1i 6 Aug 2014
built on: Mon Aug 11 21:45:22 CEST 2014
options:bn(64,64) rc4(8x,int) des(idx,cisc,16,int) aes(partial) blowfish(idx) 
compiler: gcc -fPIC -DOPENSSL_PIC -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -m64 -DL_ENDIAN -DTERMIO -g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security -D_FORTIFY_SOURCE=2 -Wl,-z,relro -Wa,--noexecstack -Wall -DMD32_REG_T=int -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DMD5_ASM -DAES_ASM -DVPAES_ASM -DBSAES_ASM -DWHIRLPOOL_ASM -DGHASH_ASM
The 'numbers' are in 1000s of bytes per second processed.
type             16 bytes     64 bytes    256 bytes   1024 bytes   8192 bytes
des ede3         20369.30k    20810.84k    20913.41k    20885.16k    20995.08k
blowfish cbc     74977.91k    81826.65k    85267.20k    86458.48k    86436.52k
aes-256 cbc      55840.73k    58654.36k    59740.07k   141040.98k   142798.34k
camellia-256 cbc    82854.92k   104024.62k   111749.97k   114186.92k   114657.96k

3DESはやっぱり遅いですね。Blowfishの1∕4程度の速度しか出ていません。

そして、AESもBlowfishに比べれば遅……くもないですね。1KBを超えてから突如として性能が良くなっています。実は加速装置はまだ使っていないはずなんですが。AESのブロックサイズは16 Bytesですし、256 Bytesと1KBに隔たりがある理由はなんでしょう? 今後の考察対象になりますね。メモリの速度とかまで関係してくると最早わかりませんが。

また、試しに比較対象にしてみたCamelliaが意外に速かったです。これ、使えるかも。

本番

さて、AES-NIを使うためには次のようなコマンドを使わないとならないようです。

openssl speed -evp aes-256-cbc

ベンチマーク用の暗号化プログラムではなく、通常利用する(openssl enc)ための暗号化プログラムを使うということでしょうか。時間があったらソースコードを見てみたいですね。

-evpをつけた複数のアルゴリズムを同時に速度比較できないようなので、AESだけで実行します。結果は次のようになりました。

OpenSSL 1.0.1i 6 Aug 2014
built on: Mon Aug 11 21:45:22 CEST 2014
options:bn(64,64) rc4(8x,int) des(idx,cisc,16,int) aes(partial) blowfish(idx) 
compiler: gcc -fPIC -DOPENSSL_PIC -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -m64 -DL_ENDIAN -DTERMIO -g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security -D_FORTIFY_SOURCE=2 -Wl,-z,relro -Wa,--noexecstack -Wall -DMD32_REG_T=int -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DMD5_ASM -DAES_ASM -DVPAES_ASM -DBSAES_ASM -DWHIRLPOOL_ASM -DGHASH_ASM
The 'numbers' are in 1000s of bytes per second processed.
type             16 bytes     64 bytes    256 bytes   1024 bytes   8192 bytes
aes-256-cbc     252170.02k   341556.71k   386134.44k   395323.59k   397369.34k

先ほどの結果と並べてみましょう。

des ede3         20369.30k    20810.84k    20913.41k    20885.16k    20995.08k
blowfish cbc     74977.91k    81826.65k    85267.20k    86458.48k    86436.52k
aes-256 cbc      55840.73k    58654.36k    59740.07k   141040.98k   142798.34k
camellia-256 cbc    82854.92k   104024.62k   111749.97k   114186.92k   114657.96k

そして、併せてグラフ化しました。

圧倒的な速さ! Blowfishの3倍〜4.5倍くらいの速度が出ています! もとのAESとの比較では、256Bytesのときに6.4倍にもなっています。さすが、暗号標準は優遇されていますね。

Intelでは?

せっかくなので、IntelのCPUでも比較してみました。Intel(R) Xeon(R) CPU E5-2620 v2 @ 2.10GHzです。1コアあたりの公称周波数は上で使ったAMDのマシンよりちょっと劣りますね。

コマンドと

openssl speed blowfish camellia-256-cbc des-ede3 aes-256-cbc -evp aes-256-cbc

結果。

OpenSSL 1.0.1e 11 Feb 2013
built on: Wed Aug  6 18:48:11 UTC 2014
options:bn(64,64) rc4(16x,int) des(idx,cisc,16,int) aes(partial) blowfish(idx)
compiler: gcc -fPIC -DOPENSSL_PIC -DZLIB -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -m64 -DL_ENDIAN -DTERMIO -g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security -D_FORTIFY_SOURCE=2 -Wl,-z,relro -Wa,--noexecstack -Wall -DMD32_REG_T=int -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DMD5_ASM -DAES_ASM -DVPAES_ASM -DBSAES_ASM -DWHIRLPOOL_ASM -DGHASH_ASM
The 'numbers' are in 1000s of bytes per second processed.
type             16 bytes     64 bytes    256 bytes   1024 bytes   8192 bytes
des ede3         20447.94k    20658.20k    20828.21k    20768.77k    20788.57k
blowfish cbc     92491.66k    97588.27k    98745.43k    99492.39k    99396.27k
aes-256 cbc      70233.34k    73782.06k    75054.58k    75234.65k    75423.74k
camellia-256 cbc    63901.00k    87021.12k    95395.67k    98536.54k    99046.74k
aes-256-cbc     345117.58k   360506.67k   364538.03k   366619.06k   365707.26k

AMDと比較して、周波数が低いので全体的に遅くなるかなと思いきや、Blowfishだけなぜか速くなっています。SSEなどベクトル演算関係の命令の速さの違いとか、opensslのバージョンによる実装の違いとか、あるかもしれませんね。

AES-NIを使わない場合(aes-256 cbcのほう)と使った場合(aes-256-cbcのほう)を比較すると、どの平文のサイズでも安定して4.9倍くらいになっています。

まとめ

Blowfishと比べるとその他のアルゴリズムは遅いものと思っていましたが、完全に勝手な思い込みでした。3DESが3回暗号化している分3倍遅いくらいで、AESもチートハードウェアのアシストがなくてもそれなりのスピードでした。そして、今まで使おうとも思ったことがなかったCamelliaが、AMDのCPUではBlowfishを上回るスピードを出してくれたのも収穫でした。