暗号

RSA公開鍵暗号についてそれなりに力を入れて考えてみたら

以外に無くは無いんだと、気がついた(上から目線)

ハローワールド。

前回調べたDH法に引き続き、代表的な公開鍵暗号のRSAについて調べてみます。
RSA公開鍵暗号はDH法が現れた翌年、R.L. Rivest, A. Shamir, and L. Adlemanによる論文"A Method for Obtaining Digital Signatures and Public-Key Cryptosystems"が発表されました。
彼らの名前の頭文字をとって「RSA」公開鍵暗号。実際にはイギリスのJ H Ellis、C C Cocks、Malcolm WilliamsonたちがRSA→DH法という順番に似たようなものを「先に」見つけているのですが、歴史の妙のお話ということで、具体的には調べませんでした。

ここでは彼らの論文[1]の流れに沿ってRSA公開鍵暗号方式について調べてみました。

RSA公開鍵暗号について

彼らの論文のAbstract(の一部)を読んでみましょう。

An encryption method is presented with the novel property that publicly revealing an encryption key does not thereby reveal the corresponding decryption key. This has two important consequences.

  1. Couriers or other secure means are not needed to transmit keys, since a message can be enciphered using an encryption key publicly revealed by the intended recipient. Only he can decipher the message, since only he knows the corresponding decryption key.
  2. A message can be “signed” using a privately held decryption key. Anyone can verify this signature using the corresponding publicly revealed encryption key. Signatures cannot be forged, and a signer cannot later deny the validity of his signature. This has obvious applications in “electronic mail” and “electronic funds transfer” systems

暗号化鍵を公開しても、それによって対応する復号鍵は公開されないという斬新な性質を持つ暗号方式について紹介します。これは2つの重要な結果をもたらします。

  1. 意図した受信者によって公開された暗号化鍵を用いてメッセージを暗号化できるので、鍵を伝送するための宅配便やその他の安全な手段は必要ありません。対応する復号鍵を知っているのは受信者だけなので、受信者だけがメッセージを解読することができます。
  2. メッセージは、非公開の復号鍵を使って「署名」することができます。誰でも、対応する公開された暗号化鍵を使って、この署名を検証することができます。署名は偽造できないし、署名者は後で署名の有効性を否定できません。これは、「電子メール」や「電子資金移動」システムに明らかに応用されるものです。

DH法が解決したものは共通鍵の配送問題ですが、RSAでは「公開鍵暗号」と「電子署名」の2つを行うことが可能であり、多くの問題を解決し応用が可能となるものです。
電子署名はDHの論文でも示唆している部分であり、それの完全なる解答と呼べるのがRSA公開鍵暗号です。

あまりにも有名なためRSA = 公開鍵暗号方式 = デジタル署名という勘違い(?)が生まれて、おおよそ夏の季語と呼べるほどには「秘密鍵で暗号化」[2]の文言へのツッコミが見られますね。

RSA公開鍵暗号の性質

RSA公開鍵暗号は2つのことができます。「公開鍵暗号」と「電子署名」です。因みにここでいう公開鍵暗号は任意のメッセージの暗号・復号できるものですね[3]

論文中では「公開鍵暗号システム」の4つの性質について記載があります。あくまでも論文内の記載はそうですが、広い意味では異なってしまいます。なので、一旦はあくまで下記はRSAの性質と理解しておきます[4]

  1. メッセージMを暗号化(E()E())し、復号(D()D())するとMが得られる。式で書くと

D(E(M))=M\begin{aligned} D(E(M)) &= M \end{aligned}

  1. 暗号化(E()E())と復号(D()D())は簡単に計算できる
  2. 暗号化(E()E())の手順を公開しても復号(D()D())は簡単に出来ない。つまり、当人だけが暗号化されたメッセージを復号でき、Dを効率的に計算ができるということである
  3. メッセージMを最初に復号(D()D())してから暗号化(E()E())することでMが得られる。式で書くと

E(D(M))=M\begin{aligned} E(D(M)) &= M \end{aligned}

秘匿(Privacy)

上記の性質を見ればメッセージの秘匿(機密性の向上)は簡単にできそうですね。

AliceがBobに対してメッセージMMを秘匿して送りたい場合事前にBobの公開鍵(ここでは暗号化)EBE_Bを受け取り、1.の性質を利用しAliceがEB(M)E_B(M)によりMEM_Eを送り、BobがDB(ME)D_B(M_E)を行うことでメッセージの送信が可能となります。ここでMEM_Eが第三者に盗聴されていても、性質3より平文MMは第三者にわからないというわけです。

署名(Signatures)

論文中では、署名に関しては背景、電子署名の必要条件などについても多く語られています[5]

そしてRSAでは電子署名は下記の方法で実現が可能です。

BobはAliceに署名付きのメッセージMを送信しようと思いました。

まず、Bobは署名SSを下記の方法で求めました。

S=DB(M)S = D_B(M)

この時論文には「暗号化されていないメッセージを復号することは、性質4によって「意味のある(makes sense)」ことになります」という注釈がされています。

次にAliceへメッセージを送信します。ただし、このときに送るのはSS。更に秘匿するためにAliceの公開鍵(EAE_A)で暗号化し送ります(EA(S)E_A(S)を送付する)。

AliceはDAD_AでSを取得できるので、最後のBobの公開鍵EbE_bを利用しメッセージを取得できます。

M=EB(S)M = E_B(S)

ここで性質を振り返ると、Bobの公開鍵で暗号化出来たため、SはBobしか生成できないはずの(EB(D))(E_B(D))である、つまりSはBobが生成したものであることがわかります。逆に言えば確実にBobが生成したため、Bobはこのメッセージに対する否認が出来ません。
また、Alice(または第三者)はMMを改ざんしMM'を生成した場合、その時は対応するSS'も生成しなければならないが、それも不可能です。つまりMMの改ざんも不可能となります。

この方法でデジタル署名を生成することが出来ます。DSAの方法とは異なり、デジタル署名から平文を生成できるのがRSAの特徴と呼べます。実際にはRSAでデジタル署名する場合は、実際はメッセージのハッシュ(SHA2などを利用する)を取得し、そのハッシュに対してRSAで署名を作成する方法が一般的かと思われます。

RSA公開鍵暗号方式の具体的な方法

RSAは「公開鍵暗号方式」について公開鍵(D()D())と秘密鍵(E()E())という概念での説明をしていました。公開鍵は暗号化、秘密鍵は復号に用いります。

暗号化

RSA暗号方式では公開鍵は2つのパラメーターがあります(e,ne, n)。2つのパラメーターのは正の整数です。

nnですが、これは2つの素数p,qp, qの積となります(素数は任意です)。このnnの長さkkはいわゆるセキュリティパラメータで、ssh-keygen-bオプションで指定するbit数とかですね。
そしてnnkkの長さを持つために、論文内では2つの素数p,qp, qk/2k/2の長さを持つことをおすすめ(RECOMMEND)しています[6]

そしてeennと互いに素である必要があります = お互いがの約数のうち1以外が一致しない = 1が最大公約数です。

RSAから少し離れますが、ϕ(x)\phi(x)をオイラーのϕ\phi関数と呼び、これは11以上xx未満の値のうちxxと素な数の個数を表します。
そしてe<ϕ(n)e < \phi(n)以下である必要が有りϕ(n)=(p1)(q1)=n(p+q)+1\phi(n) = (p - 1)(q - 1) = n - (p + q) + 1となるらしいです。

eeを上記条件でランダムな値を取るとして、メッセージMの暗号化は下記手順です。
ただし0M<n0 \leqq M < nです。

C=E(M)MemodnC = E(M) \equiv M ^ e \bmod n

えらくシンプルですね。

復号

秘密鍵ddeeより導かれます。DH法の逆ですね。ddは下記を満たす正の整数である必要があります。

ed1modϕ(n)e \cdot d \equiv 1 \bmod \phi(n)

これは任意の整数iを用いて下記のように求めることが可能です。

ed=1modϕ(n)ed+iϕ(n)=1\begin{aligned} e\cdot d &= 1 \bmod \phi(n)\\ e \cdot d + -i \cdot \phi(n) &= 1 \\ \end{aligned}

これに対してユークリッドの互除法(Wikipedia)を利用して、ddiiを求めます(eeϕ(n)\phi(n)は互いに素であるため最大公約数は必ず1となります)。
具体的な手順は具体例に記載しています。

n,dn, dを用いて暗号文CCを下記の式で復号出来ます。

M=D(C)CdmodnM = D(C) \equiv C^d \bmod n

ちなみに、上記の式の証明も論文内に記載があるので、ここでは説明しませんが、詳しく知りたい方は読んでみてください。

また、RSAでは公開鍵eeϕ(n)\phi(n)から秘密鍵ddを導出していますが、秘密鍵ddϕ(n)\phi(n)よりeeを求める方法も提示されています。

具体例

具体的な数字を利用して考えてみましょう。

p=11q=17n=pq=187ϕ(n)=(p1)(q1)=160e=23\begin{aligned} p &= 11\\ q &= 17\\ n &= p \cdot q = 187 \\ \phi(n) &= (p - 1) \cdot (q - 1) = 160\\ e &= 23 \\ \end{aligned}

ここでddを求めてみます。
目指す形はde+iϕ(n)=1d \cdot e + -i \cdot \phi(n) = 1ですね。

まずユークリッドの互除法を利用して最大公約数を求めます。と言っても必ず1になるのですが。

187=623+22(22=187623)23=221+1(1=23221)1=11\begin{aligned} 187 &= 6 \cdot 23 + 22(22 = 187 - 6 \cdot 23) \\ 23 &= 22 \cdot 1 + 1 (1 = 23 - 22 \cdot 1)\\ 1 &= 1 \cdot 1 \\ \end{aligned}

続いては上記式の「途中」の式を用いてde+iϕ(n)=1d \cdot e + -i \cdot \phi(n) = 1の形へ持っていきます。今回はd23+i187=1d \cdot 23 + -i \cdot 187 = 1ですね。

1=23221=23(187623)=723+1187d=7(i=1)\begin{aligned} 1 &= 23 - 22 \cdot 1 \\ &= 23 - (187 - 6 \cdot 23) \\ &= 7 \cdot 23 + -1 \cdot 187 \\ \therefore d &= 7(i = 1) \end{aligned}

これでddが求まりました。

ここで"sa2taka"という文字列を暗号化したいとします。
この時の変換ルールと変換結果は下記とすると文字列を数字に変換可能です。

0=00,1=01,,9=09_(space)=10a=11,b=12,z=36sa2taka=2911023011121110 = 00, 1 = 01, \ldots, 9 = 09 \\ \_(\text{space}) = 10\\ a = 11, b = 12,\ldots z = 36 \\ \text{sa2taka} = 291102301112111

まずは公開鍵e,ne, nで暗号化をしてみます。
ただしMMnn未満である必要があるため、ここでは2桁づつに区切りそれぞれの桁で暗号化を行います。今回はsに値する2929を例示してみます。

C=Memodn=2923mod187=24\begin{aligned} C &= M ^ e \bmod n\\ &= 29 ^ {23} \bmod 187 \\ &= 24 \end{aligned}

続いて秘密鍵ddで復号をしてみます。

M=Cdmodn=247mod187=29\begin{aligned} M &= C^d \bmod n\\ &= 24 ^ {7} \bmod 187\\ &= 29 \end{aligned}

他の文字列でも同様に求めることが出来ます。

また、今度は"sa2taka"に署名を付けて送ることを考えます。
単純に逆のことを行えばいいので下記のようになります(今回も送るのは29です)。

まずは署名作成。

S=Mdmodn=297mod187=160\begin{aligned} S &= M^d \bmod n\\ &= 29 ^ {7} \bmod 187\\ &= 160 \end{aligned}

そして署名検証。

M=Semodn=16023mod187=29\begin{aligned} M &= S ^ e \bmod n\\ &= 160 ^ {23} \bmod 187 \\ &= 29 \end{aligned}

すごい(小並感)

最後に

DH法みたいなものを作り気力はなかったので// TODO:とします…。


  1. R.L. Rivest, A. Shamir, and L. Adleman, “A Method for Obtaining Digital Signatures and Public-Key Cryptosystems”,https://people.csail.mit.edu/rivest/Rsapaper.pdf 2020/10/28閲覧 ↩︎

  2. ちなみにDH法が提案された論文"New directions in cryptography"には電子署名の提案がなされています。その中の文言(日本語訳)の一部にこう記載があります。「(前略)ユーザAは自分の秘密鍵でメッセージMを「復号」し、DA(M)を送信する。ユーザBはそれを受信すると、ユーザAの公開鍵で「暗号化」することで(中略)」いわゆるRSAでの電子署名の方法ですが、この時でも秘密鍵で「復号」という文言があります(ご丁寧にクオーテーションに囲まれて)。
    この論文では秘密鍵が「secret deciphering key」、公開鍵が「public enciphering key」という記載になっており、役割を完全に固定したいた文言にもなっています。後ほどRSAでも具体的な記載がありますが、「秘密鍵で暗号化」というのは少なくともDH法、RSAでは間違いです。 ↩︎

  3. おそらくRSAでこの利用方法は鍵交換のタイミングだけではないでしょうか…。わざわざ公開鍵暗号で行うより、鍵交換してから共通鍵でメッセージをやり取りするほうがずっと早いからです。実情は残念ながら知識不足ですが。 ↩︎

  4. 例えばDSAの原型となったElGamal署名でも有名なElGamalさんが作ったElGamal暗号というものがあります。これは公開鍵暗号ですが、要素4は成していません(そもそも暗号文が2つに分割されてくるし)。なので署名のアルゴリズムとして別のElGamal署名を作る必要もあったんですね。 ↩︎

  5. 署名は署名者に加えメッセージに依存する必要があるという記載が明示されています。これにより完全性・真正性の向上の他に、否認防止が可能となります。
    ちなみにDH法もそうですが(あえて記載はしていませんでした)、第三者攻撃に関しては脆弱ですので、その部分のセキュリティはまた別の対策が必要です。 ↩︎

  6. この文言はRSA暗号の標準であるRFC8017: PKCS #1では記載がおそらく有りません。kkbitのnnを生成する記載はありますが、p,qp, qの桁数などは明記されていません。というのも素数を3つ以上利用するmulti-prime RSAなんてのもあるらしいからですかね。 ↩︎