[HackTM 2023] d-phi-enc

感觉越来越难了这比赛,只作了一个一看就简单的小题,其它看都看不懂。

from Crypto.Util.number import bytes_to_long, getStrongPrime

from secret import flag

assert len(flag) == 255
e = 3
p = getStrongPrime(1024, e=e)
q = getStrongPrime(1024, e=e)
n = p * q
phi = (p - 1) * (q - 1)
d = pow(e, -1, phi)
enc_d = pow(d, e, n)
enc_phi = pow(phi, e, n) #(pq-p-q+1) (p+q+1)**3 
enc_flag = pow(bytes_to_long(flag), e, n)
print(f"{n = }")
print(f"{enc_d = }")
print(f"{enc_phi = }")
print(f"{enc_flag = }")

e=3非常小,给了pow(d,e,n),pow(phi,e,n),pow(flag,e,n)

由于所以

enc_d*e^e = (k* +1 )^e%n

k^e * enc_phi = (k*)^e%n

所以明显这是关联信息攻击,可以原来的程序,计算出来都是-1(n-1)

def related_message_attack(c1,c2, di, e,n):
    from Crypto.Util.number import GCD
    #展开(x+a)^e的系数,杨辉三角
    def poly_coef(a, e):
        assert e >= 0
        if e == 0:
            return 1
        elif e == 1:
            return [1,1]
        else:
            res = [1]
            coe_prev = poly_coef(a, e-1)
            for i in range(len(coe_prev)-1):
                res.append(sum(coe_prev[i:i+2]))
            res.append(1)
            return res

    def poly_extend(a, e, n,c):
        coef = poly_coef(a, e)
        res = [a**i * coef[i] for i in range(len(coef))]

        res[-1] = res[-1] + c
        res = [x%n for x in res]

        return res
        
    #化首1
    def poly_monic(pl,n):
        from gmpy2 import invert
        for p in pl:
            if p!=0:
                inv = invert(p,n)
                break
        return [int((x*inv)%n) for x in pl]

    #模运算,这部分写的不是很好,待优化
    def poly_mod(pl1,pl2,n):
        from functools import reduce
        assert len(pl1) == len(pl2)
        pl1 = poly_monic(pl1,n)
        pl2 = poly_monic(pl2,n)
        for i in range(len(pl1)):
            if pl1[i] > pl2[i]:
                break
            elif pl1[i] < pl2[i]:
                return poly_mod(pl2,pl1,n)
        else:
            return 0
        idx = -1
        for i in range(len(pl1)):
            if pl1[i] == 1:
                idx = i
                break
        for i in range(idx,len(pl2)):
            if pl2[i] == 1:
                pl2 = pl2[:idx] + pl2[i:]
                pl2 += [0]*(len(pl1)-len(pl2))
                break
        
        res = []
        for i in range(len(pl1)):
            if pl2[i] == 0:
                res.append(pl1[i])
            else:
                res.append(pl1[i]-pl2[i])
        
        res = [int(x%n) for x in res]
        g = int(reduce(GCD,res))
        if g > 1:
            res = [x//g for x in res]
        return res
    #最大公因式
    def poly_gcd(pl1,pl2,n):
        while pl2 != 0:
            pl1,pl2 = pl2, poly_mod(pl1,pl2,n)
        pl1 = poly_monic(pl1,n)

        return pl1

    #x^e-c1
    #(x+di)^e-c2
    pl1 = poly_extend(0,e,n,-c1)
    pl2 = poly_extend(di,e,n,-c2)

    pl_d = poly_gcd(pl1,pl2,n)

    #求得(x-m),所以取负数即为m
    m = n - pl_d[-1]
    return m

可能是什么不清楚,后来又从网上搜到一个简单点的。

from gmpy2 import invert

#这个函数原来是解出phi,但经过测试解出的是-(p+q-1)*2  phi=(p-1)(q-1)=n-(p+q)+1 所以解是p+q-1
def getM2(a,b,c1,c2,n,e):
    a3 = pow(a,e,n)
    b3 = pow(b,e,n)
    first = c1-a3*c2+2*b3
    first = first % n
    second = e*b*(a3*c2-b3)
    second = second % n
    third = second * invert(first,n)
    third = third % n
    fourth = (third+b) * invert(a,n)
    return fourth % n

这里还有个问题,phi虽然比n小,但k=2时也是比n大的,所以得到的是模n后的,phi=(p-1)(q-1)可以简单看成k(pq-p-q-1) = 2(1-p-q)这样就直接求出p+q然后就很容易得到p,q。

from output import *

e = 3
for k in range(1,3):
    print(k)
    c1 = enc_d * e**e %n   #ed = k*phi + 1   => c1 = enc_d * e^e = (e*d)^e = (k*phi + 1)^e
    c2 = enc_phi * k**e %n #                    c2 =         enc_phi * k^e = (k*phi)^e 
    diff = 1
    vv = getM2(1,diff,c1,c2,n,e)
    #print(vv)
    print('p+q:',(n-vv+2)//2)
'''
1
p+q: 8820468529041372002324038698966107072889102452877058887634498287453998997040072501409717546020769209164013911226723405860610209969068954054326071267363333989522789410364093976052951960389244009241995951348719565502276229384027370949790352653647809018302591167162614297744664920674123301610093287714014050868144462711682841900909838516794872905539836775052216863500628808277736583508580182374764197142389283888665469794215298689234712901544771897071199702872440965930331079753495886332933281500351422898210408413640120586805111875614402614790809233447071017020608120170440189652479953915574544657443320286438960533983
2
p+q: 312923382871248014067014925984412146067094621402549185870032327453115760507056850415403142556065116353933188609216161363804133557007400032321485662200928476199152365342526984153017631756765310979024793123971318866032039849942965865364222773233591801819504804711487822035015274359026776976437482432378059626872
'''

现用z3解出来p,q回到rsa的开头。也可以直接用p+q求phi再求d,反正都简单了

q = 154492600502310358961290595218855606637686112564658215263043082517847747558415354021955483686653624865913299541093297750308537763576451319637002115896403014960496288119726132921253645065026096509274270374571068515713750554820699528648387417681352310503451804260205255524204258933646537556120166683375680596359
p = 158430782368937655105724330765556539429408508837890970606989244935268012948641496393447658869411491488019889068122863613495595793430948712684483546304525461238656077222800851231763986691739214469750522749400250350318289295122266336715835355552239491316053000451282566510811015425380239420317315749002379030513
phi = (p - 1) * (q - 1)
d = pow(e, -1, phi)
m = pow(enc_flag,e,n)
print(bytes.fromhex(hex(m)[2:]))
#b"HackTM{Have you warmed up? If not, I suggest you consider the case where e=65537, although I don't know if it's solvable. Why did I say that? Because I have to make this flag much longer to avoid solving it just by calculating the cubic root of enc_flag.}"

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值