day2,
题目描述

分析
RSA加密, 对于CTF选手来说, 实在太熟悉了, 直接
http://factordb.com/ 分解 n
得到 p = 891234941, q = 1123984201
1
2
3
4
5
6
7
8
| import gmpy2
n = 1001733993063167141
d = 212353
c = 20190324
p = 891234941
q = 1123984201
e = gmpy2.invert(d, (p-1)*(q-1))
print(gmpy2.powmod(c, e, n))
|
得到明文 579706994112328949
但是在赛场上肯定是不能调用这些包的, 所以趁此机会, 把相关的 分解n , 求d的算法学习一下.
分解n
思路一: n算是比较小的,可以采用直接爆破,由于Python计算特别慢, 采用C++ 来把p、q 爆破出来。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| #include<iostream>
#include<math.h>
using namespace std;
bool isPrime(long x){
for(long i = 2; i< sqrt(x); i++){
if(x%i ==0)
return false;
}
return true;
}
int main(){
long n=1001733993063167141;
long p=2;
while(p < sqrt(n)){
if(n%p==0 && isPrime(p) && isPrime(n / p)){
cout<<'p:'<<p<<'\t'<<'q:'<<n/p<<endl;
break;
}
if(p % 100 == 0)
cout<<p<<endl;
p++;
}
return 0;
}
|
求解 e
已知 $(de) \% ((p-1)(q-1)) = 1$ , 令 $phi = (p-1) * (q-1)$
即 $d * ? - phi * k = 1$ , k 为系数,则问号就是要求的逆元
以一个具体的例子来看 $701\times?-1848\times k=1$
step1 先用辗转相除法,"求" 701和1848的最大公因数gcd
设整数a,b不同时为0, 则存在一对整数m,n,使得gcd(a, b) = am + bn

Step 2 推出相邻式子的关系
根据
\(
gcd(a,b) = gcd(b, a\%b)
\)
已知
\(
gcd(a,b)=ax+by\\a\%b = a-(a//b)*b\\gcd(b,a\%b)=bx'+((a-(a//b)*b)*y')=ay'+b(x'-a//b*y')
\)
推得
\(
x = y'\\y=x'-a//b*y'
\)
Step 3 扩展欧几里得
从Step1中,最后得出1和0可以列出$a1+b0=gcd(a,b)=1$这一式子, 再根据Step2推得的$x = y'$可以一步一步往上代入,以此类推,从而推出每一步的因子x和y,顺序如下

推到刚开始的1848和701后,我们得到y为29,即为所求的逆元。
注意:如果得到的y为负数,需要取模才能得到逆元。
容易验证: 701 * 29 = 1 (mod 1848)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| def ext_gcd(a, b): #扩展欧几里得算法
if b == 0:
return 1, 0, a
else:
x, y, gcd = ext_gcd(b, a % b) #递归直至余数等于0(需多递归一层用来判断)
x, y = y, (x - (a // b) * y) #辗转相除法反向推导每层a、b的因子使得gcd(a,b)=ax+by成立
return x, y, gcd
def computeD(fn, e):
(x, y, r) = ext_gcd(fn, e)
#y maybe < 0, so convert it
if y < 0:
return fn + y
return y
e = computeD((p-1)*(q-1), d)
print(e)
|