連載「wolfの実力」 第五回:ヒープメモリーを深堀りしてみる

組込みデバイスの設計で気になるのは処理スピードだけではありません。メモリー容量についても以前よりは制約は緩くなってきたとはいえ、多くの場合できるかぎりの節減がもとめられるのが実情で、特にRAMエリアの容量には注意が求められるケースが多いかと思います。

 

wolfSSLの場合、設計ポリシーとして静的に確保されるデータエリアは最小限となるよう設計されていますので、今回は、必要の都度確保されるヒープ領域について、その挙動、サイズについて見ていくことにします。

 

TLSの通信をヒープエリア利用の観点からみると、次のようなステップを踏むことになります。かっこの中はそれぞれのステップで代表的に使用するwolfSSLのAPI名です。

 

1)コンテクストの確保 (wolfSSL_CTX_new)

2)鍵、証明書の格納 (wolfSSL_CTX_load_verify_locations)

3)セッション管理エリアの確保 (wolfSSL_new)

4)ハンドシェイク (wolfSSL_connect/accept)

5)アプリケーションデータ転送 (wolfSSL_write/read)

 

図1は、1)~4)の準備段階でのヒープエリアの使用量の一例を示しています。必要とするヒープエリアは、前のステップで確保し引き続き必要とされるエリア(濃い青の部分)とそのフェーズで使用するエリア(薄い青の部分)があります。図1ではTLSクライアント側での値を示しています。サーバ側では絶対値に多少の違いはあるものの、全体として大きな傾向は変わりません。

 

1)と2)は特定のTLSコンテクストで使用される共通情報を設定するステップです。このフェーズでは、メモリー容量としては使用される鍵や証明書のサイズが大きなファクターとなります。この例では、サーバ認証用の証明書だけが確保されています。実際の利用状況では、クライアント認証のための鍵、証明書を格納する必要がある場合もあります。

 

3)は、特定の相手方との通信を行うためのTLSセッションの管理エリアを確保します。この例では、1セッション分のエリアを確保していますが、同時に複数のセッションを扱う場合はその分だけのエリアを確保する必要があります。

 

4)は通信の相手方とのハンドシェークを実際に行うステップです。このステップではメモリー消費の観点からも公開鍵の大きな処理が行われます。

 

公開鍵処理の最適化についてはこのシリーズの第一回でも紹介したSingle Precision (特定鍵長)最適化が大きな効果を発揮します。ヒープ領域の使用量についてもこの最適化が大きな効果を示しますので、ここではその最適化を適用した場合の例をお見せしています。現在のwolfSSLのバージョンでは、ECCのP-256, RSAの1024, 2048, 3072ビットの各鍵長をサポートしていますが、それ以外の場合はこの最適化は適用できません。また、SP最適化はトレードオフとしてコードサイズが大きくなる傾向にあるので、ROMエリアに制限がある場合には注意が必要です。

 

 

 

図2はアプリケーションデータ転送時のヒープエリアの使用量の一例を示しています。アプリケーションデータ転送時には、公開鍵のようなヒープを多用する暗号化アルゴリズムは必要とされないため、暗号化処理に関するデータエリアは比較的小さくなります。

 

一方、データ転送のためのバッファエリアが大きなウェイトを占めることになります。TLSレコードはデフォルトでは最大16kバイトとなるため、wolfSSLでもデフォルトではそのサイズのバッファを確保することになるので、ヒープエリアが潤沢に利用で着ない場合は、このサイズを気にする必要が出てきます。

 

TLSではこの最大レコードサイズをプロトコル実行時に制限することができ、サーバ側が合意するならば、そのサイズを例えば4096、あるいは8196バイトなどの2のn乗バイトで指定することができます。wolfSSLでもこのオプションをサポートしており、利用する場合は ビルド時に –enable-maxfragment (あるいはHAVE_MAX_FRAGMENT)を指定し、実行時にwolfSSL_CTX_UseMaxFragmentまたはwolfSSL_UseMaxFragment にて実際のサイズを指定します。

 

この記事に関して、ご質問、あるいはご意見、ご希望などありましたら info@wolfssl.jp までお知らせください。

 

連載「WOLFの実力」を最新版から続けて読む
第一回:SP最適化でハンドシェイク所要時間を大幅削減
第二回:データ転送速度をさぐる
第三回:DTLSの実力(その1 DTLSの動作)
第四回:DTLSの実力(その2 性能編)

連載「wolfの実力」 第四回:DTLSの実力(その2 性能編)

先月はDTLSの動作について紹介したので、今月はいよいよその性能について見ていきたいと思いますが、その前に先月紹介した動作に関して若干の復習です。ご存じの通り、UDPはその名の通りコネクションの概念のない、単発の手軽なパケットの送受信プロトコルです。DTLSはそのUDPに安全性を提供するわけなのですが、例えば、その安全性の重要な要素、なりすましを防止しようと思ったらどうしても通信相手の認証は避けて通れません。そんなこんなを考えると、結局DTLSも安全なセッションを確立するためにTLSとにたようなハンドシェークがあったり、TCPで実現しているのに近いようなパケットロスや順序性の確保といった処理が必要になってしまう、というようなお話を前回しました。

 

そういうわけで、DTLSの性能を見ていくと残念ながらUDPのような軽量さは失われてしまっていることがわります。我々ベンダの立場からは、安全性を損なわない範囲でどこまで軽量さを追求できるかが勝負所になります。

 

さて、前置きはそのくらいにして本題の性能について、wolfSSLの提供するDTLS1.2について、その処理時間に関する基本性能を見てみましょう。処理時間は、通信の冒頭で安全なセッション確立のために行われるハンドシェーク部分と実際にアプリケーションのデータを転送するペイロード転送部分の二つにわかれます。

ハンドシェークは、ペイロードのデータサイズにかかわらずほぼ一定の時間がかかります。

上のグラフはハンドシェークの処理時間をARM Cortex A7で実際にベンチマークし相対値に示したものです。本来ハンドシェークの実行時間にはUDP/IP以下の層のネットワークプロトコルの処理時間も含まれますが、このベンチマークでは同一のプロセッサ上にクライアント、サーバを置き通信させています。そのため、UDP/IP以下の層の処理時間はほぼゼロに近い処理時間となり、実質的にDTLSレイヤーの処理時間だけが抽出された形になります。

 

ハンドシェーク処理時間としては鍵交換(鍵合意)と通信相手の認証(署名検証)の時間が大半を占めます。グラフでは、鍵交換アルゴリズムとして従来型の有限体DH(FFDH)と楕円曲線DH(ECDH)、署名検証アルゴリズムとしてRSAとECDSAの二組の要素を三通りの組み合わせで比較しています。

 

処理時間には鍵長が大きく影響してきますが、このベンチマークでは現在通常用途にはおおむね十分な強度が得られるとされている鍵長、DH、RSA鍵には2048ビット、ECCには256ビットを使用しています。これらの比較では、従来型より楕円曲線によるアルゴリズムのほうがかなり高速に処理できることがわかります。

 

wolfSSLでは、これらの公開鍵処理のベースとなる整数演算部分にSP(Single Precision)最適化と呼ばれる最適化技術を導入しています。DTLSやTLSに使用される鍵長には種類はありますがいくつかに標準化されています。この鍵処理は特定の鍵長に着目すると大幅に処理時間を短縮することができます。その点に着目して代表的長さの鍵について最適化するのがSP最適化です。wolfSSLでは、現在(Version 4.4.0)RSA2048,3072,4096ビット、ECC256ビットについてSP最適化を提供しています。グラフの各アルゴリズムの左側が従来の処理、右側がSP最適化有りの場合を示しています。ご覧のようにSP最適化によって大幅に処理時間が改善されていることがわかります。

 

さて、次はペイロードの転送時間です。こちらのベンチマークもハンドシェークと同様に同一プロセッサでの転送時間を相対値で示しています。UDP/IP以下の層の処理時間は実質ゼロで、実質的にDTLSでの処理時間となります。ペイロードの処理時間は、概ね伝送データのサイズに比例しますので、ここでは1Mバイトあたりの処理時間をミリ秒で表示しています。

 

この部分の共通鍵暗号アルゴリズムとしては従来AES-CBCが広く利用されてきました。しかし、最近はこの暗号アルゴリズムとレコード単位のMAC値によるチェックを組み合わせただけでは改ざんのリスクがある点が指摘されており、AEAD(authenticated encryption with associated data)アルゴリズムの利用が推奨されています。しかし、一般的にはAEAD型の方は処理時間が増加してしまう欠点があります。グラフの右側のChacha20-Poly1305の組み合わせはAEADでありながらご覧のように従来の一般的なアルゴリズムよりも短い時間で処理できることを示しています。

 

以上、今回はDTLSの処理性能について紹介しました。この記事で紹介したベンチマークはwolfSSL製品やオープンソース版の中にも含まれていて、お客さま自身のターゲット環境でベンチマークを実行することができるようになっています。wolfSSLの通常のビルドが完了したら、下記のように、./examples/benchmarkディレクトリーのtls_benchプログラムを” -u”(DTLS指定)で実行してみてください。

 

./examples/benchmark/tls_bench -u

 

この記事に関して、ご質問、あるいはご意見、ご希望などありましたら info@wolfssl.jp までお知らせください。

 

連載「WOLFの実力」を最新版から続けて読む
第一回:SP最適化でハンドシェイク所要時間を大幅削減
第二回:データ転送速度をさぐる
第三回:DTLSの実力(その1 DTLSの動作)

連載「wolfの実力」 第三回:DTLSの実力(その1 DTLSの動作)

これまでTLSの実力についてみてきましたが、ここで少し寄り道をしてTLSの兄弟分であるDTLS(Datagram Transport Layer Security) について紹介することにします。DTLSはご存じのようにUDP(User Datagram Protocol)のセキュリティを実現するためのトランスポート層のプロトコルです。UDPはTCPのような接続の概念がなく、単純にパケットを送受することができる軽量で簡単に使えるプロトコルとして広く使われてきましたが、この分野でも本格的な応用ではセキュリティが求められることも多々あります。そのような場合に活躍するのがDTLSです。

とはいえ、DTLSについてはTLSに比べるとなじみの少ない方も大勢おられるかと思います。連載枠を二回にわけて、今回その1はDTLSのしくみ、動作について簡単に紹介して、次回その2でパフォーマンなど実力について見ていくことにします。

IETFでのDTLSの標準化は当初TLSとは比較的独立に行われていたのですが、最近はTLSと歩調をあわせるようになってきています。DTLS1.0の次の検討ではTLS1.2と歩調を合わせるために、プロトコルのバージョン名も一つスキップしてDTLS1.2としています。IETFのワーキンググループでは次のバージョンDTLS1.3の内容が議論されていますが、DTLS1.3の内容もすでに標準が発行しているTLS1.3で実現した多くの強化、改善が取り込まれていく見込みです。とはいえ、残念ながらDTLS1.3についてはまだ不確定要素も多くあるので、今回はすでに広く使われておりwolfSSLでも利用可能なDTLS1.2に基づいて紹介していくことにします。

UDPは軽量のプロトコルである一方で、パケットロスや転送順序の保証がなかったりといった暗号処理には少々やっかいな問題をかかえています。そこで、DTLSの処理の下層部分ではパケットロスや順序保障といったTCPに似たような処理を行わせています。ただし、TCPとは違って、接続、切断のパケットを飛ばすというようなプロトコルでその処理をするのではなく、内部管理だけで実現するようになっています。

【図1 DTLSプロトコルの処理】

 

DTLSではそのような管理の上にセキュリティプロトコルを実現します。一方、DTLSのプロトコル自身はTLSによく似たプロトコルになっています。TLSと同様に通信ノードの役割はクライアントとサーバに分かれていて、接続の概念もTLSと同様です。DTLSの通信はクライアントからの接続要求からはじまり、クライアントとサーバの間で一連のハンドシェークが行われ安全な接続を確立し、実際のアプリケーションデータの転送が行います。

【図2 wolfSSLのAPIを使ったDTLSの概要】

 

図2は、アプリケーションプログラムでDTLSの通信の実現の概要をwolfSSLのAPIで示したものです。このように、DTLSのAPIは最初のコンテクストを確保するところでDTLSを指定する以外、ほとんどTLS向けのAPIの使い方と同じとなっています。1つ違う点は、UDPの場合、接続の概念がないため通信の相手を何等かの形でwolfSSLライブラリ側に伝えなくてはならない点です。サーバ側ではクライアント側からClientHelloのパケットを受け取ったときはじめて通信相手が確定します。そのためUDPレイヤーの受信(recvfrom)をMSG_PEEKモードで受信して、そのあとハンドシェークを行うクライアントのアドレスをwolfSSLライブラリに登録する必要があります。これはwolfSSL_dtls_set_peerないしBSD Socketの場合にはconnectにて行います。クライアント側ではwolfSSL_dtls_set_peerで接続したいサーバのアドレスを登録します。

【図3 DTLSパケットの様子】

 

図3では、パケットキャプチャを使ってDTLSの簡単な通信の様子を見てみました。

DTLSもTLSと同様にアプリケーションデータの送受信に先立って、安全な接続のためのハンドシェークが行われていることがわかります。TLSと異なるのは、DoS攻撃の防衛のために最初のClientHelloに対して、HelloVerifyRequestと呼ばれるレコードでサーバからクライアントに対してクッキーが渡され、クライアントはこれを以後の通信で引き継がないといけないようになっている点です。ハンドシェークのあとは暗号化されたアプリケーションデータの通信が行われます。この部分はアプリケーションの必要に応じて、必要なレコードを必要な回数往復させることができます。

では、次回はDTLSの通信をベンチマークしてみることにしましょう。

 

連載「WOLFの実力」を最新版から続けて読む
第一回 SP最適化でハンドシェイク所要時間を大幅削減
第二回:データ転送速度をさぐる

 

連載「wolfの実力」 第二回:データ転送速度をさぐる

連載第一回ではTLSのハンドシェイク処理について解説したので、今回はアプリケーションデータ転送部分について少し見ていくことにします。

ご存じの通りTLSのデータ転送部分は、ネットワークプロトコルとしてはTCPの上にTLSレコードを乗せて送受信します。TLSレコードは共通鍵暗号で暗号化されたアプリケーションデータとデータの一貫性を保証するためのMAC値からできています。AES-CBCのような従来型の共通鍵暗号方式を使う場合は、主に共通鍵暗号化処理とMAC値を求めるためのハッシュ処理が行われます。これに対して、認証タグ付き暗号、いわゆるAEAD暗号ではMAC値は使わず、ブロックごとの暗号化処理とともに認証タグ値を計算します。いずれの場合でも処理時間はおおむね転送するデータのサイズに比例するので、画像ストリームのように大きなデータ、多量のデータを転送する場合には使用する暗号スイートについて考慮する必要があります。

上のグラフはTLSレコードの転送スピードの相対値を暗号スイートごとに比較したものです。それぞれのスイートごとの送信、受信スピード(毎秒のバイト数)とともに、比較のために暗号化、復号化処理単体のスピードを追加しています。

TLSの送受信処理時間の要素は、大きくはアプリケーションデータの暗号/復号化処理とTCPレイヤーのパケット送受信時間の二つです。

送信時には、TCPの送信データはバッファリングされるので、レコードの送信スピードは実際のネットワークのデータの転送速度よりずっと高速に実行できます。それに対してデータ暗号化処理は相応に処理時間を必要とします。グラフからわかるように、結果としてそのスピードは暗号化処理のスピードに近い値となります(AES-CBCの場合は、AES暗号化とともにハッシュ処理時間をあわせた処理スピード)。

一方受信の場合は、ネットワークを転送されるデータを待たなければ復号化処理はできません。復号化処理はネットワークデータを待っている間に処理されるので、TLSレコードの転送速度の値としてはTCPレイヤーの転送速度の方が見えてきます。

また、アルゴリズムによってスピードは大きく違ってきます。セキュリティ、安全性の観点からは現在広く使われているAES-CBCよりAEADによる暗号化が求められます。特にTLS1.3ではAEADのみが認められています。AEADの中でも、Chacha-Polyは大幅なスピードの向上が期待できます。また、同じAESでもGCMよりCCMの方がかなりの改善が期待できるので、アルゴリズムの選択が可能な場合は考慮するとよいでしょう。

一方で、最近のMCUではハードウェア暗号アクセラレータを搭載しているものも多く、そうした機能を利用すればソフトウェアだけで実現する場合にくらべて多くの場合、一桁程度性能が改善します。

 

以上、今回はTLSレコードの転送スピードについて紹介しました。wolfSSLには簡単なベンチマークプログラムも含まれていて、お客様の実際の環境で測定することができるようになっていますので、ぜひ実機にてお試しください。wolfSSLのベンチマークについて詳しくはinfo@wolfssl.jp にお問い合わせください。

 

連載「WOLFの実力」を最新版から続けて読む

第一回 SP最適化でハンドシェイク所要時間を大幅削減

 

連載「wolfの実力」 第一回:SP最適化でハンドシェイク所要時間を大幅削減

wolfSSLのようなライブラリを自社の製品に組み込む上でまず気になることの一つは、処理性能やメモリー資源の消費量といった性能指標ではないでしょうか。また、wolfSSLはお客様のそれぞれ異なる組み込み要件を満みたせるように豊富なビルドオプションを用意しています。この連載では、こうした豊富なオプションを使いこなしてwolfの実力を最大限に発揮させる方法について紹介していきたいと思っています。

wolfSSLでは製品に付帯してベンチマークプログラムを提供していて、お客様の製品の実装条件にあわせて実機でのベンチマークテストができるようになっています。この連載で紹介する様々な性能指標やオプションの効果についても、そのほとんどは手元の実機で実際に確認することができるはずです。ぜひ、評価用に提供しているオープンソース版wolfSSLのメリットをいかして、実際に確かめながらスムーズな製品導入を実現してください。

さて、連載第一回はSingle Precision最適化をとりあげることにします。ご存知の通り公開鍵暗号技術はTLSセキュリティの基盤となる最重要技術ですが、一方でTLS処理のなかで一番時間やリソースを消費してしまうやっかいな代物でもあります。

その公開鍵暗号アルゴリズムの基本をささえているのが大きな整数を効率的に演算する整数演算ライブラリです。その整数演算ライブラリの処理方法を大幅に見直し最適化するのがSingle Precision(SP, 特定鍵長向け)最適化です。通常の整数演算ライブラリが任意の整数長、鍵長の演算(Multiple Precision)に対応できるようになっているのに対して、SPでは特定の鍵長のアルゴリズムだけに着目して最適化します。

RSAやECCなどの公開鍵長やフォーマットは標準化されていて、その中から求められる鍵の強度により自由に選択することができるようになっています。しかし現実には実用的な見地から、多くの場合、例えばRSAならば2048ビット、ECCならば256ビットなど特定の鍵長を利用することになります。また、処理時間はおおざっぱには鍵長の二乗に比例して長くなるので、長い鍵ほど最適化への要求が高まります。

現在wolfSSL(v4.3.0)のSP最適化は、RSA 2048, 3072, 4096ビット、ECC 256ビットに特化した最適化オプションです。この最適化によって、該当する鍵長の処理では大幅に処理時間を短縮することができます。また、スタックなどメモリー使用量も削減することができます。

ただし、最適化のためにループの排除などを行っているために、トレードオフとしてコードサイズが大きくなってしまうので、コード用のフラッシュメモリー領域には余裕が必要です。

図1は公開鍵暗号処理ごとの処理時間(相対値)を通常モードとSP最適化時で比較したものです。ご覧のように処理時間を大幅に短縮できます。

公開鍵暗号の処理はTLSハンドシェークの中で多数使用され、オーバーオールなハンドシェーク処理時間のなかでも大きなウエイトを占めています。SP最適化によってその部分の処理が大幅に短縮されるので、ハンドシェーク全体の処理時間から見ても大きく改善されます。図2は暗号スイート別に見たTLSハンドシェーク処理時間を通常モードとSP最適化時で比較したものです。

SP最適化オプションの利用方法:

現在のwolfSSLでは、SP最適化オプションはデフォルトでは無効化されています。最適化を有効化するには以下のオプションを指定します。

 

configureコマンドを利用する場合:

$ configure –enable-sp –enable-sp-asm –enable-sp-math

 

ヘッダーファイルを利用する場合:

#define WOLFSSL_HAVE_SP_RSA

#define WOLFSSL_HAVE_SP_DH

#define WOLFSSL_HAVE_SP_ECC

#define WOLFSSL_SP_ASM        // gcc利用の場合

#define WOLFSSL_SP_ARM32_ASM // ARMアーキテクチャ向け、gcc利用の場合

#define WOLFSSL_SP_MATH

 

 

ベンチマーク方法:

今回紹介した性能改善効果について実機で具体的にデータ収集したい場合は、製品に同梱されている下記のツールを使ってください。

 

アルゴリズム毎のベンチマーク

wolfSSLルート/wolfcrypt/benchmark/benchmark

 

TLSハンドシェークのベンチマーク

wolfSSLルート/examples/benchmark/tls_bench

 

ご質問がありましたら info@wolfssl.jp までご連絡ください。