有同学想了解RSA的原理,我就想到了多年前做ACM时候做的一道题目POJ2447 破解62bit长度的RSA算法。这道题目很好的说明了RSA的原理,更棒的是它提供了一个练手的机会能够让大家在理解了RSA原理的基础上面,自己实现62bit破解程序。在附件中我也附上了当年实现的一个代码例子(代码能够通过ACM的样例INPUT,符合时间和内存的要求)。写的不好地方,希望大家指正。从提交结果来看,大家主要是时间上面不能通过,这个也很好理解,破解密码从来都是一个时间瓶颈的工作。
这个系列分成上下两个部分,本篇是上。上篇主要是通过ACM为切入点,介绍RSA的原理、提供一个仅做参考的C++实现的破解程序和将ACM网页中的英文翻译成中文供大家参考。下篇则是对破解程序背后的数学原理(RSA本身的数学原理已经超出了这篇文章的范畴,有兴趣者可以和作者交流)以及计算机算法优化和代码中每个函数的意义进行一个简介。
下面是对POJ2447 破解62bit长度的RSA算法的一个翻译
RSA已经是当今最著名的公钥加解密算法,它通过向使用者提供一个独一无二的私钥和一个地球人都知道的公钥来进行工作。当使用者想发送加密数据的时候,发送方首先使用地球人都知道的公钥进行加密,接受方则使用自己独一无二的私钥进行解密。更具体的RSA过程如下:
首先选择两个足够大的素数P和Q,这两个大素数的乘积N=P*Q
其次选择一个正数E它满足 条件1:(0<E<N)并且满足条件2:当T=(P-1)*(Q-1)时,E和T互质。我们把符合条件的E称为Encryption Key(加密钥)
最后我们要计算Decryption Key(解密钥)D它满足 条件1:(0<=D<T)并且满足条件2:(E*D)MOD T = 1
现在我们把得到的{E, N}对称为公钥,把得到的 {D, N}对称为私钥。至此,我们再也用不到P和Q了。
我们假设需要加密的明文是M。M是一个非负的整数,并且M<N。
我们假设需要加密的密文是C。
那么加密的过程就是C=(M^E) MOD N,解密的过程就是M=(C^D) MOD N,其中 “^”符号的含义是求幂指数
为了更直观的说明RSA算法的加解密过程,请看下面的例子
按照上述的步骤,我们首先选择P=37 Q=23,通过其可以计算得到N=PQ=851以及T=(P-1)(Q-1)=792。假设我们选择和T互质的E=5,那么D=317 ((5*317) MOD 792)=1。
我们可以得到公钥为{5, 851} 私钥为{317, 851}。假设明文M=7,那么
C=(M^E) MOD N=(7^5)MOD851=638
M=(C^D) MOD N=(638^317)MOD851 = 7
就目前的经验来看,如果我们选择了极大的P和Q的话,那么根据公钥和密文去破解明文将会花费极长的时间。但是当P和Q选择小素数时,破解并非不可能。下面提供一份当年AC这道题目的代码。现在再回过头来这份代码为啥有种满满的尴尬的感觉呢?
#include <algorithm>
__int64 x = 0, y = 0 ;
__int64 gcd(__int64 a, __int64 b)
{
if (0 == b)
{
x = 1 ; y = 0 ;
return a ;
}
__int64 g = gcd(b, a % b) ;
__int64 t = x ;
x = y ;
y = t - (a / b) * y ;
return g ;
}
__int64 mulmod(__int64 a,__int64 b,__int64 p)
{
__int64 d = 0 ;
while (b)
{
if (b % 2)
d += a ;
d %= p ;
b >>= 1 ;
a <<= 1 ;
a %= p ;
}
return d ;
}
__int64 expmod(__int64 a, __int64 b, __int64 n)
{
__int64 d = 1 ;
__int64 t = a ;
while (b)
{
if (b % 2)
d = mulmod(t, d, n) ;
b >>= 1 ;
t = mulmod(t, t, n) ;
}
return d ;
}
__int64 rho(__int64 n)
{
__int64 d = 0, t = 0, c = 240 ;
while (1)
{
int i = 1, k = 2 ;
__int64 mmx = 2, mmy = mmx ;
while (1)
{
++i ;
mmx = (mulmod(mmx, mmx, n) + c) % n ;
t = (mmy - mmx) >= 0 ? (mmy - mmx) : (mmx - mmy) ;
d = gcd(t, n) ;
if (1 != d && n != d)
break ;
if (mmy == mmx)
break ;
if (i == k)
{
k <<= 1 ;
mmy = mmx ;
}
}
if (1 != d && n != d)
return d ;
--c ;
}
}
__int64 T(__int64 n)
{
__int64 p = rho(n) ;
__int64 q = n / p ;
return (p - 1) * (q - 1) ;
}
__int64 D(__int64 e, __int64 t)
{
gcd(e, t) ;
return (x >= 0) ? x : (x + t) ;
}
__int64 M(__int64 c, __int64 d, __int64 n)
{
return expmod(c, d, n) ;
}
int main()
{
__int64 c, e, n, t, d ;
while(scanf("%I64d %I64d %I64d", &c, &e, &n)!=EOF)
{
t = T(n) ;
d = D(e, t) ;
printf("%I64d\n", M(c, d, n)) ;
}
}
抱歉上面这段没有任何注释。不过想要真正的了解RSA原理可不是一时半会儿就能想通的。我会在下一篇文章RSA原理(中)给大家带来