Challenge: maglc RSA(953 points)
Description
Alice tried to make RSA encryption more secure by using random numbers. But when I tested the encryption I found a vulnerability. Can you find it ?
enclosure: encrypt.py and output.txt
Solution
output.txt内容:
r = [8369875715811823465, 445158310791574166, 2720555425160593675, 7432270455188990462, 2446251786048361946, 55762871963467021, 7562020044022273693, 4880950714387710915, 1980725435082363925, 6123245747443869158, 4341288451522003293, 3111260810610424680, 4140237704488186322, 8334445125395496182, 5047625506525476652, 1757571238833421910, 9376059903619511820, 6110215991516233738, 2352831123581007803, 9117287170545018735, 9083707904731367018, 1859293174547632281, 2245872203465393980, 4092355223399900664, 8979431278774017347, 4456461600515791560, 2863137587848225810, 5403052783947990466, 3528811102063731114, 2874817484721206679, 8449078310597518955, 11016217750450662607, 11097228115924669078, 10892757142981824109, 9850784794499231027, 5885192258462707887, 5292818685021887106, 4870356470560820389, 9580459175047702840]
c=0xd81666bd36032affaee5abd0c8b08da132ca5780514a69231f93ee5e37008a559a54614eb176ff37cfe88fe2c53a761258c704b912146f5c21c4182eca8bca165ef60be06984dbb650a0624fae7b9ffa696069d90ae856e6844d0fe11c8c4633bf04dc02b2ed87f2948bdb903c83163ff18e99c4a4a8a2ae46cead6a334f9712
n=0xee5ebad033cb6a780b84e957981c249c35cb20af0eb9ea404558b33f7a2637fd1544ee8ebdec95e842a0abbe22b25cc5e2663f1ad4efece9cb4d1222f169c6a1f669b64afa454aa8ef9f378d0498a4c4c4b1055873576f3616a4b09ed4e81cef6d001746b56b4a2ba4db5a52de7343dd057f99bf552e987e3672f2fa7b7797e5
先理解encrypt.py文件内容:
from Crypto.Util.number import getPrime, isPrime, bytes_to_long
from random import getrandbits
from secret import flag
a = getrandbits(64)
b = getrandbits(64)
e = getPrime(64)
r = []
r.append((a*getrandbits(64)+b)%e)
k = 0
while k<len(flag):
r.append((a*r[k]+b)%e)
k+=1
p = getPrime(512)
i = 1
while True:
q = p + i
if isPrime(q):
break
i += 1
n = p*q
m = bytes_to_long(flag)
c = pow(m,e,n)
obj = open('output.txt','w')
obj.write("r = " + str(r) + "\n")
obj.write("c = " + hex(c) + "\n")
obj.write("n = " + hex(n) + "\n")
obj.close()
可以从源码看出,这就是一个典型的RSA加密过程。不过这个过程中,p,q的生成方式存在较大的漏洞。
p = getPrime(512)
i = 1
while True:
q = p + i
if isPrime(q):
break
i += 1
用上述代码生成p,q会造成一个非常严重的问题,那就是p和q十分相近。而n是已知的,那么就可以在根号n附近寻找p,q。
# 使用这种方式在根号n附近寻找相近的p,q十分好用
from gmpy2 import isqrt square is_square
def calc(n):
a = isqrt(n)
r = square(a)-n
while not is_square(r):
a += 1
r = square(a)-n
return a+isqrt(r),a-isqrt(r)
p,q = calc(n)
既然p,q问题解决了,还剩下e需要我们求解。
e = getPrime(64)
r = []
r.append((a*getrandbits(64)+b)%e)
k = 0
while k<len(flag):
r.append((a*r[k]+b)%e)
k+=1
e出现在上述代码中,可以看出它参与了生成r的运算。r是已知的,那么我们可以倒推公式,求算e。
下面开始公式推导:
我们分别使用第下一行式子减去相对自己的上一行式子可得
我们令r1-r0=t0,r2-r1=t1,依次类推rn-1-rn-2=tn-2
联立1式和2式可得:
1式乘t2,2式乘t1可得:
所以e|a*(t1·t1-t0·t2),则e|a或e|(t1·t1-t0·t2)。
又因为针对上述每个式子,都存在e|a*(tn-12-tn·tn-2) n=2,3,4,5,…
所以e是(tn-12-tn·tn-2) n=2,3,4,5,… 的最大公因数。
根据多个整数的最大公因数计算公式,我们写出如下代码:
from functools import reduce
def calc_e(r):
sub = [r1-r0 for r0,r1 in zip([r,r[1:]])]
a = [t1*t1-t2*t0 for t0,t1,t2 in zip(sub,sub[1:],sub[2:])]
e = abs(reduce(gcd,a))
return e
简要介绍一下reduce的用法:
# 导入库函数
from fuctools import reduce
# useage
reduce(function, iterable)
- function 函数(要有两个参数传递)
- 可迭代对象 (列表,元组等)
# Example
def add(x,y):
return x+y
sum1 = reduce(add,[1,2,3,4,5])
print(sum1)
# 输出1+2+3+4+5的值
现在已经攻破这道题最大的Boss,剩余的就是常规的解决RSA解密问题。这里给出完整的exp脚本。
exp.py:
from Crypto.Util.number import long_to_bytes, inverse
from functools import reduce
from gmpy2 import gcd,invert, isqrt, square, is_square
def calc(n):
a = isqrt(n)
r = square(a) - n
while not is_square(r):
a += 1
r = square(a) - n
return a + isqrt(r), a - isqrt(r)
def calc_e(r):
sub = [s1 - s0 for s0, s1 in zip(r, r[1:])]
a = [t1*t1 - t2*t0 for t0, t1, t2 in zip(sub, sub[1:], sub[2:])]
e = abs(reduce(gcd, a))
return e
r = [8369875715811823465, 445158310791574166, 2720555425160593675, 7432270455188990462, 2446251786048361946, 55762871963467021, 7562020044022273693, 4880950714387710915, 1980725435082363925, 6123245747443869158, 4341288451522003293, 3111260810610424680, 4140237704488186322, 8334445125395496182, 5047625506525476652, 1757571238833421910, 9376059903619511820, 6110215991516233738, 2352831123581007803, 9117287170545018735, 9083707904731367018, 1859293174547632281, 2245872203465393980, 4092355223399900664, 8979431278774017347, 4456461600515791560, 2863137587848225810, 5403052783947990466, 3528811102063731114, 2874817484721206679, 8449078310597518955, 11016217750450662607, 11097228115924669078, 10892757142981824109, 9850784794499231027, 5885192258462707887, 5292818685021887106, 4870356470560820389, 9580459175047702840]
c=0xd81666bd36032affaee5abd0c8b08da132ca5780514a69231f93ee5e37008a559a54614eb176ff37cfe88fe2c53a761258c704b912146f5c21c4182eca8bca165ef60be06984dbb650a0624fae7b9ffa696069d90ae856e6844d0fe11c8c4633bf04dc02b2ed87f2948bdb903c83163ff18e99c4a4a8a2ae46cead6a334f9712
n=0xee5ebad033cb6a780b84e957981c249c35cb20af0eb9ea404558b33f7a2637fd1544ee8ebdec95e842a0abbe22b25cc5e2663f1ad4efece9cb4d1222f169c6a1f669b64afa454aa8ef9f378d0498a4c4c4b1055873576f3616a4b09ed4e81cef6d001746b56b4a2ba4db5a52de7343dd057f99bf552e987e3672f2fa7b7797e5
p,q = calc(n)
e = calc_e(r)
phi = (p-1)*(q-1)
d = inverse(e,phi)
print(long_to_bytes(pow(c,d,n)))
Flag:BSDCTF{Ah!_w3LL_D0n3_7h475_l1k3_4_pr0}