署名はハッシュ関数やMACの延長で説明したほうがいいのでは?
それじゃ、署名って何よ?って話になってくるけど、暗号と署名の話 - 186::Diaryの説明を読む限りは、暗号化の延長線として話をするよりも、メッセージダイジェストやMACの延長線として話をすればいいんじゃないかと思った。 そもそも要件が違うものを暗号化と一緒に説明するから混乱する訳で。 説明のたたき台として、Rubyのコードで書いてみる。
ハッシュ関数
まずは普通のハッシュ関数を使ったダイジェストから。ある意味、誰でも作れる署名。
# 署名(ハッシュ値)の生成 signature = SHA1::hexdigest(message)
# 署名(ハッシュ値)の検証 if (sigunature == SHA1::hexdigest(message)) { puts 'OK' } else { puts 'NG' }
これは、Webサイトでファイルを配布しているときに、一緒に *****.sha1 などのファイルが置かれていたりするもの。 コマンドラインからだと sha1sum などで生成と検証ができる。 でもこれだと、誰でもダイジェストが作れちゃう。そこで、次にMACの登場。これは、限られた人だけが作れる署名。
MAC(メッセージ認証コード)
# 署名(MAC)の生成 sha1 = Digest::SHA1.new signature = HMAC::hexdigest(sha1, key, message)
# 署名(MAC)の検証 sha1 = Digest::SHA1.new if (sigunature == HMAC::hexdigest(sha1, key, message)) { puts 'OK' } else { puts 'NG' }
第一引数のsha1は使うハッシュ関数を指定しているだけ。大切なのは key が増えたこと。 このkeyを知らないと署名を作ることができない。 MACの場合は署名と検証の鍵が同じなので、検証する人が署名を作ることができる。
最後は公開鍵暗号を応用したデジタル署名。 Rubyのコードは適当…なのでこのままじゃ動かない。
デジタル署名
# 署名(デジタル署名)の生成 signature = Tekito::sign(signkey, message)
# 署名(デジタル署名)の検証 if (Tekito::verify(verifykey, message, signature)) { puts 'OK' } else { puts 'NG' }
こんどは署名用の鍵と検証用の鍵が別になってる。 なので、検証者が署名を作ることはできない。
署名の検証は暗号文の復号とは違う
3つのコードを比べて気がつくと思うけど、どれも署名 signature を元のデータ message に戻したりしていない。
# 署名(ハッシュ値)の検証 if (sigunature == SHA1::hexdigest(message))
# 署名(MAC)の検証 if (sigunature == HMAC::hexdigest(sha1, key, message))
# 署名(デジタル署名)の検証 if (Tekito::verify(verifykey, message, signature))
ハッシュ値とMACの場合は、元のデータmessageから署名を作ってみて、元の署名signatureと一致するかどうかを比較しているだけ。 デジタル署名は元のデータから署名を作ることができない(できると偽造だから)けど、代わりにtrue/falseを返すverify関数がある。
※ 本来のデジタル署名はハッシュ関数と組み合わせて使うんだけど、ここでは意図的に話を簡略化している。
署名 signature から元のデータ message に戻せるわけじゃないので、署名 signature を作ることを「秘密鍵で暗号化」というのは変という話。 だから、暗号化と署名を対にして説明するよりも、ハッシュ関数→MAC→デジタル署名の流れで説明したほうが分かりやすいと思う。 と思って、結城さんの暗号技術入門の目次を読むと、ちゃんと「第II部 認証」で「第7章 ハッシュ関数」「第8章 メッセージ認証コード」「第9章 デジタル署名」という流れになっていた。すごい。