OpenSSLで実際のRSA秘密鍵を作り、n・e・d・p・qが本物の鍵にも存在することを確認。さらにDP・DQ・InverseQと中国剰余定理の関係を、小さな数字で追います。

暗号化と認証

 暗号化と認証④

 OpenSSLとC#でRSA鍵の中身を見る

前回は、小さな数字を使ってRSAの鍵を作りました。

p = 5
q = 11

n = p × q
  = 55

φ(n) = 40

e = 3
d = 27

そして、

公開鍵 = (n, e)
秘密鍵 = (n, d)

として、暗号化した値が秘密鍵で元に戻ることを確認しました。さらに、13²⁷ mod 55 を紙で追い、C#では BigInteger.ModPow(13, 27, 55) で同じ計算ができるところまで見ました。

ここで少し気になります。

前回、紙の上で使った n、e、d、p、q は、本物のRSA鍵にも本当に入っているのでしょうか。

今回は、実際にRSA鍵を作って中を見てみます。使うのはOpenSSLとC#です。

今回作る秘密鍵は、この記事の実験用です。実際に使用している秘密鍵の内容を、画面やログ、ブログなどへ出してはいけません。

OpenSSLでRSA鍵を作る

まず、OpenSSLで2048bitのRSA秘密鍵を作ります。

Bash
openssl genpkey \
  -algorithm RSA \
  -pkeyopt rsa_keygen_bits:2048 \
  -out rsa-private.pem

これで rsa-private.pem という秘密鍵ができます。では、中を見てみます。

Bash
openssl pkey \
  -in rsa-private.pem \
  -text \
  -noout

数字そのものは非常に長いので、項目名だけ抜き出すと、こんなものが表示されます。

modulus
publicExponent
privateExponent
prime1
prime2
exponent1
exponent2
coefficient

前回より多い。ただし、上の5つには見覚えがあります。

前回の n、e、d、p、q が本当にあった

OpenSSL              RSA

modulus          →   n
publicExponent   →   e
privateExponent  →   d
prime1           →   p
prime2           →   q

前回、紙の上で使った n、e、d、p、q が、本物のRSA秘密鍵にもちゃんと入っています。

OpenSSLで表示されるRSA秘密鍵の各項目と、n・e・d・p・q・DP・DQ・InverseQの対応図
OpenSSLの出力名を、RSAで使う数学上の記号と対応させる。

でも exponent1、exponent2、coefficient って何?

ここで、知らないものが残ります。exponent1、exponent2、coefficient です。C#側では、それぞれ DP、DQ、InverseQ という名前で出てきます。

DP、DQ、InverseQ は、前回一瞬だけ触れた中国剰余定理(CRT)を使って、RSAの秘密鍵演算を効率よく行うための値です。このあと、小さな数字を使って実際に確かめます。

ここではまだ式を覚えなくて大丈夫です。

同じ秘密鍵をC#から読んでみる

OpenSSLで作った rsa-private.pem を、そのままC#から読み込んでみます。

C#
using System.Security.Cryptography;

string pem =
    File.ReadAllText("rsa-private.pem");

using RSA rsa = RSA.Create();

rsa.ImportFromPem(pem);

RSAParameters parameters =
    rsa.ExportParameters(true);

ExportParameters(true) とすると、公開鍵だけでなく、秘密鍵側のパラメータも取得できます。

parameters.Modulus
parameters.Exponent
parameters.D
parameters.P
parameters.Q
parameters.DP
parameters.DQ
parameters.InverseQ

OpenSSLとC#で名前は違いますが、同じRSA鍵を見ています。

D、P、Q、DP、DQ、InverseQ は秘密情報です。実際に使用している秘密鍵で値そのものを表示したり、ログへ出したりしないようにします。

なぜ秘密鍵に P と Q まで残してあるのか

前回、RSAの復号は m = c^d mod n でした。そして秘密鍵は (n, d) と考えました。

それなら n と d だけ持っていれば十分に見えます。鍵を作るときに使った p と q は捨ててもよさそうです。まして DP、DQ、InverseQ まで保存してある理由は、まだ分かりません。

ここで出てくるのが、中国剰余定理です。

中国剰余定理とは

中国剰余定理は、いくつかの「割った余り」が分かれば、元の数をある範囲の中で一つに絞れるという考え方です。

例えば、ある整数 x について、

x ≡ 3 mod 5
x ≡ 1 mod 11

だとします。5で割ると3余る数は 3, 8, 13, 18, 23, 28, ...。11で割ると1余る数は 1, 12, 23, 34, 45, ...。最初に両方へ現れるのは23です。

ただし23だけではなく、78、133、188……と55ごとにまた現れます。つまり、

x ≡ 23 mod 55

と一つに決まります。5と11は互いに素で、5 × 11 = 55。55を足しても5でも11でも余りは変わりません。

xを5で割ると3余り、11で割ると1余る条件から、x ≡ 23 mod 55を求める中国剰余定理の図解
複数の「割った余り」から、元の数を一定の範囲で一つに絞る。

ちなみに「中国剰余定理」という名前はかなり古く、その原型は古代中国の数学書『孫子算経』の「割った余りから元の数を求める」問題まで遡ります。今回のアイキャッチにも、その漢文を使っています。

これをRSAに使う

ここで前回のRSAへ戻ります。

p = 5
q = 11

n = p × q
  = 55

つまり、mod 55 の世界を、mod 5 と mod 11 の二つに分けられます。RSAの復号 c^d mod 55 をいきなり計算する代わりに、P側とQ側で別々に計算し、最後に中国剰余定理で一つに戻します。

RSAの復号計算をp側とq側に分け、それぞれDP・DQを使って計算し、中国剰余定理で合成する流れ
大きなmod nの計算を、p側とq側の二つの小さな計算に分ける。

DP と DQ を作る

前回の鍵は p = 5、q = 11、d = 27 でした。

DP = d mod (p - 1)
   = 27 mod 4
   = 3

DQ = d mod (q - 1)
   = 27 mod 10
   = 7

ここまでで、P = 5、Q = 11、DP = 3、DQ = 7 です。

InverseQ も作る

InverseQ は、Q × InverseQ ≡ 1 mod P となる値です。今回なら 11 × InverseQ ≡ 1 mod 5。11を5で割った余りは1なので、今回は InverseQ = 1 で成立します。

Modulus  = 55
Exponent = 3
D        = 27
P        = 5
Q        = 11
DP       = 3
DQ       = 7
InverseQ = 1

OpenSSLやC#で出てきた値を、小さな数字でも全部作れました。

本当にこれで復号できるのか

では、実際に試します。同じRSA鍵を使い、今回は平文を m = 23 とします。公開鍵は (n, e) = (55, 3) なので、暗号化すると、

c
= 23³ mod 55
= 12

普通に復号するなら 12²⁷ mod 55 を計算します。今回は、それを二つに分けます。

P側で計算する

12³ mod 5
= 2³ mod 5
= 8 mod 5
= 3

Q側で計算する

12⁷ mod 11
= 1⁷ mod 11
= 1

つまり、

m ≡ 3 mod 5
m ≡ 1 mod 11

です。これは、さっき中国剰余定理の説明で使ったものと同じです。したがって m ≡ 23 mod 55。元の平文23に戻りました。

暗号文12をp=5とq=11の側で別々に計算し、余り3と1から中国剰余定理で平文23へ戻す例
暗号文12を二方向に分けて計算し、最後に中国剰余定理で平文23へ戻す。

実際のRSA実装では、候補を一つずつ並べて23を探すわけではありません。InverseQ を使えば、二つの結果から直接合成できます。
今回なら h = (3 - 1) × 1 mod 5 = 2、m = 1 + 11 × 2 = 23 です。

だから秘密鍵に P、Q、DP、DQ、InverseQ がある

これで、最初の疑問へ戻れます。RSA秘密鍵に P、Q、DP、DQ、InverseQ まで入っているのは、秘密鍵演算をP側とQ側に分け、中国剰余定理を使って合成できるようにするためです。

教科書では 秘密鍵 = (n, d) と考えるだけでもRSAの仕組みは理解できます。実際の鍵には、効率よく計算するための情報も一緒に入っています。

では、この中国剰余定理の処理はC#の標準ライブラリのどこにあるのでしょうか。

この点は③と同じです。RSA.Decrypt() などの実際のRSA秘密鍵演算は、.NETのC#コードだけで完結せず、OS側の暗号実装に委ねられています。そのため、C#の標準ライブラリを追っても、今回の中国剰余定理の計算がそのまま出てくるわけではありません。

Linuxでは、さらにOpenSSLのソースまで降りると、p、q、dmp1、dmq1、iqmp を使ったCRTの処理を確認できます。

……ただし、そこから先はCのコードです。C#じゃないので、今回は「本当に使われている」ことだけ確認して撤退します。

では「秘密鍵 = (n, d)」は間違いだったのか

いいえ。前回はRSAの数学を理解するために (n, e) と (n, d) を使いました。今回はそこから一段下へ降りて、実際の鍵に入っている p、q、DP、DQ、InverseQ まで見ています。見ている深さが違うだけです。

まとめ

今回は、OpenSSLでRSA秘密鍵を作り、その中身をC#からも確認しました。前回使った n、e、d、p、q は、本物のRSA鍵にも実際に存在しました。

さらに DP、DQ、InverseQ という値がありました。これらは、中国剰余定理を使って秘密鍵演算を分けて計算するために使われます。

中国剰余定理は、いくつかの「割った余り」が分かれば、元の数をある範囲の中で一つに絞れるという考え方です。
今回なら、mod 5では3、mod 11では1という二つの情報から、mod 55では23と決まりました。

前回はRSAの数式を追いました。今回は、その数式が実際の鍵の中にどう現れているのかを追いました。

次回

RSA鍵の中身はかなり見えてきました。しかし、公開鍵暗号にはまだ大きな問題があります。

その公開鍵は、本当に相手のものなのか。

公開鍵をすり替えられてしまえば、暗号化そのものが正常に動いていても、安全とは言えません。そこで登場するのが電子証明書です。

次回は、暗号化と認証⑤ ― 誰の紹介なら、その公開鍵を信用できるのか。ルート証明書・中間証明書・証明書チェーンを実際に追ってみます。

返信を残す

メールアドレスが公開されることはありません。 ※ が付いている欄は必須項目です

CAPTCHA