セキュリティ / 認証

署名の仕組み ― パスキーは「暗号化」ではなく「署名」で本人を確かめている

「パスキーの仕組みを図解」「パスキーとは」で、スマホが秘密鍵で「署名」して、サイトが公開鍵で確かめる、と書きました。では、その「署名」とは何なのか。ここでは、よく混同される「暗号化」との違いから説明します。

暗号化と署名は、目的が逆

どちらも「秘密鍵と公開鍵のペア」を使いますが、何のために使うのか、どちらの鍵を先に使うのかが逆です。

暗号化目的:中身を隠す
送る人
平文読める+受け取る人の公開鍵
▼暗号化の計算▼ 暗号文読めない
送るもの:暗号文 だけ
受け取る人
暗号文+自分の秘密鍵
▼復号の計算▼ 平文元に戻る
署名目的:本物であることを証明する
送る人
平文読める+自分の秘密鍵
▼署名の計算▼ 署名平文とは別の、新しいデータ
送るもの:平文 と 署名 の 2 つ
受け取る人(だれでもよい)
平文+署名+送った人の公開鍵
▼検証の計算▼ 正しい / 正しくない平文には戻らない
暗号化署名
目的中身を隠す(ほかの人に読ませない)だれが作ったか、改ざんされていないかを証明する(中身は隠さない)
送る人が使う鍵受け取る人の公開鍵(だれでも使える)自分の秘密鍵(自分しか使えない)
送るもの暗号文だけ平文と署名の 2 つ
受け取る人が使う鍵自分の秘密鍵で元に戻す送った人の公開鍵で確かめる(だれでもできる)
結果元の中身が読める「正しい」か「正しくない」かが分かる(平文には戻らない)

パスキーで使っているのは署名のほうです。サイトが出すチャレンジ(問いかけ)は秘密ではないので、隠す必要がありません。知りたいのは「本物のスマホが答えたかどうか」だけです。

署名はどんなデータ?

「署名」と聞くと、手書きの「サイン」のような短い印を思い浮かべるかもしれません。実際の署名は、人には読めない数値(バイナリーのデータ)です。パスキーと同じ方式で、実際に作ってみました。

平文:こんにちは

署名(中身を 16 進数で表したものの先頭):
b6d360feca771345189aa64cf206849f…

署名(base64url という方法で文字にしたもの):
ttNg_sp3E0UYmqZM8gaEn1WhFI48Vl4qYzb5swrDjhtUfdcwql9aurZNYTI3Tz7REk3Yi3MX9sjFrFMDKABAoQ

中身は意味のある文字ではなく、ただの数値です。Web で送るときは、そのままでは送りにくいので、文字に変換して送っています。

平文が長くても、署名の大きさは同じ
平文平文の大きさ署名の大きさ
「こんにちは」(5 文字)15 バイト64 バイト
「あ」を 1 万文字30,000 バイト64 バイト

署名の計算では、最初に平文から「要約(ハッシュ)」を作ります。要約は、平文が何文字でもいつも同じ長さです。その要約に秘密鍵で計算をかけるので、署名もいつも同じ大きさになります。64 バイトの署名に 1 万文字の平文が入っているはずはないので、署名から平文を取り出せないことも分かります。

※ ここで作った署名は、パスキーで主に使われている ES256 という方式のもので、32 バイトの数値 2 つを並べた 64 バイトです(RFC 7518)。パスキーが実際にサイトへ送るときは、決まり(WebAuthn)で DER という別の包み方にするので、69〜72 バイトくらいになります。どちらにしても、平文の長さには左右されません(手元で 2,000 回作って確かめました)。

平文(何文字でも) → 要約(いつも 32 バイト) → 秘密鍵で計算 → 署名(いつも同じ大きさ)
手書きの「サイン」との違い
手書きのサインデジタルの署名
同じ書類にもう一度ほぼ同じ形毎回まったく違う値になる(計算に乱数を使う方式のため。どれも検証は「正しい」)
書類の中身を 1 文字変えるとサインは同じまったく違う値になる
別の書類に使い回すと使い回せてしまう「正しくない」になる(「こんにちは」の署名で「こんにちわ」を検証すると「正しくない」)

手書きのサインは「その人の印」で、書類の中身とは関係ありません。デジタルの署名は、その平文と、その秘密鍵の組み合わせからしか作れない値です。

「秘密鍵で暗号化して、公開鍵で復号」ではない?

署名は、よく「秘密鍵で暗号化して、公開鍵で復号できれば本人」と説明されます。大筋のイメージとしては分かりやすいのですが、正確には少し違います。

  • この説明は、昔からある RSA という方式の計算の形から来ています。RSA では、署名に公開鍵で計算をかけると何かが出てきます。でも、それも平文そのものではなく、平文の「要約(ハッシュ)」です。サイトは、届いた平文から自分でも要約を作り、2 つが一致するかを比べています。要約から平文に戻すことはできません(RSA の署名の決まり:RFC 8017)。
  • パスキーで主に使われている方式(楕円曲線暗号を使った署名)には、署名から元の中身を取り出す(復号する)手順がそもそもありません。決まり(FIPS 186-5)にあるのは、署名を作る手順と確かめる手順だけです。
  • 確かめるときは、公開鍵・元の中身・署名の 3 つを使って、「この署名は、ペアの秘密鍵で、この中身に対して作られたものか」を判定します。答えは「正しい」か「正しくない」だけです。

そもそもサイトは、自分が出したチャレンジの中身を知っています。だから中身を取り出す必要はなく、「自分が出したチャレンジへの、正しい署名か」を確かめれば十分なのです。

式のような形で書くと、こうなります。確かめるときに、平文そのものも材料に使うのがポイントです。

署名を作る(スマホ):署名 = 署名する計算(秘密鍵, 平文)
確かめる(サイト)  :検証する計算(公開鍵, 平文, 署名) → 「正しい」か「正しくない」

パスキーで、スマホが平文と署名の両方をサイトに送っているのは、このためです。署名の中に平文が入っていて取り出せるのなら、平文を一緒に送る必要はありません。

パスキーでの署名と検証の流れ

パスキーでの署名と検証
スマホ
ネットワーク
サイト(サーバー)
「パスキーを使用」
チャレンジ◀───問いかけ(毎回変わる乱数)
チャレンジを作り、覚えておく
署名する中身(平文)をまとめる
  • チャレンジ
  • 今開いているサイトのアドレス
  • 顔認証などをした印
(通信なし)
顔認証をして、秘密鍵で署名を作る
(通信なし)
平文と署名を送る
平文 + 署名───▶秘密鍵は送らない
検証する
  • 公開鍵・平文・署名の 3 つで、署名が正しいか
  • チャレンジは、自分が出したものか
  • アドレスは、自分のサイトか
すべて正しい → 本物のスマホが答えた → ログイン
1 つでも合わない → 偽物・使い回し・改ざん → 拒否

スマホからサイトへ送られるのは、署名した中身(平文)と署名だけです。秘密鍵は一度もスマホの外に出ません。

なぜ偽物の署名は作れないの?

  • 秘密鍵がないと作れない:正しい署名を作れるのは、ペアの秘密鍵を持っている人(スマホ)だけです。
  • 公開鍵から秘密鍵は割り出せない:公開鍵はだれに見せてもかまいません。公開鍵から秘密鍵を計算で求めることは、今のコンピューターでは事実上できないように作られています。
  • 中身を 1 文字でも変えると合わなくなる:署名は、その中身に対してだけ正しくなります。途中で書き換えられると、検証で「正しくない」になります。
  • 前の署名は使い回せない:チャレンジは毎回変わるので、前回の署名を盗んで送っても、今回のチャレンジには合いません。

パスキーは何に署名しているの?

署名する中身それで防げること
チャレンジ(問いかけ)前の署名の使い回し
今開いているサイトのアドレス偽サイトへの誘導(偽サイトのアドレスで署名しても、本物のサイトでは通らない)
顔認証などで本人確認をした印スマホを拾った人が、本人確認なしに使うこと

まとめ

  • 暗号化は「中身を隠す」、署名は「本物であることを証明する」。鍵の使い方が逆。
  • パスキーは、毎回変わるチャレンジとサイトのアドレスに、スマホの秘密鍵で署名して本人を証明している。
  • サイトは公開鍵で「正しいかどうか」を確かめるだけ。秘密鍵もパスワードも、ネットワークを流れない。
スポンサーリンク
タイトルとURLをコピーしました