900分的RSA密码学题?不怕,搞起来!!!

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。

下面开始公式推导:

(a*r0+b)%e = r1
(a*r1+b)%e = r2
(a*r2+b)%e = r3
.......
(a*r n-2+b)%e = r n-1

我们分别使用第下一行式子减去相对自己的上一行式子可得

a*(r1-r0)%e = r2-r1
a*(r2-r1)%e = r3-r2
......
a*(r n-2-r n-3)%e = r n-1-r n-2

我们令r1-r0=t0,r2-r1=t1,依次类推rn-1-rn-2=tn-2

联立1式和2式可得:

a*t0%e = t1
a*t1%e = t2

1式乘t2,2式乘t1可得:

a*(t1·t1-t0·t2)%e =0

所以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}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嘉·沐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值