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庫提供的種種數學調用

本題出題的目的是考察算法知識、數論知識、與對數據的分析判斷,很多同學使用了各種外界工具來輔助解題,但依舊希望各位能夠去了解、學習上述知識點與算法,為后續的密碼學學習打下基礎

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM