ハイブリッド暗号方式は、本文の暗号化に共通鍵暗号を使い、その鍵の確立に公開鍵暗号技術を組み合わせる方式です。鍵を暗号化して渡す構成と、鍵共有によって双方で鍵を導出する構成があります。HTTPS、SSH、S/MIME、PGPといった日常の暗号化通信は、どれもこの役割分担の上に成り立っています。一方で2024年8月にNISTが耐量子計算機暗号の標準(FIPS 203)を確定させてから、「ハイブリッド」は従来の鍵交換と耐量子方式を併用する構成を指す場面も増えました。本記事では従来型の手順を表とPythonの実行コードで確かめ、エンベロープ暗号化やPQCハイブリッドとの違い、2026年10月に確定したNISTの移行期限までを扱います。
まとめ
ハイブリッド暗号方式は、公開鍵暗号が苦手な「長いデータを速く暗号化すること」を共通鍵暗号に任せ、共通鍵暗号が苦手な「鍵を安全に渡すこと」を公開鍵暗号に任せる構成です。RSA-3072をSHA-256を用いるOAEPで使うと直接暗号化できるのは318バイトまでですが、AES-256の鍵は32バイトなので鍵だけなら包めます。構成のすべてはこの差から決まっています。
押さえておくべき変化は3つあります。1つ目は、OpenSSL 3.5やOpenSSH 10.0などの実装で、楕円曲線方式と耐量子KEMを併用する鍵交換が既定の優先候補になったことです。2つ目は、NIST IR 8547の最終版(2026年10月27日)が、RSAや楕円曲線による鍵確立と署名を強度にかかわらず2030年より後は非推奨、2035年より後は使用不可と定めたことです。3つ目は、そのNISTがPQCハイブリッドを「最終的にPQCだけの構成へもう一度移るまでの一時的な措置」と位置づけたことです。設計で迷ったら、本文の暗号化はAES-GCMのまま、鍵の受け渡しと署名の方式を後から差し替えられる構成にしておくのが判断の軸になります。
ハイブリッド暗号方式の仕組みと処理手順
ここで図解するRSA-OAEP型の構成では、共通鍵暗号が本文の暗号化を、公開鍵暗号がその共通鍵の暗号化と配送を担当します。共通鍵暗号と公開鍵暗号それぞれの特徴やアルゴリズムの比較は公開鍵暗号方式と共通鍵暗号方式の違いで扱っているため、ここでは2つを組み合わせたときの流れに絞ります。
RSA-OAEP型の鍵配送の4手順と送受信者の使用鍵
どの手順で誰のどの鍵を使うかを表にすると、取り違えが起きにくくなります。前提として、受信者は事前に公開鍵と秘密鍵のペアを作り、公開鍵だけを送信者に渡しています。
| 手順 | 担当 | 使う鍵 | 処理 |
|---|---|---|---|
| 1 | 送信者 | なし(乱数) | 使い捨ての共通鍵を生成 |
| 2 | 送信者 | 手順1の共通鍵 | 本文を暗号化 |
| 3 | 送信者 | 受信者の公開鍵 | 共通鍵を暗号化して本文と一緒に送る |
| 4 | 受信者 | 自分の秘密鍵→共通鍵 | 共通鍵を取り出し、本文を復号 |
この構成で本質的なのは、公開鍵暗号が扱うデータが常に「鍵1本ぶん」に固定される点です。本文が1バイトでも1ギガバイトでも、公開鍵暗号の処理量は変わりません。送信者が秘密を何も持たずに暗号化を始められる点も、公開鍵暗号を使う理由です。
KEM/DEM構成の役割分担とHPKE
暗号理論では、鍵を運ぶ部分をKEM(鍵カプセル化メカニズム)、本文を暗号化する部分をDEM(データカプセル化メカニズム)と呼び、両者を組み合わせた設計をKEM/DEM構成と呼びます。ハイブリッド暗号方式は、このKEM/DEM構成の代表的な実装です。後半で扱うRFC 9180のHPKEは、KEM・鍵導出関数(KDF)・認証付き暗号(AEAD)の3つを組み合わせる形でこの構成を標準化したもので、名前もHybrid Public Key Encryptionです。
ITパスポート試験で問われる鍵の組合せと取り違えやすい点
国家試験では、この役割分担そのものが問われます。ITパスポート試験の令和5年度公開問題の問86は、メッセージの暗号化に使う鍵と、その鍵の暗号化に使う鍵の組合せを図から選ばせる形式でした。正解は「メッセージの暗号化=共通鍵、共通鍵の暗号化=受信者の公開鍵」です。
取り違えやすいのは、本文と共通鍵に使う方式を逆にする組合せと、受信者ではなく送信者の公開鍵を選ぶ組合せです。判断の軸は2つで足ります。RSA-OAEPなどは1回で暗号化できる長さに上限があり、大きな本文の処理には共通鍵暗号が適すること、そして受信者だけが復号できるように受信者の公開鍵を使うことです。情報処理安全確保支援士の学習で共通鍵暗号・公開鍵暗号・ハイブリッド暗号を並べて整理するときも、この2点と次章の性能差が軸になります。
公開鍵暗号だけで暗号化しない理由:318バイトの上限と速度差
「最初から公開鍵暗号だけで本文を暗号化すればよいのでは」という疑問は、実際にサイズと速度を測ると解けます。次の値は、Python用ライブラリcryptography 50.0.2(検証環境で使用したOpenSSL 4.1.0、Intel Core i9-9880H)で生成して確認したものです。
| 対象 | 方式 | 実測値 |
|---|---|---|
| AES-256の共通鍵 | 共通鍵暗号 | 32バイト |
| 共通鍵をRSA-3072 OAEPで暗号化 | 公開鍵暗号 | 384バイト |
| RSA-3072 OAEP-SHA256の平文上限 | 公開鍵暗号 | 318バイト(319で例外) |
| 18バイトの本文をAES-256-GCMで暗号化 | 共通鍵暗号 | 34バイト(タグ16バイト込み) |
| RSA-3072 OAEPの復号 | 公開鍵暗号 | 毎秒217回(1回4.60ミリ秒) |
| AES-256-GCMの暗号化 | 共通鍵暗号 | 毎秒1,114MiB |
318バイトという上限は、鍵長3,072ビット(384バイト)からOAEPのハッシュ長32バイトの2倍と2バイトを引いた値です。数メガバイトのファイルは物理的に入りません。分割して暗号化する手もありますが、RSAで1回復号する4.60ミリ秒のあいだに、AES-GCMは約5MiBを暗号化し終えます。AES-GCMの暗号文は平文より認証タグの16バイト分長くなるだけで、ほかに渡すのは12バイトのnonceです。鍵だけを公開鍵で包む設計は、この非対称性から必然的に決まります。RSA側の鍵長とパディングの選び方はRSA暗号の仕組みと鍵長・パディングの選び方、楕円曲線との強度の比較はECDSAとRSAの鍵長・安全性・速度の比較にまとめています。
エンベロープ暗号化との違い:鍵を包む鍵が公開鍵か共通鍵か
クラウドの鍵管理サービスで出てくるエンベロープ暗号化も、データキーで本文を暗号化し、そのデータキーを別の鍵で暗号化する二段構えです。AWS KMSの開発者ガイドは、エンベロープ暗号化を「平文をデータキーで暗号化し、そのデータキーを別の鍵で暗号化する手法」と定義しています。違いは、データキーを包む側の鍵が何かにあります。
| 比較項目 | ハイブリッド暗号方式 | エンベロープ暗号化 |
|---|---|---|
| 本文の暗号化 | 共通鍵(使い捨て) | データキー(共通鍵) |
| 鍵を包む鍵 | 受信者の公開鍵 | 共通鍵・公開鍵のどちらも可 |
| 主な目的 | 相手へ安全に届ける | 保存データの鍵を守る |
| 包むときに必要なもの | 公開鍵だけ | KMSの権限(共通鍵の場合) |
| 代表例 | S/MIME・PGP・HPKE | AWS KMS・Cloud KMS |
AWS KMSの既定である対称KMSキーでデータキーを包む場合、暗号化する側も復号する側もKMSを呼び出す権限が必要です。誰でも暗号化できて受信者だけが復号できる、という公開鍵暗号の性質はここにはありません。公開鍵でデータキーを包む構成は、エンベロープ暗号化とハイブリッド暗号方式の両方に該当します。ただし、鍵共有から共通鍵を導出するハイブリッド構成もあるため、両者全体を単純な包含関係では整理できません。保存データの暗号化を設計するならエンベロープ暗号化で考え、組織の外の相手へ届けるならハイブリッド暗号方式で考える、と使い分けると迷いません。KMSのキーポリシー設計はAWS KMSとは?仕組み・料金とキーポリシー設計・採用判断で解説しています。
TLS・SSH・PGPでのハイブリッド暗号方式の使われ方
実際のプロトコルでは、共通鍵を公開鍵で直接暗号化して送る形と、鍵共有で双方が同じ共通鍵を導出する形の2通りがあります。ハイブリッド暗号方式を「共通鍵を公開鍵で包む方式」とだけ覚えていると、TLSの仕様を読んだときに対応が取れなくなります。
| プロトコル | 共通鍵の渡し方 | 本文の暗号化 |
|---|---|---|
| TLS 1.3 | 鍵共有(ECDHE・X25519MLKEM768) | AES-GCM・ChaCha20-Poly1305 |
| SSH | 鍵共有(mlkem768x25519-sha256など) | AES-GCM・ChaCha20-Poly1305 |
| S/MIME・OpenPGP | 受信者の公開鍵で共通鍵を暗号化 | AESなど |
| HPKE | KEMで共有秘密を生成 | AES-GCM・ChaCha20-Poly1305 |
TLS 1.3では、クライアントとサーバーが互いの公開値だけを交換して同じ共有秘密を計算するため、共通鍵そのものは通信路を流れません。公開鍵暗号は共有秘密の確立と、証明書による相手の認証に使われます。ハンドシェイクの詳細はTLS 1.3とは?RFC 8446の仕組みと0-RTTの採否で扱っています。SSHも同じ構図で、OpenSSHのリリースノートによると、10.0(2025年4月9日)から鍵共有の既定がmlkem768x25519-sha256になりました。手元のOpenSSH 10.3で ssh -G 接続先 を実行すると、kexalgorithmsの先頭にこの方式が並びます。SSHの公開鍵認証の流れはSSHの仕組みと公開鍵認証、VPNでの組み方はIPsecのAH・ESP・IKEの仕組みを参照してください。
PythonでRSA-OAEPとAES-GCMを組み合わせる実装
鍵を直接包む古典的なハイブリッド暗号方式は、標準的なライブラリで20行ほどに収まります。以下はcryptography 50.0.2で実行し、復号まで確認したコードです。送受信を分ける場合はwrapped_key、nonce、ciphertextを受信側へ渡します。この例は送信者の身元を認証しないため、必要な場合は署名などを別途組み合わせます。
import os
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
# 受信者の鍵ペア(本番では事前に生成し、秘密鍵は鍵管理基盤に置く)
private_key = rsa.generate_private_key(public_exponent=65537, key_size=3072)
public_key = private_key.public_key()
# 1. セッション鍵を生成し、本文を共通鍵暗号で暗号化する
session_key = AESGCM.generate_key(bit_length=256)
nonce = os.urandom(12)
ciphertext = AESGCM(session_key).encrypt(nonce, b"secret payload!!!!", None)
# 2. セッション鍵だけを公開鍵暗号で包む
oaep = padding.OAEP(
mgf=padding.MGF1(hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None,
)
wrapped_key = public_key.encrypt(session_key, oaep)
# 3. 受信側は秘密鍵でセッション鍵を取り出し、本文を復号する
recovered_key = private_key.decrypt(wrapped_key, oaep)
plaintext = AESGCM(recovered_key).decrypt(nonce, ciphertext, None)
実装で落としやすいのはnonceの扱いです。AES-GCMは同じ鍵で同じnonceを二度使うと、2つの平文のXORが露出するうえに認証用の鍵まで復元され、改ざんを検知できなくなります。セッション鍵を使い回す設計にした時点でこの危険が生じますが、上のコードのように送信のたびにセッション鍵を作り直せば構造的に起きません。パディングはOAEPを指定してください。PKCS#1 v1.5はパディングオラクル攻撃の対象として長く知られており、新規実装で選ぶ理由がありません。
PQCハイブリッド鍵交換:もう一つの「ハイブリッド」
2024年以降、「ハイブリッド暗号」は別の対象を指す場面が増えました。従来の楕円曲線鍵共有と耐量子KEMを同時に走らせ、2つの共有秘密を結合して1つの鍵にする方式です。仕様書や設定画面で見かけたら、どちらの意味かを先に確かめてください。
従来型とPQCハイブリッドの組み合わせ方の違い
| 比較項目 | 従来型(本記事の前半) | PQCハイブリッド |
|---|---|---|
| 組み合わせるもの | 共通鍵暗号+公開鍵暗号 | 従来の鍵交換+耐量子KEM |
| 目的 | 速度とデータ長の制約を回避 | どちらかが破られても安全を保つ |
| 代表例 | RSA-OAEP+AES-GCM | X25519MLKEM768 |
| 置き換わる部分 | — | 鍵の受け渡し側だけ |
NIST IR 8547の最終版は3.2節でこれを「PQC-Classical Hybrid Protocols」として扱い、構成要素の少なくとも一方が安全なら全体の安全が保たれるよう設計されるものだと説明しています。鍵確立については、従来方式の共有秘密ZとPQC側の共有秘密Tを連結したZ||Tから鍵を導出する方法を、NIST SP 800-56Cの汎用的な合成手法として認めています。注目すべきは、同じ節が「ハイブリッドは実装と構成を複雑にし、通常はPQCのみの暗号へ移る2回目の移行につながる一時的な措置と見込まれる」と書いている点です。ハイブリッドを入れたら終わりではなく、もう一度切り替える前提で暗号の設定を差し替えやすくしておく必要があります。
X25519MLKEM768の採用状況とサイズ
TLSで使われるX25519MLKEM768は、ML-KEM-768とX25519を連結した鍵共有です。2026年8月にRFC 10024として標準化され、IANAのTLSパラメータ登録ではコードポイント0x11EC(4588)が割り当てられています。同じRFCが定める3方式のうち、IANAの推奨(Recommended)欄がYなのはX25519MLKEM768だけです。クライアント側は、デスクトップ版Chromeが131、デスクトップ版Firefoxが132でこの方式を既定にし、AppleもiOS 26以降のURLSessionとNetworkフレームワークで既定にしています。OpenSSL 3.5ではクライアントが既定で送る鍵共有がX25519MLKEM768とX25519になったため、接続先も対応していれば、設定を変えなくてもライブラリの更新だけで使われ始めます。メール暗号化でも、2026年6月に公開されたRFC 9980がOpenPGPの耐量子拡張を定め、ML-KEM-768+X25519を実装必須にしました。OpenPGPは従来型のハイブリッド暗号方式で共通鍵を包むプロトコルなので、鍵を包む側がさらにPQCハイブリッドになる二重の構成です。
代償はサイズです。ML-KEM-768の公開鍵は1,184バイト、KEM暗号文は1,088バイトで、X25519の32バイトと比べて桁が変わります。ClientHelloが1つのTCPセグメントに収まらなくなり、古い中継装置で接続が切れる事例があるため、切り替え前に社内経路を含めて確認が要ります。ML-KEMそのものの仕組み、OpenSSLでの確認コマンド、nginxの設定で耐量子の鍵交換が外れる落とし穴は耐量子暗号とは:ML-KEMの仕組みとOpenSSL・SSHでの確認手順で扱っています。
PythonのHPKEでML-KEM-768とX25519を束ねる実装
cryptographyは47.0.0(2026年4月24日)でML-KEMとHPKEのモジュールを追加しましたが、当初はAWS-LCかBoringSSLでビルドした環境が必要でした。48.0.0(2026年5月4日)でOpenSSL 3.5.0以降に対応し、PyPIの標準ホイールでも動くようになっています。まずML-KEM-768単体で、鍵カプセル化の入出力を確かめます。
from cryptography.hazmat.primitives.asymmetric.mlkem import MLKEM768PrivateKey
private_key = MLKEM768PrivateKey.generate()
public_key = private_key.public_key()
# 送信側: 共有秘密とKEM暗号文を同時に得る
shared_secret, kem_ciphertext = public_key.encapsulate()
# 受信側: KEM暗号文から同じ共有秘密を復元する
assert private_key.decapsulate(kem_ciphertext) == shared_secret
50.0.2で測ると、公開鍵1,184バイト、秘密鍵のシード64バイト、共有秘密32バイト、KEM暗号文1,088バイトでした。RSA-3072で包んだ鍵が384バイトだったのと比べると、KEM暗号文だけで約2.8倍です。従来方式との併用まで試すなら、HPKEのKEMにMLKEM768_X25519を選びます。TLSのX25519MLKEM768と同じ組合せです。
from cryptography.hazmat.primitives import hpke
from cryptography.hazmat.primitives.asymmetric import x25519
from cryptography.hazmat.primitives.asymmetric.mlkem import MLKEM768PrivateKey
# ML-KEM-768 と X25519 を束ねたハイブリッド鍵
private_key = hpke.MLKEM768X25519PrivateKey(
MLKEM768PrivateKey.generate(),
x25519.X25519PrivateKey.generate(),
)
suite = hpke.Suite(
hpke.KEM.MLKEM768_X25519,
hpke.KDF.HKDF_SHA256,
hpke.AEAD.AES_256_GCM,
)
blob = suite.encrypt(b"hybrid pqc", private_key.public_key(), b"context-info")
assert suite.decrypt(blob, private_key, b"context-info") == b"hybrid pqc"
出力の先頭に付くencapsulated keyは1,120バイトで、ML-KEM-768の1,088バイトとX25519の32バイトの合計と一致します。10バイトの本文に対してblob全体は1,146バイトになり、残りは本文と認証タグ16バイトです。KEM・KDF・AEADを引数で明示する形になっており、前半で見た「鍵を運ぶ部分」と「本文を暗号化する部分」がそのままAPIに現れています。
2030年・2035年の移行期限:NIST IR 8547最終版とCRYPTREC改定案
NIST IR 8547最終版が定めた年次
NIST IR 8547は2024年11月12日の初期公開草案を経て、2026年10月27日に最終版が公開されました。最終版のTable 2(署名)とTable 4(鍵確立)は、ECDSA・EdDSA・RSA・有限体DH・楕円曲線DHについて、112ビット以上の強度のものを一律に「2030年より後は非推奨(Deprecated after 2030)、2035年より後は使用不可(Disallowed after 2035)」としています。草案では強度によって年次が分かれていましたが、最終版では量子計算機に弱い方式すべてが同じ年次になりました。
「after 2030」は2030年中を含まないので、「2030年以降」と訳すと1年ずれます。米連邦機関の重要システムにはさらに早い期限があり、同文書は大統領令14412とOMB覚書M-26-15に基づき、鍵確立を2030年12月31日まで、署名を2031年12月31日までに耐量子暗号へ移すよう求めています。PQC側の鍵確立方式については、ML-KEM-768を既定のパラメータとして推奨しています。
CRYPTREC暗号リストの改定案と政府統一基準
国内の政府調達で参照されるのはCRYPTREC暗号リストです。2026年3月の改定で電子政府推奨暗号リストに「耐量子計算機暗号(PQC)リスト」が加わり、2026年10月27日には署名方式などを追加する改定案の意見募集が総務省・デジタル庁・経済産業省から始まりました(11月11日まで)。報道資料は、ML-DSAとSLH-DSAの安全性評価が完了しておらず改定内容は確定していないと明記しています。政府機関等の統一基準は、情報システムで使う暗号をこのリストに基づいて選ぶよう求めているため、公共案件ではNISTの年次とあわせて掲載状況の確認が必要です。改定案の表の中身は耐量子暗号の解説記事で比較しています。
長期秘匿データの経路から着手する移行順序
実務の優先順位ははっきりしています。最初に手を付けるのは、長期間秘匿が必要なデータを流している経路です。暗号化された通信をいま保存しておき、量子計算機が実用化された将来に復号する攻撃(Harvest Now, Decrypt Later)が想定されているためです。AES-256による本文の暗号化は継続できますが、鍵確立に加え、相手の認証に使うRSA・ECDSAなどの署名も耐量子方式への移行対象です。秘匿期間が短い経路は記録後の解読リスクでは優先度を下げられますが、システムの重要度、認証への影響、適用される移行期限も合わせて判断します。量子計算機の開発がどの段階にあるかは量子コンピュータの仕組みと実用化の現在地で整理しています。
暗号鍵の管理方法:ハイブリッド暗号方式が破綻する条件
暗号アルゴリズムが安全でも、秘密鍵の漏洩、nonceの再利用、公開鍵のすり替えによって機密性や認証が失われます。設計段階で次の4条件に当てはまっていないかを確認してください。
- 秘密鍵をアプリケーションのリポジトリや設定ファイルに平文で置いている
- セッション鍵を使い回し、AES-GCMで同じnonceを再利用している
- 公開鍵の正当性を、証明書検証や信頼できる経路でのフィンガープリント照合などで確認せず、受け取った鍵をそのまま使っている
- 鍵の更新手順が無く、漏洩時に無効化できない
見落とされやすいのは3番目です。ハイブリッド暗号方式は「正しい相手の公開鍵を持っている」ことを前提に成立するため、公開鍵をすり替えられれば暗号化していても中身は読まれます。これを防ぐには、TLSでの証明書検証やSSHでの信頼済みホスト鍵との照合など、利用するプロトコルに応じて公開鍵と相手の身元を結び付けて確認します。TLSの設定や暗号スイートが社内の方針どおりになっているかを外部から点検したい場合は、脆弱性診断・セキュリティ診断の対象に含めると漏れを防げます。
長期保持する秘密鍵は、自前でファイルを暗号化して置くより、鍵管理サービスやHSMに預けて鍵を取り出さずに暗号化・復号させるほうが確実で、アクセスの記録も残ります。なお、ログイン認証を行うサーバーでは、パスワードを復号可能な形で保存せず、ソルトと適切な計算コストを設定したパスワードハッシュ方式で検証用の値を保存します。両者の使い分けはハッシュ化と暗号化の違いで解説しています。
よくある質問
ハイブリッド暗号方式と公開鍵暗号方式は何が違いますか?
公開鍵暗号方式は公開鍵と秘密鍵のペアを用いる暗号方式の分類で、ハイブリッド暗号方式は共通鍵暗号と公開鍵暗号技術を組み合わせた構成です。ハイブリッド暗号方式の内部では、公開鍵暗号が共通鍵を運ぶ役割で使われています。両者は対立する選択肢ではありません。
RSA暗号の解読には何年かかりますか?
現在の計算機では、公開されている最大級の記録でも829ビットのRSA-250の素因数分解(2020年2月)に約2,700コア年を要しており、2,048ビット以上のRSAを解いた例はありません。量子計算機については、Googleの研究者が2025年5月の論文で、物理量子ビット100万個未満、ゲートエラー率0.1%、表面符号の周期1マイクロ秒、制御系の応答10マイクロ秒などを仮定し、2,048ビットのRSAを1週間未満で素因数分解できると見積もっています。そうした量子計算機はまだ存在しませんが、移行に10年単位かかることを考えると、見積もりが縮んでいる事実は無視できません。
RSAはもう使えなくなりますか?
直ちに使えなくなるわけではありません。NIST IR 8547の最終版では、RSAによる鍵確立と署名は2030年より後が非推奨、2035年より後が使用不可です。新規に構築するシステムなら、鍵交換にPQCハイブリッドを選べるライブラリと設定にしておくのが安全側の判断です。
量子暗号通信とPQCハイブリッドは同じものですか?
別物です。量子鍵配送(QKD)は、光ファイバーや自由空間の光通信路と専用装置を使い、量子状態の性質を利用して鍵を共有する仕組みです。PQCハイブリッドは普通のCPUで動く数学的なアルゴリズムの組合せで、ライブラリの更新で導入できます。インターネット上のTLSやSSHで使われているのは後者です。
量子コンピュータが実用化されたら暗号化した通信は全部読まれますか?
影響を受けるのは公開鍵暗号の部分です。AESのような共通鍵暗号について、NIST IR 8547最終版はAES-128・192・256を耐量子のセキュリティカテゴリ1・3・5に位置づけており、置き換えの対象にしていません。X25519MLKEM768のような鍵交換に切り替えた経路は、いま記録された通信を将来解読される攻撃への備えができた状態になります。一方で、相手の認証に使う署名は別に移行が必要で、署名の偽造のような能動的な攻撃にはそちらで備えます。