メインコンテンツまでスキップ
RSA 暗号のしくみ

RSA 暗号のしくみ

RSA は公開鍵暗号の 1 つである。公開鍵で暗号化し、対応する秘密鍵で復号する。2 つの素数の積は簡単に求められるが、大きな積から元の素数を求めることは難しい。この性質が安全性の基礎である。

数式の読み方

gcd(a, b) は a と b の最大公約数である。両方を割り切れる正の整数のうち、最も大きい値を表す。例えば 12 と 18 の最大公約数は 6 である。最大公約数が 1 の場合、2 つの数は「互いに素」である。各数が素数である必要はない。

gcd⁡(12,18)=6,gcd⁡(3,40)=1\gcd(12,18) = 6, \qquad \gcd(3,40) = 1

a mod n は a を n で割った余りである。例えば 17 を 5 で割ると、商が 3、余りが 2 になる。RSA では大きな累乗の値そのものではなく、n で割った余りを使う。

17=3×5+2,17 mod 5=217 = 3 \times 5 + 2, \qquad 17 \bmod 5 = 2

a ≡ b (mod n) は、a と b をそれぞれ n で割った余りが同じであることを表す。例えば 17 と 2 は、どちらも 5 で割った余りが 2 である。

17≡2(mod5)17 \equiv 2 \pmod 5

1. テキスト用の鍵の生成

OAEP (SHA-256、MGF1-SHA-256、空のラベル) を使うため、2048 ビットの RSA 鍵を生成する。手計算用の小さい鍵では、OAEP に必要な領域が足りない。鍵と平文はブラウザ内だけで扱う。

鍵を生成すると、入力したテキストの暗号化・復号が自動で行われる。

2. 公開鍵による暗号化

UTF-8: 22 / 190 バイト

テキストを UTF-8 のバイト列 M に変換し、OAEP で 256 バイトの符号化データ EM にする。OAEP は単なるゼロ埋めではなく、ハッシュと 32 バイトの乱数を使う。EM を整数 m として RSA で暗号化する。同じテキストでも、暗号文は毎回変わる。

M=UTF8⁡(text),m=OS2IP⁡(OAEP⁡(M))M = \operatorname{UTF8}(\mathrm{text}),\quad m = \operatorname{OS2IP}(\operatorname{OAEP}(M))
∣M∣=22,∣PS∣=256−22−2×32−2=168|M| = 22,\quad |PS| = 256 - 22 - 2 \times 32 - 2 = 168

PS は OAEP 内部のゼロ列である。空ラベルのハッシュ (32 バイト)、区切り (1 バイト)、M と合わせたデータを、乱数から作る MGF1 のマスクで処理する。先頭の 1 バイト、マスク済みの乱数 (32 バイト)、マスク済みのデータ (223 バイト) で EM が構成される。

DB=SHA256⁡(ε) ∥ PS ∥ 01 ∥ MDB = \operatorname{SHA256}(\varepsilon)\,\|\,PS\,\|\,\mathtt{01}\,\|\,M
EM=00 ∥ maskedSeed ∥ maskedDB,c=m65537 mod nEM = \mathtt{00}\,\|\,maskedSeed\,\|\,maskedDB,\quad c = m^{65537}\bmod n

3. 秘密鍵による復号

暗号文 c に秘密指数 d と n を使って整数 m を復元する。256 バイトの EM に戻した後、OAEP を検証して取り除き、UTF-8 として元のテキストに戻す。公開指数 e は復号の計算には不要である。

m=cd mod n,M=OAEPDecode⁡(I2OSP⁡(m,256))m = c^d \bmod n,\quad M = \operatorname{OAEPDecode}(\operatorname{I2OSP}(m,256))

4. PEM 形式と OpenSSL コマンド

以下は別の 2048 ビット鍵を新しく作成する OpenSSL 3 の例である。OAEP (SHA-256) を使用する。2048 ビット鍵で暗号化できる平文は最大 190 バイトであり、長いデータには共通鍵暗号との組み合わせを使う。

鍵の作成と公開鍵の取り出し

openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out private.pem
openssl pkey -in private.pem -pubout -out public.pem

平文を message.txt に保存してから、次のコマンドを順に実行する。private.pem は暗号化していない秘密鍵なので、厳重に管理する。

公開鍵によるファイルの暗号化

openssl pkeyutl -encrypt -pubin -inkey public.pem -in message.txt -out encrypted.bin -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 -pkeyopt rsa_mgf1_md:sha256

秘密鍵によるファイルの復号

openssl pkeyutl -decrypt -inkey private.pem -in encrypted.bin -out decrypted.txt -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 -pkeyopt rsa_mgf1_md:sha256

decrypted.txt に元の平文が出力される。OAEP には乱数が使われるため、同じ平文でも暗号文は毎回変わる。

OpenSSL 公式ドキュメント