Where_Free

羸弱 无知 自大 懒惰

2019广东外语外贸大学CTF新手赛-密码学-RSA题解

题面

n=100000463700003241

e=17

密文:

 1 30876669824664856
 2 30876669824664856
 3 30876669824664856
 4 77223069454039395
 5 82242047293765567
 6 24233423779340487
 7 15484404506016653
 8 98468829472585108
 9 75555576962313807
10 42582342140719252
11 99781733958238709
12 77223069454039395
13 82242047293765567
14 75555576962313807
15 69867427593611884
16 52722366704774877
17 33922570905674122
18 87013233200361725
19 86151045766218388
20 87013233200361725
21 64866053818555083
22 79408929452159624
23 55986180764196875
24 40591873855071567
25 24233423779340487
26 95973722241816075
27 52722366704774877
28 91914702290680719
29 64866053818555083
30 75555576962313807 
31 94279162165241579 
32 87013233200361725 
33 95973722241816075 
34 52722366704774877
35 91914702290680719 
36 52722366704774877 
37 88815074647411982 
38 88815074647411982 
39 59675813170817903
40 7715722791264684
41 59675813170817903
42 7715722791264684
43 22373291521975461
44 59675813170817903
45 77223069454039395
46 10528298511885015
47 94279162165241579
48 69867427593611884
49 98468829472585108
50 
51 
52 11080055013504306
53 55617650536440882
54 52950329497873673
55 69867427593611884
56 55617650536440882
57 43009662331064017
58 32609881881220234
59 38938329728907166
60 10528298511885015
61 87013233200361725
62 24233423779340487
63 32520592532905261
64 40591873855071567
65 75555576962313807

 

分析:

题面已明示是RSA加密,已公开n与公钥e,n为1e18内的数字(64位).要爆破RSA,显然是先分析n的值。

n的值是由两个素数p和q相乘得出,所以我们需要将n因数分解。

n为64位,可能有1e18内的任意一对素数生成,计算机每秒运行少于1e9次,所以n^2暴力的素数表爆破是时间过长的。我们需要优化爆破算法。

我们可以取一个素数p,q=n/p,检测q是否为素数,q*p是否为n,以此来爆破p q(耗时1200秒左右)

根据这个思路,我们用米勒素数判定来检测p q即可实现(素数打表速度过慢)

也可以通过生成1e9的素数表,通过二分搜索来实现爆破,速度更快

代码如下:

  1 #include <iostream>
  2 #include <map>
  3 #include <time.h>
  4 using namespace std;
  5 #define ll long long
  6 /**
  7 Miller_Rabin 算法进行素数测试
  8 快速判断一个<2^63的数是不是素数,主要是根据费马小定理
  9 */
 10 //#define ll __int128
 11 const int S=8; ///随机化算法判定次数
 12 ll MOD;
 13 ///计算ret=(a*b)%c  a,b,c<2^63
 14 ll mult_mod(ll a,ll b,ll c)
 15 {
 16     a%=c;
 17     b%=c;
 18     ll ret=0;
 19     ll temp=a;
 20     while(b)
 21     {
 22         if(b&1)
 23         {
 24             ret+=temp;
 25             if(ret>c)
 26                 ret-=c;//直接取模慢很多
 27         }
 28         temp<<=1;
 29         if(temp>c)
 30             temp-=c;
 31         b>>=1;
 32     }
 33     return ret;
 34 }
 35 
 36 ///计算ret=(a^n)%mod
 37 ll pow_mod(ll a,ll n,ll mod)
 38 {
 39     ll ret=1;
 40     ll temp=a%mod;
 41     while(n)
 42     {
 43         if(n&1)
 44             ret=mult_mod(ret,temp,mod);
 45         temp=mult_mod(temp,temp,mod);
 46         n>>=1;
 47     }
 48     return ret;
 49 }
 50 
 51 ///通过费马小定理 a^(n-1)=1(mod n)来判断n是否为素数
 52 ///中间使用了二次判断,令n-1=x*2^t
 53 ///是合数返回true,不一定是合数返回false
 54 bool check(ll a,ll n,ll x,ll t)
 55 {
 56     ll ret=pow_mod(a,x,n);
 57     ll last=ret;//记录上一次的x
 58     for(int i=1;i<=t;i++)
 59     {
 60         ret=mult_mod(ret,ret,n);
 61         if(ret==1&&last!=1&&last!=n-1)
 62             return true;//二次判断为是合数
 63         last=ret;
 64     }
 65     if(ret!=1)
 66         return true;//是合数,费马小定理
 67     return false;
 68 }
 69 
 70 
 71 ///Miller_Rabbin算法
 72 ///是素数返回true(可能是伪素数),否则返回false
 73 bool Miller_Rabbin(ll n)
 74 {
 75     if(n<2) return false;
 76     if(n==2) return true;
 77     if((n&1)==0) return false;//偶数
 78     ll x=n-1;
 79     ll t=0;
 80     while((x&1)==0)
 81     {
 82         x>>=1;
 83         t++;
 84     }
 85     srand(time(NULL));
 86     for(int i=0;i<S;i++)
 87     {
 88         ll a=rand()%(n-1)+1; // 生成随机数 0<a<=n-1  去试试
 89         if(check(a,n,x,t))
 90             return false;
 91     }
 92     return true;
 93 }
 94 int main(){
 95     ll n,p,q;
 96     cin>>n;
 97     for(int i=0;i<2000000000;i++){
 98         if(Miller_Rabbin(i)){
 99             p=n/i;
100             if(Miller_Rabbin(p)&&i*p==n){
101                 cout<<p<<" "<<i<<'\n';
102                 break;
103             }
104         }
105     }
106 }
爆破p q

爆破出p q 后我们手搓RSA加密来生成密钥

(拓展欧几里得算法、欧拉函数、快速幂运算)

代码如下:

 1 #include <iostream>
 2 using namespace std;
 3 #define ll long long
 4 ll exgcd(ll a,ll b,ll &x,ll &y){
 5     
 6     if(a==0&&b==0) return -1;
 7     if(b==0){
 8         x=1,y=0;
 9         return a;
10     }
11     ll d=exgcd(b,a%b,y,x);
12     //cout<<a<<" "<<b<<'\n';
13     y-=a/b*x;
14     return d;
15 }
16 ll poww(ll a,ll b,ll c){  //快速幂取模
17     ll ans(1),base=a%c;
18     //a=a%c;
19     while(b){
20         if(b&1) ans=(ans*base)%c;
21         base=base*base%c;
22         b>>=1;
23     }
24     return ans;
25 }
26 
27 int main(){
28     int flag(0);
29     ll p,q,ou,ed,n,e(17),x(1),y(1),num1,ans,s;
30     cin>>flag;
31     if(flag==1){
32         cout<<"依次输入 p q 与 e:";
33         cin>>p>>q;
34         n=p*q;
35         ou=(p-1)*(q-1);
36         cin>>e;
37         num1=exgcd(e,ou,x,y);
38         //y=y+e/ou*x;
39         if(x<=0)x=(x+ou)%ou;
40         //x=(x+e)%e;
41         cout<<"N值:"<<n<<'\n';
42         cout<<"公钥:"<<e<<'\n';
43         cout<<"密钥:"<<x<<'\n';
44         return 0;
45     }
46     if(flag==2){
47         cin>>s>>e>>n;
48         ans=poww(s,e,n);
49         cout<<ans<<'\n';
50     }
51 }
RSA加密生成密钥

得到密钥后我们手写py脚本,通过密文算出明文(快速幂运算)

 1 def poww(a,n,mod):
 2     ret=1
 3     tmp=a%mod
 4     while(n>0):
 5         if(n%2!=0):
 6             ret=(ret*tmp)%mod
 7         tmp=tmp*tmp%mod
 8         n>>=1
 9     return ret
10 s1=e=n=1.0
11 n=int(input())
12 e=int(input())
13 while(True):
14      s1=int(input())
15      ans=poww(s1,e,n)
16      print(ans)
解密密文

观察生成的明文,我们发现其都在ASCII码的范围之内,尝试转出字符,可得到网址与博客密码

进入博客后可以看到一篇加密后的林肯的《底斯堡演讲》

因为题面提示,此密文为古典密码,我们可以通过分析字频(英文字母e i s)或者暴力破解(跑所有古典密码解密方案,并用词典进行对比),可以发现此加密为凯撒加密,即可得到flag

 

坑点、考点、思路总结:

首先你得会RSA加密(我学了一小时不到就来出题了)

在不会各种算法、数论知识的情况下可以借助外界工具解题,如在线因数分解,py库提供的种种数学调用

本题出题的目的是考察算法知识、数论知识、与对数据的分析判断,很多同学使用了各种外界工具来辅助解题,但依旧希望各位能够去了解、学习上述知识点与算法,为后续的密码学学习打下基础

 

posted on 2019-11-23 01:29  Where_Free  阅读(754)  评论(1编辑  收藏  举报

导航