1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

公開鍵暗号とは何か:共通鍵暗号との違いから整理する

1
Posted at

概要

ネットショッピングで住所や支払い情報を入力する。
ブラウザで銀行のサイトを開く。
GitHubにSSHで接続する。
スマホアプリがサーバーと通信する。

普段は画面のボタンや鍵マークだけを見て使っていますが、裏側では「この通信相手は本物か」「途中で盗み見られないか」「送った内容が書き換えられていないか」といった確認が行われています。

この裏側を支えている技術の1つが、公開鍵暗号です。

ただし、公開鍵暗号は最初に聞くと少し不思議な技術です。
なぜなら、「公開してよい鍵」と「自分だけが守る鍵」という、一見すると矛盾しているような2種類の鍵が登場するからです。

たとえば、誰かに大切な荷物を送る場面を考えてみます。
共通鍵暗号は、送り手と受け手が同じ鍵を持っていて、その鍵で箱を閉めたり開けたりするイメージです。これは分かりやすい一方で、「その鍵をどうやって安全に相手へ渡すのか」という問題が残ります。

一方、公開鍵暗号では、考え方が少し変わります。
公開してよい鍵は相手に渡し、秘密にする鍵は自分だけが持ちます。これにより、インターネットのように相手と直接会えない環境でも、安全な通信や署名確認を行うための土台を作れます。

本記事では、公開鍵暗号をいきなり数式やアルゴリズムから説明するのではなく、身近なサービスの例から整理します。
そのうえで、共通鍵暗号との違い、公開鍵と秘密鍵の役割、デジタル署名、鍵共有、証明書、TLSでの使われ方までを順番に見ていきます。

💡 豆知識
暗号でいう「鍵」は、家の鍵やパスワードそのものというより、暗号処理に使うランダム性の高いデータです。
そのため、見た目は人間が覚える文字列というより、コンピュータが扱う長いデータとして表されることが多いです。

この記事の立ち位置

この記事は、以前作成した「スマホ決済の裏側から見る、情報セキュリティを支える暗号技術の全体像」から派生する個別解説記事です。

全体像の記事では、暗号技術を「何を守るのか」「どの道具を使うのか」「実サービスではどう組み合わせるのか」という視点で広く整理しました。

本記事では、その中でも特に重要な 公開鍵暗号 に焦点を当てます。

ただし、公開鍵暗号だけを単体で説明するのではなく、共通鍵暗号との違いや、TLSのような実際の通信での使われ方につなげて整理します。

全体像の記事 本記事
暗号技術全体の地図を整理する 公開鍵暗号を個別に深掘りする
暗号化、ハッシュ、MAC、署名、鍵共有などを広く見る 公開鍵と秘密鍵の役割を中心に見る
スマホ決済やWeb通信の裏側を広く扱う 共通鍵暗号との違い、証明書、TLSでの役割を扱う

この記事で分かること

この記事では、次の内容を整理します。

  • なぜ公開鍵暗号が必要なのか
  • 共通鍵暗号と公開鍵暗号の違い
  • 公開鍵と秘密鍵の基本的な役割
  • 公開鍵暗号でできること
  • デジタル署名が何を確認しているのか
  • 鍵共有やKEMがなぜ重要なのか
  • 証明書やPKIがなぜ必要なのか
  • TLSでは公開鍵暗号と共通鍵暗号がどう組み合わされるのか
  • 初学者が混同しやすいポイント
  • 耐量子暗号との関係

対象読者

この記事は、次のような人を想定しています。

  • 情報セキュリティを学び始めた人
  • 共通鍵暗号と公開鍵暗号の違いがまだ曖昧な人
  • 「公開鍵」「秘密鍵」「証明書」「署名」という言葉を整理したい人
  • TLSやHTTPSの仕組みを、暗号技術の観点から少し理解したい人
  • 暗号技術の細かい数式に入る前に、まず役割の違いをつかみたい人

本記事で扱わないこと

本記事は、公開鍵暗号の全体像を初学者向けに整理することを目的にしています。
そのため、学習用の最小コードは扱いますが、以下は詳しく扱いません。

  • RSA、楕円曲線暗号、格子暗号などの詳細な数学的仕組み
  • 素因数分解問題や離散対数問題の厳密な説明
  • 実サービスにそのまま投入できる詳細な実装コードや運用設計
  • 証明書検証の詳細な実装手順
  • 実システムにおける鍵管理設計の詳細
  • 電子署名に関する法制度の詳細

これらは重要なテーマですが、最初からすべて詰め込むと見通しが悪くなるため、必要に応じて別記事で扱います。


1. 身近な例から考える:安全に「鍵」を渡すのは意外と難しい

ネットショッピングで支払い情報を入力するとき、メッセージアプリで会話するとき、GitHubにSSHで接続するとき。
私たちは毎日のように、インターネット越しに大切な情報をやり取りしています。

このとき、多くの人が最初に思い浮かべる安全対策は「暗号化」かもしれません。
たしかに、通信内容を第三者に読まれないようにする暗号化は欠かせません。

ただし、暗号化を考えるときには、もう1つ大切な問題があります。
それは、暗号化に使う鍵を、どうやって安全に相手へ渡すのかという問題です。

1.1 鍵付きの箱で考えてみる

まずは、難しい用語から離れて、鍵付きの箱をイメージしてみます。

あなたが友人に大切な書類を送りたいとします。
そのまま送ると誰かに読まれてしまうかもしれないので、書類を箱に入れて鍵をかけます。

ここで、送り手と受け手が同じ鍵を使う方式を考えると、流れは次のようになります。

この考え方は、共通鍵暗号のイメージに近いです。
共通鍵暗号では、暗号化する側と復号する側が、基本的に同じ秘密鍵を使います。

NISTの用語集でも、共通鍵は暗号化と復号のような操作とその逆操作に使われる暗号鍵として説明されています。
参考: https://csrc.nist.gov/glossary/term/symmetric_key

1.2 共通鍵暗号は便利だが、「鍵を渡す方法」が問題になる

同じ鍵で閉めて、同じ鍵で開ける。
この考え方は直感的で、実際にも共通鍵暗号は大量のデータを効率よく保護する場面で重要です。

NISTの鍵管理に関する説明でも、共通鍵暗号は公開鍵暗号より計算効率がよく、通信中や保存中の大量の情報を保護するために広く使われると説明されています。
参考: https://csrc.nist.gov/projects/key-management/key-establishment

しかし、ここで困るのが「最初の鍵の受け渡し」です。

たとえば、友人と直接会えるなら、その場で鍵を手渡しできるかもしれません。
しかし、インターネットでは相手と直接会えません。
ネットショッピングのたびに、Webサイトの運営者と対面して鍵を交換することもできません。

つまり、共通鍵暗号そのものが便利でも、次のような問題が残ります。

場面 困ること
ネットショッピング 初めてアクセスするサイトと、事前に秘密の鍵を共有していない
メッセージアプリ 新しい相手と安全に会話を始めるための鍵をどう作るかが問題になる
SSH接続 接続先や接続者が本物か確認しながら、安全に通信したい
API通信 サーバー同士が毎回安全に通信できるようにしたい

暗号化の話をすると、つい「どうやって読めなくするか」に注目しがちです。
しかし実際には、その前段階として 「鍵をどう準備するか」 が大きなポイントになります。

1.3 インターネットでは「知らない相手」と安全に話し始める必要がある

現実世界なら、相手と直接会って鍵を渡すことができます。
しかし、インターネットでは多くの場合、初めて接続する相手と通信を始めます。

たとえば、はじめて利用するネットショップを開いたとき、あなたの端末とそのWebサーバーは、まだ共通の秘密鍵を持っていません。
それでも、住所や支払い情報を安全に送れるようにする必要があります。

この「まだ共通の秘密を持っていない相手と、どうやって安全な通信を始めるのか」という問題は、公開鍵暗号を理解するうえで大切な出発点です。

ここで登場するのが、公開鍵と秘密鍵という考え方です。

公開鍵暗号では、最初から同じ鍵を共有しておくのではなく、公開してよい鍵本人だけが守る鍵 を分けて使います。
NISTの用語集でも、公開鍵暗号は、秘密に保つ秘密鍵と、他者に提供できる公開鍵を使う暗号システムとして説明されています。
参考: https://csrc.nist.gov/glossary/term/asymmetric_key_cryptography

1.4 公開鍵暗号は「鍵を安全に渡せない問題」への重要な答え

公開鍵暗号の発想を、先ほどの箱の例で考えてみます。

受け手が「誰でも使ってよい南京錠」をたくさん配っておきます。
この南京錠は、閉めることは誰でもできます。
しかし、開けられる鍵は受け手だけが持っています。

送り手は、その南京錠で箱を閉めて送ります。
途中で誰かが箱を手に入れても、開けるための鍵を持っていないので中身を読めません。

もちろん、実際の公開鍵暗号は南京錠そのものではなく、数学的な性質を使って実現されています。
しかし、最初のイメージとしては「閉めるための情報は公開できるが、開けるための情報は本人だけが持つ」と考えると分かりやすいです。

この仕組みにより、相手と事前に秘密の鍵を共有していなくても、安全な通信を始めるための土台を作れます。

1.5 ただし、公開鍵暗号だけで全部を守るわけではない

ここまで読むと、「それなら公開鍵暗号だけ使えばよいのでは?」と思うかもしれません。

しかし、実際のシステムでは、公開鍵暗号だけで通信内容をすべて直接暗号化するというより、共通鍵暗号と組み合わせて使うことが多いです。

理由の1つは、処理効率です。
大量のデータを守る場面では、共通鍵暗号のほうが効率よく扱いやすいからです。

そのため、実際の通信では次のように役割分担することがあります。

技術 主な役割のイメージ
公開鍵暗号 最初に安全な鍵を準備する、相手を確認する、署名を検証する
共通鍵暗号 実際の通信本文を効率よく保護する

たとえばTLS 1.3では、ハンドシェイクで通信相手の認証、暗号方式の交渉、共有鍵材料の確立を行い、その後の通信データは確立した鍵を使って保護します。
RFC 8446では、TLSが盗聴、改ざん、メッセージ偽造を防ぐように設計されており、ハンドシェイクプロトコルとレコードプロトコルの2つの主要な構成要素を持つと説明されています。
参考: https://datatracker.ietf.org/doc/html/rfc8446

つまり、公開鍵暗号は「共通鍵暗号の代わり」というより、共通鍵暗号を安全に使い始めるための橋渡し役として理解すると、実際の使われ方に近づきます。

💡 豆知識
「公開鍵暗号」という名前を見ると、公開鍵で通信内容を全部暗号化しているように感じるかもしれません。
しかし実際のHTTPS通信では、公開鍵暗号・鍵共有・証明書・共通鍵暗号などが組み合わされています。
そのため、暗号技術は1つの道具ではなく、目的に応じて使い分ける「道具箱」として見ると理解しやすくなります。

この章では、公開鍵暗号が必要になる背景として、「鍵を安全に渡すのが難しい」という問題を見ました。

次の章では、この比較対象として重要な 共通鍵暗号 をもう少し整理します。
共通鍵暗号の強みと弱みを押さえることで、公開鍵暗号がなぜ必要なのかがより見えやすくなります。

2. 共通鍵暗号のおさらい:同じ鍵を持つ相手同士で守る

前の章では、「暗号化したい」という話の前に、そもそも鍵をどうやって安全に渡すのかが難しい、という問題を見ました。

ここで一度、比較対象となる 共通鍵暗号 を整理しておきます。
公開鍵暗号を理解するには、「公開鍵暗号が何を解決しようとしているのか」を知る必要があります。そのためには、まず共通鍵暗号の得意なことと困ることを押さえるのが近道です。

2.1 共通鍵暗号は「同じ鍵で閉めて、同じ鍵で開ける」方式

共通鍵暗号は、暗号化する側と復号する側が 同じ秘密鍵 を使う方式です。

たとえば、鍵付きの箱で考えると次のようなイメージです。

  • 送り手は、共通鍵で箱を閉める
  • 受け手は、同じ共通鍵で箱を開ける
  • 鍵を持っていない第三者は、中身を読めない

NISTの用語集でも、共通鍵は「暗号化と復号のような操作と逆操作の両方に使われる暗号鍵」と説明されています。
参考: NIST CSRC Glossary - Symmetric key

ここで大切なのは、同じ鍵を持っている人だけが読めるという点です。
言い換えると、鍵が守られている限り、通信内容や保存データを第三者から隠すために使えます。

2.2 代表例はAES

共通鍵暗号の代表例としてよく出てくるのが AES です。

AESは、NISTのFIPS 197として標準化されているブロック暗号です。
FIPS 197では、AES-128、AES-192、AES-256の3種類が規定されており、それぞれ鍵長が128ビット、192ビット、256ビットであることを示しています。また、いずれも128ビットのブロックを変換する方式として説明されています。
参考: NIST FIPS 197 - Advanced Encryption Standard (AES)

ここで「ブロック暗号」という言葉が出てきました。
これは、データを一定のサイズのかたまりに分けて処理する暗号方式のことです。

ただし、実際にデータを安全に暗号化するには、AESという部品だけでなく、暗号利用モード認証の仕組みも重要になります。

たとえば、現在よく使われる方式の1つに AES-GCM があります。
GCMは、暗号化だけでなく改ざん検知も一緒に行える「認証付き暗号」の方式です。NIST SP 800-38Dでは、GCMを「認証付き暗号」として規定し、GMACというメッセージ認証用の特殊化も説明しています。
参考: NIST SP 800-38D - Galois/Counter Mode (GCM) and GMAC

💡 豆知識
AESの「128」「192」「256」は、処理するデータのブロックサイズではなく、鍵の長さを表します。
AESのブロックサイズは128ビットで固定されており、鍵の長さによってAES-128、AES-192、AES-256と呼び分けられます。

2.3 共通鍵暗号が得意なこと

共通鍵暗号の大きな強みは、大量のデータを効率よく処理しやすいことです。

NISTの鍵確立に関する説明でも、共通鍵暗号は公開鍵暗号より計算効率がよく、通信中や保存中の大量の情報を保護するために広く使われると説明されています。
参考: NIST CSRC - Key Establishment

そのため、Web通信、ファイル暗号化、ディスク暗号化、VPNなど、実際のデータ本体を守る場面では、共通鍵暗号が中心的な役割を持ちます。

共通鍵暗号が得意な場面 理由
Web通信の本文保護 通信中のデータを効率よく暗号化できる
ファイル暗号化 大きなファイルでも扱いやすい
ディスク暗号化 継続的に大量データを読み書きするため効率が重要
VPN通信 長時間・大量の通信を保護する必要がある

つまり、共通鍵暗号は「実際にデータを守る現場」でよく働く技術です。

2.4 ただし、共通鍵暗号だけでは困ることがある

共通鍵暗号は便利ですが、1つ大きな問題があります。

それは、通信を始める前に、同じ秘密鍵をどうやって相手と共有するのかという問題です。

たとえば、あなたが友人とだけ暗号化したメッセージをやり取りするなら、事前に会って鍵を決めておけるかもしれません。

しかし、インターネット上のサービスではそう簡単ではありません。

  • 初めてアクセスするECサイトとは、事前に秘密鍵を共有していない
  • 世界中のユーザーと通信するサーバーが、全員と個別に鍵を手渡しすることはできない
  • 鍵をそのままネットワークに流すと、途中で盗み見られる可能性がある
  • 同じ鍵を多くの人で使い回すと、誰か1人から漏れたときの被害が大きい

図にすると、共通鍵暗号の困りどころは次のように整理できます。

ここが、公開鍵暗号につながる重要なポイントです。

共通鍵暗号は、データを守る力は強いです。
しかし、最初の鍵共有をどう安全に行うかは、別の工夫が必要になります。

2.5 AES-GCMをPythonで試してみる

ここでは、共通鍵暗号のイメージを少し具体化するために、PythonでAES-GCMを使う最小例を見てみます。

ただし、このコードは 学習用のサンプル です。
実サービスで暗号処理を実装する場合は、利用するフレームワークやクラウドサービスの推奨設定、鍵管理、運用設計まで含めて確認する必要があります。また、秘密鍵をコードに直書きしたり、ログに出力したりしてはいけません。

Pythonでは、cryptography ライブラリの AESGCM を使うと、AES-GCMによる暗号化・復号・改ざん検知を試せます。cryptography のドキュメントでは、AEADは暗号文の機密性と完全性を提供する方式であり、AES-GCMでは128、192、256ビットの鍵を使えると説明されています。
参考: cryptography documentation - Authenticated encryption

インストールしていない場合は、次のように追加します。

pip install cryptography

以下は、AES-GCMでメッセージを暗号化し、復号し、最後に暗号文を少し改ざんして検知できることを確認する例です。

import os

from cryptography.exceptions import InvalidTag
from cryptography.hazmat.primitives.ciphers.aead import AESGCM

# ============================================================
# AES-GCMの学習用サンプル
# ============================================================
# 注意:
# - このコードは仕組みを理解するための最小例です。
# - 実サービスでは、鍵管理、nonce管理、例外処理、ログ設計などを
#   用途に合わせて慎重に設計する必要があります。
# - 秘密鍵をソースコードに直書きしたり、ログに出力したりしてはいけません。
# ============================================================

# 1. AES-GCMで使う共通鍵を生成する
#    AESGCM.generate_key(bit_length=128) は128ビットの鍵を生成します。
#    生成した鍵は「秘密情報」なので、本来は安全に保管する必要があります。
key = AESGCM.generate_key(bit_length=128)

# 2. AES-GCMを使うためのオブジェクトを作成する
#    暗号化と復号の両方で同じkeyを使います。
aesgcm = AESGCM(key)

# 3. nonceを生成する
#    nonceは「同じ鍵のもとで使い回してはいけない値」です。
#    AES-GCMでは12バイトのnonceがよく使われます。
#    nonce自体は秘密にする必要はありませんが、同じkeyで再利用してはいけません。
nonce = os.urandom(12)

# 4. 暗号化したいデータを用意する
#    PythonのAESGCMはbytesを扱うため、文字列をUTF-8でbytesに変換します。
plaintext = "これは秘密のメッセージです".encode("utf-8")

# 5. AADを用意する
#    AADは「暗号化はしないが、改ざんされていないか確認したい追加データ」です。
#    例: ヘッダー、送信元情報、プロトコルのメタデータなど。
aad = "送信元:client / 宛先:server".encode("utf-8")

# 6. 暗号化する
#    encrypt() の戻り値は、暗号文と認証タグを含むbytesです。
#    認証タグは、復号時に改ざんを検知するために使われます。
ciphertext = aesgcm.encrypt(nonce, plaintext, aad)

# 7. 復号する
#    復号にも、同じkey、同じnonce、同じAADが必要です。
#    どれかが違う場合や暗号文が改ざんされた場合は、復号に失敗します。
decrypted = aesgcm.decrypt(nonce, ciphertext, aad)

print(decrypted.decode("utf-8"))

# 8. 改ざん検知を試す
#    暗号文の先頭1バイトを変更して、復号できなくなることを確認します。
tampered_ciphertext = bytearray(ciphertext)
tampered_ciphertext[0] ^= 0x01  # 1ビットだけ反転させる

try:
    aesgcm.decrypt(nonce, bytes(tampered_ciphertext), aad)
except InvalidTag:
    print("改ざん、または鍵・nonce・AADの不一致を検知しました")

実行すると、最初の復号では元のメッセージが表示され、改ざんした暗号文では InvalidTag が発生します。

これは秘密のメッセージです
改ざん、または鍵・nonce・AADの不一致を検知しました

この例から分かるように、AES-GCMでは単に「読めない形にする」だけではなく、途中で書き換えられていないかを確認する役割も持てます。

2.6 コードから見る重要ポイント

先ほどのコードで特に重要なのは、次の4つです。

要素 役割 注意点
key 暗号化・復号に使う共通鍵 絶対に漏らさない。コードに直書きしない。
nonce 同じ鍵で暗号化するたびに変える値 秘密ではないが、同じ鍵で再利用しない。
aad 暗号化しないが改ざん検知したい追加データ 復号時にも同じ値が必要。
ciphertext 暗号化されたデータと認証タグを含むデータ 改ざんされると復号に失敗する。

cryptography のドキュメントでも、AES-GCMでは同じ鍵でnonceを再利用してはいけないこと、暗号文には16バイトの認証タグが付くこと、タグ検証に失敗すると InvalidTag が発生することが説明されています。
参考: cryptography documentation - AESGCM

ここで特に注意したいのは、nonce です。

nonceは「Number used once」の略として説明されることが多く、文字どおり一度だけ使う値というイメージです。
nonce自体は秘密ではありません。暗号文と一緒に送ってもよい値です。

しかし、同じ鍵で同じnonceを使い回すことは危険です。
そのため、実装では「安全な乱数で生成する」「カウンタで重複しないように管理する」など、方式や利用場面に応じた設計が必要になります。

💡 豆知識
「nonce」は「一度だけ使う値」という意味でよく説明されます。
ただし、「完全にランダムでなければならない」というより、方式ごとに求められる条件を満たし、同じ鍵のもとで重複しないことが重要です。
AES-GCMでは、このnonceの扱いを間違えると安全性に大きく影響します。

2.7 共通鍵暗号の強みと弱みをまとめる

ここまでをまとめると、共通鍵暗号は次のような技術です。

観点 内容
基本 暗号化と復号に同じ秘密鍵を使う
強み 大量データを効率よく保護しやすい
代表例 AES、ChaCha20、AES-GCM、ChaCha20-Poly1305など
注意点 鍵を安全に共有・保管する必要がある
実サービスでの役割 通信本文や保存データの保護で重要

共通鍵暗号は、暗号技術の中でも実用性の高い強力な道具です。
しかし、インターネットのように「まだ秘密鍵を共有していない相手」と通信を始める場面では、鍵の受け渡しが問題になります。

そこで次の章では、いよいよ 公開鍵暗号 の基本に入ります。

公開鍵暗号は、共通鍵暗号の代わりというより、共通鍵暗号を安全に使い始めるための土台として登場します。
その中心になるのが、公開してよい公開鍵自分だけが守る秘密鍵 という考え方です。


3. 公開鍵暗号の基本:公開鍵と秘密鍵を分けて考える

前の章では、共通鍵暗号が「同じ鍵を持っている相手同士」でデータを守る方式であることを見ました。
共通鍵暗号は大量データを効率よく守れる一方で、最初にその鍵をどうやって安全に共有するのか、という問題がありました。

ここで登場するのが 公開鍵暗号 です。

公開鍵暗号では、最初から同じ秘密鍵を共有しておくのではなく、次の2つの鍵をペアで使います。

  • 公開鍵:相手に渡してよい鍵
  • 秘密鍵:自分だけが守る鍵

NISTの用語集では、公開鍵暗号は、秘密に保つ秘密鍵と、他者に提供できる公開鍵を使う暗号システムとして説明されています。
参考: NIST CSRC Glossary - Asymmetric-key cryptography

また、公開鍵は「非対称暗号アルゴリズムで使われ、秘密鍵と対応しており、公開してよい鍵」と説明されています。デジタル署名の場合は、対応する秘密鍵で作られた署名を検証するためにも使われます。
参考: NIST CSRC Glossary - Public key

3.1 「公開してよい鍵」と「絶対に守る鍵」

公開鍵暗号で最初に混乱しやすいのは、鍵なのに公開してよいものがあるという点です。

日常生活の感覚では、鍵は人に見せてはいけないものです。
家の鍵を誰かにコピーされたら困りますし、ロッカーの鍵をなくすと中身を守れなくなります。

しかし、公開鍵暗号では少し考え方が変わります。

公開鍵は、他の人に渡してもよい鍵です。
一方で、秘密鍵は本人だけが守る必要があります。

だれが持つか 主な使い道 漏れたときの影響
公開鍵 他の人に配ってよい 暗号化、署名検証など それだけでは通常すぐ秘密は漏れない。ただし偽物とすり替えられると危険
秘密鍵 本人だけが持つ 復号、署名生成など 復号されたり、本人になりすまされて署名されたりする可能性がある

ここで大切なのは、公開鍵と秘密鍵が 別々の無関係な鍵ではなく、数学的に対応したペア であることです。
公開鍵で暗号化したものは、対応する秘密鍵で復号できます。
秘密鍵で作った署名は、対応する公開鍵で検証できます。

ただし、上の図はあくまで役割のイメージです。
暗号化と署名では、同じ「公開鍵」「秘密鍵」という言葉が出てきますが、目的は異なります。

  • 暗号化:第三者に読まれないようにする
  • 署名:誰が作ったものか、途中で改ざんされていないかを確認する

この違いは、第5章で改めて整理します。

3.2 公開鍵暗号を箱の例で考える

もう一度、箱の例に戻って考えてみます。

共通鍵暗号では、送り手と受け手が同じ鍵を持っていました。
そのため、箱を閉める鍵と開ける鍵が同じです。

一方、公開鍵暗号では、次のように考えるとイメージしやすくなります。

  1. 受け手が「誰でも閉められる南京錠」を配る
  2. 送り手は、その南京錠で箱を閉める
  3. 閉められた箱は、受け手だけが持つ鍵で開ける
  4. 途中で誰かが箱を見ても、開ける鍵を持っていなければ中身を読めない

この例でいうと、公開鍵は「誰でも閉められる南京錠」に近い存在です。
秘密鍵は、その南京錠を開けられる本人専用の鍵にあたります。

もちろん、実際の公開鍵暗号は物理的な南京錠ではなく、数学的な計算で実現されています。
しかし、最初の理解としては、閉めるための情報は公開できるが、開けるための情報は本人だけが持つ と考えると分かりやすいです。

3.3 公開鍵暗号の裏側にある「一方向性」のイメージ

公開鍵暗号が成り立つ背景には、ざっくり言うと 一方向には計算しやすいが、逆向きに戻すのは現実的には難しい という考え方があります。

たとえば、RSAでは大きな素数に関係する数学的な性質を利用します。
細かい安全性証明や実装上の注意点はここでは扱いませんが、イメージとしては次のような流れです。

1. 大きな素数 p, q を選ぶ
2. n = p × q を計算する
3. n などから公開鍵を作る
4. p, q などの秘密情報から秘密鍵を作る

掛け算そのものは簡単です。
しかし、非常に大きな数 n だけを見て、元の pq を求めることは難しくなります。

この「計算しやすい向き」と「戻すのが難しい向き」の差を利用することで、公開鍵を配っても秘密鍵を守る仕組みを作ります。

RSAについては、RFC 8017で、RSAアルゴリズムに基づく公開鍵暗号の実装に関する推奨事項がまとめられています。RFC 8017では、暗号化方式、署名方式、鍵の表現などが扱われています。
参考: RFC 8017 - PKCS #1: RSA Cryptography Specifications Version 2.2

💡 豆知識
RSAという名前は、提案者である Rivest、Shamir、Adleman の3人の名前に由来します。
暗号技術の名前には、AESのように標準名から来るものもあれば、RSAのように研究者名に由来するものもあります。

3.4 注意:教科書的なRSAをそのまま使うわけではない

RSAの説明では、よく次のような式が出てきます。

暗号化: c = m^e mod n
復号  : m = c^d mod n

ここで、m は元のメッセージ、c は暗号文、en は公開鍵に含まれる値、d は秘密鍵に関係する値です。

ただし、このような 教科書的なRSAをそのまま実装に使うのは危険 です。
実際には、メッセージに適切なパディングを加えたり、乱数性を持たせたりする必要があります。

たとえば、RSAで暗号化を行う場合には、RSA-OAEPのような方式が使われます。
RFC 8017でも、RSAES-OAEPという暗号化方式が規定されています。
参考: RFC 8017 - RSAES-OAEP

そのため、記事や学習でRSAの数式を見るときは、次のように分けて考えるのが安全です。

観点 内容
教科書的な式 公開鍵暗号の雰囲気を理解するためのモデル
実際の実装 OAEPやPSSなど、安全に使うための方式を組み合わせる
学習時の注意 数式をそのままコード化して使わない

暗号技術では、「数学的にそれっぽく動くこと」と「実際に安全に使えること」は別です。
この違いは大切です。

3.5 PythonでRSA-OAEPによる「共通鍵の受け渡し」を試す

ここでは、公開鍵暗号のイメージを具体化するために、PythonでRSA-OAEPを使う例を見てみます。

ただし、このコードも 学習用のサンプル です。
実サービスでは、鍵の生成・保存・ローテーション・失効・アクセス制御・監査ログなど、運用面の設計が必要になります。秘密鍵をソースコードに直書きしたり、リポジトリに含めたりしてはいけません。

また、公開鍵暗号は大量データを直接暗号化する用途には向きません。
そこでこの例では、2章のAES-GCMにつながるように、通信本文そのものではなく、AES-GCMで使う共通鍵をRSA-OAEPで暗号化する 形にします。

cryptography のRSAドキュメントでは、OAEPはRSA暗号化で使われるパディング方式として説明されています。
参考: cryptography documentation - RSA

インストールしていない場合は、次のように追加します。

pip install cryptography

以下は、RSAの鍵ペアを生成し、公開鍵でAES用の共通鍵を暗号化し、秘密鍵で復号する例です。

import os

from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding, rsa

# ============================================================
# RSA-OAEPの学習用サンプル
# ============================================================
# 注意:
# - このコードは、公開鍵暗号の考え方を理解するための最小例です。
# - 実サービスでは、秘密鍵の保存、アクセス制御、ローテーション、
#   失効、監査ログなどを含めた鍵管理が必要です。
# - 秘密鍵をソースコードに直書きしたり、GitHubなどに置いたりしてはいけません。
# ============================================================

# 1. RSAの秘密鍵を生成する
#    public_exponent=65537 は、RSAで広く使われる公開指数です。
#    key_size=2048 は学習用の例として指定しています。
private_key = rsa.generate_private_key(
    public_exponent=65537,
    key_size=2048,
)

# 2. 秘密鍵に対応する公開鍵を取り出す
#    この公開鍵は、相手に渡してよい情報です。
public_key = private_key.public_key()

# 3. AES-GCMなどの共通鍵暗号で使う鍵を用意する
#    ここでは256ビット、つまり32バイトのランダムな鍵を作っています。
#    実際の通信では、このような共通鍵を使って本文データを効率よく暗号化します。
session_key = os.urandom(32)

# 4. 公開鍵で共通鍵を暗号化する
#    OAEPは、RSA暗号化を安全に使うためのパディング方式です。
#    ここではSHA-256を使っています。
encrypted_session_key = public_key.encrypt(
    session_key,
    padding.OAEP(
        mgf=padding.MGF1(algorithm=hashes.SHA256()),
        algorithm=hashes.SHA256(),
        label=None,
    ),
)

# 5. 秘密鍵で共通鍵を復号する
#    復号できるのは、対応する秘密鍵を持っている側だけです。
decrypted_session_key = private_key.decrypt(
    encrypted_session_key,
    padding.OAEP(
        mgf=padding.MGF1(algorithm=hashes.SHA256()),
        algorithm=hashes.SHA256(),
        label=None,
    ),
)

# 6. 元の共通鍵と復号した共通鍵が一致するか確認する
#    一致すれば、公開鍵で包んだ共通鍵を、秘密鍵で取り出せたことになります。
print(session_key == decrypted_session_key)

実行すると、次のように表示されます。

True

このコードで確認したいポイントは、次の流れです。

つまり、公開鍵暗号はここでは「通信本文を全部暗号化する主役」というより、共通鍵を安全に届けるための包み紙 のような役割をしています。

3.6 間違った秘密鍵では復号できない

公開鍵暗号のイメージをもう少し確かめるために、別の秘密鍵で復号しようとするとどうなるかを見てみます。

# 7. 別人の秘密鍵を生成する
#    これは、正しい秘密鍵を持っていない第三者を表すための鍵です。
wrong_private_key = rsa.generate_private_key(
    public_exponent=65537,
    key_size=2048,
)

try:
    # 8. 間違った秘密鍵で復号しようとする
    #    公開鍵と対応していない秘密鍵では、正しく復号できません。
    wrong_private_key.decrypt(
        encrypted_session_key,
        padding.OAEP(
            mgf=padding.MGF1(algorithm=hashes.SHA256()),
            algorithm=hashes.SHA256(),
            label=None,
        ),
    )
except ValueError:
    print("対応する秘密鍵ではないため、復号できませんでした")

実行すると、次のように表示されます。

対応する秘密鍵ではないため、復号できませんでした

ここから分かるのは、公開鍵と秘密鍵が ペアとして対応している ということです。

公開鍵は誰に渡してもよい情報ですが、その公開鍵で暗号化された情報を取り出せるのは、対応する秘密鍵を持つ人だけです。

補足
上のコードでは分かりやすさを優先して、RSA鍵ペアをその場で生成しています。
実際のシステムでは、秘密鍵をどこで生成し、どこに保存し、誰が使えるようにするかが非常に重要になります。
このような鍵管理の考え方については、NIST SP 800-57 Part 1 Rev.5でも整理されています。
参考: NIST SP 800-57 Part 1 Rev.5 - Recommendation for Key Management

3.7 公開鍵暗号で大切なのは「公開鍵が本物か」

ここまで見ると、公開鍵暗号はかなり便利に見えます。

しかし、公開鍵暗号には大切な注意点があります。
それは、受け取った公開鍵が本当に相手のものなのかを確認する必要がある という点です。

たとえば、あなたがネットショップと安全に通信したいとします。
そのとき、攻撃者が途中で偽物の公開鍵を渡してきたらどうなるでしょうか。

あなたはネットショップの公開鍵だと思って暗号化します。
しかし実際には、それは攻撃者の公開鍵かもしれません。
その場合、攻撃者は自分の秘密鍵で中身を読めてしまう可能性があります。

つまり、公開鍵は「公開してよい」ものですが、誰の公開鍵なのかを確認しなくてよい という意味ではありません。

この問題を解決するために、Webの世界では証明書やPKIという仕組みが使われます。
証明書については、第6章で詳しく整理します。

3.8 この章のまとめ

この章では、公開鍵暗号の基本として、公開鍵と秘密鍵の考え方を整理しました。

ポイント 内容
公開鍵 他の人に渡してよい鍵
秘密鍵 本人だけが守る鍵
暗号化の使い方 公開鍵で暗号化し、秘密鍵で復号する
署名の使い方 秘密鍵で署名し、公開鍵で検証する
実用上の注意 公開鍵が本当に相手のものか確認する必要がある

公開鍵暗号は、共通鍵暗号で問題になった「最初の鍵共有」を助ける重要な技術です。
ただし、公開鍵暗号だけですべてを守るわけではありません。

次の章では、ここまで見てきた 共通鍵暗号公開鍵暗号 の違いを、表や具体例を使って整理します。


4. 共通鍵暗号と公開鍵暗号の違い

前章までで、共通鍵暗号と公開鍵暗号をそれぞれ見てきました。

共通鍵暗号は、同じ秘密鍵を持っている相手同士でデータを守る方式でした。
一方、公開鍵暗号は、公開鍵と秘密鍵という2種類の鍵を使う方式でした。

ここで大切なのは、どちらが上位互換かという見方をしないことです。

共通鍵暗号と公開鍵暗号は、得意なことが違います。
実際のサービスでは、片方だけで完結するというより、それぞれの得意分野を組み合わせて使うことが多いです。

この章では、両者の違いを「鍵の考え方」「得意なこと」「困りごと」「実サービスでの役割」という視点から整理します。

4.1 まずは全体像を表で見る

まず、共通鍵暗号と公開鍵暗号の違いを表で見てみます。

観点 共通鍵暗号 公開鍵暗号
鍵の考え方 同じ秘密鍵を共有する 公開鍵と秘密鍵のペアを使う
鍵を秘密にする範囲 共通鍵を持つ全員が秘密にする 秘密鍵だけを本人が守り、公開鍵は配布できる
得意なこと 大量データの暗号化・復号 鍵共有、鍵配送、署名、相手確認
苦手なこと 最初の鍵共有が難しい 大量データを直接処理する用途には向きにくい
代表例 AES、ChaCha20、AES-GCM、ChaCha20-Poly1305 RSA、Diffie-Hellman、ECDH、ECDSA、EdDSA、ML-KEM、ML-DSA
実サービスでの役割 通信本文や保存データを効率よく守る 通信開始時の鍵共有、証明書、デジタル署名などを支える

NISTの用語集では、共通鍵は暗号化と復号のような操作と逆操作に使われる単一の暗号鍵として説明されています。
参考: NIST CSRC Glossary - Symmetric key

一方、公開鍵は、秘密鍵と対応する非対称暗号アルゴリズム用の鍵であり、公開してよい鍵として説明されています。デジタル署名では、対応する秘密鍵で作られた署名を検証するためにも使われます。
参考: NIST CSRC Glossary - Public key

ここから分かるように、両者の違いは「鍵が1つか2つか」だけではありません。
どの場面で、何を守るために使うのか が大きく違います。

4.2 鍵の考え方が違う

共通鍵暗号では、送り手と受け手が同じ鍵を持ちます。

この方式では、鍵を持っている人なら暗号化も復号もできます。
そのため、鍵を共有する相手が増えるほど、鍵を安全に管理する難しさも増えます。

一方、公開鍵暗号では、公開鍵と秘密鍵を分けます。

公開鍵は相手に渡せます。
しかし、秘密鍵は本人だけが守ります。

この仕組みによって、インターネットのように相手と直接会えない環境でも、安全な通信を始めるための準備がしやすくなります。

ただし、公開鍵暗号にも別の問題があります。
それは、受け取った公開鍵が本当に相手のものか確認する必要があるという点です。

公開鍵は公開できるからこそ、攻撃者が偽物の公開鍵を渡してくる可能性もあります。
この問題を扱うのが、第6章で説明する証明書やPKIです。

4.3 守る場面が違う

共通鍵暗号と公開鍵暗号は、守る場面も違います。

共通鍵暗号は、通信本文や保存データのような 実際のデータ本体 を守る場面でよく使われます。
たとえば、Web通信で送られるリクエストやレスポンス、ファイル暗号化、ディスク暗号化などです。

公開鍵暗号は、どちらかというと 安全な通信を始めるための準備相手・データの確認 で重要になります。

場面 主に使われる技術 理由
大きなファイルを暗号化する 共通鍵暗号 大量データを効率よく処理しやすい
HTTPS通信の本文を守る 共通鍵系の暗号・AEAD 通信データを継続的に保護する必要がある
サーバーが本物か確認する 公開鍵暗号、証明書、デジタル署名 公開鍵と証明書を使って相手を確認する
通信に使う鍵を安全に準備する 公開鍵暗号、鍵共有、KEM 事前に共通鍵を持っていない相手と安全に通信を始めるため
ソフトウェアの配布元を確認する デジタル署名 秘密鍵で署名し、公開鍵で検証できるため

ここで注意したいのは、公開鍵暗号が「データを守らない」という意味ではないことです。
公開鍵暗号も、暗号化や署名に使われます。

ただし、実際の通信では、公開鍵暗号だけで通信本文をすべて直接暗号化するというより、共通鍵を安全に準備したり、相手を確認したりするために使われることが多いです。

RFC 5280でも、公開鍵で生の利用者データを直接暗号化する dataEncipherment の用途は非常に一般的ではなく、ほとんどのアプリケーションでは鍵配送や鍵共有によって共通鍵を確立すると説明されています。
参考: RFC 5280 - Internet X.509 Public Key Infrastructure Certificate and CRL Profile

4.4 処理効率の考え方が違う

公開鍵暗号は便利ですが、共通鍵暗号と同じ感覚で大量データを処理するものではありません。

2章で見たように、AES-GCMのような共通鍵系の方式は、通信本文やファイルのようなデータを効率よく保護する場面で活躍します。
一方、3章で試したRSA-OAEPの例では、通信本文そのものではなく、AES-GCMで使う共通鍵を包む形にしました。

これは、実際のシステムでよく使われる考え方です。

イメージとしては、次のように分けると分かりやすいです。

役割 例え 暗号技術
大きな荷物を運ぶ 実際の荷物を効率よく運ぶトラック 共通鍵暗号
トラックの鍵を安全に渡す 鍵を安全に受け渡す仕組み 公開鍵暗号、鍵共有、KEM
相手が本物か確認する 受け取り先の身分証を確認する 証明書、デジタル署名

つまり、公開鍵暗号は「すべてのデータを直接守る万能道具」というより、共通鍵暗号を安全に使い始めるための重要な道具として見ると、実際の使われ方に近づきます。

💡 豆知識
「公開鍵暗号は共通鍵暗号より高度だから、全部公開鍵暗号で暗号化すればよい」と考えたくなるかもしれません。
しかし、暗号技術では「高度そうか」よりも「目的に合っているか」が大切です。
大量データを守るなら共通鍵暗号、相手確認や鍵共有なら公開鍵暗号、というように役割分担して使うのが基本です。

4.5 実サービスでは組み合わせて使う

実際のWeb通信では、共通鍵暗号と公開鍵暗号が組み合わされます。

たとえばTLS 1.3では、ハンドシェイクで通信相手の認証、暗号方式やパラメータの交渉、共有鍵材料の確立を行います。
その後、レコードプロトコルがハンドシェイクで確立したパラメータを使い、通信データを保護します。RFC 8446では、TLS 1.3の残された暗号スイートがAEADアルゴリズムであり、認証・鍵交換の仕組みとレコード保護アルゴリズムを分けるように変更されたことも説明されています。
参考: RFC 8446 - The Transport Layer Security (TLS) Protocol Version 1.3

ざっくり図にすると、次のような流れです。

この流れを見ると、公開鍵暗号と共通鍵暗号の関係が見えやすくなります。

  • 公開鍵暗号は、通信を始めるときの認証や鍵共有を支える
  • 共通鍵暗号は、その後の通信本文を効率よく守る
  • 証明書は、公開鍵が本当に相手のものか確認するために使われる

このように、実サービスでは複数の暗号技術が役割分担して動いています。

4.6 「どちらが安全か」ではなく「何に使うか」で考える

共通鍵暗号と公開鍵暗号を比べるとき、「どちらが安全なのか」と考えたくなるかもしれません。

しかし、この質問には単純には答えられません。

なぜなら、安全性は次のような要素に左右されるからです。

  • どのアルゴリズムを使うか
  • 鍵長が十分か
  • 実装が正しいか
  • 乱数やnonceを正しく扱っているか
  • 秘密鍵や共通鍵を安全に保管できているか
  • 古い方式や非推奨の方式を使っていないか
  • 証明書検証や失効確認を適切に行っているか

たとえば、AES-GCMを使っていても、同じ鍵とnonceを使い回すと危険です。
RSAを使っていても、教科書的なRSAをそのまま使ったり、秘密鍵を漏らしたりすれば安全ではありません。

また、鍵長の数字だけをそのまま比較するのも注意が必要です。
AES-256の「256」とRSA-2048の「2048」は、どちらも鍵長に関係する数字ですが、方式が違うため、単純に「2048のほうが8倍強い」とは言えません。

CRYPTRECの暗号リストでも、公開鍵暗号、共通鍵暗号、ハッシュ関数、メッセージ認証コードなどは用途ごとに分類されています。
この分類からも、暗号技術は1つの物差しで比べるより、用途に応じて選ぶものだと分かります。
参考: CRYPTREC - Specifications of CRYPTREC Ciphers List

4.7 この章のまとめ

この章では、共通鍵暗号と公開鍵暗号の違いを整理しました。

観点 まとめ
共通鍵暗号 同じ秘密鍵を共有し、通信本文や保存データを効率よく守る
公開鍵暗号 公開鍵と秘密鍵のペアを使い、鍵共有・署名・相手確認を支える
両者の関係 どちらか一方が上位互換ではなく、役割が違う
実サービス TLSのように、公開鍵暗号と共通鍵暗号を組み合わせて使うことが多い

公開鍵暗号を理解するときは、「公開鍵で暗号化して秘密鍵で復号する」という説明だけで止まらないことが大切です。

実際には、公開鍵暗号は暗号化だけでなく、署名や鍵共有にも関わります。
また、共通鍵暗号を安全に使い始めるための橋渡し役としても重要です。

次の章では、公開鍵暗号でできることを 暗号化・デジタル署名・鍵共有 の3つに分けて、もう少し具体的に整理します。


5. 公開鍵暗号でできること

前章では、公開鍵暗号が「公開鍵」と「秘密鍵」のペアを使う仕組みだと整理しました。

では、公開鍵暗号は実際に何をしているのでしょうか。
この章では、公開鍵暗号の代表的な役割を次の3つに分けて整理します。

役割 何をするか 身近な例
暗号化・鍵配送 相手の公開鍵で秘密情報を包み、相手だけが秘密鍵で取り出せるようにする 共通鍵を安全に渡す、ハイブリッド暗号
デジタル署名 自分の秘密鍵で署名し、相手が公開鍵で検証できるようにする ソフトウェア配布、電子署名、ブロックチェーンの取引
鍵共有・KEM 通信に使う共通鍵を、ネットワーク越しに安全に作る HTTPS/TLS、メッセージアプリ、耐量子暗号

ポイントは、公開鍵暗号でできることは「暗号化」だけではないということです。

公開鍵暗号は、通信内容を隠すためだけでなく、相手を確認したり、データが改ざんされていないことを確かめたり、共通鍵暗号を安全に使い始めるためにも使われます。

5.1 暗号化・鍵配送

まずは、もっともイメージしやすい「暗号化」から見ていきます。

公開鍵暗号による暗号化では、基本的に次のような流れになります。

  1. 受け手が公開鍵と秘密鍵のペアを作る
  2. 受け手は公開鍵を送り手に渡す
  3. 送り手は受け手の公開鍵でデータを暗号化する
  4. 受け手は自分だけが持つ秘密鍵で復号する

この考え方は、3章で扱ったRSA-OAEPのサンプルコードと同じ方向です。
RSA-OAEPは、RSA暗号化を安全に使うための方式としてRFC 8017で定義されています。
参考: RFC 8017 - PKCS #1: RSA Cryptography Specifications Version 2.2

ただし、ここで大切な注意点があります。

実際の通信では、公開鍵暗号で長い本文データをそのまま全部暗号化するとは限りません。

たとえば、Web通信でやり取りするデータは、HTML、画像、JSON、ファイルなど、サイズが大きくなることがあります。
これらをすべて公開鍵暗号だけで処理するのは効率がよくありません。

そのため、実際には次のように組み合わせることが多いです。

  1. 本文データを守るための共通鍵を用意する
  2. その共通鍵を公開鍵暗号で安全に受け渡す、または共有する
  3. 実際の本文データはAES-GCMなどの共通鍵暗号で暗号化する

このように、公開鍵暗号と共通鍵暗号を組み合わせる考え方は、ハイブリッド暗号と呼ばれることがあります。

RFC 9180で定義されているHPKE(Hybrid Public Key Encryption)も、公開鍵暗号と共通鍵暗号を組み合わせて、受信者の公開鍵に対して任意サイズの平文を暗号化するための仕組みとして説明されています。
参考: RFC 9180 - Hybrid Public Key Encryption

💡 豆知識
「公開鍵暗号」と聞くと、公開鍵でメッセージ本文を全部暗号化するイメージを持ちやすいです。
しかし実際には、公開鍵暗号は 共通鍵を安全に準備するための役割 を担い、本文の暗号化は共通鍵暗号が担当する、という分担がよく使われます。

5.2 デジタル署名

公開鍵暗号でもう1つ重要なのが、デジタル署名です。

デジタル署名は、紙の署名や印鑑のように「本人が確認した」という意味合いを持ちます。
ただし、実際には画像としてのサインを貼り付けるものではありません。

デジタル署名では、次のように鍵を使います。

役割
秘密鍵 署名を作るために使う
公開鍵 署名が正しいか検証するために使う

暗号化では「公開鍵で暗号化し、秘密鍵で復号する」と説明されることが多いですが、署名では向きが少し変わります。

  • 署名を作る人だけが、秘密鍵を使って署名を作る
  • 検証する人は、公開鍵を使って署名が正しいか確認する

NIST FIPS 186-5では、デジタル署名は、データの不正な変更の検出、署名者の認証、第三者に対して署名者が生成したことを示す証拠として使われると説明されています。
参考: NIST FIPS 186-5 - Digital Signature Standard

つまり、デジタル署名で主に確認できるのは次の3つです。

観点 説明
改ざん検出 署名後にデータが変わると、検証に失敗する
署名者の確認 対応する秘密鍵を持つ人が署名したことを確認できる
否認防止の材料 後から「自分は署名していない」と否定しにくくする材料になる

ただし、「署名者の確認」は、その公開鍵が本当に署名者のものだと確認できていることが前提です。
この点は、次の6章で扱う証明書やPKIにつながります。

PythonでRSA-PSS署名を試す

ここでは、RSA-PSSを使って「署名」と「検証」のイメージを確認します。

cryptography の公式ドキュメントでは、RSA署名のパディングとしてPSSが新しいプロトコルやアプリケーションで推奨される選択肢と説明されています。
参考: cryptography documentation - RSA

以下は学習用の最小例です。

# ============================================================
# RSA-PSSによるデジタル署名の学習用サンプル
# ============================================================
# 注意:
# - このコードは、署名と検証の流れを理解するための最小例です。
# - 実サービスでは、秘密鍵の安全な保管、鍵のローテーション、
#   証明書の検証、ログ設計などを用途に合わせて設計する必要があります。
# - 秘密鍵をソースコードに直書きしたり、リポジトリに含めたりしてはいけません。
# ============================================================

from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding, rsa

# 1. 署名者の秘密鍵を生成する
#    実サービスでは、秘密鍵は安全な場所で生成・保管します。
private_key = rsa.generate_private_key(
    public_exponent=65537,
    key_size=2048,
)

# 2. 秘密鍵に対応する公開鍵を取り出す
#    検証者は、この公開鍵を使って署名を検証します。
public_key = private_key.public_key()

# 3. 署名したいメッセージを用意する
#    ここでは、ソフトウェア更新ファイルや取引データの代わりに短い文字列を使います。
message = b"transfer 1000 yen to Bob"

# 4. 秘密鍵でメッセージに署名する
#    PSSはRSA署名で使われるパディング方式です。
#    SHA-256は、メッセージを固定長の値に要約するハッシュ関数です。
signature = private_key.sign(
    message,
    padding.PSS(
        mgf=padding.MGF1(hashes.SHA256()),
        salt_length=padding.PSS.MAX_LENGTH,
    ),
    hashes.SHA256(),
)

print("signature length:", len(signature))

# 5. 公開鍵で署名を検証する
#    メッセージと署名が正しく対応していれば、例外は発生しません。
try:
    public_key.verify(
        signature,
        message,
        padding.PSS(
            mgf=padding.MGF1(hashes.SHA256()),
            salt_length=padding.PSS.MAX_LENGTH,
        ),
        hashes.SHA256(),
    )
    print("署名の検証に成功しました")
except InvalidSignature:
    print("署名の検証に失敗しました")

# 6. メッセージを改ざんして検証する
#    署名後にメッセージが変わると、同じ署名では検証に失敗します。
tampered_message = b"transfer 9000 yen to Bob"

try:
    public_key.verify(
        signature,
        tampered_message,
        padding.PSS(
            mgf=padding.MGF1(hashes.SHA256()),
            salt_length=padding.PSS.MAX_LENGTH,
        ),
        hashes.SHA256(),
    )
    print("改ざん後のメッセージでも検証に成功しました")
except InvalidSignature:
    print("改ざんを検知しました")

実行すると、元のメッセージでは署名検証に成功し、改ざんしたメッセージでは検証に失敗します。

signature length: 256
署名の検証に成功しました
改ざんを検知しました

ここで大切なのは、デジタル署名は メッセージを隠すための仕組みではない という点です。

署名されたメッセージ自体は、必要に応じて公開されることもあります。
署名が守っているのは、主に「誰が署名したのか」「途中で変えられていないか」という点です。

💡 豆知識
ブロックチェーンの取引でも、秘密鍵で取引データに署名し、ネットワーク上の参加者が署名を検証する考え方が使われます。
ここでも大切なのは、「秘密鍵を持つ人だけが正しい署名を作れる」という性質です。

5.3 鍵共有・KEM

最後に、鍵共有とKEMを見ていきます。

共通鍵暗号では、通信する2者が同じ秘密鍵を持つ必要がありました。
しかし、インターネット上では、事前に直接会って鍵を渡せるとは限りません。

そこで使われるのが、鍵共有KEMです。

鍵共有:同じ秘密を直接送らずに作る

鍵共有の代表例として、Diffie-Hellman系の方式があります。

Diffie-Hellman系の鍵共有では、最終的に使う共通鍵そのものをネットワークに流すのではなく、互いの公開情報を交換し、それぞれが手元の秘密情報と組み合わせて同じ共有秘密を計算します。

NIST SP 800-56A Rev.3では、有限体や楕円曲線上の離散対数問題に基づくDiffie-Hellman系の鍵確立方式が扱われています。
参考: NIST SP 800-56A Rev.3 - Recommendation for Pair-Wise Key-Establishment Schemes

PythonでX25519鍵共有を試す

ここでは、楕円曲線Diffie-Hellman系の例として、X25519を使った鍵共有を見てみます。

cryptography の公式ドキュメントでは、X25519は安全でない通信路上で2者が共有秘密に合意できる楕円曲線Diffie-Hellman鍵共有であり、得られた共有秘密は多くの場合、HKDFなどの鍵導出関数に通すべきだと説明されています。
参考: cryptography documentation - X25519 key exchange

# ============================================================
# X25519による鍵共有の学習用サンプル
# ============================================================
# 注意:
# - このコードは、鍵共有の考え方を理解するための最小例です。
# - 実サービスでは、相手の公開鍵が本物か確認する仕組み、
#   セッションごとの鍵生成、鍵導出時のパラメータ設計などが必要です。
# - 共有秘密をそのまま暗号鍵として使うのではなく、通常はHKDFなどで鍵導出します。
# ============================================================

from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import x25519
from cryptography.hazmat.primitives.kdf.hkdf import HKDF

# 1. Aliceの秘密鍵と公開鍵を生成する
#    秘密鍵はAliceだけが持ち、公開鍵はBobへ送れます。
alice_private_key = x25519.X25519PrivateKey.generate()
alice_public_key = alice_private_key.public_key()

# 2. Bobの秘密鍵と公開鍵を生成する
#    秘密鍵はBobだけが持ち、公開鍵はAliceへ送れます。
bob_private_key = x25519.X25519PrivateKey.generate()
bob_public_key = bob_private_key.public_key()

# 3. Alice側で共有秘密を計算する
#    Aliceの秘密鍵とBobの公開鍵を組み合わせます。
alice_shared_secret = alice_private_key.exchange(bob_public_key)

# 4. Bob側で共有秘密を計算する
#    Bobの秘密鍵とAliceの公開鍵を組み合わせます。
bob_shared_secret = bob_private_key.exchange(alice_public_key)

# 5. 両者が計算した共有秘密が一致することを確認する
#    共有秘密そのものはネットワーク上に送っていません。
assert alice_shared_secret == bob_shared_secret

# 6. 共有秘密から、実際に使うセッション鍵を導出する
#    HKDFに通すことで、暗号用途に使いやすい鍵を作ります。
def derive_session_key(shared_secret: bytes) -> bytes:
    return HKDF(
        algorithm=hashes.SHA256(),
        length=32,              # 32バイト = 256ビットの鍵を導出する
        salt=None,              # 学習用のためNone。実設計では用途に応じて検討する
        info=b"demo handshake", # この鍵がどの文脈で使われるかを表す情報
    ).derive(shared_secret)

alice_session_key = derive_session_key(alice_shared_secret)
bob_session_key = derive_session_key(bob_shared_secret)

# 7. AliceとBobが同じセッション鍵を得たことを確認する
assert alice_session_key == bob_session_key

print("Alice and Bob derived the same session key")
print("session key length:", len(alice_session_key))

実行例は次のようになります。

Alice and Bob derived the same session key
session key length: 32

このコードでは、AliceとBobが共有秘密そのものをネットワークに送っていない点が重要です。
お互いの公開鍵は交換していますが、秘密鍵はそれぞれの手元に残ります。
そのうえで、両者が同じセッション鍵を導出できています。

ただし、ここでも注意があります。

このコードだけでは、「受け取った公開鍵が本当に相手のものか」は確認していません。
そのため、実際の通信では、証明書や署名などを使って相手確認を組み合わせる必要があります。

KEM:共通鍵を作るためのもう1つの考え方

KEMは、Key Encapsulation Mechanism の略で、日本語では「鍵カプセル化メカニズム」と呼ばれます。

名前だけ見ると難しく感じますが、ざっくり言えば、次のような仕組みです。

  1. 受け手が公開鍵と秘密鍵のペアを用意する
  2. 送り手は受け手の公開鍵を使って、共有秘密とカプセル化データを作る
  3. 送り手はカプセル化データを受け手に送る
  4. 受け手は秘密鍵を使って、同じ共有秘密を取り出す
  5. その共有秘密から、共通鍵暗号で使う鍵を作る

NIST FIPS 203では、KEMは公開チャネル上で2者が共有秘密鍵を確立するために使えるアルゴリズム群であり、その共有秘密鍵を共通鍵暗号による暗号化や認証に使えると説明されています。
参考: NIST FIPS 203 - Module-Lattice-Based Key-Encapsulation Mechanism Standard

KEMは、耐量子暗号の文脈でも重要です。
たとえば、NISTが標準化したML-KEMは、現時点では量子コンピュータを持つ攻撃者に対しても安全だと考えられている鍵カプセル化メカニズムとして位置づけられています。
ただし、暗号技術の安全性評価は研究や実装状況によって更新される可能性があるため、「一度標準化されたら永久に安心」と考えるのではなく、継続的に公式情報を確認することが大切です。

ただし、本記事ではML-KEMの数学的な中身までは扱いません。
ここではまず、KEMは共通鍵を安全に作るための公開鍵暗号系の仕組み と押さえれば十分です。

5.4 この章のまとめ

この章では、公開鍵暗号でできることを3つに分けて整理しました。

役割 使う鍵の向き 主な目的
暗号化・鍵配送 相手の公開鍵で暗号化し、相手の秘密鍵で復号する 秘密情報や共通鍵を安全に渡す
デジタル署名 自分の秘密鍵で署名し、相手が公開鍵で検証する 改ざん検出、署名者確認、否認防止の材料
鍵共有・KEM 公開情報と秘密情報を組み合わせて共有秘密を作る 共通鍵暗号で使う鍵を安全に準備する

公開鍵暗号は、暗号化だけでなく、署名や鍵共有にも使われます。
そして、どの使い方でも大切になるのが、その公開鍵が本当に相手のものなのかという確認です。

公開鍵は公開できます。
しかし、公開できるからこそ、偽物の公開鍵を信じてしまう危険があります。

次の章では、この問題に対応するための仕組みとして、証明書とPKIを見ていきます。


6. 証明書とPKI:公開鍵が本物かを確認する

前の章では、公開鍵暗号でできることとして、暗号化・デジタル署名・鍵共有を見てきました。

ここで、もう1つ大切な問題があります。

それは、受け取った公開鍵が、本当に相手のものなのかという問題です。

公開鍵は、その名前のとおり公開できます。
しかし、「公開できること」と「本物だと確認できること」は別の話です。

たとえば、あなたがネットショップにアクセスしているつもりでも、もし攻撃者が偽物の公開鍵を渡してきたらどうなるでしょうか。
あなたの端末は、その偽物の公開鍵を信じて通信を始めてしまうかもしれません。

このような問題に対応するために使われるのが、証明書PKIです。

6.1 公開鍵は「見えてよい」が、「誰のものか」は確認が必要

公開鍵暗号では、公開鍵を相手に渡せます。
これは便利です。

しかし、インターネット上では、次のような不安があります。

  • この公開鍵は、本当に example.com のものなのか
  • 攻撃者が途中で別の公開鍵にすり替えていないか
  • 有効期限切れの古い公開鍵を使っていないか
  • 秘密鍵が漏えいしたため、もう使ってはいけない証明書ではないか

つまり、公開鍵を安全に使うには、公開鍵そのものだけでなく、公開鍵の持ち主を確認する仕組みが必要です。

ここで登場するのが証明書です。

証明書は、ざっくり言うと次のようなものです。

この公開鍵は、この名前の相手に対応しています。
そのことを、信頼された第三者が確認して署名しました。

現実世界でたとえるなら、証明書は「身分証明書」に近いです。
名札を自分で作るだけなら誰でもできますが、公的な身分証明書には発行者がいます。暗号の世界でも、公開鍵をただ配るだけではなく、「誰の公開鍵なのか」を確認するための発行者が必要になります。

6.2 証明書には何が入っているのか

証明書には、公開鍵だけでなく、その公開鍵を安全に使うための情報が含まれています。

RFC 5280は、インターネットで使われるX.509 v3証明書と証明書失効リストのプロファイルを定めており、証明書の形式、拡張、認証パス検証の手順などを扱っています。
参考: RFC 5280 - Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List Profile

代表的な項目を、初学者向けに整理すると次のようになります。

項目 何を表すか
Subject 証明書の対象 Webサイト、組織、サーバーなど
Subject Public Key Info 対象に対応する公開鍵 サーバーの公開鍵
Issuer 証明書を発行した認証局 中間認証局など
Validity 証明書の有効期間 notBefore から notAfter まで
Subject Alternative Name その証明書が対応するDNS名やIPアドレス example.com など
Signature 発行者による署名 証明書が改ざんされていないか確認する材料

ここで大切なのは、証明書の中に秘密鍵は入っていないという点です。

証明書には公開鍵が含まれます。
一方、秘密鍵はサーバー側で厳重に保管されます。

💡 豆知識
「証明書ファイル」と「秘密鍵ファイル」は別物です。
サーバー構築で cert.pemfullchain.pem と、privkey.pem のようなファイル名が分かれているのはこのためです。
証明書は公開される前提の情報ですが、秘密鍵は漏らしてはいけません。

6.3 認証局は「公開鍵の身元確認」を助ける

証明書を発行する組織を、認証局と呼びます。
英語では CA(Certificate Authority) です。

認証局は、証明書を発行するときに、対象となるドメインや組織などを確認します。
たとえばWebサイト向けの証明書であれば、「この申請者は本当にこのドメインを管理しているのか」といった確認が行われます。

CA/Browser ForumのBaseline Requirementsでは、加入者証明書のSubject Alternative Nameには少なくとも1つの dNSName または iPAddress を含める必要があるとされています。
参考: CA/Browser Forum - Baseline Requirements

ここで重要なのは、ブラウザが単に「証明書っぽいデータ」を見ているわけではないことです。

ブラウザやOSには、あらかじめ信頼するルート認証局の情報が入っています。
サーバーから提示された証明書が、その信頼できる認証局につながるかを確認することで、「この公開鍵は本当にこのサイトのものだと考えてよいか」を判断します。

このように、証明書は1枚だけで完結するとは限りません。
多くの場合、サーバー証明書、中間証明書、ルート証明書という形で、信頼のつながりを確認します。

このつながりを 証明書チェーン と呼びます。

6.4 PKIは「信頼の仕組み」全体を指す

ここで、PKIという言葉が出てきます。

PKIは Public Key Infrastructure の略で、日本語では「公開鍵基盤」と呼ばれます。

少し固い言葉ですが、ざっくり言えば、PKIは次のような仕組みの集まりです。

  • 公開鍵と持ち主を結びつける証明書
  • 証明書を発行する認証局
  • 証明書チェーンの検証
  • 証明書の有効期限確認
  • 証明書の失効確認
  • ルート認証局を信頼の起点として扱う仕組み

つまり、PKIは「公開鍵暗号そのもの」ではありません。
公開鍵暗号を現実のインターネットで安全に使うための、信頼を管理する仕組みです。

要素 役割
公開鍵暗号 公開鍵と秘密鍵を使って暗号化、署名、鍵共有などを行う
証明書 公開鍵と持ち主の対応を示す
認証局 証明書を発行し、公開鍵の身元確認を助ける
PKI 証明書、認証局、検証、失効確認などを含む仕組み全体

💡 豆知識
PKIの「Infrastructure」は、道路や電力網のような「基盤」を意味します。
公開鍵暗号は暗号の道具ですが、PKIはその道具を社会全体で使うためのルールや仕組みに近いです。

6.5 ブラウザは何を確認しているのか

HTTPSのサイトにアクセスすると、ブラウザはサーバーから証明書を受け取ります。

このとき、ブラウザは大まかに次のようなことを確認します。

細かい検証手順は実装やポリシーによって異なりますが、基本的には次のような観点が重要です。

確認すること なぜ必要か
証明書チェーン 信頼できるルート認証局につながるかを確認するため
署名 証明書が認証局によって発行され、改ざんされていないか確認するため
有効期限 古い証明書を使い続けないため
ドメイン名 example.com にアクセスしているのに別ドメイン用の証明書を信じないため
失効状態 秘密鍵漏えいなどで無効化された証明書を使わないため

RFC 5280では、認証パス検証において、証明書の発行者と主体のつながり、信頼の起点、検証対象の証明書、有効期間などを確認する考え方が示されています。
参考: RFC 5280 - Certification Path Validation

また、TLS 1.3では、証明書を用いる認証において Certificate メッセージや CertificateVerify メッセージが使われます。CertificateVerify は、エンドポイントが証明書に対応する秘密鍵を持っていることを明示的に証明するために使われます。
参考: RFC 8446 - TLS 1.3

ここで大切なのは、証明書の確認は「暗号化できるか」だけの確認ではないことです。
相手が誰なのか提示された公開鍵を信じてよいのかを確認するための処理です。

6.6 「鍵マーク」は万能マークではない

ブラウザのアドレスバーには、HTTPS接続であることを示すアイコンが表示されることがあります。
ただし、ブラウザのUIは時期や製品によって変わるため、この記事では特定のアイコン表示を前提にしすぎないようにします。

大切なのは、アイコンの見た目そのものではなく、裏側で次のような確認が行われている点です。

  • TLSで暗号化された接続になっているか
  • 証明書が信頼できる認証局につながるか
  • 接続先のドメイン名と証明書の名前が対応しているか
  • 証明書が有効期間内か
  • 証明書が失効していないか

つまり、HTTPSの表示は「通信が暗号化されている」ことだけでなく、接続先の確認とも関係します。

ただし、ここで注意が必要です。

HTTPSだからといって、そのサイトの内容や運営者の信頼性が完全に保証されるわけではありません。
攻撃者が管理するフィッシングサイトであっても、そのドメイン用の正しい証明書を取得してHTTPS化することはあり得ます。

そのため、HTTPSは大切ですが、次のような確認も引き続き必要です。

  • URLのドメイン名が本当に正しいか
  • メールやSNSのリンクから不自然に誘導されていないか
  • ログイン情報や決済情報を入力する前に、サイトの文脈が自然か
  • 組織名やサービス名を装った紛らわしいドメインではないか

💡 豆知識
HTTPSは「通信経路を守る仕組み」であり、「そのWebサイトの内容が必ず安全である」と保証するものではありません。
たとえるなら、鍵付きの安全な通路を通っていても、その先のお店が本当に目的のお店かどうかは別途確認が必要、というイメージです。

6.7 証明書の失効:有効期限内でも使ってはいけない場合がある

証明書には有効期限があります。
しかし、有効期限内であっても、その証明書を使い続けてはいけない場合があります。

代表的なのは、秘密鍵が漏えいした、または漏えいした疑いがある場合です。
この場合、証明書の有効期限がまだ残っていても、その証明書は無効にする必要があります。

このように、証明書を途中で無効にすることを 失効 と呼びます。

RFC 5280では、証明書が有効期間内であっても、名前の変更、CAとの関係変更、対応する秘密鍵の侵害または侵害の疑いなどにより、証明書が無効になる場合があると説明されています。また、CRLは失効した証明書の一覧として説明されています。
参考: RFC 5280 - Revocation

失効確認には、代表的に次のような仕組みがあります。

仕組み 概要
CRL 失効した証明書の一覧を配布する方式
OCSP 証明書の状態をオンラインで問い合わせる方式
OCSP Stapling サーバーがOCSP応答を添えて提示する方式

この記事では詳細な運用方式までは扱いませんが、少なくとも次の点は押さえておくとよいです。

証明書は「有効期限内なら必ず安全」というわけではありません。
秘密鍵漏えいなどがあれば、有効期限内でも失効させる必要があります。

6.8 Certificate Transparency:証明書を見える化する仕組み

証明書に関する最近の重要な仕組みとして、Certificate Transparency があります。
日本語では「証明書透明性」と呼ばれることがあります。

Certificate Transparencyは、誤って発行された証明書や、不審な証明書を見つけやすくするために、証明書の発行状況を公開ログに記録する考え方です。

RFC 6962では、Certificate Transparencyは、発行されたTLS証明書を公開ログに記録し、誰でも監査できるようにする実験的プロトコルとして説明されています。また、ログは公開監査可能で追記専用の形を取り、誤発行そのものを直接防ぐのではなく、関係者が誤発行を検出できるようにするものだと説明されています。
参考: RFC 6962 - Certificate Transparency

イメージとしては、証明書の発行履歴を「公開された台帳」に記録しておくようなものです。

ただし、Certificate Transparencyは万能ではありません。
不審な証明書を「発見しやすくする」仕組みであり、誤発行を完全に防ぐものではありません。

それでも、証明書の発行状況を外部から監視できるようにする点で、PKIの信頼性を高める重要な仕組みです。

6.9 Pythonで証明書の情報を見てみる

最後に、Pythonで実際のWebサイトの証明書情報を少しだけ見てみます。

以下のコードは、Python標準ライブラリの sslsocket を使って、サーバー証明書の情報を取得する学習用サンプルです。
Pythonの ssl モジュールは、TLS/SSLによる暗号化とピア認証の機能を提供し、create_default_context() は用途に応じたデフォルト設定の SSLContext を作成します。
参考: Python documentation - ssl

注意
実行環境のOS、Python、OpenSSL、ネットワーク条件によって出力は変わります。
また、ここでは証明書の一部情報を表示するだけで、PKI検証の詳細を自作しているわけではありません。

import socket
import ssl
from pprint import pprint

# ============================================================
# サーバー証明書の情報を確認する学習用サンプル
# ============================================================
# 注意:
# - 実行にはインターネット接続が必要です。
# - ここでは example.com の443番ポートにTLS接続します。
# - create_default_context() を使うことで、標準的な証明書検証設定を利用します。
# - 実サービスでは、証明書検証を無効化する実装を安易に入れてはいけません。
# ============================================================

hostname = "example.com"
port = 443

# 1. クライアント用途のSSLContextを作成する
#    OSやPython環境が持つ信頼済みCA証明書を使って、証明書検証を行います。
context = ssl.create_default_context()

# 2. TCP接続を作成する
#    まずは通常のソケットとして、対象ホストの443番ポートに接続します。
with socket.create_connection((hostname, port), timeout=5) as sock:

    # 3. ソケットをTLSで包む
    #    server_hostnameを指定することで、SNIとホスト名検証に必要な情報を渡します。
    with context.wrap_socket(sock, server_hostname=hostname) as tls_sock:

        # 4. ピア証明書を取得する
        #    getpeercert() は、接続先が提示した証明書の情報を辞書形式で返します。
        cert = tls_sock.getpeercert()

        # 5. TLSバージョンや暗号スイートを表示する
        #    実際にどのTLSバージョン・暗号スイートで接続されたかを確認できます。
        print("TLS version:", tls_sock.version())
        print("Cipher:", tls_sock.cipher())

        # 6. 証明書の主要情報を表示する
        #    issuer, subject, notBefore, notAfter, subjectAltNameなどを確認できます。
        pprint(cert)

このコードを実行すると、証明書の発行者、有効期間、Subject Alternative Nameなどを確認できます。

ここで特に見てほしいのは、subjectAltNamenotAfter です。

項目 見るポイント
subjectAltName 接続先のドメイン名が証明書に含まれているか
issuer どの認証局が発行した証明書か
notBefore / notAfter 証明書の有効期間
TLS version 接続で使われたTLSバージョン
Cipher 接続で使われた暗号スイート

💡 豆知識
証明書の検証を試すコードでは、ネット上に verify=False や検証無効化の例が出てくることがあります。
仕組みの確認だけなら一時的に使われることもありますが、実サービスで証明書検証を無効にすると、中間者攻撃に弱くなります。
「エラーが出るから検証を切る」のではなく、なぜ検証に失敗しているのかを確認することが大切です。

6.10 自己署名証明書はなぜ警告されるのか

ローカル開発や社内検証で、自己署名証明書という言葉を見かけることがあります。

自己署名証明書は、名前のとおり、自分自身の秘密鍵で署名した証明書です。
暗号技術として署名ができていても、一般のブラウザから見ると「信頼できる認証局につながっている」とは判断できません。

そのため、多くの場合ブラウザは警告を出します。

ここで誤解しやすいのは、自己署名証明書が常に「暗号として壊れている」という意味ではない点です。

問題は、暗号アルゴリズムそのものというより、信頼のつながりを確認できないことです。

証明書の種類 何が違うか
公開認証局が発行した証明書 ブラウザやOSが信頼するルート認証局につながる
自己署名証明書 自分で自分を署名しているため、通常は信頼の起点につながらない

社内システムや検証環境では、独自のルートCAを端末に配布して信頼させる構成もあります。
ただし、その場合も「誰がルートCAを管理するのか」「秘密鍵をどう守るのか」「失効や更新をどう扱うのか」といった運用設計が重要です。

6.11 この章のまとめ

この章では、公開鍵を安全に使うために必要な証明書とPKIを整理しました。

観点 まとめ
公開鍵の問題 公開鍵は見えてよいが、本当に相手のものか確認が必要
証明書 公開鍵と持ち主の対応を示す情報
認証局 証明書を発行し、公開鍵の身元確認を助ける存在
証明書チェーン サーバー証明書から信頼済みルートへつながる確認経路
PKI 証明書、認証局、検証、失効確認などを含む仕組み全体
注意点 HTTPSは通信経路を守るが、サイト内容の安全性まで保証するわけではない

公開鍵暗号は強力ですが、公開鍵が本物か分からなければ安全に使えません。
そのため、証明書やPKIは、公開鍵暗号をインターネット上で実用するための重要な土台になります。

次の章では、これまで見てきた共通鍵暗号、公開鍵暗号、鍵共有、証明書が、TLSの中でどのように組み合わされるのかを整理します。


7. TLSではどう組み合わせて使われるのか

ここまで、共通鍵暗号、公開鍵暗号、デジタル署名、鍵共有、証明書を順番に整理してきました。

ただ、これらは実際のサービスでバラバラに使われているわけではありません。
たとえば、ブラウザで https://... から始まるWebサイトにアクセスするとき、裏側ではこれらの技術が組み合わされて動いています。

この章では、HTTPS通信で使われる TLS を例にして、公開鍵暗号と共通鍵暗号がどのように役割分担しているのかを整理します。

TLS 1.3を定めるRFC 8446では、TLSはインターネット上のクライアント・サーバー間通信について、盗聴、改ざん、メッセージ偽造を防ぐように設計されたプロトコルとして説明されています。
参考: https://datatracker.ietf.org/doc/html/rfc8446

7.1 TLSは「暗号アルゴリズム1つ」ではなく、通信を守る仕組み

最初に押さえておきたいのは、TLSはAESやRSAのような単独の暗号アルゴリズムではない、という点です。

TLSは、いろいろな暗号技術を組み合わせて、通信全体を安全にするためのプロトコルです。
プロトコルというのは、ざっくり言えば「通信するときの約束事」です。

たとえば、HTTPS通信では次のようなことを順番に行う必要があります。

確認したいこと TLSの中で関係する仕組み
接続先のサーバーは本物か 証明書、認証局、デジタル署名
どの暗号方式を使うか ハンドシェイクでの暗号方式の交渉
通信用の鍵をどう作るか 鍵共有、鍵導出
通信本文をどう守るか 共通鍵暗号、AEAD
通信内容が改ざんされていないか 認証タグ、Finishedメッセージなど

つまりTLSは、暗号技術を集めた「通信を安全に始めて、安全に続けるための流れ」と考えると分かりやすいです。

7.2 TLSの大きな流れ

TLS 1.3の流れを、かなり単純化すると次のようになります。

この図だけを見ると複雑に感じるかもしれません。
しかし、やっていることを大きく分けると、次の3つです。

段階 何をしているか 主に関係する技術
1. 相手と方式を決める TLSのバージョン、暗号方式、鍵共有方式などを決める TLSハンドシェイク
2. 相手を確認し、通信鍵を作る 証明書や署名を検証し、共有秘密から通信鍵を作る 公開鍵暗号、証明書、署名、鍵共有、HKDF
3. 通信本文を守る 作った通信鍵で実際のHTTPデータを保護する 共通鍵暗号、AEAD

ここでのポイントは、公開鍵暗号は主に通信開始時に活躍し、通信本文の保護は共通鍵系の暗号が担当するということです。

7.3 ハンドシェイク:安全な通信を始めるための準備

TLSの前半部分は、ハンドシェイク と呼ばれます。

日常の握手と同じように、通信を始める前に「これからこの条件で安全に話しましょう」と確認する段階です。

RFC 8446では、TLSのハンドシェイクプロトコルは通信相手の認証、暗号方式やパラメータの交渉、共有鍵材料の確立を行うものとして説明されています。
参考: https://datatracker.ietf.org/doc/html/rfc8446#section-1

TLS 1.3のハンドシェイクを、初学者向けに整理すると次のようになります。

1. ClientHello

ブラウザなどのクライアントが、サーバーに最初のメッセージを送ります。

ここには、たとえば次のような情報が含まれます。

  • 対応しているTLSバージョン
  • 利用できる暗号スイート
  • 対応している鍵共有グループ
  • 鍵共有に使う情報
  • 対応している署名アルゴリズム

TLS 1.3では、クライアントが ClientHello の中で暗号スイート、対応グループ、key_share、署名アルゴリズムなどを提示します。
参考: https://datatracker.ietf.org/doc/html/rfc8446#section-4.1.1

2. ServerHello

サーバーは、クライアントが提示した候補の中から、実際に使う方式を選びます。

この段階で、クライアントとサーバーは鍵共有に必要な情報を交換します。
TLS 1.3では、ClientHelloServerHello の組み合わせによって共有鍵が決まり、ECDHEなどの鍵確立を使う場合は key_share 拡張に鍵共有情報が含まれます。
参考: https://datatracker.ietf.org/doc/html/rfc8446#section-2

3. 証明書と署名でサーバーを確認する

次に、サーバーは証明書を提示します。

ブラウザは、6章で見たように、証明書チェーン、ドメイン名、有効期限、署名などを確認します。

さらにTLS 1.3では、証明書に対応する秘密鍵をサーバーが本当に持っていることを示すため、CertificateVerify というメッセージが使われます。
RFC 8446では、CertificateVerify は証明書中の公開鍵に対応する秘密鍵を使って、ハンドシェイク全体に対する署名を行うものとして説明されています。
参考: https://datatracker.ietf.org/doc/html/rfc8446#section-4.4.3

ここでデジタル署名が使われるため、公開鍵暗号が重要になります。

4. Finishedでハンドシェイクの改ざんを検出する

証明書を確認しただけでは、ハンドシェイク全体が安全だったとは言い切れません。

途中のメッセージが書き換えられていないか、クライアントとサーバーが同じ鍵を計算できているかも確認する必要があります。

そこで使われるのが Finished メッセージです。

RFC 8446では、Finished メッセージはハンドシェイク全体に対するMACであり、鍵確認、相手の身元と交換された鍵の結び付け、PSKモードでのハンドシェイク認証を提供すると説明されています。
参考: https://datatracker.ietf.org/doc/html/rfc8446#section-4.4.4

細かい計算式を追わなくても、ここでは次のように理解しておくと十分です。

Finishedは、「ここまでのやり取りをお互いに同じ内容として理解しているか」を確認するための仕上げのメッセージです。

7.4 レコードプロトコル:通信本文を守る

ハンドシェイクが終わると、ブラウザとサーバーは実際のHTTPデータをやり取りします。

たとえば、次のようなデータです。

  • ログインフォームに入力した情報
  • ネットショッピングの購入情報
  • APIリクエストやレスポンス
  • WebページのHTML、CSS、JavaScript

この通信本文を毎回公開鍵暗号で直接暗号化しているわけではありません。
ハンドシェイクで作った通信鍵を使い、共通鍵系の暗号で保護します。

RFC 8446では、TLSのレコードプロトコルは、ハンドシェイクで確立されたパラメータを使って通信を保護し、通信を複数のレコードに分け、それぞれをトラフィック鍵で独立に保護すると説明されています。
参考: https://datatracker.ietf.org/doc/html/rfc8446#section-1

ここで登場するのが、2章で扱ったAES-GCMのようなAEADです。

TLS 1.3の暗号スイートでは、クライアントが対応するAEADアルゴリズムとHKDF用ハッシュの組み合わせを提示する形になっています。
参考: https://datatracker.ietf.org/doc/html/rfc8446#section-4.1.1

7.5 TLSの中での役割分担

ここまでの内容を、この記事で扱ってきた暗号技術と対応させると次のようになります。

技術 TLSでの主な役割 本記事で見た章
共通鍵暗号 / AEAD 通信本文を暗号化し、改ざんを検出する 2章
公開鍵暗号 証明書、署名、鍵共有などの土台になる 3章・5章
デジタル署名 サーバーが秘密鍵を持っていることを示し、証明書やハンドシェイクを検証する 5章
鍵共有 通信用の共有秘密を作る 5章
証明書 / PKI 公開鍵が本当にそのサーバーのものか確認する 6章
HKDF 共有秘密から実際に使う通信鍵を導出する 5章

この表を見ると、TLSは「公開鍵暗号だけでできている」わけでも、「共通鍵暗号だけでできている」わけでもないことが分かります。

それぞれの技術が、自分の得意な役割を担当しています。

7.6 「公開鍵暗号でHTTPS通信を暗号化している」は少し雑な説明

HTTPSの説明では、「公開鍵暗号で通信を暗号化している」と言われることがあります。

大まかな説明として完全に間違いとまでは言えませんが、やや省略が多い表現です。

より正確には、次のように分けて考えるとよいです。

よくある説明 より正確な整理
公開鍵暗号でHTTPS通信を暗号化する 公開鍵暗号は、証明書の検証、署名、鍵共有などで重要になる
通信本文は公開鍵で暗号化される 通信本文は、ハンドシェイクで作った鍵を使って共通鍵系の暗号で保護される
証明書があれば完全に安全 証明書は接続先確認に役立つが、サイト内容や運営者の信頼性まで保証するわけではない

この記事では、公開鍵暗号を「通信本文を直接暗号化する主役」というより、安全な通信を始めるための土台として説明してきました。

TLSの流れを見ると、その意味がより分かりやすくなります。

7.7 TLS 1.3で変わった豆知識

TLS 1.3は、TLS 1.2以前と比べていくつか大きな変更があります。

この記事のテーマに関係するところでは、特に次の点が重要です。

TLS 1.3の特徴 ざっくりした意味
静的RSA鍵交換が削除された サーバーのRSA秘密鍵だけで過去通信を復号できるような構成を避ける方向になった
公開鍵ベースの鍵交換がForward Secrecyを提供する 後から長期秘密鍵が漏れても、過去の通信内容を守りやすくする
ServerHello以降のハンドシェイクメッセージが暗号化される ハンドシェイク中に見える情報を減らす
HKDFが鍵導出の基礎として使われる 共有秘密から用途ごとに分離された鍵を作りやすくする

RFC 8446では、TLS 1.3の主な変更点として、静的RSAと静的Diffie-Hellmanの暗号スイートが削除され、公開鍵ベースの鍵交換方式がForward Secrecyを提供するようになったこと、ServerHello以降のハンドシェイクメッセージが暗号化されること、HKDFが基礎的な鍵導出プリミティブとして使われることが説明されています。
参考: https://datatracker.ietf.org/doc/html/rfc8446#section-1.2

💡 豆知識
Forward Secrecyは、日本語では「前方秘匿性」と呼ばれることがあります。
ざっくり言えば、あとから長期的な秘密鍵が漏れても、過去の通信までまとめて読まれにくくする性質です。
「今の鍵が漏れたら過去も全部終わり」にならないようにする考え方、と見るとイメージしやすいです。

7.8 PythonでTLS接続時の情報を確認してみる

最後に、PythonでTLS接続時の情報を少しだけ確認してみます。

ここでは、Python標準ライブラリの ssl モジュールを使います。
ssl.create_default_context() は、一般的なクライアント用途向けに、証明書検証やホスト名確認を含む比較的安全なデフォルト設定を作る関数です。
参考: https://docs.python.org/3/library/ssl.html

注意
このコードは学習用です。
実行結果は、接続先サーバー、PythonやOpenSSLのバージョン、OS、ネットワーク環境によって変わります。

import socket
import ssl
from pprint import pprint

# 確認したいHTTPSサーバーを指定する
hostname = "www.python.org"
port = 443

# クライアント用途向けのデフォルトTLS設定を作成する
# 証明書検証やホスト名確認などが有効になる
context = ssl.create_default_context()

# まず通常のTCP接続を作る
with socket.create_connection((hostname, port), timeout=5) as tcp_socket:
    # TCP接続をTLSで包む
    # server_hostnameを渡すことで、SNIとホスト名検証に利用される
    with context.wrap_socket(tcp_socket, server_hostname=hostname) as tls_socket:
        # 実際にネゴシエーションされたTLSバージョンを表示する
        print("TLS version:", tls_socket.version())

        # 実際に選ばれた暗号スイートを表示する
        print("Cipher:", tls_socket.cipher())

        # 接続先サーバーの証明書情報を取得する
        cert = tls_socket.getpeercert()

        # 証明書の主体者情報を表示する
        print("\nSubject:")
        pprint(cert.get("subject"))

        # 証明書の発行者情報を表示する
        print("\nIssuer:")
        pprint(cert.get("issuer"))

        # 証明書に含まれるSANの一部を表示する
        # SANは、証明書がどのホスト名に対して有効かを確認するために重要
        print("\nSubject Alternative Name:")
        pprint(cert.get("subjectAltName", [])[:5])

このコードで見ているのは、主に次の情報です。

出力 何を見ているか
TLS version TLS 1.3やTLS 1.2など、実際に使われたTLSバージョン
Cipher 実際に選ばれた暗号スイート
Subject 証明書の主体者情報
Issuer 証明書を発行した認証局の情報
Subject Alternative Name 証明書が対象とするホスト名など

Pythonの公式ドキュメントでも、SSLSocket には実際に使われている暗号を取得する cipher() や、接続相手の証明書を取得する getpeercert() などのメソッドがあると説明されています。
参考: https://docs.python.org/3/library/ssl.html

このコードから分かるように、TLSでは単に「暗号化している」だけでなく、次のような確認が同時に関係しています。

  • どのTLSバージョンで接続したか
  • どの暗号スイートが選ばれたか
  • サーバー証明書はどの認証局から発行されているか
  • 証明書は接続先ホスト名に対応しているか

7.9 この章のまとめ

この章では、TLSを例に、公開鍵暗号と共通鍵暗号がどう組み合わされるのかを整理しました。

観点 まとめ
TLSの役割 HTTPSなどで通信を安全にするためのプロトコル
ハンドシェイク 相手確認、暗号方式の交渉、共有鍵材料の確立を行う
公開鍵暗号の役割 証明書、署名、鍵共有などで安全な通信開始を支える
共通鍵暗号の役割 ハンドシェイク後の通信本文を効率よく保護する
証明書の役割 公開鍵が本当に接続先のものか確認する
注意点 HTTPSは通信経路を守るが、サイト内容の安全性まで保証するわけではない

TLSを見ると、公開鍵暗号は単体で完結する技術ではなく、共通鍵暗号、証明書、署名、鍵共有と組み合わせて使われることが分かります。

次の章では、ここまでの内容を踏まえて、初学者が特に混同しやすいポイントをQ&A形式で整理します。


8. 初学者が混同しやすいポイント

ここまで、公開鍵暗号、共通鍵暗号、デジタル署名、鍵共有、証明書、TLSを順番に整理してきました。

ただ、これらの用語はセットで出てくることが多いため、最初はかなり混同しやすいです。
自分も暗号技術を学び始めたとき、「公開鍵は公開してよいのに、なぜ安全なのか」「署名は暗号化と何が違うのか」といった点で一度立ち止まりました。

この章では、初学者が特につまずきやすいポイントをQ&A形式で整理します。

8.1 公開鍵は誰に見られても本当に大丈夫なのか

基本的には、公開鍵そのものは他人に見られても大丈夫です。
公開鍵暗号は、公開鍵を他者に渡せることを前提に設計されています。

NISTの用語集でも、公開鍵暗号は、秘密に保つ秘密鍵と、他者に提供できる公開鍵を使う暗号システムとして説明されています。
参考: https://csrc.nist.gov/glossary/term/asymmetric_key_cryptography

ただし、ここで注意したいのは、公開鍵が見られてもよいことと、その公開鍵が本物だと確認できることは別問題だという点です。

たとえば、あなたがネットショップにアクセスしているつもりでも、攻撃者が偽物の公開鍵を渡してきたらどうなるでしょうか。

このような状況では、公開鍵暗号の仕組み自体が壊れていなくても、利用者は攻撃者の公開鍵を信じてしまう可能性があります。

そのため、実際のHTTPS通信では、証明書やPKIによって「この公開鍵は本当にこのドメインのものか」を確認します。
RFC 5280では、インターネットで使われるX.509証明書や証明書失効リストの形式、認証パス検証の考え方が定められています。
参考: https://datatracker.ietf.org/doc/html/rfc5280

つまり、公開鍵については次のように考えると分かりやすいです。

観点 考え方
公開鍵を他人に見られること 基本的には問題ない
公開鍵から秘密鍵を求められること 実用上困難であることが前提
公開鍵が本物かどうか 証明書やPKIで確認する必要がある
秘密鍵を他人に見られること 絶対に避ける必要がある

💡 豆知識
公開鍵は、名前の通り「公開してよい鍵」です。
しかし、インターネット上では「誰かが公開している鍵」ではなく、「本当に相手本人の鍵か」が大切になります。
ここが、公開鍵暗号と証明書がセットで語られる理由です。

8.2 公開鍵暗号があれば共通鍵暗号はいらないのか

結論から言うと、いりません、とはなりません

公開鍵暗号は便利ですが、実際の通信では共通鍵暗号と組み合わせて使われることが多いです。

理由の1つは、共通鍵暗号が大量データの保護に向いているからです。
共通鍵暗号では、同じ秘密鍵を使って暗号化と復号を行います。NISTの用語集でも、共通鍵は暗号化と復号のような操作と逆操作の両方に使われる鍵として説明されています。
参考: https://csrc.nist.gov/glossary/term/symmetric_key

一方、公開鍵暗号は、通信を始める前の準備や相手確認で重要な役割を持ちます。

TLS 1.3でも、ハンドシェイクでは通信相手の認証、暗号方式の交渉、共有鍵材料の確立が行われ、その後の通信データは確立したパラメータを使って保護されます。
参考: https://datatracker.ietf.org/doc/html/rfc8446

そのため、かなりざっくり言うと、次のような役割分担になります。

技術 主な役割
公開鍵暗号 安全な通信を始めるための準備を支える
共通鍵暗号 実際の通信本文を効率よく保護する
証明書 公開鍵が本物かを確認する
デジタル署名 改ざんされていないことや、相手が秘密鍵を持っていることを確認する

ここで大切なのは、公開鍵暗号と共通鍵暗号を競合関係で見るのではなく、役割分担する関係として見ることです。

8.3 秘密鍵とパスワードは同じなのか

秘密鍵とパスワードは、どちらも「秘密にするもの」です。
そのため、感覚的には似て見えるかもしれません。

しかし、役割はかなり違います。

観点 秘密鍵 パスワード
主な役割 署名生成、復号、鍵共有などの暗号処理に使う 利用者本人であることを確認するために使うことが多い
長いランダムなデータとして扱われることが多い 人間が入力できる文字列として扱われることが多い
管理 ファイル、HSM、鍵管理サービスなどで保護する ハッシュ化して保存する、再利用を避けるなどの対策が必要
漏えい時の影響 なりすまし署名や復号につながる可能性がある 不正ログインにつながる可能性がある

たとえば、SSHの秘密鍵ファイルを考えると分かりやすいです。
SSHでは、秘密鍵そのものを使って認証を行います。ただし、秘密鍵ファイルにはさらにパスフレーズを設定できる場合があります。

このとき、秘密鍵とパスフレーズは同じものではありません。

パスフレーズは、秘密鍵ファイルを盗まれたときにすぐ悪用されにくくするための追加の保護です。
ただし、パスフレーズを設定していても、秘密鍵ファイル自体を雑に扱ってよいわけではありません。

NIST SP 800-57 Part 1 Rev.5では、暗号鍵材料の管理に関する一般的なガイダンスが示されています。鍵は生成して終わりではなく、保管、利用、更新、失効、破棄まで含めて管理する必要があります。
参考: https://csrc.nist.gov/pubs/sp/800/57/pt1/r5/final

💡 豆知識
パスワードは「本人だけが知っている言葉」に近いイメージですが、秘密鍵は「本人だけが持っている暗号用の道具」に近いです。
そのため、秘密鍵は人間が暗記するものというより、ファイルや専用デバイス、鍵管理システムで守る対象として考えると分かりやすいです。

8.4 デジタル署名は暗号化なのか

デジタル署名は、公開鍵暗号の仕組みを使います。
しかし、目的は暗号化とは異なります。

暗号化の主な目的は、第三者に中身を読まれないようにすることです。
一方、デジタル署名の主な目的は、誰が作ったのか、途中で改ざんされていないかを確認することです。

FIPS 186-5では、デジタル署名は、データの不正変更の検出、署名者の身元確認、第三者に対する証拠として使われるものとして説明されています。
参考: https://csrc.nist.gov/pubs/fips/186-5/final

目的 使う技術 何を守るか
中身を読まれないようにしたい 暗号化 機密性
中身が変わっていないことを確認したい デジタル署名、MACなど 完全性
誰が作ったかを確認したい デジタル署名、証明書など 認証

デジタル署名では、基本的に次のような流れになります。

ここで重要なのは、署名されたメッセージの中身は、署名しただけでは隠れないという点です。
署名は「読めなくする」ためのものではなく、「本当にその人が作ったのか」「途中で変わっていないか」を確認するためのものです。

そのため、実際の通信では、必要に応じて暗号化と署名を組み合わせます。

8.5 証明書があれば、そのサイトは絶対に安全なのか

証明書があることは重要ですが、それだけで「そのサイトが絶対に安全」とは言えません。

HTTPSで使われる証明書は、主に次のような確認に関わります。

  • 接続先のドメイン名と証明書の内容が対応しているか
  • 証明書が信頼された認証局から発行されているか
  • 証明書の有効期限が切れていないか
  • 証明書が失効していないか
  • 証明書チェーンが正しく検証できるか

これは見落としやすいポイントです。
しかし、証明書が確認しているのは、主に 通信相手や通信経路の安全性 です。

たとえば、次のようなことまでは証明書だけでは保証できません。

証明書で確認しやすいこと 証明書だけでは保証できないこと
接続先のドメイン名と証明書の対応 サイト運営者のビジネスが信頼できるか
通信経路上で盗み見・改ざんされにくいこと サイトの内容が正しいか
証明書チェーンが信頼できること 入力フォームの送信先が悪用目的でないか
有効期限や失効状態 サイトに脆弱性がないか

つまり、ブラウザの鍵マークやHTTPS表示は大切ですが、それだけでサイトの中身まで完全に安全だと判断するのは危険です。

💡 豆知識
昔は「HTTPSなら安心」と言われることもありました。
しかし現在は、悪意あるサイトでもHTTPSを使うことがあります。
HTTPSは通信経路を守る重要な仕組みですが、サイトの内容や相手の意図まで保証するものではありません。

8.6 鍵長が長ければ長いほど常に安全なのか

鍵長はセキュリティに関係します。
しかし、単純に「長ければ長いほど、どんな場合でも安全」と考えるのは少し雑です。

暗号技術では、鍵長だけでなく、次のような要素も重要になります。

  • どのアルゴリズムを使っているか
  • そのアルゴリズムが現在も推奨されているか
  • 実装に脆弱性がないか
  • 乱数生成が適切か
  • 鍵を安全に保存・更新・破棄できているか
  • プロトコル全体として安全に設計されているか

たとえば、同じ「長い鍵」を使っていても、古い方式や危険な使い方をしていれば安全とは言えません。
また、公開鍵暗号と共通鍵暗号では、同じビット数をそのまま同じ安全性として比較できるわけでもありません。

そのため、実務では「鍵長だけを見る」のではなく、標準化団体やガイドラインで推奨されている方式、ライブラリの安全なAPI、適切な鍵管理を組み合わせて考える必要があります。

8.7 自分で暗号方式を作ってはいけないのか

学習目的で、小さなおもちゃの暗号を作って仕組みを理解することは良い勉強になります。
しかし、実サービスで自作暗号を使うのは基本的に避けるべきです。

理由は、暗号技術の安全性が、見た目の複雑さだけでは判断できないからです。

一見すると複雑に見える処理でも、専門家が解析すると簡単に破られることがあります。
逆に、標準化された暗号方式は、長い時間をかけて多くの研究者や技術者によって分析されています。

実装でも同じです。
アルゴリズムそのものが安全でも、使い方を間違えると危険になります。

たとえば、2章で扱ったAES-GCMでは、nonceの再利用を避ける必要がありました。
これは、アルゴリズム名だけ知っていても見落としやすいポイントです。

暗号を実サービスで使う場合は、次の考え方が大切です。

避けたいこと 推奨される考え方
独自暗号を本番で使う 標準化・広く検証された方式を使う
低レベルAPIを雰囲気で使う ライブラリの推奨APIを使う
サンプルコードをそのまま本番投入する 鍵管理・ログ・エラー処理・運用まで設計する
秘密鍵をソースコードに置く 鍵管理サービスや適切な保管方法を使う

💡 豆知識
暗号の世界では「自作暗号は危険」とよく言われます。
これは学習のために実装してはいけないという意味ではなく、十分に検証されていない方式を本番の安全対策として使うのは危険、という意味です。

8.8 この章のまとめ

この章では、公開鍵暗号を学ぶときに混同しやすいポイントを整理しました。

よくある疑問 整理した答え
公開鍵は見られても大丈夫か 公開鍵自体は公開できるが、本物かどうかの確認が必要
公開鍵暗号があれば共通鍵暗号はいらないか いらないわけではなく、実際には組み合わせて使うことが多い
秘密鍵とパスワードは同じか どちらも秘密にするが、役割や管理方法は異なる
デジタル署名は暗号化か 署名は主に改ざん検出や本人確認のための仕組み
証明書があればサイトは絶対安全か 通信相手や通信経路の確認には重要だが、サイト内容までは保証しない
鍵長が長ければ常に安全か 鍵長だけでなく、方式、実装、乱数、鍵管理、プロトコル設計が重要
自作暗号を使ってよいか 学習目的なら有用だが、本番では標準化・検証された方式を使うべき

ここまで、公開鍵暗号の基本的な役割と、実際に使うときの注意点を一通り整理しました。

次の章では、少し発展的な話題として、量子コンピュータ時代に向けた公開鍵暗号の変化、つまり耐量子暗号との関係を整理します。

9. 耐量子暗号との関係

ここまで、公開鍵暗号を「公開鍵と秘密鍵のペアを使う仕組み」として見てきました。

公開鍵暗号は、HTTPS、電子署名、ソフトウェア配布、SSH、ブロックチェーンなど、さまざまな場所で使われています。
つまり、現代のインターネットやデジタル社会を支える土台の1つです。

しかし、この公開鍵暗号には、将来的に大きな転換点が来る可能性があります。
それが、量子コンピュータの発展です。

量子コンピュータと聞くと、少しSFのように感じるかもしれません。
ただし、暗号の世界ではかなり前から「将来、十分に強力な量子コンピュータが登場した場合、現在広く使われている公開鍵暗号の一部が危険になる可能性がある」と考えられてきました。

この問題に備えるために研究・標準化が進められているのが、耐量子暗号です。

耐量子暗号は英語で Post-Quantum Cryptography と呼ばれ、PQCと略されることがあります。
ここでの「Post」は「量子コンピュータが登場した後でも使えるように備える」という意味合いで捉えると分かりやすいです。

参考: NIST, What Is Post-Quantum Cryptography?
https://www.nist.gov/cybersecurity-and-privacy/what-post-quantum-cryptography

9.1 なぜ公開鍵暗号が量子コンピュータの影響を受けるのか

現在広く使われている公開鍵暗号の多くは、ある数学的な問題を解くのが難しい、という性質に支えられています。

たとえば、かなりざっくり言うと次のようなイメージです。

方式の例 安全性を支える問題のイメージ 使われる場面の例
RSA 大きな数を素因数分解するのが難しい 暗号化、署名
DH / DSA 離散対数問題を解くのが難しい 鍵共有、署名
ECDH / ECDSA 楕円曲線上の離散対数問題を解くのが難しい TLSの鍵共有、証明書の署名、ブロックチェーン

これらは、現在の一般的なコンピュータでは現実的な時間で解くことが難しいと考えられているため、暗号技術として使われてきました。

しかし、十分に強力な量子コンピュータが実現すると、この前提が崩れる可能性があります。
NISTは、暗号学的に意味のある量子コンピュータが構築された場合に備えて、現在の暗号アルゴリズムを引退させ、古典コンピュータと量子コンピュータの両方に対して解くのが難しい数学問題に基づく方式へ移行する必要があると説明しています。

参考: NIST, What Is Post-Quantum Cryptography?
https://www.nist.gov/cybersecurity-and-privacy/what-post-quantum-cryptography

ただし、ここで誤解したくないのは、量子コンピュータが出てきたら、すべての暗号が一瞬で無意味になるという話ではないことです。

特に大きな影響を受けると考えられているのは、RSAや楕円曲線暗号のような、現在広く使われている公開鍵暗号系の仕組みです。
一方で、共通鍵暗号やハッシュ関数については別の観点で安全性を見直す必要はありますが、この記事の主題である公開鍵暗号ほど「仕組みそのものを置き換える」話として語られることが多いわけではありません。

この記事では深い数学には入りません。
まずは、次のように押さえておけば十分です。

現在よく使われている公開鍵暗号の一部は、将来的な量子コンピュータによって安全性の前提が崩れる可能性がある。
そのため、量子コンピュータにも耐えられる新しい公開鍵暗号系の標準化が進められている。

9.2 耐量子暗号は「量子コンピュータで動かす暗号」ではない

耐量子暗号という名前を聞くと、量子コンピュータを使って暗号化する技術のように聞こえるかもしれません。

しかし、ここは少し注意が必要です。

耐量子暗号は、基本的には現在のコンピュータ上で動かせる暗号方式です。
そのうえで、将来の量子コンピュータによる攻撃にも耐えられるような数学的問題を使います。

似た言葉に、量子暗号があります。
こちらは量子力学の性質を使う技術であり、耐量子暗号とは別の考え方です。

用語 ざっくりした意味 イメージ
耐量子暗号 / PQC 量子コンピュータによる攻撃にも耐えることを目指す、通常のコンピュータ上で動く暗号方式 今のインターネット技術へ組み込みやすい新しい暗号アルゴリズム
量子暗号 量子力学の性質を利用する暗号・鍵配送技術 専用の物理装置や通信路が関係することが多い

NISTも、Post-Quantum CryptographyとQuantum Cryptographyは名前が似ているが異なるものだと説明しています。PQCは量子コンピュータからの攻撃への防御であり、量子暗号は量子力学の性質に基づく技術です。

参考: NIST, What Is Post-Quantum Cryptography?
https://www.nist.gov/cybersecurity-and-privacy/what-post-quantum-cryptography

この記事で扱うのは、前者の 耐量子暗号 / PQC です。

9.3 NISTが標準化した主な耐量子暗号

耐量子暗号の標準化で特に重要なのが、NISTのPost-Quantum Cryptographyプロジェクトです。

NISTは、産業界・学術界・政府機関を含む国際的なプロセスを通じて候補方式を評価し、2024年8月に主要なPQC標準として次の3つのFIPSを公開しました。

標準 方式名 主な役割 この記事とのつながり
FIPS 203 ML-KEM 共有秘密を作るためのKEM 5章で扱った鍵共有・KEMにつながる
FIPS 204 ML-DSA デジタル署名 5章で扱った署名につながる
FIPS 205 SLH-DSA ハッシュベースのデジタル署名 署名方式の別系統として関係する

参考: NIST CSRC, Post-Quantum Cryptography
https://csrc.nist.gov/projects/post-quantum-cryptography

参考: NIST FIPS 203, Module-Lattice-Based Key-Encapsulation Mechanism Standard
https://csrc.nist.gov/pubs/fips/203/final

参考: NIST FIPS 204, Module-Lattice-Based Digital Signature Standard
https://csrc.nist.gov/pubs/fips/204/final

参考: NIST FIPS 205, Stateless Hash-Based Digital Signature Standard
https://csrc.nist.gov/pubs/fips/205/final

ここで大切なのは、耐量子暗号も「公開鍵暗号の世界の延長線上」にあるという点です。

つまり、突然まったく別の分野が出てくるというより、この記事で見てきた次の話とつながっています。

  • 共通鍵を安全に作るための 鍵共有・KEM
  • データの改ざんや署名者を確認するための デジタル署名
  • 証明書やTLSのように、公開鍵暗号を組み込んでいる既存の仕組み

耐量子暗号への移行は、これらを将来に向けてどう置き換えていくか、という話になります。

💡 豆知識
NISTは2025年3月に、ML-KEMのバックアップとしてHQCというKEM方式を標準化対象に選んだことも発表しています。
ここでいう「5番目のアルゴリズム」はPQC標準化全体での位置づけであり、HQCはML-KEMとは異なる数学的アプローチに基づくKEMとして選ばれています。
https://www.nist.gov/news-events/news/2025/03/nist-selects-hqc-fifth-algorithm-post-quantum-encryption

9.4 ML-KEM:耐量子暗号時代の「鍵を安全に作る」仕組み

5章では、KEMを「公開チャネル上で共有秘密を作るための仕組み」として紹介しました。

ML-KEMも、このKEMの一種です。
NIST FIPS 203では、KEMは2者が公開チャネル上で共有秘密鍵を確立するために使えるアルゴリズム群であり、その共有秘密鍵は共通鍵暗号による暗号化や認証に使えると説明されています。

参考: NIST FIPS 203
https://csrc.nist.gov/pubs/fips/203/final

KEMの流れをかなり簡略化すると、次のようになります。

ここでのポイントは、公開鍵暗号で通信本文を全部暗号化するのではなく、共通鍵暗号で使うための鍵材料を安全に作ることです。

2章で見たAES-GCMのような共通鍵暗号は、実際のデータを守るのが得意でした。
一方で、KEMはその前段階として、「では、その共通鍵をどう安全に準備するのか」を担当します。

疑似コードで表すと、次のようなイメージです。

# サーバー側: 公開鍵と秘密鍵のペアを用意する
(public_key, secret_key) = KeyGen()

# クライアント側: サーバーの公開鍵を使って共有秘密を作る
# ciphertext は、共有秘密をサーバーに届けるための「カプセル」のようなもの
(ciphertext, shared_secret_client) = Encaps(public_key)

# サーバー側: 秘密鍵でカプセルを開き、同じ共有秘密を得る
shared_secret_server = Decaps(secret_key, ciphertext)

# 両者は同じ shared_secret をもとに、通信本文を守るための共通鍵を作る
# 実際にはHKDFなどの鍵導出関数を使って、用途ごとの鍵に分けることが多い
session_key = KDF(shared_secret_client)

これは実際に動くコードではなく、処理の流れを理解するための疑似コードです。
実装では、標準化されたライブラリやプロトコルの実装を利用し、独自に暗号処理を組み立てないことが重要です。

9.5 ML-DSAとSLH-DSA:耐量子暗号時代のデジタル署名

耐量子暗号で重要なのは、鍵共有だけではありません。
デジタル署名も大きな影響を受けます。

たとえば、現在のWebやソフトウェア配布では、次のような場面で署名が使われます。

  • サーバー証明書が認証局によって署名されていることを確認する
  • ソフトウェアやアップデートファイルが改ざんされていないことを確認する
  • Gitのコミットやリリース成果物に署名する
  • ブロックチェーン上の取引が秘密鍵の所有者によって承認されたことを確認する

もし将来的に、現在使われている署名方式の安全性が崩れると、単に通信内容が読まれるだけでなく、本物らしく見える偽物の署名を作られる危険があります。

NIST FIPS 204は、ML-DSAをデジタル署名の生成と検証に使えるアルゴリズム群として規定しています。
また、FIPS 205は、SLH-DSAというステートレスなハッシュベース署名方式を規定しています。

参考: NIST FIPS 204
https://csrc.nist.gov/pubs/fips/204/final

参考: NIST FIPS 205
https://csrc.nist.gov/pubs/fips/205/final

かなりざっくり整理すると、次のようになります。

方式 分類 役割 補足
ML-DSA 格子ベース署名 署名生成・署名検証 FIPS 204で標準化
SLH-DSA ハッシュベース署名 署名生成・署名検証 FIPS 205で標準化。SPHINCS+に基づく

ここでも、この記事で見てきた公開鍵暗号の基本形は変わりません。

変わるのは、「その署名を支える数学的な土台」です。
RSAやECDSAの代わりに、現時点で量子コンピュータに対しても安全と考えられている別の数学的問題に基づく方式を使う、という流れになります。

9.6 「今すぐ全部置き換わる」と考えない

ここまで読むと、「では、明日からRSAやECDSAを全部やめるべきなのか」と感じるかもしれません。

しかし、実際の移行はそこまで単純ではありません。

公開鍵暗号は、OS、ブラウザ、サーバー、証明書、TLSライブラリ、VPN、認証基盤、ソフトウェア署名、組込み機器など、非常に多くの場所に組み込まれています。
そのため、耐量子暗号への移行では、まず自分たちのシステムのどこで公開鍵暗号が使われているのかを把握する必要があります。

NIST NCCoEのMigration to Post-Quantum Cryptographyプロジェクトでも、量子コンピュータに脆弱な公開鍵アルゴリズムがハードウェア、ソフトウェア、サービスのどこで使われているかを理解し、NISTのPQCアルゴリズムを使うための移行計画を立てる必要があると説明されています。

参考: NIST NCCoE, Migration to Post-Quantum Cryptography
https://www.nccoe.nist.gov/applied-cryptography/migration-to-pqc

実務的には、次のような流れで考えることになります。

このように、耐量子暗号への移行は、暗号アルゴリズムを1つ差し替えれば終わる話ではありません。
プロトコル、証明書、ライブラリ、運用、互換性、性能などを含めた、かなり大きな移行作業になります。

9.7 「あとで復号されるかもしれない」リスク

耐量子暗号の話でよく出てくる考え方に、Harvest Now, Decrypt Later があります。

これは、今すぐ暗号を破れなくても、暗号化された通信やデータを今のうちに集めて保存しておき、将来それを復号できるようになったときに読む、という考え方です。

NISTも、現在は暗号を破れなくても、将来の量子コンピュータによる解読を期待して暗号化データを収集・保存するリスクを説明しています。

参考: NIST, What Is Post-Quantum Cryptography?
https://www.nist.gov/cybersecurity-and-privacy/what-post-quantum-cryptography

このリスクは、特に長期間秘密にしておく必要がある情報で重要になります。

データの例 なぜ問題になりやすいか
医療情報 長期間にわたり個人に影響する可能性がある
金融情報 将来の不正利用や分析につながる可能性がある
企業の機密情報 技術情報や取引情報が後から価値を持つことがある
政府・安全保障関連情報 長期保存される機密情報が多い

もちろん、これはすべての個人や組織が今すぐ同じ対応をしなければならない、という意味ではありません。
ただし、「量子コンピュータが実用化してから考えればよい」というより、長期間守る必要がある情報ほど、早めに移行計画を考える必要があるということです。

9.8 初学者向けに押さえておきたいポイント

耐量子暗号は発展的なテーマなので、最初から細かい方式名をすべて覚える必要はありません。

この記事の流れでは、まず次のように整理しておくと十分です。

ポイント 説明
影響が大きいのは公開鍵暗号 RSAや楕円曲線暗号のような公開鍵暗号系が主な移行対象になる
共通鍵暗号を置き換える話だけではない 鍵共有、KEM、デジタル署名、証明書、TLSなどに関係する
PQCは量子暗号とは違う 基本的には現在のコンピュータ上で動く、量子攻撃に備えた暗号方式
ML-KEMは鍵共有に近い役割 共通鍵暗号で使う共有秘密を作るために使われる
ML-DSA / SLH-DSAは署名方式 データの改ざん検出や署名者確認に使われる
移行は段階的に進む 既存システム、証明書、プロトコル、ライブラリとの互換性を考える必要がある

個人的には、耐量子暗号を学ぶときも、いきなり数式に入るより、この記事で整理した役割に当てはめると理解しやすいと感じています。

  • ML-KEMは「どうやって安全に共有秘密を作るか」の話
  • ML-DSAやSLH-DSAは「どうやって署名を作り、検証するか」の話
  • PQC移行は「既存の公開鍵暗号を、将来に備えてどう置き換えるか」の話

こう考えると、耐量子暗号も突然出てきた別世界の技術ではなく、公開鍵暗号の延長として見えてきます。

9.9 この章のまとめ

この章では、公開鍵暗号と耐量子暗号の関係を整理しました。

  • 現在広く使われている公開鍵暗号の一部は、将来的な量子コンピュータの影響を受ける可能性がある
  • 耐量子暗号は、量子コンピュータによる攻撃にも耐えることを目指す暗号方式である
  • PQCは量子暗号とは異なり、基本的には現在のコンピュータ上で動く暗号方式である
  • NISTは2024年にML-KEM、ML-DSA、SLH-DSAをFIPSとして標準化した
  • ML-KEMはKEM、ML-DSAとSLH-DSAはデジタル署名に関係する
  • 耐量子暗号への移行では、暗号を使っている場所の棚卸しや段階的な移行計画が重要になる

ここまで、公開鍵暗号の基本、共通鍵暗号との違い、デジタル署名、鍵共有、証明書、TLS、そして耐量子暗号との関係まで整理してきました。

次の章では、記事全体を振り返りながら、公開鍵暗号をどのように理解するとよいのかをまとめます。

10. まとめ

ここまで、公開鍵暗号について、身近な例から順番に整理してきました。

最初は「公開してよい鍵」と「秘密にする鍵」という考え方が少し不思議に見えたかもしれません。
しかし、共通鍵暗号の「同じ鍵をどう安全に共有するのか」という問題から考えると、公開鍵暗号がなぜ必要になるのかが見えやすくなります。

公開鍵暗号は、インターネット上で相手と直接会えない状況でも、安全に鍵を準備したり、相手を確認したり、データが改ざんされていないかを確かめたりするための重要な土台です。

10.1 この記事で整理したこと

この記事では、公開鍵暗号を次の流れで見てきました。

内容 押さえておきたいポイント
1章 身近な例から考える鍵の受け渡し 暗号化そのものだけでなく、鍵をどう安全に渡すかが重要
2章 共通鍵暗号のおさらい 同じ鍵で暗号化・復号する。大量データの保護に向いている
3章 公開鍵と秘密鍵の基本 公開鍵は渡してよい鍵、秘密鍵は守る鍵
4章 共通鍵暗号との違い どちらが上位互換ではなく、役割が違う
5章 公開鍵暗号でできること 暗号化だけでなく、署名や鍵共有にも使われる
6章 証明書とPKI 公開鍵が本物か確認する仕組みが必要
7章 TLSでの組み合わせ 公開鍵暗号と共通鍵暗号は組み合わせて使われる
8章 混同しやすいポイント 署名・暗号化・証明書・HTTPSの役割を分けて考える
9章 耐量子暗号との関係 公開鍵暗号は将来の移行も重要なテーマになる

この流れを一言でまとめるなら、次のようになります。

公開鍵暗号は、共通鍵暗号を置き換える技術ではなく、共通鍵暗号を安全に使うための準備や、相手確認、署名検証を支える技術です。

10.2 共通鍵暗号と公開鍵暗号は「役割分担」で考える

この記事の中で特に大切なのは、共通鍵暗号と公開鍵暗号を「どちらが強いか」で比べないことです。

共通鍵暗号は、同じ秘密鍵を共有している相手同士で、通信本文のようなデータを効率よく守るのが得意です。
一方、公開鍵暗号は、相手と事前に同じ鍵を共有していない状況で、鍵を安全に準備したり、署名を検証したりするのが得意です。

かなりざっくり表すと、次のような役割分担になります。

実際のHTTPS通信でも、公開鍵暗号だけで通信本文をすべて暗号化しているわけではありません。
証明書で相手を確認し、鍵共有によって通信に使う鍵を作り、その後の通信本文は共通鍵系の暗号で保護する、というように複数の技術が連携しています。

このように見ると、公開鍵暗号は単独で完結する技術というより、安全な通信を始めるための入口を作る技術として理解しやすくなります。

10.3 公開鍵暗号で特に覚えておきたいこと

初学者の段階では、細かい数式やアルゴリズム名をすべて覚えるより、まずは次のポイントを押さえるのが大切だと思います。

ポイント 説明
公開鍵は公開してよい ただし、その公開鍵が本物か確認する必要がある
秘密鍵は絶対に守る 秘密鍵が漏れると、復号や署名の安全性が崩れる可能性がある
公開鍵暗号は暗号化だけではない デジタル署名、鍵共有、KEMなどにも関係する
証明書は公開鍵の身元確認に使う 「この公開鍵はこの相手のもの」と確認するための仕組み
TLSでは複数の暗号技術が連携する 公開鍵暗号、共通鍵暗号、署名、証明書、鍵導出などが組み合わさる
自作暗号は避ける 既存の標準化された方式や信頼できるライブラリを使うことが重要

特に、公開鍵は公開してよいが、何でも信じてよいわけではないという点は重要です。

公開鍵暗号では、「鍵を公開できる」という性質が便利です。
しかし、攻撃者が偽物の公開鍵を渡してきた場合、その鍵を信じてしまうと安全な通信だと思い込んだまま攻撃者と通信してしまう可能性があります。

そのため、証明書やPKIのように、公開鍵が本物かを確認する仕組みが必要になります。

10.4 豆知識:公開鍵暗号は「魔法の鍵」ではない

公開鍵暗号は便利ですが、何でも解決できる魔法の鍵ではありません。

たとえば、次のような点には注意が必要です。

  • 秘密鍵を安全に保管しなければならない
  • 公開鍵が本物か確認する仕組みが必要になる
  • 古いアルゴリズムや不適切なパラメータを使うと安全性が下がる
  • 実装ミスや乱数の扱いの問題で安全性が崩れることがある
  • 将来的には耐量子暗号への移行も考える必要がある

つまり、公開鍵暗号は「仕組みを知ればそれで終わり」ではなく、どの場面で、どの方式を、どのように安全に使うかまで含めて考える必要があります。

このあたりは、情報セキュリティの面白いところでもあり、難しいところでもあります。

10.5 次に学ぶと理解しやすいテーマ

公開鍵暗号の全体像をつかんだら、次は興味に合わせて以下のテーマに進むと理解が深まりやすいです。

次に学ぶテーマ つながり
デジタル署名 秘密鍵で署名し、公開鍵で検証する仕組みを深掘りできる
証明書とPKI HTTPSやブラウザの鍵マークの意味をより詳しく理解できる
TLS 1.3 暗号技術が実際の通信でどう組み合わされるかを学べる
鍵管理 秘密鍵や共通鍵を安全に扱う運用面を理解できる
耐量子暗号 将来の公開鍵暗号の移行課題を学べる

最初からすべてを完璧に理解する必要はありません。
まずは、この記事で整理したように「何を守るための技術なのか」「どの鍵を誰が持つのか」「実際には何と組み合わせて使うのか」を意識すると、暗号技術全体の見通しがかなりよくなります。

10.6 最後に

公開鍵暗号は、現代のインターネットを支える大切な技術です。

しかし、難しい数式から入ると、最初の段階で少し距離を感じてしまうかもしれません。
そのため本記事では、鍵付きの箱、ネットショッピング、HTTPS、証明書といった身近な例から順番に整理しました。

この記事を通じて、公開鍵暗号を次のように捉えられるようになっていれば十分です。

公開鍵暗号は、インターネット上で相手と直接会えない状況でも、安全に鍵を準備し、相手を確認し、データの正しさを確かめるための技術である。

暗号技術は、1つのアルゴリズムだけで完結するものではありません。
複数の技術が役割分担しながら組み合わさることで、私たちが普段使っているWebサービスやスマホアプリの安全性が支えられています。

公開鍵暗号は、その組み合わせの中でも特に大切な「入口」を担う技術です。
今後、TLS、証明書、デジタル署名、耐量子暗号などを学ぶときにも、この基本的な見方はきっと役に立つと思います。

1
0
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?