ゼロから学ぶRSA暗号 — 公開鍵を支える数論
RSAは「掛けられるが外せない鍵」を公開できるようにする。この記事は合同算術から積み上げる——鍵生成、2回のべき乗剰余、そしてオイラーの定理から「なぜ元のメッセージが戻るのか」を1行ずつ証明する。そのうえで手計算で追える実例、安全性が素因数分解の難しさに乗っている理由、そして教科書RSAをパディング無しで出荷してはならない理由まで。
要点
- 公開鍵暗号は、誰もが公開鍵と秘密鍵を持ち、公開鍵で暗号化したものを秘密鍵だけで復号する方式である。
- RSAの安全性は、大きな素数2つの掛け算は容易だが、その積の素因数分解は効率的な方法が知られていない点に基づく。
- RSAは暗号化を c ≡ m^e mod n、復号を m ≡ c^d mod n で行い、ed = 1 + kφ(n) とオイラーの定理でメッセージが戻る。
- φ(n)を求めることは素因数分解と等価で、2048bitが現在の下限だが、Shorのアルゴリズムは量子計算機上で整数を多項式時間で分解する。
- 教科書RSAは決定的で可鍛性があり小さな指数でメッセージが漏れるため、暗号化にはOAEP、署名にはPSSのパディングが必要である。
"Rivest
一次資料 — この記事の根拠
この解説の公開 2026-09-23
"Rivest"RivestA Method for Obtaining Digital Signatures and Public-Key CryptosystemsShamir & Adleman 1978
https://dl.acm.org/doi/10.1145/359340.359342"CACM 21(2):120-126
PKCS #1: RSA Cryptography Specifications Version 2.2RFC 8017論文ページ
問題: 共有していない秘密で合意する
歴史のほとんどの期間、暗号とは双方が同じ秘密を知っていることを意味していました。あなたと私が事前に鍵を取り決め、私がそれでメッセージを撹拌し、あなたが同じ鍵で戻す。これが共通鍵暗号で、高速でよく理解されています——ただし解けそうにない「最初の一歩」問題を抱えています。安全に話すためには、まず安全に会って鍵を交換しなければならない。一度も連絡したことのない店で買い物をしたいインターネットには、その事前の面会がありません。
公開鍵暗号は、初めて聞くと不可能に響くアイデアでこの循環を断ち切ります——掛けられるが外せない鍵。誰もが、世界に公開する公開鍵と、決して明かさない秘密鍵を持ちます。誰でもあなたの公開鍵であなた宛のメッセージを暗号化でき、復号できるのはあなたの秘密鍵だけ。事前の面会も、共有された秘密も不要です。
Rivest・Shamir・Adlemanが1978年にこれの最初の実用的な構成を発表し、いまもその名前が RSA として残っています。使われるのはふつうの整数の算術だけ——特殊な数学は出てきません。この記事はそれを土台から組み立てます。必要な算術、鍵生成、2つの操作、それらが互いを打ち消す証明、小さな実例、そして教科書版が実トラフィックに触れる前にパディングを要する理由。(他の道具との位置関係はゼロから学ぶ暗号技術にあります。)
前提: 時計の上の算術
RSAで起きることはすべて、ある整数 を法とする(modulo)世界の話です。意味は「ふつうに計算し、 で割って、余りだけを残す」。おなじみの例は の時計算術です。10時の4時間後は2時—— を で割った余りが だからです。
「 と は で割った余りが等しい」を表す記法は
で、「 は を法として と合同」と読みます。要するに、 で割った余りだけを見る目で眺めると と は区別がつかない、ということです。だから 。必要なのは合同式についての3つの事実だけで、3つとも納得しやすいものです。
- 足し算と掛け算は生き残る。 かつ なら および 。計算のどの時点で で割って余りにしても答えは変わりません——これが巨大な数の扱いを可能にしている当のものです。
- したがってべき乗は安い。 なので、2乗を繰り返し、そのたびに で余りを取ればよい。 は2048回の掛け算ではなく約11回の2乗で済みます。これが2乗によるべき乗剰余で、2048bitの数でRSAが使える理由です。
- 割り算だけが特別。 一般の「 で割る」はありません。ときどき存在するのがモジュラ逆元—— となる数 です。これは と が1以外の共通因数を持たないときちょうど存在し、拡張ユークリッドの互除法が高速に見つけてくれます。
もう1つ道具を。オイラーのトーシェント関数 は、 のうち と共通因数を持たないものの個数を数えます。素数 なら のすべてが該当するので 。異なる2つの素数の積——RSAが必要とする唯一の場合——では
から除かれるものを数えれば見えます。 の倍数が 個、 の倍数が 個、そして 自身を二重に数えているので、 です。要するに、 の倍数と の倍数を取り除くと、残りはちょうど 個になる、という式です。
RSAが乗っている非対称性
公開鍵方式には、やるのは簡単で、戻すのが難しい操作が必要です。RSAのそれは素数の掛け算です。
1024bitの素数2つを掛け合わせるのは、計算機には測定できないほどの時間です。逆向き——2048bitの積だけから2つの素数を復元する——は素因数分解であり、効率的なアルゴリズムは知られていません。公表されている最良の古典的手法である一般数体篩法は、このサイズでは準指数的、しかし依然として絶望的な時間がかかります。公開の場で分解された最大のRSA法数である829bitの RSA-250 は、2020年に約2700コア年を要しました。2048bitはそのはるか先です。
つまり——積は公開、因数は秘密。RSAの残りは、この差を暗号方式に変換する機構です。
鍵生成
5つの手順で、どれも必要な道具はもう揃っています。
1. 大きな異なる素数 , を2つ選ぶ。 実務では適切な大きさのランダムな奇数を生成し、素数判定(Miller–Rabin)に2つ通るまで試します。2048bit鍵ならそれぞれ約1024bitです。
2. 法 を計算する。 この数は公開されます。「2048bitのRSA鍵」というときの大きさはこれです。
3. を計算する。 この数は秘密にしなければなりません——そして を分解できる者は誰でもこれを計算できる、というのが安全性の核心そのものです。
4. 公開指数 を選ぶ。 かつ 。この互いに素という条件は美学ではなく、手順5に解が存在するための条件そのものです。実在の鍵はほぼすべて を使います。これは素数で、2進表記 10000000000000001 に1が2つしかないので、暗号化は17回の2乗と1回の掛け算で済みます。
5. 秘密指数 を、 のモジュラ逆元として計算する。
「すなわち」を開くと、 は「 に掛けると の倍数のちょうど1つ先に着地する数」です。合同式を使わずに書くと、ある整数 について ——そしてこの形こそ、あとの証明で必要になるものです。拡張ユークリッドの互除法が と からマイクロ秒で を出します。要するに は「 乗した効果をちょうど打ち消す指数」です。
結果として2つの鍵が得られます。
- 公開鍵 — どこに公開してもよい。
- 秘密鍵 — 決して送信しない。そして , , は破棄するか守る。どれ1つでも を渡してしまいます。
暗号化と復号
メッセージを の整数 として表します。(バイト列から整数へどう持っていくかがパディングの居場所で、それは後の節です。)すると両方向がただ1回のべき乗剰余です。
これがアルゴリズムの全部です。要するに、暗号化も復号も「べき乗して で割った余りを取る」という同じ操作で、違うのは使う指数だけです。公開指数でべき乗すれば鍵がかかり、秘密指数でべき乗すれば開き、全体を通して で余りを取る。2つの操作の非対称性は、 を知っているか知らないかという非対称性そのものにすぎません。
当然の疑問は、なぜ2つめが1つめを打ち消すのかです。
なぜメッセージが戻ってくるのか
エンジンはオイラーの定理です。ここで述べて、一度だけ使います。
オイラーの定理。 ならば 。
言葉にすると、 と互いに素な数を 乗すると、 を法としてちょうど1に着地する。(素数 について というフェルマーの小定理は の特別な場合です。)これが与えてくれるのは、指数を周回させる手段です。 を掛けても を法として何も変わらないので、指数は実質的に を法として生きている。だからこそ は ではなく を法として定義されたのです。
では復号を、1行ずつ。暗号文から始めて代入します。
暗号化の定義により だから。
べきのべきは指数の積になるから——ここまで剰余の話は出てこない。
鍵生成の手順5が、ある整数 についてちょうど を用意してくれたから。この一歩を使えるようにするために構成全体が設計されている。
で分け、 とまとめただけ——まだ指数法則の話。
オイラーの定理が を1に置き換えるから( のとき)。
1は何乗しても1だから。 よって 。そして を要求していたので、戻ってくる余りは「 と合同な何か」ではなく そのものです。メッセージが返ってきました。この6行が言っているのは要するに、 乗してから 乗すると指数が ずつ 周して元の位置(1乗)に戻る、ということです。
何が働いたかに注目してください。この方式の全体は、「 が の倍数より1だけ大きくなるように を選ぶ」という作業です。なぜならそれがオイラーの定理が潰してくれる指数だからです。そして は と から計算できる——だから因数を秘密にしなければならないのです。
正直な補足を1つ。上の証明には穴があります。オイラーの定理は を必要としましたが、メッセージが原理的には または の倍数になりうる。その場合もRSAは正しく復号します。ただし議論は、 に対してオイラーの定理を直接使うのではなく、中国剰余定理で素因数ごとに分けて扱います。ランダムなメッセージがそういう に当たる確率はおよそ ——実際の鍵サイズでは天文学的に小さく、そもそもパディングが をランダム化するので実務上は無関係です。厳密な扱いがここに1ページ費やすのを見て驚かないために、穴の存在は知っておく価値があります。
手計算で追える実例
実際の鍵は617桁の数を使います。代わりに極小の素数を取って、どの手順も鉛筆で検証できるようにします。
鍵生成。 , とします。
- を選ぶ。 を確認。✓
- となる を探す。 を試すと 。✓
よって公開鍵は 、秘密鍵は 。()——証明が必要としたちょうどその形です。
を暗号化。
なので 。つまり暗号文は「5を3回掛けて33で割った余り」にすぎません。
復号。 を、毎回余りを取りながら2乗の繰り返しで計算します。
5が戻ってきました。ここに出た数はすべて確認できる大きさで、同じ6行を2048bitの整数でやっているのがあなたのブラウザです。
この玩具のような例が見せてくれることが2つあります。1つめ、 は より小さくなければなりません。 ならメッセージは33通りしかなく、 は として戻ってきます。2つめ、暗号化は決定的です——5はいつも26に写る——そして33通りしかないなら、攻撃者は全部を暗号化して答えを引くだけで済みます。これがサイズの小ささによる作り物ではないことを、次の次の節で説明します。
なぜ破るのが難しいのか
攻撃者は と を見て を欲しがっています。経路を並べます。
を素因数分解する。 と を手に入れれば を計算し、拡張ユークリッドの互除法で を得て復号できます。これが第一の攻撃で、RSAの安全性が素因数分解の難しさに乗っている理由です。2048bitでは既知の古典的手法すべての手が届きません。一般数体篩法のコストは桁数について準指数的に増え、829bitの公開記録ですでに数千コア年を要しています。
別の方法で を求める。 助けになりません。 と の両方を知れば が分かり、和と積から2次方程式の解の公式で と が復元できます。 を求めることは素因数分解と等価です。
の 乗根を直接取る。 整数の上では 乗根は簡単です。しかし分解を知らない合成数 を法として を計算する「RSA問題」には、効率的な解法が知られていません。ただし正確に述べておくべきことが1つ。RSAを破ることが素因数分解と同じ難しさである、という証明はありません。 素因数分解ができればRSAは破れます。RSAへのあらゆる攻撃が素因数分解アルゴリズムを含意するかどうかは未解決問題です。
を総当たりする。 候補のメッセージを暗号化して突き合わせる——メッセージ空間が小さいときは常に致命的で、パディングが存在する理由です。
実務上の帰結。1024bit鍵は非推奨、2048bitが現在の下限、3072bitがNISTのガイダンスでおおよそ128bit安全性水準に対応します。そしてこの構築物全体に期限があります。Shorのアルゴリズムは十分に大きな量子計算機の上で整数を多項式時間で分解するので、標準化団体は耐量子方式への移行を進めています。上の古典的な分析は、いま記録して後で復号できる敵からデータを守ってはくれません。
教科書RSAは出荷してよいRSAではない
ここまでの内容は暗号学者が教科書RSAと呼ぶもので、書いたまま配備すれば重大な脆弱性になります。数学は正しい。その上に直接建てた方式が壊れているのです。理由は3つ、どれも単独で致命的です。
決定的である。 同じ鍵の下では同じ平文がいつも同じ暗号文になります。だからメッセージ空間を推測できる攻撃者は数論を一切使わずに勝てます——公開鍵(公開されています)で候補を全部暗号化し、突き合わせるだけ。はい/いいえのフィールド、クレジットカード番号、部屋番号、貧弱な乱数生成器から出たAES鍵。すべて表引きで復元されます。形式的には、教科書RSAは IND-CPA 安全性を満たさず、修正には乱数性が必要です。
可鍛性(malleability)がある。 べき乗が掛け算に分配されるので、
要するに、暗号文どうしを掛けると、中身の平文どうしを掛けたものの暗号文になる。だから暗号文を読めない攻撃者でも、それに を掛けて「復号すると になるもの」をあなたに渡せます。「復号できた」を「正当である」と扱うプロトコルはすべて悪用可能です。
小さな指数は小さなメッセージを漏らす。 なら—— と短いメッセージなら簡単に起きます—— が整数の上でそのまま成り立ち、周回が一度も起きません。 のふつうの整数の3乗根を取ればメッセージが読めます。素因数分解は不要です。
治療法はパディングです。メッセージを のほぼ全幅まで埋め、新鮮な乱数バイトを混ぜ、復号側が検証できる構造を付ける標準化された変換のことです。
- 暗号化には RSAES-OAEP(Optimal Asymmetric Encryption Padding)。乱数化されているので同じ平文が毎回違う暗号文になり、掛け算の構造も壊します。
- 署名には RSASSA-PSS。
- 古い PKCS#1 v1.5 の暗号化パディングは、Bleichenbacherの1998年のパディングオラクル攻撃の住処です。エラー応答で「パディングが不正」と「メッセージが不正」を区別してしまうサーバは、平文を持っていなかった暗号文の復号をさせられてしまいます。この種のバグはTLS実装で何度も再発見されています(ROBOT, 2017)。v1.5は旧互換専用と扱ってください。
RSAが実データそのものを暗号化しない理由はもう1つあります。 という制約が2048bit鍵の上限を「256バイトからパディングの分を引いた量」に縛り、さらにべき乗剰余は共通鍵暗号より桁違いに遅い。実システムはハイブリッドです——RSA(使う場合)が短い共通鍵を暗号化し、AESが本体を暗号化する。現代のTLS 1.3ではその役割さえ無くなりました。鍵確立は前方秘匿性のために一時的なDiffie–Hellmanへ移り、RSAが主に生き残っているのは証明書の署名アルゴリズムとしてです。(部品の組み合わせ方はゼロから学ぶTLSを参照。)
署名: 同じ2つの指数を逆順に
と は互いに逆元なので、逆の順で適用しても往復します——。これがデジタル署名を与えます。 を独占する署名者が
を作り、誰でも公開鍵を使って
を確認して検証します。検証を通る を作れるのは の保持者だけなので、署名はメッセージをその鍵に結びつけます。2本の式を並べると要するに、秘密指数で「鍵をかけた」ハッシュを公開指数で開き、手元で計算したハッシュと一致するかを見ている、ということです。
ハッシュ に注目してください。署名するのはメッセージそのものではなくダイジェストで、理由は2つ。メッセージはほぼ常に の許容量より長いから。そして生の値に署名すると上の可鍛性を受け継ぐから——攻撃者が2つの署名を掛け合わせて、その積に対する署名を偽造できてしまいます。衝突耐性のあるハッシュとPSSパディングが両方を塞ぎます。現代のウェブで実際に効いているのはこの操作です。ブラウザが検証する証明書チェーンはすべて、この検証の積み重ねです。
落とし穴
自分で実装しないこと。 これは定番の助言で、正しい助言です。以下はすべて、配備されたRSAで実際に起きた破りの類型であり、ライブラリ作者が何十年も費やしてきた領域です。
標準が使うのは ではなく 。 FIPSやPKCS#1は を を法として定義します。これは を割り切ります。証明は同じように通り、得られる は小さいので速い。ライブラリの と自分が から導いた を比べて違っていても、どちらも有効なことがあります——2つの指数は を法として合同です。
乱数の弱さは致命的で、しかも鍵をまたいで効く。 エントロピー源が悪くて独立に生成した2つの鍵が素数を共有すると、 がそれを暴き、両方の鍵が——ほぼ無コストの計算で——落ちます。2012年の調査("Mining your Ps and Qs")は、まさにこの形で壊れた稼働中のTLSホストを数万台発見しました。大半は、エントロピーが存在する前の初回起動時に鍵を生成した組み込み機器でした。
時間はサイドチャネル。 素朴なべき乗剰余は のビットによって所要時間が変わり、それを使ってネットワーク越しに秘密鍵が抽出されています。実装はブラインディング——べき乗の前に乱数因子を掛け、後で割り戻す——と定数時間のコード経路で防ぎます。
CRT高速化への故障注入攻撃。 復号はふつう中国剰余定理で、 を法とする計算と を法とする計算に分けて約4倍速くします。片方の半分だけが1回の計算誤りで壊れると、壊れた署名と正しい署名を比べてGCDを取るだけで が露出します。ライブラリは結果を出す前に検証して防ぎます。
小さな秘密指数は破れる。 復号を速くするために小さな を選ぶとWienerの攻撃を招きます。 がおおよそ 以下のとき を効率的に復元します。小さな公開指数は問題ありません( が標準)が、 は大きくなければなりません。
パディングの検査は定数時間で行い、エラーは区別できてはならない。 これがBleichenbacherの教訓です。脆弱性は算術の側には一度も無く、エラーメッセージの側にありました。
現場ではこう使う
RSAの算術を自分で書く場面は、現場にはまずありません。触るのは鍵の生成・形式・パディングの選択で、事故もほぼそこで起きます。
いつ触るか。 バックエンド/インフラのエンジニアがTLS証明書のCSRを作るとき、SSH鍵を発行するとき、JWTの署名アルゴリズムを決めるとき。セキュリティ担当なら、既存システムの鍵長とパディングを棚卸しするとき。
実際に打つコマンドと、そこに出てくる名前。
- 鍵生成:
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:3072 -out key.pem。公開指数は既定で65537です。 - 中身の確認:
openssl pkey -in key.pem -text -nooutを打つとmodulus()、publicExponent()、privateExponent()、prime1/prime2()に加え、exponent1/exponent2/coefficientが並びます。最後の3つは落とし穴の節で触れたCRT高速化用の前計算値です。秘密鍵ファイルは だけでなく と を丸ごと抱えている——だから漏えいしたら一巻の終わりです。 - JWT:
algのRS256は PKCS#1 v1.5 署名、PS256は PSS 署名です。どちらも公開鍵で検証する方式で、共有秘密のHS256とは別物です。 - アプリのコード: Pythonの
cryptographyならpadding.OAEP(mgf=padding.MGF1(hashes.SHA256()), algorithm=hashes.SHA256(), label=None)のようにパディングを明示して呼びます。
知らないと事故になる落とし穴。
- Javaの
Cipher.getInstance("RSA")はパディング指定を省くと PKCS#1 v1.5 になります(標準プロバイダの既定)。新規コードでは"RSA/ECB/OAEPWithSHA-256AndMGF1Padding"のように明示します。「ECB」と書いてありますが、RSAではブロックモードの意味は持ちません。 - JWTのアルゴリズム取り違え。 検証側がトークン自身の
algを信じると、RS256の公開鍵をHS256のHMAC鍵として使わせる偽造が成立します。検証時は許可するアルゴリズムを固定します。 - SSHの
ssh-rsaは鍵の種類とは別に、SHA-1署名の名前でもあります。 OpenSSH 8.8 以降はこのSHA-1署名が既定で無効なので、RSA鍵でもrsa-sha2-256/rsa-sha2-512に対応していない古い相手とは繋がらなくなります。「鍵が壊れた」のではありません。 - RSAでデータ本体を暗号化しようとして長さ制限にぶつかる。 2048bit鍵ではパディング込みで256バイトが上限です。ファイルを分割してRSAで暗号化する設計は誤りで、前節のとおり共通鍵をRSAで包むハイブリッドにします。
面接・設計レビューで問われる問いと答えの筋道。
- 「TLS 1.3でRSAは何をしているか」→ 鍵交換はもう担っていない。証明書の署名と、ハンドシェイク中にサーバが秘密鍵を持っていることを示す署名(CertificateVerify)に使われる。
- 「なぜRSAで直接データを暗号化しないのか」→ の長さ制限と速度。だから共通鍵を包むだけにする。
- 「教科書RSAの何がまずいか」→ 決定的・可鍛性・小さな指数の3点と、その答えがOAEP/PSSであること。
- 「新規に鍵を選ぶなら」→ RSAを使うなら2048bit以上、パディングはOAEP/PSS。そもそも署名だけならECDSAやEd25519も候補に挙げ、耐量子方式への移行を視野に入れる、まで言えると十分です。
まとめ
- 共通鍵暗号は敵対的なネットワーク越しには確立できない共有秘密を必要とする。公開鍵暗号は「掛けられるが外せない鍵」でその最初の一歩を解決する
- RSAが乗る非対称性は1つだけ——大きな素数2つの掛け算は自明、積の素因数分解は自明でない
- 鍵生成: 、、 と互いに素な を選び、。公開 、秘密
- 暗号化は 、復号は ——それぞれべき乗剰余1回
- 往復するのは だから。 がオイラーの定理から従う
- 安全性は の素因数分解が非現実的であること。 の復元は素因数分解と等価で、2048bitが今日の下限——ただしShorのアルゴリズムは大規模な量子計算機の上でこれを終わらせる
- 教科書RSAは絶対に出荷してはならない。決定的で、可鍛性があり、小さな指数で破れる。暗号化にはOAEP、署名にはPSSを使う
- 実務でRSAが暗号化するのはデータではなく共通鍵で、TLS 1.3で生き残っている役割は証明書への署名
周辺の全体像はゼロから学ぶ暗号技術から。RSA署名が実際のハンドシェイクの中で働くところはゼロから学ぶTLSへ。
確認問題
- 鍵生成は を要求します。これを満たさない を選ぶと、具体的に何が壊れますか。
- はなぜ ではなく を法として計算されるのでしょうか。
- 実例の公開鍵 を使って を暗号化してください。その後 で復号し、2が戻ることを確認してください。
- 攻撃者がある2048bit RSA鍵について を知りましたが、 も も知りません。この鍵は危険な状態でしょうか。理由を述べてください。
- あるサービスが1桁のPINを2048bit公開鍵で教科書RSAのまま暗号化し、暗号文を保存しています。鍵は強く、素因数分解は非現実的です。それでも攻撃者がPINを読める方法と、それを防ぐ対策を説明してください。
解答
- が と共通因数を持つと、 は を法とするモジュラ逆元を持たないので、 となる が存在しません。手順5に解が無く、秘密鍵が作れない——互いに素という条件は、逆元の存在条件そのものです。
- オイラーの定理により なので、指数にさらに を足しても何も変わりません。つまり指数は ではなく を法として周回します。復号は が の倍数より1だけ大きいことを必要とし、それがまさに「 がその法での である」の定義です。
- なので 。復号すると、;;;。メッセージ2が戻ります。
- 完全に危険です。 と から が得られ、2数の和と積が分かれば解の公式で と が出ます。 を求めることは の素因数分解と等価で、どちらからでも が即座に得られます。
- 教科書RSAは決定的で、公開鍵は公開されているので、攻撃者は10通りのPINそれぞれを暗号化して保存された暗号文と突き合わせるだけです——べき乗10回、素因数分解は不要。対策は乱数化パディング(RSAES-OAEP)で、暗号化のたびに新鮮な乱数バイトを混ぜるので同じPINが毎回違う暗号文になり、引き当て表が作れなくなります。
コメント
コメントにはログインが必要です