発注の承認、送金の指示、リリースの許可。実行してよいかどうかが「誰が書いたか」で決まる文書は、世の中にたくさんあります。受け取った側が確かめたいのは2点です。差出人が名乗りどおりの本人であること。届いた文面が、書かれたときから1文字も変わっていないこと。

前回までの暗号化は、読める人を絞る道具でした。今日は逆です。中身は隠しません。書いた人と、書き換えられていないことを証明します。

OpenSSL で手を動かして学ぶ暗号の基礎、第4回はデジタル署名です。環境の準備は第0回、今日使う鍵ペアの出自は第3回からどうぞ。

コマンドを打つ前に、今日やることを3コマにしておきます。

向きを、逆にする。
暗号化 錠前で閉める 鍵で開ける 署名 鍵で作る 署名 錠前で確かめる 暗号化 錠前で閉める 鍵で開ける 署名 鍵で作る 署名 錠前で確かめる

道具は同じ鍵ペア。向きを変えると「アリスにしか読めない」が「アリスにしか作れない」になる。

文書に、実印を押す。
アリス 秘密鍵 署名する 承認書(読めるまま) + 署名 署名(256バイト) アリス 秘密鍵 署名する 承認書(読めるまま) + 署名 署名(256バイト)

文書は隠さない。横に実印を添えるだけ。署名は暗号化ではない。

誰でも、確かめられる。
ボブ 承認書 + 署名 署名 + アリスの錠前 Verified OK ボブ 承認書 + 署名 署名 + アリスの錠前 Verified OK

この文書はアリスの鍵の持ち主が署名し、署名のあと1ビットも変わっていない。

鍵ペアを逆向きに使う:秘密鍵で作り、公開鍵で確かめる

第3回の鍵ペアをそのまま使います。手元にない場合は、この2行で作り直せます。

openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out alice.pem
openssl pkey -in alice.pem -pubout -out alice.pub

前回の使い方はこうでした。公開鍵で施錠し、秘密鍵で開ける。閉める鍵は世界中の誰でも持てるが、開けられるのはアリスだけ。

署名はこの向きを逆にします。秘密鍵で作り、公開鍵で確かめる。作れるのはアリスだけだが、確かめるのは世界中の誰でもできる。道具は同じ鍵ペアなのに、向きを変えるだけで「アリスにしか読めない」が「アリスにしか書けない」に変わります。

施錠専用のはずの鍵で、なぜ確かめられるのか。施錠専用・開錠専用という前回の呼び名は、実は暗号化という場面での役割分担にすぎません。鍵ペアの実体は対になった2つの数で、片方の鍵で施した変換は、もう片方の鍵でだけ元に戻せます。暗号化はこの性質を、公開鍵で施して秘密鍵で戻す向きで使いました。署名は同じ性質を、秘密鍵で施して公開鍵で戻す向きで使います。どちらの向きでも、対でしか戻せないことは変わりません。

openssl dgst -sign で承認書に署名する

アリスが承認書を書き、署名します。

printf '2026-09-01 付で、A社への発注を承認します。上限は 1,000,000 円。\n' > approval.txt
openssl dgst -sha256 -sign alice.pem -out approval.sig approval.txt

コマンドは第1回で散々使った dgst です。なぜハッシュのコマンドで署名を作るのかは、後で種明かしします。

できた署名を覗きます。

wc -c approval.sig
#      256 approval.sig

xxd approval.sig | head -2
# 00000000: 6fea 7c96 1803 f2c1 ab73 3eeb eb93 141c  o.|......s>.....
# 00000010: 5006 b3e7 0f55 c1ad 2b77 3efb 5833 09fd  P....U..+w>.X3..

256バイトのバイナリです。これが承認書に添える「アリスの実印」になります。本文の approval.txt はそのまま平文で、隠されてはいません。署名は暗号化ではない、というのが今日の大事な線引きです。

公開鍵があれば、誰でも検証できる

受け取った側は、承認書・署名・アリスの公開鍵の3点で検証します。

openssl dgst -sha256 -verify alice.pub -signature approval.sig approval.txt
# Verified OK

Verified OK。この一行が保証するのは2つです。この文書は alice.pem の持ち主が署名した。そして、署名されたときから1ビットも変わっていない。

2つ目を確かめます。第1回の請求書と同じ手口で、金額の1を9に書き換えます。

printf '2026-09-01 付で、A社への発注を承認します。上限は 9,000,000 円。\n' > approval.txt
openssl dgst -sha256 -verify alice.pub -signature approval.sig approval.txt
# 805D22FC01000000:error:02000068:rsa routines:ossl_rsa_verify:bad signature:crypto/rsa/rsa_sign.c:441:
# 805D22FC01000000:error:1C880004:Provider routines:rsa_verify_directly:RSA lib:providers/implementations/signature/rsa_sig.c:1057:
# Verification failure

100万円の承認を900万円に書き換えた瞬間、署名は無効になりました(先頭の英数字はエラーの識別番号で、手元では別の値になります)。第1回ではハッシュ値の変化として見えた改ざんが、今回は Verification failure という判定で突き返されます。終了コードも 1 が返るので、スクリプトからそのまま合否に使えます。

1文字でも変えると、印が合わない。
9 ,000,000 1 を 9 に改ざん + 署名 署名(元のまま) + アリスの錠前 ✕ Verification failure 9 ,000,000 1 を 9 に改ざん + 署名 署名(元のまま) + アリスの錠前 ✕ Verification failure

書き換えた人は、アリスの秘密鍵がないので署名を作り直せない。

書き換えた本人が署名を作り直せないことも重要です。署名の作成には秘密鍵が要る。イブが文書を書き換えても、アリスの秘密鍵がなければ、その文書に合う署名を作れません。

種明かし:署名はハッシュと秘密鍵の合流

第0回の予告に「第1回のハッシュと第3回の鍵は、第4回で合流します」と書きました。ここがその合流地点です。

dgst -sign の中では、2段階のことが起きています。まずファイルの SHA-256 ハッシュを取る。ここは第1回そのままです。次に、そのハッシュ値を秘密鍵で処理して256バイトの署名にする。ここが第3回の鍵の出番です。

検証側は同じことを逆から確かめます。手元のファイルのハッシュを取り、公開鍵で署名の中のハッシュと突き合わせる。一致すれば Verified OK です。

署名のコマンドが dgst なのは、署名の対象が実はファイル本体ではなくハッシュ値だからです。この設計のおかげで、第3回で見た「RSA は245バイトまで」という制限が消えます。どんな巨大なファイルも、ハッシュにすれば64文字。署名の相手はいつもその64文字です。

中身は、ハッシュに鍵。
作る SHA-256 64文字 + 署名 確かめる SHA-256 64文字 = 署名 + 64文字 作る SHA-256 64文字 + 署名 確かめる SHA-256 64文字 署名 + 64文字 =

署名の相手は、文書そのものではなく、その64文字のハッシュ。だから巨大なファイルにも署名できる。

第1回の宿題:.asc の正体はデジタル署名

第1回のダウンロード検証で、リリースページの .sha256 の隣に .asc というファイルが並んでいました。「公表されているハッシュ値そのものが差し替えられていたら?」という宿題つきで、正体はデジタル署名だとだけ書きました。

答え合わせをします。あの .asc は、配布ファイルに対する OpenPGP 形式の署名です。OpenSSL プロジェクトの秘密鍵で作られていて、検証には openssl コマンドではなく gpg という別のツールを使います。形式も道具も今日とは違いますが、中身は同じです。ファイルのハッシュに秘密鍵で署名し、公開鍵で検証する。

これで第1回の疑問に答えが出ます。ハッシュ値の一覧は、サイトが改ざんされれば一緒に差し替えられます。しかし署名は、プロジェクトの秘密鍵がなければ作り直せません。ハッシュが「壊れていないこと」を守り、署名が「配った本人のものであること」を守る。2段構えです。

注意点

署名は中身を隠さない

approval.txt は最後まで平文でした。署名を付けても、読める人は絞られません。「署名したから安全に送れる」と「暗号化したから読まれない」は別の話です。両方必要なら、署名してから暗号化します。

「秘密鍵で暗号化したものが署名」は概念図

署名の説明として「ハッシュを秘密鍵で暗号化したもの」という言い方をよく見ます。頭の整理には便利で、本記事の「逆向き」という説明もその延長です。ただし技術的には、署名と暗号化は詰め物(パディング)の方式が違う別の演算で、ライブラリも別の操作として区別しています。概念図として使い、実装の説明としては使わない、くらいの距離感が正確です。

署名が証明するのは「鍵の持ち主」まで

Verified OK が言っているのは、正確には「alice.pub と対になる秘密鍵の持ち主が署名した」です。その公開鍵が本当にアリスのものかどうかは、署名は何も保証しません。

イブが自分の鍵ペアを作り、「これがアリスの公開鍵です」と偽って配ったらどうなるか。イブの署名した文書が、アリスの署名として Verified OK になります。検証は完璧に成功し、結論だけが間違う。第3回の最後に積み残した「この公開鍵は本当に本人のものか」という問題が、署名でも解けずに残りました。

印が証明するのは「鍵の持ち主」まで。
イブ 「アリスの錠前です」 実はイブの錠前 配る ボブ 署名 イブが署名した文書 OK イブ 「アリスの錠前です」 実はイブの錠前 配る ボブ 署名 イブが署名した文書 OK

検証は完璧に成功し、結論だけが間違う。

秘密鍵で作り、公開鍵で確かめる。作れるのは鍵の持ち主だけ、確かめるのは誰でも。これがデジタル署名の全部です。

残った問題は、公開鍵と持ち主の結びつけです。次回は、公開鍵に身元保証を付ける仕組み、証明書と PKI。自分で証明書を発行して、ブラウザに警告されるところまでやります。