RSA 暗号のしくみ
RSA は公開鍵暗号の 1 つである。公開鍵で暗号化し、対応する秘密鍵で復号する。2 つの素数の積は簡単に求められるが、大きな積から元の素数を求めることは難しい。この性質が安全性の基礎である。
数式の読み方
gcd(a, b) は a と b の最大公約数である。両方を割り切れる正の整数のうち、最も大きい値を表す。例えば 12 と 18 の最大公約数は 6 である。最大公約数が 1 の場合、2 つの数は「互いに素」である。各数が素数である必要はない。
a mod n は a を n で割った余りである。例えば 17 を 5 で割ると、商が 3、余りが 2 になる。RSA では大きな累乗の値そのものではなく、n で割った余りを使う。
a ≡ b (mod n) は、a と b をそれぞれ n で割った余りが同じであることを表す。例えば 17 と 2 は、どちらも 5 で割った余りが 2 である。
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 で暗号化する。同じテキストでも、暗号文は毎回変わる。
PS は OAEP 内部のゼロ列である。空ラベルのハッシュ (32 バイト)、区切り (1 バイト)、M と合わせたデータを、乱数から作る MGF1 のマスクで処理する。先頭の 1 バイト、マスク済みの乱数 (32 バイト)、マスク済みのデータ (223 バイト) で EM が構成される。
3. 秘密鍵による復号
暗号文 c に秘密指数 d と n を使って整数 m を復元する。256 バイトの EM に戻した後、OAEP を検証して取り除き、UTF-8 として元のテキストに戻す。公開指数 e は復号の計算には不要である。
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 公式ドキュメント