ssecutils
Security / Browser-native guide

公開鍵暗号の基本

RSA、ECDSA、Ed25519、鍵交換、署名、証明書の役割を開発者向けに整理します。

8Zero tracking reading surface

「公開鍵」と「秘密鍵」、結局なに?

SSH のセットアップで「公開鍵を貼り付けてください」と言われ、JWT の検証で「公開鍵」「秘密鍵」が出てきて、HTTPS の証明書も「公開鍵」「秘密鍵」で語られる──現代の認証/暗号の至るところに登場するこの2つを、初学者向けに整理します。

要点は「2つで1セットの鍵ペアで、片方で施錠したものはもう片方でしか開けられない」という非対称な関係。これが 公開鍵暗号(Public-Key Cryptography)の核心です。

共通鍵暗号との違い

まず比較対象として共通鍵暗号(対称鍵暗号)を理解しましょう。これは「同じ鍵で施錠も開錠もする」普通の鍵のイメージ。

# 共通鍵暗号(AES など)
encrypted = AES_encrypt("hello", key)
decrypted = AES_decrypt(encrypted, key)  // 同じ key を使う

共通鍵暗号の問題は1つ:「鍵をどうやって安全に相手に渡すか」。鍵を平文の通信路で送ったら盗聴されて終わりです。これが「鍵配送問題」と呼ばれる古典的な難問でした。

この難問を1976年に Diffie と Hellman が解決したのが公開鍵暗号。鍵を2つに分け、片方を公開しても安全な仕組みです:

# 公開鍵暗号(RSA など)
encrypted = RSA_encrypt("hello", public_key)   // 公開されている鍵で施錠
decrypted = RSA_decrypt(encrypted, private_key) // 秘密鍵を持つ人だけ開錠可能
項目共通鍵暗号公開鍵暗号
鍵の数1個(同一)2個(公開/秘密のペア)
速度速い(1秒で GB 単位)遅い(1秒で KB 単位)
鍵配送難しい公開鍵は配ってOK
用途大量データの暗号化鍵交換、署名、認証
代表例AES, ChaCha20RSA, ECDSA, Ed25519

公開鍵暗号は圧倒的に遅いので、大量データの暗号化には向きません。実際の HTTPS では「公開鍵暗号で共通鍵を交換 → 以降の通信は共通鍵で高速暗号化」のハイブリッド構成を取ります(後述)。

2つの使い方: 暗号化と署名

鍵ペアの「片方で施錠 → もう片方で開錠」という性質は、暗号化デジタル署名の2つの目的に使えます。

使い方1: 暗号化(Encryption)

受信者の公開鍵で暗号化すると、対応する秘密鍵を持つ受信者だけが復号できる。「秘密のメッセージを送る」用途。

Alice → Bob にメッセージを送る:
  Alice: ciphertext = encrypt("hi", Bob_public_key)  // Bob の公開鍵で施錠
  Alice: ciphertext を送信
  Bob:   plaintext  = decrypt(ciphertext, Bob_private_key) // Bob だけが復号可能

Alice は Bob の公開鍵さえ知っていれば暗号文を作れます。盗聴されても Bob の秘密鍵がないと復号できないので安全。

使い方2: デジタル署名(Signature)

逆向きに使うのが署名。送信者の秘密鍵で署名すると、対応する公開鍵を持つ誰でも検証できる。「このメッセージは確かにこの人が送った」用途。

Alice が「私が送りました」を証明:
  Alice: signature = sign("hi", Alice_private_key)  // Alice の秘密鍵で署名
  Alice: ("hi", signature) を送信
  受信者: verify("hi", signature, Alice_public_key) → True/False

署名できるのは秘密鍵を持つ Alice だけ。検証は公開鍵を知っている誰でも可能。これにより「本人性の証明」「改ざん検知」が同時に達成できます。JWT の署名や HTTPS の証明書、ソフトウェアの署名はすべてこの仕組み。

重要: 「署名は逆向きの暗号化」と説明されることが多いですが、現代の暗号アルゴリズム(特に楕円曲線系)では署名と暗号化は別の数学操作です。「鍵ペアの非対称性を使う」という抽象は同じでも、実装は異なります。

主要アルゴリズムの紹介

RSA(1977年〜)

最も歴史のある公開鍵暗号。大きな素数の積を素因数分解するのが計算的に困難という性質を利用しています。

  • 暗号化と署名の両方に使える
  • 2048 bit が現代の最低ライン、3072 bit 以上が推奨
  • 遅い(鍵長が大きい)、署名サイズが大きい
  • SSL/TLS の旧来構成、JWT の RS256、SSH の RSA 鍵で使われる
# RSA 鍵生成
openssl genrsa -out private.pem 2048
openssl rsa -in private.pem -pubout -out public.pem

ECDSA(楕円曲線署名、2000年代〜)

楕円曲線上の離散対数問題の困難さを利用。RSA と同等のセキュリティをはるかに短い鍵長で実現できます。

  • 署名専用(暗号化はECCの別アルゴリズム ECIES)
  • 256 bit 鍵で RSA 3072 bit 相当のセキュリティ
  • RSA より速い
  • JWT の ES256, Bitcoin の署名, TLS の現代構成で使われる

曲線の選択肢で代表的なのは secp256r1(NIST P-256)と secp256k1(Bitcoin)。どちらも 256 bit ですが用途が分かれています。

Ed25519(2011年〜、現代の推奨)

ECDSA の問題点(実装の落とし穴、サイドチャネル攻撃)を改善した楕円曲線署名。SSH の現代的な推奨方式

  • 署名専用
  • 256 bit 固定
  • 非常に速い、決定的署名(同じメッセージなら同じ署名)
  • NIST 規格ではないがオープンスタンダード(RFC 8032)
  • SSH-Ed25519, JWT の EdDSA, Signal プロトコル等で使われる
# Ed25519 SSH 鍵生成(現代の推奨)
ssh-keygen -t ed25519 -C "your_email@example.com"

SSH 鍵を作る時は -t ed25519 を指定するのが現代の標準。古い RSA 鍵を使い続けている場合は乗り換えを検討。

鍵交換(Key Exchange): HTTPS の核心

公開鍵暗号は遅いので、HTTPS では「公開鍵暗号で共通鍵を作って、以降は共通鍵で高速通信」というハイブリッド構成を取ります。この「共通鍵を作る」プロセスが鍵交換

古い方式: RSA 鍵交換

2010年頃まで主流だった素朴な方式:

  1. クライアントがランダムな共通鍵を生成
  2. サーバの公開鍵で暗号化して送信
  3. サーバが秘密鍵で復号して共通鍵を取得
  4. 以降は共通鍵で通信

弱点:サーバの秘密鍵が後日漏洩したら、過去の通信ログが全部復号される(前方秘匿性なし)。Snowden 事件以降、これは致命的とみなされて TLS 1.3 では廃止されました。

現代の方式: Diffie-Hellman 鍵交換(DH/ECDH)

1976年の Diffie-Hellman アルゴリズムは「鍵を交換せずに、両者が同じ秘密値に独立に到達する」魔法のような仕組み。絵で説明すると

公開: 黄色い絵の具(誰でも知っている)
Alice: 黄色 + 自分の秘密の色 → 緑色(公開)
Bob:   黄色 + 自分の秘密の色 → 紫色(公開)

Alice: 紫色 + 自分の秘密の色 → 茶色
Bob:   緑色 + 自分の秘密の色 → 茶色

二人とも同じ茶色に到達!しかも傍受者は緑/紫から茶色を逆算できない

実際の数学では「絵の具の混合」を「離散対数の指数演算」で行います。毎回新しい一時鍵を使う(Ephemeral)ことで、サーバの長期秘密鍵が漏れても過去の通信は守られる前方秘匿性(Forward Secrecy)を実現。

現代の TLS 1.3 では ECDHE(楕円曲線版のephemeral DH)が標準。HTTPS と TLS の中身もこれです。

公開鍵基盤(PKI): 公開鍵を信頼するには

公開鍵暗号には1つ大問題があります。「この公開鍵は本当に Alice のもの?」を、どう保証するか。攻撃者が偽の公開鍵を Alice の名前で配ったら、Alice 宛のはずの暗号文が攻撃者に読まれてしまいます。

この問題を解決するのが PKI(Public Key Infrastructure)。「信頼できる第三者」が「この公開鍵は確かに Alice のもの」と署名した証明書(Certificate)で配布する仕組みです。

HTTPS の場合:

  1. サイト運営者が認証局(CA)に「うちの公開鍵に署名してください」と申請
  2. CA がドメイン所有確認を行い、サイトの公開鍵に CA の秘密鍵で署名 → 証明書発行
  3. ブラウザは「信頼するCA一覧」を内蔵していて、CAの署名が確認できれば証明書を信頼

Let's Encrypt が無料で証明書を発行するようになって、HTTPS 化のハードルが大幅に下がりました。詳しくは HTTPS と TLS の仕組み 参照。

HMAC と公開鍵署名の違い

「メッセージの正当性を検証する」という意味では HMAC も似ていますが、根本的に違います:

項目HMAC公開鍵署名
使う鍵共通鍵(双方が同じ秘密鍵を持つ)鍵ペア(送信者の秘密鍵、受信者は公開鍵)
誰が検証できる?秘密鍵を共有している人のみ公開鍵を知っている全員
第三者への証明不可(双方が偽造可能)可能(Non-repudiation)
速度非常に速い遅い
用途API認証、Webhook検証HTTPS証明書、JWT(RS/ES)、ソフト署名

JWT の HS256(HMAC)と RS256(RSA)の違いも本質はここ。「双方が同じ秘密鍵で OK か」「第三者が検証する必要があるか」で選びます。

量子コンピュータと耐量子暗号

2026年現在、暗号界の話題は「量子コンピュータが実用化されたら現代の公開鍵暗号は破られる」というシナリオです。

Shor のアルゴリズム(1994)により、十分大きな量子コンピュータがあれば素因数分解と離散対数問題は多項式時間で解けることが証明されています。これは RSA / ECDSA / DH のすべてが破れることを意味します。

対策として NIST が標準化した耐量子暗号(Post-Quantum Cryptography, PQC)

  • ML-KEM(旧 Kyber): 鍵交換用、2024年標準化
  • ML-DSA(旧 Dilithium): 署名用、2024年標準化
  • SLH-DSA(旧 SPHINCS+): ハッシュベース署名

Google Chrome / Cloudflare はすでに X25519 + ML-KEM のハイブリッド鍵交換を実運用に投入しています。「今盗まれた暗号文を量子計算機ができた未来で復号する(Harvest Now, Decrypt Later)」攻撃への対策として、機密性が長期に求められる通信から優先的に切り替えが進んでいます。

実用上の注意点

  • 鍵の保管: 秘密鍵が漏れたら全てが終わり。~/.ssh/id_ed25519 はパーミッション 600 必須、生成時にパスフレーズを設定するのが推奨
  • 古い鍵の更新: RSA-1024 や DSA は破られている。SSH/PGP/SSL の古い鍵は Ed25519 / RSA-3072+ に作り直す
  • 独自実装は避ける: 公開鍵暗号の実装は数学的にも実装的にも非常に難しい。libsodium / OpenSSL / 言語標準ライブラリを使う
  • サイドチャネル攻撃に注意: 計算時間や電力消費から秘密鍵が漏れることがある。サーバ側では定数時間実装のライブラリを使う

おわりに

公開鍵暗号は現代インターネットの「信頼の根」を支える仕組みです。HTTPS、SSH、JWT、Bitcoin、Signal──すべてが鍵ペアの非対称性に依存しています。

本サイトの JWT Decoder は HS256(HMAC = 共通鍵)と RS256/ES256(公開鍵署名)の両方の検証に対応しています。実際にトークンを貼り付けて、共通鍵と公開鍵で検証フローがどう違うか体感できます。HMAC Generator と並べて触ると、対称鍵 vs 非対称鍵のメンタルモデルが定着します。

この基礎知識は HTTPS と TLSJWT のセキュリティ問題パスワードハッシュ など多くの記事の前提となっています。詰まったら戻って読み直す、リファレンスとして活用してください。

Tool companion

この記事と一緒に使えるツール

Related reading

関連記事