第七届“湖湘杯”Crypto的signin

51 篇文章 8 订阅

第七届“湖湘杯”Crypto的signin

下载附件,打开查看题目逻辑代码:

from Crypto.Util.number import *
from secret import flag
import random

m1 = bytes_to_long(flag[:len(flag) // 2])
m2 = bytes_to_long(flag[len(flag) // 2:])

def gen(pbits, qbits):
    p1, q1 = getPrime(pbits), getPrime(qbits)
    n1 = p1**4*q1
    q2 = getPrime(qbits)
    bound = p1 // (8*q1*q2) + 1
    p2 = random.randrange(p1, p1 + bound)
    while not isPrime(p2):
        p2 = random.randrange(p1, p1 + bound)
    n2 = p2**4*q2
    return (n1, n2), (p1, q1), (p2, q2)

e = 0x10001
pbits = int(360)
qbits = int(128)
pk, sk1, sk2 = gen(pbits, qbits)
c1 = pow(m1, e, pk[0])
c2 = pow(m2, e, pk[1])
print(f'pk = {pk}')
print(f'c1, c2 = {c1, c2}')

"""
pk = (1150398070565459492080597718626032792435556703413923483458704675295997646493249759818468321328556510074044954676615760446708253531839417036997811506222349194302791943489195718713797322878586379546657275419261647635859989280700191441312691274285176619391539387875252135478424580680264554294179123254566796890998243909286508189826458854346825493157697201495100628216832191035903848391447704849808577310612723700318670466035077202673373956324725108350230357879374234418393233, 1242678737076048096780023147702514112272319497423818488193557934695583793070332178723043194823444815153743889740338870676093799728875725651036060313223096288606947708155579060628807516053981975820338028456770109640111153719903207363617099371353910243497871090334898522942934052035102902892149792570965804205461900841595290667647854346905445201396273291648968142608158533514391348407631818144116768794595226974831093526512117505486679153727123796834305088741279455621586989)
c1, c2 = (361624030197288323178211941746074961985876772079713896964822566468795093475887773853629454653096485450671233584616088768705417987527877166166213574572987732852155320225332020636386698169212072312758052524652761304795529199864805108000796457423822443871436659548626629448170698048984709740274043050729249408577243328282313593461300703078854044587993248807613713896590402657788194264718603549894361488507629356532718775278399264279359256975688280723740017979438505001819438, 33322989148902718763644384246610630825314206644879155585369541624158380990667828419255828083639294898100922608833810585530801931417726134558845725168047585271855248605561256531342703212030641555260907310067120102069499927711242804407691706542428236208695153618955781372741765233319988193384708525251620506966304554054884590718068210659709406626033891748214407992041364462525367373648910810036622684929049996166651416565651803952838857960054689875755131784246099270581394)
"""

.
.
大体分析一下,题目先是把 flag 分成两部分,然后分别生成两个大素数 3608bit 的 p1,1288bit 的 p2。
然后继续生成了两个相邻的大素数q1、q2,用p1的 4 次方和 q1相乘得到N1,N2则是用 p2 的 4 次方和 q2 相乘,再用一个比较小的 E 加密。
(其实根据题目中涉及指数的N n1 = p1**4*q1n2 = p2**4*q2 就可以发现和 2020 年羊城杯 Crypto 的 RRRRRRRSA 有很大的相似性。
可以参考博客:https://blog.csdn.net/xiao__1bai/article/details/121576940 )

因为题目只给了N1N2C1C2。所以我们从这两对数来寻找突破口,可以发现N1和N2的大小和很相近的,可以尝试一下 wiener attack 攻击。
.
.
按wiener attack 攻击流程展开:
由于(p1/p2)**4 接近于1,所以 N1/N2 的比例很相近于q1/q2
所以在 q1/q2 在区间(N1/N2,1)之间 (这是关键,不用P1/P2是因为4次方不好求)
尝试对 N1/N2 进行连分数展开并求其各项渐进分数,其中某个连分数的分子可能就是q1。
.
.
.
修改以前的连分数低解密指数脚本:

import gmpy2
N1, N2 = (
    1150398070565459492080597718626032792435556703413923483458704675295997646493249759818468321328556510074044954676615760446708253531839417036997811506222349194302791943489195718713797322878586379546657275419261647635859989280700191441312691274285176619391539387875252135478424580680264554294179123254566796890998243909286508189826458854346825493157697201495100628216832191035903848391447704849808577310612723700318670466035077202673373956324725108350230357879374234418393233,
    1242678737076048096780023147702514112272319497423818488193557934695583793070332178723043194823444815153743889740338870676093799728875725651036060313223096288606947708155579060628807516053981975820338028456770109640111153719903207363617099371353910243497871090334898522942934052035102902892149792570965804205461900841595290667647854346905445201396273291648968142608158533514391348407631818144116768794595226974831093526512117505486679153727123796834305088741279455621586989)
c1, c2 = (
    361624030197288323178211941746074961985876772079713896964822566468795093475887773853629454653096485450671233584616088768705417987527877166166213574572987732852155320225332020636386698169212072312758052524652761304795529199864805108000796457423822443871436659548626629448170698048984709740274043050729249408577243328282313593461300703078854044587993248807613713896590402657788194264718603549894361488507629356532718775278399264279359256975688280723740017979438505001819438,
    33322989148902718763644384246610630825314206644879155585369541624158380990667828419255828083639294898100922608833810585530801931417726134558845725168047585271855248605561256531342703212030641555260907310067120102069499927711242804407691706542428236208695153618955781372741765233319988193384708525251620506966304554054884590718068210659709406626033891748214407992041364462525367373648910810036622684929049996166651416565651803952838857960054689875755131784246099270581394)
e = 0x10001

def continuedFra(x, y): 		#不断生成连分数的项,如127/52 = 2 + 1/2+ 1/3+ 1/1+ 1/5,生成[2,2,3,1,5]
    cF = []
    while y:
        cF += [x // y]
        x, y = y, x % y		#这里是连分数生成项的算法
    return cF

def Simplify(ctnf): 			#对前面生成的连分数项化简
    numerator = 1
    denominator = 0
    for x in ctnf[::-1]: 		#注意这里是倒叙遍历,从后面把连分数项合成总和。
        numerator, denominator = x * numerator + denominator, numerator 
    return (numerator, denominator) 		#把连分数分成和算出来的分母以元组的形式导出来,如Simplify(continuedFra(127,52))生成(127, 52)

def getit(c):
    cf=[]
    for i in range(1,len(c)):
        cf.append(Simplify(c[:i])) 	#各个阶段的连分数的分子和分母
    return cf 							#得到一串连分数,如:[(2, 1), (5, 2), (17, 7), (22, 9)]

def wienerAttack(e, n):				#低解密指数攻击,自己修改要碰撞的分子或分母
    cf=continuedFra(e,n)
    for (q1,q2) in getit(cf):			#遍历得到的连分数,令分子分母分别是Q1,Q2,因为前面我们说了N1/N2=(p1/p2)**2 (q1/q2)
        if q1 == 0:
            continue
        if N1%q1==0 and q1!=1:		#满足这个条件就找到了Q1,其实同理也可以找出Q2
            return (q1,q2)
    print('没找到能覆盖的分子/分母')

q1,q2=wienerAttack(N1,N2)				#找出一个Q1,其实这里也可以找出Q2的,但处于p2=sympy.nextprime(p1)的限制,只能用p1求出p2,不能用p2求出p1

from Crypto.Util.number import *
p1=gmpy2.iroot(N1//q1,4)[0]			
p2=gmpy2.iroot(N2//q2,4)[0]

phi1=((p1-1)*p1*p1*p1)*(q1-1)
phi2=((p2-1)*p2*p2*p2)*(q2-1)

d1=gmpy2.invert(e,phi1)				#逆模求d
d2=gmpy2.invert(e,phi2)				#逆模求d
m1=long_to_bytes(gmpy2.powmod(c1,d1,N1))		#普通解密算法,但是要用将long型数转为字节型数据
m2=long_to_bytes(gmpy2.powmod(c2,d2,N2))		#普通解密算法,但是要用将long型数转为字节型数据
print((m1+m2))							#拼接flag字符。

结果:
在这里插入图片描述
.
.
解毕!敬礼!

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

沐一 · 林

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

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

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

打赏作者

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

抵扣说明:

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

余额充值