原题地址:https://adworld.xctf.org.cn/challenges/details?hash=08957e3e-3b35-11ed-abf3-fa163e4fa609&task_category_id=5
原题代码如下:
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 for _ in range (3 ): p = random_prime(2 ^1024 ) q = random_prime(2 ^1024 ) n = p*q p1=p>>724 ct=n * inverse_mod(q % (2 ** 265 ), 2 ^265 ) % 2 ^265 print ('p1=' ,p1) print ('ct=' ,ct) print ("n=" ,n) e = 65537 alarm(80 ) m = randint(2 ,n-1 ) c=pow (m,e,n) print ('c=' , c) print ('---------------------------------------------' ) m1 = int (input ("m=" )) print ('---------------------------------------------' ) print () if m1!=m: print ("Nope" ) exit() print (open ("flag.txt" ,"r" ).read())
分析题目,取两个1024位大质数p、q相乘得n,输出p的高300位p1 和处理q得到的ct 。m任取(所以不能通过自然语言判断)后加密为c并输出。我们的任务是通过p1、ct和n推出p、q来解密m。验证3轮都正确后输出flag。
线性同余方程的解法
首先对ct进行分析可得线性同余方程组:
设 q 1 = q m o d 2 265 设 i = i n v e r s e ( q 1 , 2 265 ) 则有 { c t = n × i m o d 2 265 1 ≡ q 1 × i m o d 2 265 \text{设} q_1 = q \space mod \space 2^{265} \\
\text{设} i=inverse(q_1, 2^{265}) \\
\text{则有}
\begin{cases}
ct = n \times i \space mod \space 2^{265} \\
1 \equiv q_1 \times i \space mod \space 2^{265}
\end{cases}
设 q 1 = q m o d 2 265 设 i = in v erse ( q 1 , 2 265 ) 则有 { c t = n × i m o d 2 265 1 ≡ q 1 × i m o d 2 265
对于线性同余方程a x ≡ b ( m o d n ) ax \equiv b \space (mod \space n) a x ≡ b ( m o d n ) :
若 d = g c d ( a , n ) d = gcd(a, n) d = g c d ( a , n ) ,d d d 整除 b b b ,那么b d \frac b d d b 为整数。由裴蜀定理 ,存在整数对( r , s ) (r,s) ( r , s ) (可用扩展欧几里得算法求得)使得a r + s n = d ar+sn=d a r + s n = d ,因此x 0 = r × b d x_0=r \times \frac b d x 0 = r × d b 是方程 (1) 的一个解。其他的解都关于n d \frac n d d n 与 x x x 同余。即x ≡ x 0 + ( n d ) × t ( m o d n ) ( 0 ⩽ t ⩽ d − 1 ) x \equiv x_0+(\frac n d) \times t \space (mod \space n) \space (0 \leqslant t \leqslant d-1) x ≡ x 0 + ( d n ) × t ( m o d n ) ( 0 ⩽ t ⩽ d − 1 ) 。
根据上述线性同余方程的求解方法,可以求得i = r × c t m o d 2 265 i=r \times ct \space mod \space 2^{265} i = r × c t m o d 2 265 ,进而求得q 1 = i n v e r s e ( i , 2 265 ) q_1=inverse(i,2^{265}) q 1 = in v erse ( i , 2 265 ) 。
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import gmpy2from Crypto.Util.number import *def ext_gcd (a, b ): if b == 0 : return 1 , 0 , a else : x, y, gcd = ext_gcd(b, a % b) x, y = y, (x - (a // b) * y) return x, y, gcd ct = int (input ("ct=" )) n = int (input ("n=" )) i = (ext_gcd(n,2 **265 )[0 ] * ct) % 2 **265 q1 = gmpy2.invert(i,2 **265 ) print (q1)
至此,我们已经获得了p的高300位p1 和q的低265位q1 。
Coppersmith已知高位攻击
知道p或q的高位为其位数的约一半时即可
已知e/n,爆破1024位的p,至少需要知道570位二进制。
网上搜了搜发现有道数据一模一样的题:鹤城杯2021 Crypto babyrsa
原理是知道n和q的低265位 可以求出p的低265位 ,结合p的高300位 就是565位,爆破剩下5位。
跑脚本罢。
摘录代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 from gmpy2 import *from Crypto.Util.number import * p1 = q1 = n = mod=pow (2 ,265 ) p0=n*invert(q1,mod)%mod pbar=(p1<<724 )+p0 PR.<x> = PolynomialRing(Zmod(n)) for i in range (32 ): f=pbar+x*mod*32 f=f.monic() pp=f.small_roots(X=2 ^454 ,beta=0.4 ) if (pp): break pbar+=mod p=pbar+pp[0 ]*32 *mod assert n%p==0 print (p)
拿到了p后就是常规操作了。
写在最后
标号难度1…无官方wp,我交上去的时候也只有9个人出来。
纠结了半个月。
还是要善于搜索,前置知识很重要。