簡略RSA暗号

<背景> 暗号文、平文ともに、正の整数とする。

以下の式によって、暗号化、復号化を行うこととする。

暗号文 = 平文のe乗 mod p*q
平文 = 暗号文のd乗 mod p*q

ここで、d = (n*(p-1)(q-1)+1)/e (今回は簡略化のためn=1)とする。 

受信者 Aさん が、送信者 B さんから、暗号を受け取りたい。

受信者 Aさん: p, q, eを決め、p*qの積とeのセットを公開鍵として、Bさんに送る(公開する)。
送信者 Bさん: 上の式に従って、平文を暗号化し、暗号文をAさんに送る
受信者 Aさん: 上の式に従って、秘密鍵dを計算しておき、暗号文を、平文に復号する。


デジタル署名 (秘密鍵で暗号化すれば、公開鍵で復号できることを利用)

受信者 Bさんは、送信者が Aさんであることを、確認したい。

送信者 Aさん: p, q, 公開鍵eを決め、p*qとeをBさんに送る
送信者 Aさん: 平文1と、秘密鍵dで平文を暗号化した暗号文の2つを送る

受信者 Bさん: 暗号文を公開鍵で復号し、平文2を得る
送信者 Bさん: Aさんから届いた平文1と、復号した平文2が一致するなら、Aさんである。(平文は、Aさんしか知らないはずである)

というのがエッセンス。実際は、Aさんが送る平文1に、さらに安全性を高める工夫がある。
この方法には、
(1)送信者がAさんであること、(2)送られてきた平文に改ざんがないことを確認できる


<問題> 上の暗号化のプログラムと、復号のプログラムを作成せよ。

<実行例>
素数p = 3
素数q = 11
公開鍵e = 7
平文 = 9 (← ここまで入力。Bさんは、33と7しか伝えられない.33は素因数分解できるが、現実にはもっと大きな2つの素数を使い、大きな積を公開する)
暗号文 = 15 (Bさんは、暗号文15を送信する)

素数p = 3 
素数q = 11
公開鍵 = 7 (← ここまで入力すると、下を表示。Aさんは、ここまで準備できている)
秘密鍵 = 3 
暗号文 = 15 (Bさんから届いた暗号文15を、準備に従って復号すると、下)
平文 = 9 (Aさんは9と復号、解読)

矢沢久雄 : "素因数分解とRSA暗号" 日経ソフトウェア 2010年8月号付録 (プログラムを改変)



解答例
/* 暗号化 */
#include <stdio.h>

int main (void) {
   unsigned int p, q, pubkey, plaintext, ciphertext, i;

   printf("素数p = ");
   scanf("%u", &p);

   printf("素数q = ");
   scanf("%u", &q);

   printf("公開鍵e = "); /* public key */
   scanf("%u", &pubkey);

   printf("平文 = ");
   scanf("%u", &plaintext);

   ciphertext = 1;

   for (i = 1; i <= pubkey; i++)
     ciphertext *= plaintext;  /* plaintextの数をpubkey乗する */

   ciphertext %= p*q; /* 素数pとqの積で割った余りが、暗号文 */

   printf("暗号文 =  %u\n", ciphertext);

   return 0;
}

/* ここからは、復号のプログラム。別のプログラムです。
 それぞれ、別のファイルに作成、コンパイルして実行のこと */
#include <stdio.h>

int main (int argc, char *argv[]) {
   unsigned int p, q, pubkey, prikey, ciphertext, plaintext,i;
   unsigned int n;
   n = 1;

   printf("素数p = ");
   scanf("%u", &p);

   printf("素数q = ");
   scanf("%u", &q);

   printf("公開鍵 = ");
   scanf("%u", &pubkey);

   prikey = (n*(p -1)*(q-1) + 1)/pubkey;
   printf("秘密鍵 = %u\n", prikey);

   printf("暗号文 = ");
   scanf("%u", &ciphertext);

   plaintext = 1;
   for (i = 1; i <= prikey; i++)
      plaintext *= ciphertext;

   plaintext %= p*q;

   printf("平文 = %u\n", plaintext);

   return 0;
}