🔐

早速ですがDenoでEd25519鍵を作ります

2022/10/08に公開

https://deno.com/blog/v1.26

9月29日にリリースされたDeno v1.26.0ではWeb Crypto APIのX25519とEd25519がサポートされました。

https://wicg.github.io/webcrypto-secure-curves/

ただ現在X25519とEd25519はWICGのDraft段階にあたるため、完全なWeb標準として導入されたものではないのですが、各ブラウザに今後順次導入されるかもしれないため気になる機能です。

> deno --version
deno 1.26.1 (release, x86_64-pc-windows-msvc)
v8 10.7.193.3
typescript 4.8.3

今回は10月6日に公開されたばかりのDeno v1.26.1を使います。
実は一度v1.26.0でEd25519鍵の作成を試みましたが、完全に機能を実装していなかったせいか生成した鍵が壊れていたため、v1.26.1以上でないと使えないことに注意が必要です。
またWindowsを使い動作検証していますが、他のOSでも問題なく動作すると思います。

では作ります。

> dir
...
2022/10/08  20:00    <DIR>          .
2022/10/08  20:00    <DIR>          ..
2022/10/06  19:43        66,400,256 deno.exe
2022/10/08  20:00                 0 id_ed25519
2022/10/08  20:00                 0 main.ts
2022/10/08  20:00                 0 new.txt
...

事前にこのようなファイルを作成しておきます。
まずはmain.tsにコードを書きます。

main.ts
function btos(b: ArrayBuffer) {
  return String.fromCharCode(...new Uint8Array(b));
}

const { privateKey, publicKey } = await crypto.subtle.generateKey(
  { name: "Ed25519" },
  true,
  ["sign", "verify"],
) as CryptoKeyPair;
const privateKeyDer = await crypto.subtle.exportKey("pkcs8", privateKey);
const publicKeyDer = await crypto.subtle.exportKey("spki", publicKey);
const privateKeyPem = "-----BEGIN PRIVATE KEY-----\n" + btoa(btos(privateKeyDer)) + "\n-----END PRIVATE KEY-----\n";
const publicKeyPem = "-----BEGIN PUBLIC KEY-----\n" + btoa(btos(publicKeyDer)) + "\n-----END PUBLIC KEY-----\n";

console.log(privateKeyPem);
console.log(publicKeyPem);

RSA鍵やECDSA鍵と異なり、Ed25519鍵は鍵長が256bit固定でBase64にすると約64文字になるため、Base64文字列を途中で折り返す処理を書かなくて良くなり非常にシンプルなコードになりました。

> deno run main.ts
-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----

-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----

秘密鍵と公開鍵を生成できました。
最初に作成したid_ed25519に秘密鍵を転記しましょう。

id_ed25519
-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----

公開鍵も同様にid_ed25519.pubファイルを作り転記してもよいのですが、今回は試しにOpenSSLを使い、Ed25519の秘密鍵から同じ公開鍵を取り出せるか試してみます。

> openssl version
OpenSSL 3.0.3 3 May 2022 (Library: OpenSSL 3.0.3 3 May 2022)

v3.0.0以上のOpenSSLがインストールされているか確認します。

> openssl pkey -pubout -in id_ed25519 -out id_ed25519.pub

このコマンドを使えば秘密鍵から公開鍵を取り出せます。

id_ed25519.pub
-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----

OpenSSLでもDenoと同じ公開鍵を生成できることが分かります。
実際に使ってみましょう。

new.txt
Hello, World!
> openssl pkeyutl -sign -rawin -inkey id_ed25519 -in new.txt -out new.txt.sig

署名したいテキストファイル内にメッセージを書き、秘密鍵を使ってテキストファイルに署名します。
RSA鍵やECDSA鍵と異なり、Ed25519鍵は-rawinオプションが必要になるため忘れずにつけておきましょう。

> openssl pkeyutl -verify -rawin -pubin -inkey id_ed25519.pub -in new.txt -sigfile new.txt.sig
Signature Verified Successfully

公開鍵と先程生成したnew.txt.sigファイルを使ってテキストファイルの署名を検証すると成功しました。
-pubinオプションをつけることで誰でも公開鍵を参照して署名の検証ができます。

new.txt
Hello, World!!
> openssl pkeyutl -verify -rawin -pubin -inkey id_ed25519.pub -in new.txt -sigfile new.txt.sig
Signature Verification Failure

テキストファイル内のメッセージを少しでも改ざんすると署名の検証が失敗します。
Denoで作成したEd25519鍵を問題なく使えることが分かります。

今回は動作検証のためOpenSSLを使いましたが、OpenSSLがなくてもDenoだけあればX25519とEd25519に関する処理を簡単に行えるようになりました。最高!!

Discussion