BUUCTF Crypto [V&N2020 公开赛]easy_RSA wp

这道题我们看到加密的脚本,首先我们可以关注到,这题目的素数生成机制是不断的乘然后再减一可以得到素数,我们可以发现,因子p再加一也就是p+1是光滑到,于是我们可以使用Williams’p+1 algorithm求解
可以直接调用库的函数

// 命令行调用即可
python2 -m primefac -vs -m=p+1  7941371739956577280160664419383740967516918938781306610817149744988379280561359039016508679365806108722198157199058807892703837558280678711420411242914059658055366348123106473335186505617418956630780649894945233345985279471106888635177256011468979083320605103256178446993230320443790240285158260236926519042413378204298514714890725325831769281505530787739922007367026883959544239568886349070557272869042275528961483412544495589811933856131557221673534170105409

然后解得了p,再看看q怎么解,其实可以直接用invert函数求解,但是因为q大于p,所以要再加上p的倍数

q2=gmpy2.invert(d,p**2)
for i in range(1000000):
	q=gmpy2.iroot(q2+i*p**2,2)
	if(q[1]==1):
		print q[0],i
		break
q=q[0]
r=n//p//q

然后可以直接通过n除p和q就可解出来所有的元素,然后我们来看一下flag的加密方式,看到这个我们首先是可以想到rabbin算法,但是呢模数是素数,无法使用,我们便只能采用求解二次平方根的一个算法Tonelli–Shanks算法,网上找了一个算法脚本,很快的就能求解出来解出flag,脚本如下:

import gmpy2
from Crypto.Util.number import *
def legendre(a, p):
    return pow(a, (p - 1) // 2, p)


def tonelli(n, p):
    assert legendre(n, p) == 1
    q = p - 1
    s = 0
    while q % 2 == 0:
        q //= 2
        s += 1
    if s == 1:
        return pow(n, (p + 1) // 4, p)
    for z in range(2, 10000):
#    for z in range(2, p):
        if p - 1 == legendre(z, p):
            break
    c = pow(z, q, p)
    r = pow(n, (q + 1) // 2, p)
    t = pow(n, q, p)
    m = s
    t2 = 0
    while (t - 1) % p != 0:
        t2 = (t * t) % p
        for i in range(1, m):
            if (t2 - 1) % p == 0:
                break
            t2 = (t2 * t2) % p
        b = pow(c, 1 << (m - i - 1), p)
        r = (r * b) % p
        c = (b * b) % p
        t = (t * c) % p
        m = i
    return r
n=7941371739956577280160664419383740967516918938781306610817149744988379280561359039016508679365806108722198157199058807892703837558280678711420411242914059658055366348123106473335186505617418956630780649894945233345985279471106888635177256011468979083320605103256178446993230320443790240285158260236926519042413378204298514714890725325831769281505530787739922007367026883959544239568886349070557272869042275528961483412544495589811933856131557221673534170105409
d=gmpy2.mpz(7515987842794170949444517202158067021118454558360145030399453487603693522695746732547224100845570119375977629070702308991221388721952258969752305904378724402002545947182529859604584400048983091861594720299791743887521228492714135449584003054386457751933095902983841246048952155097668245322664318518861440)
cipher=1618155233923718966393124032999431934705026408748451436388483012584983753140040289666712916510617403356206112730613485227084128314043665913357106301736817062412927135716281544348612150328867226515184078966397180771624148797528036548243343316501503364783092550480439749404301122277056732857399413805293899249313045684662146333448668209567898831091274930053147799756622844119463942087160062353526056879436998061803187343431081504474584816590199768034450005448200

#python2 -m primefac -vs -m=p+1  7941371739956577280160664419383740967516918938781306610817149744988379280561359039016508679365806108722198157199058807892703837558280678711420411242914059658055366348123106473335186505617418956630780649894945233345985279471106888635177256011468979083320605103256178446993230320443790240285158260236926519042413378204298514714890725325831769281505530787739922007367026883959544239568886349070557272869042275528961483412544495589811933856131557221673534170105409
p=gmpy2.mpz(102634610559478918970860957918259981057327949366949344137104804864768237961662136189827166317524151288799657758536256924609797810164397005081733039415393)

q2=gmpy2.invert(d,p**2)
for i in range(1000000):
	q=gmpy2.iroot(q2+i*p**2,2)
	if(q[1]==1):
		print q[0],i
		break
q=q[0]
r=n//p//q

e=0x10001
phi=(p-1)*(q-1)*(r-1)
D=gmpy2.invert(e,phi)
c=pow(cipher,D,n)
print c

m=tonelli(c,r)
print m
print long_to_bytes(m)
#flag{fd462593-25e4-4631-a96a-0cd5c72b2d1b}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值