TLSでポスト量子暗号を試してみる (その1: 鍵交換)

# 1. はじめに

米NISTのポスト量子暗号標準化([Post-Quantum Cryptography Standardization](https://wiki2.org/en/NIST_Post-Quantum_Cryptography_Standardization+Newton))にむけたコンペティションは2021年のラウンド３では鍵カプセル化にはKyber. デジタル署名としてCRYSTALS-Dilithium,　FALCON,　SPHINCS+が選択され、2024年にはCRYSTAL-KYBERがML-KEM, DilithiumがML-DSA、SPHINCS+がSLH-DSAとして標準化されました。
TLSプロトコルの中ではまだ扱いについて[ドラフトの最終段階で](https://datatracker.ietf.org/doc/draft-ietf-tls-hybrid-design/)標準が確定したわけではありませんが、基本的にはこれらのアルゴリズムは、プロトコルの構造を大きく変更することなしに、新たな鍵交換や署名アルゴリズムの追加として取り扱うことができるようになる見込みです。つまり、TLSハンドシェークのClient Hello/Server HelloにおいてSupported GroupやSignature Algorithms拡張の中の曲線やアルゴリズムの種類の追加で対応することができます.wolfSSLでは暗号ライブラリーwolfCryptの中でこれらのアルゴリズムが実装され、TLSサーバやクライアントアプリケーションを動作させることができるので、この記事ではそれらを使ってポスト量子暗号のうち特に鍵交換を試してみます。署名に関しては[その２:署名](https://qiita.com/kj1/items/f311c0eb2baf049b3cc3)を参照してください。

プロトコルの様子はWiresharkで見ることもできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263939/c040cfc0-3442-4fc0-aebd-b3ea6da5fee3.png)


なお、現段階ではこれらのポスト量子暗号のアルゴリズムが広範囲の条件で十分な堅牢さを持っていることが保証されているわけではありません。同プロジェクトでは従来型の楕円曲線暗号と組み合わせたいわゆるハイブリッド暗号を使用することを推奨しています。wolfSSLでも、PQCアルゴリズム単体のものと、ECCとのハイブリッドアルゴリズムが提供されています。

# 2. PQCの鍵交換

wolfSSL (wolfCrypt)では、鍵カプセル化と署名検証アルゴリズムの二つを提供していますが、今回は鍵カプセル化とそれのTLSでの鍵交換への適応について見ていくことにします。wolfCryptでは鍵カプセル化(KEM: Key encapsulation mechanisms)のために3つの主要なAPIを用意しています。これらのAPIは、TLS1.3の亜hん度シェーク(ClientHelloとServerHello)の中でつぎのように使用されます。

- kyber_keygen<br>
    鍵カプセル化のための公開鍵、プライベート鍵のペアを生成します。クライアントはClientHelloのKeyShareで公開鍵を送ります。
- kyber_encapsulate<br>
    サーバは公開鍵を受け取ります。共有秘密値を生成し、受け取った公開鍵を使ってカプセル化します。
- kyber_decapsulate<br>
    サーバからカプセル可された値と自分のプライベート鍵を使って共有秘密値を取り出します。


TLS1.3の実際にはECC(ECDH)とのハイブリッドアルゴリズムを使用することが推奨されています。ハイブリッドの場合は、ECDHの処理もこれと並行して行いCLient Hello, Server HelloのKey Shareには両方の鍵を結合して格納します。

以下にliboqsのサポートするKEMアルゴリズムをまとめます。

|アルゴリズム|詳細種別|公開鍵サイズ|プライベイト鍵サイズ|
|---|---|---|---|
|Kyber| Kyber512|800	|1632|
|     | Kyber768|800	|1632|
|     | Kyber1024|1184	|2400|


表: KEMアルゴリズムの鍵サイズ

# 3. ダウンロード、ビルド

それでは、実際にliboqsとwolfSSLを動かしてみることにします。

wolfSSLをダウンロード、ビルドします。ここではUbuntuでの手順を説明します。

```
$ git clone --depth 1 https://github.com/wolfssl/wolfssl
$ cd wolfssl
$ ./autogen.sh
$ ./configure --enable-kyber --enable-dilithium
$ make all
```
これで、wolfSSLライブラリと一連のサンプルプログラムがビルドされました。

## 4. 実行させてみる
###4.1 ベンチマークプログラム

まずは、アルゴリズムごとの簡単なベンチマークプログラムを実行させてみます。
ベンチマークには、ML-KEM (Kyber), 署名： ML-DSA (Dilithium) が含まれています。このベンチマークプログラムではこれらのアルゴリズムを約１秒間繰り返し、平均所要時間をミリ秒で、また１秒あたりの操作回数を表示します。

```
...
ML-KEM 1024   256  key gen     49400 ops took 1.001 sec, avg 0.020 ms, 49346.810 ops/sec
ML-KEM 1024   256    encap     47800 ops took 1.002 sec, avg 0.021 ms, 47718.972 ops/sec
ML-KEM 1024   256    decap     37300 ops took 1.002 sec, avg 0.027 ms, 37236.665 ops/sec
...
ML-DSA    87     sign      4200 ops took 1.003 sec, avg 0.239 ms, 4185.648 ops/sec
ML-DSA    87   verify      9800 ops took 1.001 sec, avg 0.102 ms, 9793.938 ops/sec
...

```

###  4.2 サンプルサーバ、クライアント

次に、サンプルサーバとクライアントでTLS通信を行わせて見ます。ローカルPCにサーバ用とクライアント用の二つのウィンドウを開いてそれぞれ次のようにサンプルサーバとクライアントを起動します。この時、Wiresharkも立ち上げておきます。鍵交換アルゴリズムとしてECC-P521とKyber Level 5のハイブリッドを指定してみます。

```
$ ./examples/server/server -v 4 --pqc P521_KYBER_LEVEL5
```

```
$ ./examples/client/client -v 4 --pqc P521_KYBER_LEVEL5
```

サーバ、クライアントはTLS接続と１往復のメッセージ通信を行います。それぞれのウィンドウには次のようなTLS1.3の接続情報とアプリケーションメッセージが表示されます。

```
$ ./examples/server/server -v 4 --pqc P521_KYBER_LEVEL5
Using Post-Quantum KEM: P521_KYBER_LEVEL5
Alternate cert chain used
 issuer : /C=US/ST=Montana/L=Bozeman/O=wolfSSL_2048/OU=Programming-2048/CN=www.wolfssl.com/emailAddress=info@wolfssl.com
 subject: /C=US/ST=Montana/L=Bozeman/O=wolfSSL_2048/OU=Programming-2048/CN=www.wolfssl.com/emailAddress=info@wolfssl.com
 altname = example.com
 serial number:53:16:7c:a0:56:50:46:27:82:ed:60:b4:da:33:d8:6a:c0:ea:dc:31 
SSL version is TLSv1.3
SSL cipher suite is TLS_AES_128_GCM_SHA256
SSL signature algorithm is (null)
SSL curve name is SECP521R1
Server Random : A840F6090DBD557AB550F853EAC1BC88D810598299F1BED1F0ECCB96E8C9FE68
Client message: hello wolfssl!
```

```
$ ./examples/client/client -v 4 --pqc P521_KYBER_LEVEL5
Using Post-Quantum KEM: P521_KYBER_LEVEL5
Alternate cert chain used
 issuer : /C=US/ST=Montana/L=Bozeman/O=Sawtooth/OU=Consulting/CN=www.wolfssl.com/emailAddress=info@wolfssl.com
 subject: /C=US/ST=Montana/L=Bozeman/O=wolfSSL/OU=Support/CN=www.wolfssl.com/emailAddress=info@wolfssl.com
 altname = example.com
 serial number:01 
SSL version is TLSv1.3
SSL cipher suite is TLS_AES_128_GCM_SHA256
SSL signature algorithm is (null)
SSL curve name is SECP521R1
Session timeout set to 500 seconds
Client Random : 218C741111D307A2841373F8872AE8F45F1D06EB7E7064F38D5FBFFEC6345B5E
I hear you fa shizzle!
```

Wiresharkには下のようなTLS1.3のパケットのやりとりがキャプチャーできます。TLS1.3なので "Cleint Hello", "Server Hello"の後のハンドシェークメッセージは暗号化されているのでキャプチャー情報としては "Application Data" と表示されます。

![wireshark1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263939/2a08e57f-779e-3e43-b9de-6e435fd99b76.png)

Server Helloの中を見てみると、"Cipher Suite: TLS_AES_128_GCM_SHA256" とあり、通常のTLS1.3の暗号スイートの一つとして合意していることがわかります。鍵交換アルゴリズムは、"Group: Unknown (12093)"　となっていて、WiresharkがまだQSアルゴリズムのIDに対応していないため、生のID値がそのまま表示されています。

```
    Handshake Protocol: Server Hello
        ...
        Cipher Suite: TLS_AES_128_GCM_SHA256 (0x1301)
        Compression Method: null (0)
        Extensions Length: 1715
        Extension: key_share (len=1705)
            Type: key_share (51)
            Length: 1705
            Key Share extension
               Key Share Entry: Group: p521_kyber1024, Key Exchange length: 1701
    Group: p521_kyber1024 (12093)
```

Supported Group拡張には現行の楕円曲線の種別、FFDHの鍵長に加えてPQのグループが生のID種別で表示されています。

```
Supported Groups (11 groups)
    ...
    Supported Group: kyber512 (0x023a)
    Supported Group: kyber768 (0x023c)
    Supported Group: kyber1024 (0x023d)
    Supported Group: p256_kyber512 (0x2f3a)
    Supported Group: p384_kyber768 (0x2f3c)
    Supported Group: p521_kyber1024 (0x2f3d)
```

サンプルサーバ(./examples/server/server)とクライアント(./examples/client/client)ではたくさんのコマンドアーギュメントが指定できるようになっています。ヘルプオプション("-?")を指定すると一番下にPQCオプションで指定できるアルゴリズムが表示されます。

```
$ ./examples/server/server -?
$ ./examples/client/client -?
...
--pqc <alg> Key Share with specified post-quantum algorithm only [KYBER_LEVEL1, KYBER_LEVEL3,
            KYBER_LEVEL5,  P256_KYBER_LEVEL1, P384_KYBER_LEVEL3, P521_KYBER_LEVEL5]
```

## 5. まとめ

ポスト量子暗号アルゴリズムを実際のTLSの中で試してみました。ベンチマークでわかるように、これらのアルゴリズムの処理時間は現行アルゴリズムと比べても遜色ない性能が実現できていることがわかります。次回は署名、検証について紹介する予定です。