公開鍵暗号方式とは、共通鍵とハッシュと署名から学ぶ暗号の基礎

回 4-5 道 4 ネットワークと暗号

公開鍵暗号方式は、閉じる鍵 (公開鍵) と開ける鍵 (秘密鍵) を別々にした暗号の決まりです。公開鍵は誰に配ってもよく、それで閉じた物は秘密鍵を持つ本人しか開けられないので、会ったことのない相手とも先に合言葉を渡さずに秘密の話を始められます。実際の通信では、遅い公開鍵暗号は鍵の受け渡しと署名にだけ使い、中身は速い共通鍵暗号で守ります。

暗号の部品 4 つ (共通鍵暗号、公開鍵暗号、ハッシュ、署名) が、それぞれ何を守るかを切り分けられるようになります。

なぜ鍵を公開しても秘密が守れるのか

鍵を公開しても秘密が守れるのは、閉じる鍵と開ける鍵を別の物にしてあるからです。閉じる鍵を配っても、開ける鍵は手元から出ないので、閉じた物は本人にしか開けられません。

初めて使う通販のサイトに、カードの番号を送るとします。途中には家の Wi-Fi、通信会社、いくつもの中継の機械があり、誰かが読んでいるかもしれません。番号を暗号にしたくても、開ける合言葉 (鍵) をサイトとまだ共有していません。合言葉を先に送れば、それも途中で読まれます。

この「鍵をどうやって安全に渡すか」という問いに答えたのが、公開鍵暗号方式です。この回では、暗号の部品を 4 つに分けて、それぞれが何を守るかを見ます。

部品守る物鍵
共通鍵暗号中身を読まれない両者で同じ鍵
公開鍵暗号鍵を渡さずに秘密を送る公開鍵と秘密鍵
ハッシュ書き換えに気づく鍵なし
署名誰が書いたかを示す秘密鍵で付け公開鍵で確かめる
公開鍵は誰に配ってもよい錠前で、閉じた箱を開けられるのは秘密鍵を持つ本人だけという図

暗号の部品は、どう組み合わさっているのか

暗号の部品は守る物がそれぞれ違い、実際の通信では組み合わせて使います。

共通鍵暗号は、同じ鍵で閉じて開ける

共通鍵暗号は、閉じるのと開けるのに同じ鍵を使う暗号です。速く、長いデータもそのまま暗号にできます。代表は AES で、米国の標準 FIPS 197 は AES-128、AES-192、AES-256 の 3 つを定め、どれもデータを 128 ビットの塊ごとに変換し、数字は鍵の長さ (ビット) を表すと書いています。

弱いところは、同じ鍵を事前に安全な道で相手へ渡す必要があることです。通販のサイトのように相手が何百万人もいると、会って渡すことはできません。これを鍵配送の問題と呼びます。

公開鍵暗号は、閉じる鍵と開ける鍵を分ける

公開鍵暗号は、対になった 2 つの鍵を使い、片方で閉じた物はもう片方でしか開けられない暗号です。受け取る人が鍵の対を作り、閉じる鍵 (公開鍵) を配り、開ける鍵 (秘密鍵) を手元に残します。流れは次の通りです。

  1. 受け取る人が、公開鍵と秘密鍵の対を作る
  2. 公開鍵を、送る人に渡す (途中で読まれてもよい)
  3. 送る人が、公開鍵で中身を閉じて送る
  4. 受け取る人が、秘密鍵で開ける

代表は RSA です。RSA の仕様 RFC 8017 では、公開鍵は 2 つの数 n と e の組で、暗号にする計算は c = m^e mod n (m を e 回かけて n で割った余り) と書かれています。n は 2 つの大きな素数をかけた数で、秘密鍵はその 2 つの素数を知っていれば計算できます。RSA の安全は、桁の大きい n を素数に分ける (素因数分解する) のが現実の時間では終わらないことに頼っています。米国の NIST の SP 800-57 は、2048 ビットの RSA を、112 ビットの強さの区分に置いています。

署名の用途には、RSA のほか DSA や ECDSA (楕円曲線という別の数学を使う方式) もあります。

公開鍵と秘密鍵

ハッシュは、データの指紋を作る

ハッシュ関数は、どんな長さのデータからも、決まった長さの短い値 (ハッシュ値) を作る計算です。鍵は使いません。米国の標準 FIPS 180-4 の SHA-256 は、256 ビットの値を出します。同じ入力からは必ず同じ値が出て、1 字でも違えば値は大きく変わり、値から元の入力を戻すことは現実的にできません。

暗号と違って元に戻せないので、中身を隠す道具ではなく、書き換えに気づく道具です。暗号化は鍵があれば戻せ、ハッシュは戻せない、と覚えます。

ハッシュ関数は戻せない肉挽き機で、1 字違うと値が大きく変わる図

署名は、秘密鍵で付けて公開鍵で確かめる

デジタル署名は、秘密鍵で付けて公開鍵で確かめる、誰が書いたかを示す仕組みです。書いた人が、文書のハッシュ値と秘密鍵から署名を作り、受け取った人は、文書と署名と公開鍵で確かめの計算をします。確かめが通れば、本人が書いて書き換えられていないと分かります。RSA では、公開鍵で署名を戻してハッシュ値と比べます。DSA や ECDSA は計算が違いますが、鍵の分け方は同じです。

暗号化が「誰でも閉じられて、本人だけが開ける」なら、署名は「本人だけが付けられて、誰でも確かめられる」です。署名は中身を隠しません。

実際の通信は、部品を組み合わせる

実際の通信は、公開鍵の仕組みで共通鍵を安全に決め、中身は速い共通鍵暗号で守ります。公開鍵暗号は計算が重く、長いデータをそのまま暗号にするのに向かないからです。

HTTPS の土台の TLS 1.3 (RFC 8446) では、鍵の決め方はディフィー・ヘルマン鍵交換 (互いに公開した値から、同じ秘密の値を両側で計算する方法) が中心です。RFC 8446 は、以前の版にあった、サーバーの RSA の鍵で共通鍵を送る方式 (static RSA) を取り除いたと書いています。サーバーが本物かは、署名と証明書 (公開鍵が誰の物かを、信頼される機関が署名して保証する書類) で確かめます。

TLS が守る物と守らない物、証明書の確かめを切ると何が起きるかは、セキュリティのレッスン TLS 1.3 の中身 で扱います。この回は、その下の部品の話です。

動かして確かめる

部品を 1 つずつ Python で動かします。数は仕組みを見るために小さくしてあります。仕事では暗号を自分で書かず、検証された道具 (ライブラリ) を使います。

まず共通鍵暗号です。鍵からハッシュで作った並びを、XOR (2 つのビットが違えば 1) で重ねます。同じ鍵でもう一度重ねると元に戻ります。

動かす 同じ鍵で閉じて開ける

python実行可能
出力

▶ 実行ボタンを押すと結果がここに表示されます

実行すると、次の通りに出ます

bb 6b b1 2e 60 3a c2 0b 52 17
会議は3時
cc 98 98 37 30

k1 で閉じたバイト列は、同じ k1 で元の文に戻り、別の鍵 k2 では意味の無いバイトになりました。

次に、小さな数で RSA を動かします。素数 61 と 53 から鍵の対を作り、65 という数を閉じて開けます。pow(e, -1, phi) は、e をかけて phi で割ると 1 余る数 (逆数) を求めます。

動かす 小さな数の RSA

python実行可能
出力

▶ 実行ボタンを押すと結果がここに表示されます

実行すると、次の通りに出ます

公開鍵 (3233, 17)
秘密鍵 2753
暗号文 2790
戻す 65

公開鍵 (3233, 17) で閉じた 65 は 2790 になり、秘密鍵 2753 で 65 に戻りました。2753 は、3233 が 61 と 53 の積だと知る人だけが計算できます。

ハッシュの性質も確かめます。abc と、1 字だけ違う abd の SHA-256 を比べます。値は 64 字あるので、頭の 16 字だけを出します。

動かす ハッシュは 1 字で大きく変わる

python実行可能
出力

▶ 実行ボタンを押すと結果がここに表示されます

実行すると、次の通りに出ます

abc ba7816bf8f01cfea
abd a52d159f262b2c6d
abc ba7816bf8f01cfea
ビット数 256
違うビット 122
バイト 32

同じ abc からは同じ値が出て、1 字違いの abd では 256 ビットのうち 122 ビットが違いました。100 万字の入力でも値は 32 バイトです。

最後に署名です。上の RSA の鍵で、文のハッシュ値に秘密鍵をかけて署名を作り、公開鍵で確かめます。

動かす 秘密鍵で署名し公開鍵で確かめる

python実行可能
出力

▶ 実行ボタンを押すと結果がここに表示されます

実行すると、次の通りに出ます

署名 982
True
False

1 万円の文に付けた署名は、同じ文では確かめが通り、9 万円に書き換えた文では通りませんでした。作るには秘密鍵が要り、確かめるのは公開鍵だけでできます。

どこで暗号が破れるのか

暗号は、数学が解かれるより、鍵の大きさや使い方の前提が崩れて破れることが多いです。3 つ動かします。

小さい鍵は、素因数分解で秘密鍵が出る

上の RSA は n が 3233 と小さいので、2 から順に割れば素数が見つかり、秘密鍵まで計算できます。

動かす 小さい n を割って秘密鍵を出す

python実行可能
出力

▶ 実行ボタンを押すと結果がここに表示されます

実行すると、次の通りに出ます

p q 53 61
割った回数 52
秘密鍵 2753
617 桁

52 回割っただけで 53 と 61 が見つかり、秘密鍵 2753 が出ました。2048 ビットの n は 10 進数で 617 桁ほどで、順に割る方法では終わりません。この大きさが、公開鍵を配っても安全という前提を支えています。

同じ鍵の流れを 2 回使うと、中身が漏れる

共通鍵暗号で、同じ鍵から作った同じ並びを 2 つの文に重ねると、片方の文を知る人には、もう片方も読めます。

動かす 同じ並びを 2 回使う

python実行可能
出力

▶ 実行ボタンを押すと結果がここに表示されます

実行すると、次の通りに出ます

b'PAY 9999'

2 つの暗号文を XOR すると鍵の並びが消えます。1 つ目の文が「PAY 1000」だと知る人は、それを重ねるだけで 2 つ目の文を取り出せました。実際の共通鍵暗号が、毎回違う値 (ナンス、使い捨ての番号) を混ぜるのはこのためです。

詰め物の無い RSA は、候補を総当たりされる

RSA の計算そのもの (c = m^e mod n) は、同じ中身から毎回同じ暗号文を作ります。中身の候補が少ないと、公開鍵で候補を全部閉じて、届いた暗号文と同じ物を探せます。

動かす 候補を閉じて当てる

python実行可能
出力

▶ 実行ボタンを押すと結果がここに表示されます

実行すると、次の通りに出ます

中身は 42

秘密鍵を使わずに、中身が 42 だと当てられました。公開鍵は誰でも持っているので、閉じる計算は誰でもできるからです。RFC 8017 は、新しい用途では、閉じる前に乱れた詰め物を足す RSAES-OAEP を使えるようにすることを求めています。

崩れる前提は、鍵が十分に大きいこと、鍵の並びを 1 回しか使わないこと、中身の候補が多いこと、そして下の実例のように鍵が予測できないことです。

仕事でどう確かめるか

仕事では、暗号を自分で組まず、部品の選び方と使い方を確かめます。

1 つ目は、守りたい物と部品を合わせることです。中身を隠すなら暗号、書き換えに気づくならハッシュか HMAC (共通鍵とハッシュで作る書き換えの印)、誰が書いたかを示すなら署名です。パスワードの保存には、ただのハッシュではなく、遅くなるように作られた専用の方式を使います。

2 つ目は、印を比べるときの書き方です。Webhook (外のサービスから届く知らせ) の HMAC を確かめるとき、Python の公式文書は、== ではなく hmac.compare_digest で比べるよう勧めています。比べる時間の差から値を推測される攻撃 (タイミング攻撃) を減らすためです。

動かす HMAC で書き換えに気づく

python実行可能
出力

▶ 実行ボタンを押すと結果がここに表示されます

実行すると、次の通りに出ます

d783b3f3c3a5067d
67d309ec0b6f8d65
False

3 つ目は、古い部品を見つけることです。設定やコードを md5 や sha1 で検索し、出てきた所が何を守っているかを確かめます。

関わる実例

次の 2 件は、数学ではなく、鍵の作り方と古い部品から崩れた例です。

Debian の OpenSSL の予測できる乱数 CVE-2008-0166 (NVD の公開 2008 年 5 月 13 日)

米国の脆弱性データベース NVD によると、Debian 系の OS の OpenSSL (0.9.8c-1 から 0.9.8g-9 より前) は、予測できる数を出す乱数の作り方を使っていて、外から暗号の鍵を総当たりで当てやすくなっていました。

崩れた前提は「鍵は予測できない」です。鍵の大きさや計算が正しくても、元の乱数が予測できれば、鍵は候補を並べて試せます。

SHA-1 の衝突の公表 (2017 年 2 月 23 日)

Google と CWI Amsterdam の研究者は、中身が違うのに SHA-1 のハッシュ値が同じになる 2 つの PDF を作り、公表しました。発表は、計算に SHA-1 の計算を合計 9,223,372,036,854,775,808 回使ったと書き、SHA-256 などへの移行を急ぐよう呼びかけています。

崩れた前提は「違うデータが同じハッシュ値になる組は、見つけられない」です。ハッシュに頼る署名や証明書では、同じ値の別の文書を作れれば、本物の代わりに偽物を通せます。

よくある問い

公開鍵がバレても大丈夫ですか

大丈夫です。公開鍵は、配ることを前提に作られています。公開鍵でできるのは、閉じることと署名を確かめることで、開けることと署名を作ることには秘密鍵が要ります。守るべきは秘密鍵で、それを手元から出さないことと、公開鍵が本当に相手の物かを証明書で確かめることが大事です。

共通鍵暗号方式の欠点は何ですか

欠点は、同じ鍵を相手と事前に安全な道で共有しなければならないことです (鍵配送の問題)。相手が増えると、相手ごとに鍵を用意して管理する手間も増えます。そのため実際の通信では、公開鍵の仕組みで共通鍵を決め、中身は速い共通鍵暗号で守ります。

署名鍵とは何ですか

署名鍵は、デジタル署名を作るのに使う秘密鍵のことです。対になる公開鍵は、署名を確かめる鍵 (検証鍵) として配ります。暗号化では公開鍵で閉じて秘密鍵で開けますが、署名では秘密鍵で付けて公開鍵で確かめるので、鍵の向きが逆になります。

AES 128 と AES 256 の違いは何ですか

違いは鍵の長さです。米国の標準 FIPS 197 によると、AES-128 と AES-256 はどちらもデータを 128 ビットの塊ごとに変換し、数字は鍵の長さ (ビット) を表します。鍵が長いほど、総当たりで鍵を当てるのに要る試行が増えます。

確認クイズ

答えだと思う選択肢を押すと、その場で正誤と理由が開きます。4 問すべてに正しく答えると、この回は修了で、石が緑に変わります (この端末のブラウザに残ります)。間違えた問いは、あとから解き直せます。

1 問目

公開鍵暗号方式で、相手だけに読ませたい文を送るとき、送る人はどの鍵で閉じますか。

2 問目

このコードを動かすと何が出ますか。

秘密鍵で戻す

n, d = 3233, 2753
print(pow(2790, d, n))

3 問目

ダウンロードしたファイルが、配布元の物から書き換えられていないかを確かめたいとき、まず使う部品はどれですか。

4 問目

TLS 1.3 で、中身のデータを暗号にするのに主に使うのはどれですか。

説明課題

次のことを、自分の言葉で 3 行にまとめてください。書いたら、下の模範解答を開いて比べてください。

  • 共通鍵暗号、公開鍵暗号、ハッシュ、署名が、それぞれ何を守るか
  • HTTPS の通信で、それらがどう組み合わさっているか

模範解答

自分の説明を書いてから開いて、比べてください。

この回の先の一歩

API の鍵の置き場、パスワードの保存、Webhook の署名の確かめのように、仕事で暗号の部品を選ぶ場面では、どの部品が何を守るかを言い分けられることが、取り違えの事故を防ぎます。

もっと深く

この回の続きを、ゆめさくのコースの章や道具で深められます。頁の中の確認クイズに答えたあと、手を動かす量を増やしたいときに使ってください。

一次資料

どれも 2026年10月27日に開いて、題と中身を確かめました。

次へ

道 4 ネットワークと暗号の回

  1. 4-1層に分けて考えるOSI、TCP/IP、パケット頁で読む
  2. 4-2IP とサブネットIP アドレス、CIDR、ルーティング頁で読む
  3. 4-3TCP と UDP再送、輻輳制御、ポート頁で読む
  4. 4-4HTTP と DNSHTTPS、HTTP/3、名前解決頁で読む
  5. 4-5TLS と暗号の基礎共通鍵、公開鍵、ハッシュ、署名この回

道 4 の頁へ戻るほかの道を見る