Diffie-Hellman鍵交換

秘密情報(パスワードの類)を安全に共有するための Diffie-Hellman(DH)鍵交換を実際に試してみよう。盗聴されても大丈夫だが,中間者攻撃(MITM)には注意しなければならない。

通常のDH鍵交換

Diffie-Hellman Key Exchange というページではブラウザ(JavaScript)で実行できるようになっているが,手動で行う方法も書いてある。以下では $ とその左側はプロンプトである(打ち込まない)。まず

$ openssl genpkey -genparam -algorithm DH -out param.pem

でパラメータ param.pem を生成し,共有する(盗聴されてもかまわない)。次に,このパラメータを使って,Alice と Bob は秘密鍵・公開鍵を作る:

A$ openssl genpkey -paramfile param.pem -out priv1.pem
A$ openssl pkey -in priv1.pem -pubout -out pub1.pem

B$ openssl genpkey -paramfile param.pem -out priv2.pem
B$ openssl pkey -in priv2.pem -pubout -out pub2.pem

互いの公開鍵を交換し(盗聴されてもかまわない),自分の秘密鍵と相手の公開鍵から,秘密情報を作る:

A$ openssl pkeyutl -derive -inkey priv1.pem -peerkey pub2.pem -out shared1.bin
B$ openssl pkeyutl -derive -inkey priv2.pem -peerkey pub1.pem -out shared2.bin

秘密情報は等しい(shared1.bin == shared2.bin)。バイナリなので,パスワードにして使いたいときは,Base64 に変換すればよい:

A$ base64 shared1.bin
B$ base64 shared2.bin

ECDH鍵交換

楕円曲線(elliptic curve)を使った ECDH 鍵交換もしてみよう。Creating elliptic curve ECDH key with opensslCommand-line Elliptic Curve operations を参照した。

まず,どんな楕円曲線が使えるか調べる。CentOS 7 上の OpenSSL では

$ openssl version
OpenSSL 1.0.2k-fips  26 Jan 2017
$ openssl ecparam -list_curves
  secp256k1 : SECG curve over a 256 bit prime field
  secp384r1 : NIST/SECG curve over a 384 bit prime field
  secp521r1 : NIST/SECG curve over a 521 bit prime field
  prime256v1: X9.62/SECG curve over a 256 bit prime field

macOS (Monterey) 上の OpenSSL の中身は LibreSSL である:

% openssl version
LibreSSL 2.8.3
% openssl ecparam -list_curves
(たくさん)

一番長い secp521r1 を使うことにする。まずパラメータを生成する:

$ openssl ecparam -name secp521r1 -out param.pem

このあとは通常のDH鍵交換と同じである。

もっとも,生成されるパラメータは一定のようなので,パラメータの生成をさぼって,次のようにしてもよさそうだ:

A$ openssl ecparam -name secp521r1 -genkey -noout -out key1.pem
A$ openssl pkey -in key1.pem -pubout -out pub1.pem

B$ openssl ecparam -name secp521r1 -genkey -noout -out key2.pem
B$ openssl pkey -in key2.pem -pubout -out pub2.pem

A$ openssl pkeyutl -derive -inkey key1.pem -peerkey pub2.pem -out shared1.bin
B$ openssl pkeyutl -derive -inkey key2.pem -peerkey pub1.pem -out shared2.bin