RSA暗号体験入門

目次 | 第1章 | 第2章 | 第3章 | 第4章

第3章 RSA暗号方式 応用編

 本章ではRSA暗号に関する研究を行う人を対象に,より深い内容について説明します。 そのため,単に公開鍵暗号やRSA暗号の概要を知りたいだけの人は読む必要はありません。


3.1 RSA暗号の効率

 RSA暗号によって暗号化や復号化などの処理を行う際に,もし全く工夫のない計算手 順を取れば,それは膨大な計算量となるでしょう。例えば,111^37 mod 323を計算するこ とを考えます。単純な方法では,111に自分自身を36回掛けて(非常に大きな値になる), それを323で割った余りを求めることになります。
 この程度であればコンピュータを用いれば簡単に計算できますが, もしここで用いた数を100桁以上に増やした場合はどうでしょうか。 実際RSA暗号が安全であるためには,数は150桁は必要です。この方法を用いて150桁の 数を150桁の数でべき乗するとなると,どんなコンピュータを用いても人間の寿命よりも はるかに長い時間を要することになるでしょう。したがって,この方法ではRSA暗号を実 用化することは不可能です。そこで,もっと効率的に計算できる方法が求められます。
 実はそのような単純な計算方法よりもずっと効率的な方法は存在します。すなわち,乗算 をするたびに剰余を取っていく方法です。この方法を用いると,上の例の式を次のよう に計算できます。
    111^2 mod 323=111*111 mod 323=12321 mod 323=47
    111^3 mod 323=111*47 mod 323=5217 mod 323=49
    111^4 mod 323=111*49 mod 323=5439 mod 323=271
        ・・・・・・・・・・
    111^37 mod 323=111*305 mod 323=33855 mod 323=263
 この方法では,36回の小さな乗算と36回の小さな除算により値が大きくならないため, 上の単純な方法と比べると圧倒的に計算量が少なくて済みます。
 しかし,これでもRSAで使われる大きさの指数ではまだ実現不可能なほど計算量が多いのです。
 ただしそれほど心配することはありません。実は,これよりもさらに効率的な方法が存在します。具体的には以下の通りです。
 最初に指数(上の例では37)の2進表現を求め,自分自身の値を1に設定しておきます。 まず,その2進表現の左端の値から見ていきます。もし1の場合は,自分自身の平方にその元 になる数(上の例では111)を乗じます。また,もし0の場合は,自分自身を平方します。
 次に,ここで求められた値の剰余をmod nで取ります。この値が次の2進表現の値を見る際の自 分自身の値となります。以上の操作を2進表現の右端まで見終わるまで繰り返します。この作業に よって,非常に効率的に暗号化や復号化などの計算ができるようになります。

 では,ここで実際に計算例を示しましょう。 上の例では111を37乗しましたが,指数の37は2進表現では100101と表されます。 また,最初に自分自身の値を1に設定しておきます。
 この左端の値は1なので,1を平方して元になる数111で乗じます。さらに,その値の剰 余をmod 323で取ります。 つまり,111 mod 323となります。次に,2進表現の左から2番目の値 を見ると0なので,自分自身の値を平方してその剰余をmod 323で取ります。 つまり,
    111^2 mod 323=111^2 mod 323=12321 mod 323=47
となります。次に,2進表現の左から3番目の値を見ると0なので,自分自身の値を平方して その剰余をmod 323で取ります。つまり,
    111^4 mod 323=47^2 mod 323=2209 mod 323=271
となります。次に,2進表現の左から4番目の値を見ると1なので,自分自身の値を平方して, さらに元になる数111で乗じ,その剰余をmod 323で取ります。つまり,
    111^9 mod 323=271^2*111 mod 323=8151951 mod 323=77
となります。次に,2進表現の左から5番目の値を見ると0なので,自分自身の値を平方して その剰余をmod 323で取ります。つまり,
    111^18 mod 323=77^2 mod 323=5929 mod 323=115
となります。次に,2進表現の左から6番目(最後)の値を見ると1なので,自分自身の値を 平方して,さらに元になる数111で乗じ,その剰余をmod 323で取ります。つまり,
    111^37 mod 323=115^2*111 mod 323=1467975 mod 323=263
となります。
 以上のように,111^37 mod 323をたった6回の小さな乗算と除算によって求めること ができます。この方法を用いることにより,たとえ扱う数が150桁を超えていようとも, RSA暗号の処理の効率は十分現実的なものとなります。


3.2 効率的な鍵の生成法

 暗号の処理を行うためには,暗号化のための鍵(公開鍵)と復号化のための鍵(秘密鍵) を予め作っておく必要があります。 そのための手順は第2章で説明しましたが,復習も兼ねて以下にもう一度示しておきます。

[1] 2つの大きな素数p,qを選択する。
[2] n=pqとφ(n)=(p−1)(q−1)を計算する。このnを係数と呼ぶ。
[3] gcd(e,φ(n))=1の関係をもつ乱数e(公開指数)を選択する。この公開指数 eと係数nが公開鍵(e,n)となる。
[4] 拡張Euclidアルゴリズムを用いて,1=de mod φ(n)となるd(秘密指数)を計算する。 つまり,mod φ(n)でのeの乗法の逆数を探し,これをd(秘密指数)とする。この秘密指数 dと係数nが秘密鍵(d,n)となる。
[5] 公開鍵(e,n)を直接公開する。p,q,dは誰にも知られないようにしておく。

 以上の手順により,公開鍵(e,n)と秘密鍵(d,n)を作成することができます。以下 にその過程の詳細について述べます。


3.2.1 素数の選び方

 [1]で選択した素数p,qは,それぞれ256ビット前後が一般的です。
 素数の数は無限ですが,数が大きくなればなるほど,その割合は小さくなります。無作為 に選んだ数pが素数である確率は,約1/ln pです。100桁の数では,それが素数であ る確率は約230分の1です。素数を見つける場合,√p以下のすべての数でpを割って みて,割り切れるかどうかを調べていく方法もありますが,桁数が大きくなると膨大な時間が 掛かってしまい,現実的に不可能です。実際のところ,ある大きな数が絶対に素数かど うかを判定するための現実的な方法は知られていません。
 しかし,ある数がおそらく素数であろうことを判定する方法はあります。 その方法を以下に示します(証明にはフェルマーの小定理を用いますがここでは触れません)。

(1) 適当な範囲で奇数の乱数nを選択する。
(2) 小さい素数でnが割り切れるかどうかを調べ,もし因数が見つかれば,手順(1)に戻 る。
(3) 以下の作業を,nが素数でないと証明されるか,nが素数であると感じるのに必要 な回数だけ繰り返す。
(3-1) aを無作為に選択し,a^c mod n を計算する(cはn-1=(2^b)*c となるよう な奇数)。a^c mod n を計算する間,mod n での平方を計算するたびに,その結果が1で あるか調べる。もしそうであれば,その平方された数が±1(1の平方根)であるかどう かを調べる。もし異なれば,nは素数ではない。
(3-2) 次に,a^c mod n の計算の結果が±1であれば,nはこのaについては素数か どうかの検査は合格である。そうでなければ,最高でもb−1回その結果をそれを平方し たもので置き換え,それが±1であるかどうかを調べる。もし1であれば,nは素数では ない。もし−1ならば,nはaについて素数かどうかの検査は合格である。もしb−1回 平方し終わったら,nは素数ではない。

この方法では,その数を調べるのに時間を掛ければ掛けるほど, その数が素数である確率は高まります。


3.2.2 dとeの見つけ方

 [3]でeを選択しますが,これはどんな値でもよいというわけではありません。 φ(n)=(p−1)(q−1)の最小公倍数と互いに素な数でなければなりません。
 しかしながら,実際にはφ(n)を因数分解せずに,Euclidアルゴリズムを用いて, gcd(φ(n),e)=1を確認できます。

 以下にEuclidアルゴリズム(最大公約数を求るためのアルゴリズム)を簡単に示します。 ただし,aとbの最大公約数を求めるものとします。
(1) aとbを交換することによりa>bとする。
(2) c=a mod bなるcを見つける。もしC=0なら終了する。
(3) a<=b<=cとする。手順(1)に戻る。
 これによりeを求めることができます。

 次に,[4]でdを求めますが,そのためには拡張Euclidアルゴリズムを用います。以下に拡 張Euclidアルゴリズムを簡単に示します。
(1) (u1,u2,u3)=(1,u,0), (v1,v2,v3)=(0,v,1)
(2) v2=0になるまで以下の計算を繰り返す。
(2-1) (t1,t2,t3)=(u1,u2,u3)-(v1,v2,v3)(u2/v2) (ただしu2/v2はu2をv2で割 ったときの商)
(2-2) (u1,u2,u3)=(v1,v2,v3)
(2-3) (v1,v2,v3)=(t1,t2,t3)
 これにより,dを求めることができます。


3.2.3 効率的なeの選び方

 実はeを常に同じ値にしてもRSA暗号の安全性は低くならないことが分かっています。 これを利用して,eが小さいか計算しやすい値にすれば,そのeを用いた計算は効率的に なります。dはeを使って求められる(その逆でも構わない)ので,eを小さな定数にするこ とは容易です。これを利用すると,dを使った復号化の処理時間は変わりませんが,eを 使った暗号化の処理時間はより短くできます。
 ただし,dの値を小さくすることはできません。 もしdの値が小さければ,攻撃者が暗号文を解読しようとしたときにdを探す回数が少な くなってしまうからです。つまり,eは小さくてもRSA暗号の安全性に影響は生じませんが, dは小さいと安全性が保たれないということです。
 よく利用されるeの値は3と65537です。3をよく使う理由は,2は(p-1)(q-1) と互いに素でないため使えませんが,3は素になりうまく使えるからです。 しかも,暗号する際にたった2回乗算をするだけで済むので非常に効率的なのです。 eに3を用いても,いくつかの現実的な使い方に関する制限を守っていれば, RSA暗号の安全性を弱めることがないことが知られています。
 eを3として普通にRSAで暗号化する場合,いくつかの問題が発生します。1つ目は, 暗号化される平文Mが小さい場合,特にMがnの3乗根より小さい場合,Mを3乗してmod nで余りを取っても,結果は単にMとなり,簡単に暗号文から平文を求められてしまうと いう事です。この問題は,暗号化する前に平文Mに乱数をパディング(連結)して,そ の3乗がnよりも大きくなるようにしてやることによって解決されます。
 また,3を公開指数eとして使う場合の問題として,3がφ(n)と互いに素である場合 にしかうまく働かないということがあります(そうでないと逆数dを持たない)。 3とφ(n)=(p−1)(q−1)が互いに素になるためには, どのようにpとqを選択するのかが問題となります。 p−1が3と互いに素であることを確かにするためには,p mod 3を2にすればよいでしょう。 そうすれば,p−1mod 3は1となります。 同様に,q mod 3も2にすればよいです。 選択する素数 mod 3を,2にするには,奇数の乱数を3倍して2を加え, 素数かどうか調べる値としてその値を使えばよい。
 また,公開指数eの値として65537もよく使われますが,その理由としては, これが素数であり,しかも65537=2^16+1 が成り立つためです。これを2進表現したものは1を 2つしか含まないので,この値でべき乗するには17回の乗算で済みます。 これは3を指数eとした場合の2回と比べると多いですが, 512ビットを無作為に選択した場合に必要とする平均乗算回数768回と比べると圧倒的に少ないといえます。 また,65537をeとして使う場合,eに3を使う場合に生じる問題をほとんど避けることが可能です。
 eに3を用いた場合の問題として,平文Mの3乗M^3が係数nより小さい場合に簡単 に暗号文から平文Mを求められてしまうということがありました。 しかし,eが65537の場合には,M^65537がnより小さくなることはほとんどないので, 暗号文の65537乗根を求められて平文を知られてしまうということにはなりません。
 また,eに3を用いた場合,φ(n)が3と互いに素であるようなnを選ばなければなりませんでした。 しかし,eが65537の場合には,p mod 65537またはq mod 65537が1になったらそれを捨て るだけでよく,その確率は非常に低いので,nを見つけるのは非常に簡単です。
 以上のように,RSA暗号の公開指数eを3または65537にすると暗号化の処理が非常 に簡単になるので,公開指数eの選択の際にはこれら値を用いるとよいでしょう。


3.3 平文が短い場合の対処法

 RSAで暗号化する際に,平文mが係数nと比べて非常に短い場合,いくつかの問題が 生じます。例えば,2.4で示した簡単な電子投票の例で,暗号化されるべき投票内容 Mが各候補者の名前ではなく各候補者に付けられた1桁の番号(2〜7)であったとします。 このとき,投票者が選んだ候補者の番号(2〜7のどれか)が暗号化されて送られること になります。RSAでの暗号化の計算方法はM^e mod nを求めることなので,Mが1桁の 数であればeが小さいとき(普通はeが小さくても安全性は保証される)にはM^e<n となってしまいます。 したがって,このとき送信される暗号文はM^eとなります。 これを盗聴した者は,eの値を知っている場合,簡単に投票内容Mを知ることができるでしょう。
 また,eが大きな値でありM^e>nとなる場合であっても,Mが6通りしかないので 暗号文M^e mod nも当然6通りしか存在しありません。そのため,暗号文の盗聴者は,その 盗聴して得られた暗号文と6通りの各候補者に付けられた番号を暗号化した結果とを比較 していき,一致するものを調べれば簡単に投票内容を知ることができます。つまり,暗号化 したものが盗聴して得られた暗号文と同一の内容となる候補者の番号が投票内容であるこ とから,盗聴者は誰が誰に投票したかを知ることができるのです。
 実際RSA暗号では,このような平文の値が小さい場合でも安全性を確保できるようにする ために,PKCS(Public-Key Cryptography Standard)と呼ばれる符号化の手段が開発 されています。しかし,それは一般的なRSAの利用で用いられる手法であり,上の例のよ うに平文の長さが常に一定の場合には,後述するもっと単純化されたパディングの手法を 用いる方が効率的です。


3.3.1 パディング

 単純化されたパディングの手法とは以下の通りです。すなわち,暗号化する前に,平 文(投票内容)の左側に0でない正の乱数をパディング(連結)すればよいのです。乱 数をパディングしてできた値は,係数nの桁数よりも1桁少ない程度の大きさが理想的です。 ただし,パディングしてできた値は,n未満でなくてはならありません。この手法を用い ることにより,上述した問題はすべて解決されます。
 ちなみに,PKCSでは,パディングされた乱数と元の平文データとの境目を表すための 特別の数をその間に挿入したりする必要があるので, このような単純に乱数をパディングするだけの手法よりも若干複雑になります。

 ところで,たった1桁の平文mの前(左側)に乱数rを連結した場合,平文mが常に同 じ場合には暗号文(r.m)^e mod nの1の位(右端)に偏りは生じないのでしょうか。 ただし,”.”を連結演算子とします。一見すると,mが同じものどうしではそれぞれ暗号文 の1の位が等しくなる,あるいは何らかの偏りが生じるように感じられるかもしれありません。
 しかし,実はそのようなことは全くありません。それどころか,この暗号文,すなわち平文mの 左側に乱数rを連結したものを暗号化したものは,平文mにどのような偏りが存在してい ようとも,その暗号文全体において全く数字的な偏りは生じないのです。以下にそれを 証明してみましょう。

 ”.”を連結演算子,x及びyを非負の整数とすると,左側のr(ただしr>>m)は完 全にランダムな値なので,
    (r.m)^e=n*x+y    (n>y)
と表すとき,xは1の位の値も含めてランダムな値となります(均等にばらつく)。
 ところで,ある程度以上(2桁以上)の素数p,qの1の位の値はすべて必ず1,3, 7,9のどれかです。したがって,n=p*qの1の位の値はすべて必ず1,3,7, 9のどれかとなります。 これら4つの数は,次のような興味深い数学的性質を持ちます。 すなわち,nの1の位の候補1,3,7,9のどれに対して0から9までの数を掛けても,それらの答 えの1の位には必ず0から9までの数がすべて1つずつ均等に現れるのです。 この1,3,7,9の数学的性質から,n*xの値は1の位も含めて必ずランダムな値となります。 したがって,rがランダムであれば,(r.m)^eもランダムなので, yの値は1の位を含めて必ずランダムな値となります。
 以上のことから,たとえm,e,nが常に同じでも,rが乱数で常に異なれば, (r.m)^e mod nの1の位の値は完全に0から9まで均等にばらつくことになります。 したがって,パディングする際に平文mを右端に連結しても全く問題ないといえます。



目次 | 第1章 | 第2章 | 第3章 | 第4章

CyberSyndrome - The Proxy Search Engine