RSA
- RSA加密算法详解
- 前言
- 算法描述
- 真正的描述
- 密钥的生成
- 加密
- 解密
- 解密证明
- RSA算法C实现
- RSA算法的有效实现
- 如何快速计算`a^m mod n`?
- C代码
- 如何计算`φ(n)`?
- C代码
- 如何计算`e`对于`φ(n)`的乘法逆元`d`?
- C代码
- 如何检测一个数是素数?
- 如何找到足够大的素数`p、q`?
RSA加密算法详解
前言
随着网络的迅速发展与普及,对称加密算法越来越难以满足网络通信中对安全性的需求,随着人们对密码学的研究逐渐加深非对称加密算法出现并迅速应用到网络通信中。(。。。额,随便瞎扯:)
在一个有n
个网络用户组成的网络通信区域里,如果使用对称加密算法保证通信的安全,因为任意两个用户之间通信需要一个密钥那么要管理的密钥有(n-1)!
个,在用户数量较大的情况下这个数是很庞大的,所要耗费的资源也是巨大的;如果使用非对称加密算法,因为任意一个用户与其他用户通信只需要一对密钥那么要管理的密钥有2n
个,比之对称加密算法要节省很多资源。
算法描述
我是这么理解的:
RSA算法是把公钥公开,任何人都可以使用公钥进行加密,但所得密文只有拥有私钥的人才能解密。
RSA算法在只拥有公钥与密文的情况下难以解密得到密文的依据是:
对于两个不相等的大素数p、q
的乘积n
,在仅知道n
不知道p、q
的情况下小于n
的正整数中与n
互素的数的数目是难以计算的(称这个数为φ(n)
)。
由欧拉函数可知:φ(n)=(p-1)*(q-1)
。
真正的描述
密钥的生成
选择两个不相等的大素数p、q
,计算n=p*q
、φ(n)=(p-1)*(q-1)
,选择一个随机数e(0<e<φ(n))
,e
与φ(n)
互素。计算d=e^(-1)modφ(n)
(即计算e
对于φ(n)
的乘法逆元)。
经过以上计算得到:
公钥:KU={e,n}
私钥:KR={d,p,q}
或KR={d,n}
加密
对明文进行分组,令其每一个分组都小于n
,用M
代表明文C
代表密文。
已知:明文M
、公钥KU={e,n}
,
有: C=M^e mod n
。
解密
已知:密文C
、私钥KR={d,n}
,
有: M=C^d mod n
。
解密证明
M
=C^d mod n
=(M^e mod n)^d mod n
=M^ed mod n
=M^(1+kφ(n)) mod n
(因为ed=1 mod φ(n)
,k
为整数)=[M * ( M^kφ(n) )] mod n
=M mod n * [( M^φ(n) )^k ] mod n
=M mod n * 1^k mod n
(因为φ(n)=n-1、M^(n-1) mod n = 1
,故M^φ(n) mod n = 1
)=M mod n
=M
前面已经说了:
对于两个不相等的大素数p、q
的乘积n
,在仅知道n
不知道p、q
的情况下,难以求得φ(n)
(因为n
为两个大素数的乘积,故不为素数,不能用欧拉函数求φ(n)
,n
又为一个非常大的数难以用从1
开始到n-1
逐个数去判断是否与n互素来计算φ(n)
),所以在仅知道公钥KU={e,n}
的情况下难以求得e
对于φ(n)
的乘法逆元d
。
RSA算法C实现
RSA算法的有效实现
如何快速计算a^m mod n
?
在这里描述一种帮助计算的算法——快速取模指数算法。
先用一个例子来描述:a^13 =( ( ( a^1 )^2 * a^1 )^2 * a^0 )^2 * a^1
在上面的式子中等号右边a
的次方数与13
的二进制表示1101
各位的值有关,比如1101
第一位为1
,( ( ( a^1 )^2 * a^1 )^2 * a^0 )^2 * a^1
第一个a的次方数为1
,1101
第二位为1
,( ( ( a^1 )^2 * a^1 )^2 * a^0 )^2 * a^1
第二个a的次方数为1
,1101
第三位为0
,( ( ( a^1 )^2 * a^1 )^2 * a^0 )^2 * a^1
第三个a的次方数为0
,1101
第四位为1
,( ( ( a^1 )^2 * a^1 )^2 * a^0 )^2 * a^1
第四个a的次方数为1
。
如果按照a^13 =( ( ( a^1 )^2 * a^1 )^2 * a^0 )^2 * a^1
来计算a^13 mod n
,这样并没有简化计算过程,但如果对每个括号里的值都进行一次mod n
运算,这就大大简化计算过程,即:a^13 mod n=( ( ( a^1 mod n )^2 mod n * a^1 mod n )^2 mod n * a^0 mod n )^2 mod n * a^1 mod n
当然,a
的次方数的二进制表示有几位等号右边就有几个括号几个a
。
在上面的计算中可以看到等号右边在不断重复( x )^2 mod n * a^y mod n
,x
为上一轮计算的结果,y
为当前轮计算所对应的位的值。
C代码
int mod_square(int a, int m, int n)
{
int i, j, c;
for (i = 0; m / pow(2, i) >= 1; i++);//判断 m 二进制有几位
int ZU[100];
j = i; c = 1;
for (; i > 0; i--)//用 ZU 数组存放 m 二进制各位,从低位到高位存放
{
ZU[i - 1] = m / pow(2, i - 1);
m = m % int(pow(2, i - 1));
}
for (; j > 0; j--)
{
if (ZU[j - 1] == 0)c = (c*c) % n;//位值为 0 时
else c = (((c*c) % n)*a) % n;//位值为 1 时
}
return c;
}
如何计算φ(n)
?
对于φ(n)
可以使用欧拉函数的性质求得。
欧拉函数的性质:
(1)n
是素数时,φ(n)=n-1
;
(2)n=p*q
,且p
和q
是互异的素数时,φ(n) = φ(p) * φ(q) = (p-1) * (q-1)
;
(3)对于任何大于1
的整数均可表示成素数幂之积的形式,即n= p1^e1 * p2^e2 * p3^e3 *p4^e4 ..... pt^et
,pi (i=1,2,...,t)
是素数,有以下定理成立。
定理:φ(n)=p1^(e1-1)*(p1-1) * p2^(e2-1)*(p2-1) *..... pt^(et-1) * (pt-1)
或表示成:φ(n)=n * (1- 1/p1) * (1- 1/p2) * (1- 1/p3) * ..... (1- 1/pt)
查了一些资料,发现p1、p2、p3.....pt
等都是n
的质因数,下面介绍快速求得n
表示成素数幂之积的形式中的素数的方法:
for(i=2;n!=1;i++)
{
if(n%i==0)
{
printf("%d",i);
while(n%i==0) n/=i;
}
}
(因为表达能力不足,只能用代码描述 :)
这个循环中输出的i
都是n
的质因数,可以用φ(n)=n * (1- 1/p1) * (1- 1/p2) * (1- 1/p3) * ..... (1- 1/pt)
求φ(n)
。
C代码
int euler(int n)
{
int i, a = n;
for (i = 2; n != 1; i++)
{
if (n%i == 0)
{
a=a - (a / i);
while (n%i == 0) n /= i;
}
}
return a;
}
如何计算e
对于φ(n)
的乘法逆元d
?
可以用扩展欧几里得算法、欧拉函数等来计算乘法逆元,但只有扩展欧几里得算法具有普遍性,故这里介绍扩展欧几里得算法c代码实现。
扩展欧几里得算法的一种描述:
要计算a^(-1) mond n
,引入中间变量Xi
,基于商qi
和余数ri
之间的关系,首先将n
和a
分别赋值给ri
的前两个变量,将0和1分别赋值给xi
的前两个变量,完成初始化;然后循环利用qi = ri-1 / ri
,ri+1 = ri-1 - qi * ri
和xi+1 = xi - qi * xi
,直到余数ri = 1
结束循环,xi
就是a
对于n
的乘法逆元。前提是a
与n
互素,否则a
对于n
的乘法逆元不存在。
C代码
//这里使用了递归,对 q、r、x 都设置了两个变量交互存值
//inverse(a, n,1,1,0,1);设置 x0、x1的初始值为 0、1,q0、q1的初始值为任意
int inverse(int r1,int r0, int q0,int q1,int x0,int x1)
{
q1 = r0 / r1; r0 = r0 % r1; x0 = x0 - (q1*x1);
if (r0 == 1)return x0;
q0 = r1 / r0; r1 = r1 % r0; x1 = x1 - (q0*x0);
if (r1 == 1)return x1;
return inverse(r1, r0, q0, q1, x0, x1);
}
如何检测一个数是素数?
如何找到足够大的素数p、q
?