第一步
选择两个大质数p和q,越大越好,然后计算它们的乘积
N=p∗q
。 接着计算N的欧拉函数
φ(N)=φ(p)φ(q)=(p−1)(q−1)
(对正整数N,欧拉函数φ(N)是小于或等于N的正整数中与N互质的数的数目) 然后从随机选择一个整数e,要求e满足
0<e<φ(N)
并且与φ(N)互质。
最后,就可以计算出秘钥d了,它满足:
e∗d≡1(mod(φ(N)))
参见:
模逆元
扩展欧几里得算法
其中数e和N是公钥,用于加密信息,对所有使用者公开;数d和N是私钥,用于解密信息,用户自己保存。
第二步
信息发送者用对方的公钥e和N对发送的明文M进行加密运算可以获得加密信息C,对应的密文计算方法是:
C=MemodN
第三步
当信息的接收者接收到密文C后,采用私钥d和N进行解密获取明文信息M,对应的解密运算方法是:
M=CdmodN
由于在进行加密和解密的时候,要对明文或者密文进行幂的取模运算,求幂的结果往往很大,可能远远超出计算机处理的范围,所以必须简化计算方式。
对于任意整数b都可以用以下形式表示(n为b的二进制位个数,
bi
为实际二进制位,为0或者为1):
∑i=0n−1bi2i=b020+b121+b222+...+bn−12n−1
即 ab 就可以表示为:
ab=ab020+b121+b222+...+bn−12n−1=ab020×ab121×ab222×⋅⋅⋅×abn−12n−1
因此,可以用各项
abi2i={a2i,1,if bi is 1if bi is 0
的积来计算 ab ,也就是连续项 a2i 的积,其中跳过了那些二进制位 bi 为0的项。此外,我们可以只对前面项的计算结果进行平方来计算 a2i ,因为 a2i=(a2i−1)2 。
所以可以从右到左扫描,把相应二进制位为1的项包括在累乘器中,每一步都进行取模就可以得到最后的结果。
c++模拟实现
#include<iostream>
#include<cmath>
#include<cstring>
#include<ctime>
#include<cstdlib>
using namespace std;
#define MAX 50
long public_text[MAX]; //明文
long private_text[MAX]; //密文
int p = 521;
int q = 941; //因为只探究加密原理,所以此处的p和q直接指定为两个较小的素数
int N = p * q;
int e = 1777; //e与(p-1)*(q-1)互质
int d = 0;
int gcdEx(int a,int b,int & x,int & y) //扩展欧几里德算法
{
if(b == 0)
{
x = 1;
y = 0;
return a;
}
else
{
int r = gcdEx(b,a % b,x,y);
int temp = x;
x = y;
y = temp - a / b * y;
return r;
}
}
long mod(long a,int b,int N) //快速幂取模算法
{
long result = 1;
long temp = a;
while(b > 0)
{
if(b & 1 == 1) //按位与,每次判断最低位是否为1
{
result = (result * temp) % N;
}
temp = (temp * temp) % N;
b >>= 1; //右移1位
}
return result;
}
void init()
{
cout << "明文为:" << endl;
srand(time(NULL));
for(int i = 0;i < MAX;i++)
{
public_text[i] = rand() % 500 + 200; //生成200到700之间的随机数
cout << public_text[i] << " ";
}
cout << endl;
int on = (p - 1) * (q - 1);
int y = 0;
gcdEx(e,on,d,y);
if(d < 0)
{
d += on;
}
cout << "PK = (N,e) = (" << N << "," << e << ")" << endl;
cout << "SK = (N,d) = (" << N << "," << d << ")" << endl;
}
void RSA_Encrypt() //加密
{
cout << endl << "明文用公钥PK(" << N << "," << e << ")加密后的密文为:" << endl;
for(int i = 0;i < MAX;i++)
{
private_text[i] = mod(public_text[i],e,N); //分别对每部分明文进行加密
cout << private_text[i] << " ";
}
cout << endl;
}
void RSA_Decrypt() //解密
{
cout << endl << "密文用私钥SK(" << N << "," << d << ")解密后的明文为:" << endl;
for(int i = 0;i < MAX;i++)
{
cout << mod(private_text[i],d,N) << " "; //输出解密后的明文
}
cout << endl;
}
int main(int argc,char *argv[])
{
init();
RSA_Encrypt();
RSA_Decrypt();
return 0;
}