YubiKey PIV Restore
私はハードウェアキーが好きです。YubiKey は、秘密鍵が一度もコンピューターを目にすることなく署名してくれます。けれど、ひとつの考えがずっと私を離しませんでした。カードは鍵を自分で生成し、まさにそれがカードを後戻りのきかないものにします。紛失したり、チップが力尽きたりすれば、アイデンティティは消えます。バックアップもなく、やり直しもききません。
暗号通貨のウォレットは、この問題を何年も前に解いていました。紙に書いたひと握りの単語があれば、どんな新しい端末もまた同じウォレットになります。まさにそれを、私は自分の YubiKey にも欲しかったのです。そこで piv-restore を作り、いつものアプローチをひっくり返しました。鍵はウォレットのリカバリーフレーズから決定論的に生まれ、そのあとでカードに書き込まれます。引き出しの中のフレーズがバックアップです。どんな空のカードも、また私のアイデンティティになれます。
ひとつの鍵、3つの世界
このプロジェクトで私がいちばん気に入っているアイデアはこれです。同じフレーズから、同じ Ed25519 鍵が3回生まれます。TON ウォレットとして。カード上の署名鍵として。OpenPGP のプライマリキーとして。ウォレットもカードも PGP 証明書も、同じ公開鍵を示します。どこかで私の署名を検証する人は、いつも同じアイデンティティを検証していることになります。ついでに、同じ鍵は OpenSSH の1行としても出てきます。
復号についてだけは、私は逆を望みました。そのためにカードの上には、専用の分離された鍵が置かれています。おかげで誰でも、ごく普通の age を使ってオフラインで私のカード宛てにファイルを暗号化でき、それを開けるのはカード自身だけです。
ちゃんと動く
その途中で、OpenPGP に教訓をひとつ授けられました。証明書のフィンガープリントは、作成時刻もいっしょにハッシュします。もし現在時刻をそのまま使っていたら、同じフレーズでも実行のたびに違うフィンガープリントになっていたでしょう。そこで作成時刻はハードコードされていて、エクスポートは乱数を一切消費しません。念のため、結果は2つ目の独立した OpenPGP 実装とクロス検証しました。どちらも同じフィンガープリントを返します。
フレーズの入力用には、ウォレットのリカバリー画面のような小さなオフライン UI を自分で作りました。間違った単語はその場で赤く色づきます。ウォレットとまったく同じように。ネットワークもビルドステップも要らず、単語は私が意識して表示するまでマスクされたままです。
派生プロジェクト: age-plugin-piv25519
このプロジェクトからは、独立した派生プロジェクトも生まれました。Ed25519 は本来、復号ができません。けれど Ed25519 の署名は決定論的です。同じカード、同じテキストなら、毎回同じ署名。つまりこの署名は、カードだけが生み出せる、繰り返し取り出せる秘密なのです。プラグインはこれを使って、age ファイルを物理カードに結び付けます。開けられるのは、カードと PIN、そして設定によってはタッチがあってはじめてです。
この決定論性の仮定がプラグイン全体を支えているので、私はそれを実際のハードウェア上で検証しました。さらに組み込みのセルフテストが、プラグインを信頼する前に各カードを確かめます。ソースコードは公開されています: github.com/kleberbaum/age-plugin-piv25519。
いまの状況
piv-restore そのものは、まだ公開していません。このページはそのアプローチを語るものです。age プラグインのほうは、すでに GitHub でオープンになっています。