今年遇到的另一道rsa题,知识点比较杂记录一下。
题目很简单,给出两段rsa加密逻辑:
from libnum import s2n
from gmpy2 import next_prime
from Crypto.Util.number import getPrime, getStrongPrime
flag = b'***************************'
m = s2n(flag)
data1 = getPrime(128)
data2 = getPrime(128)
if data1 > data2:
data1, data2 = data2, data1
pad = data1 * data2
e = 65537
p = getStrongPrime(512)
q = next_prime(p ^ (1 << 512) - 1 ^ 1145141919810)
n = p * q
m = m ^ (pad**3)
c = pow(m, e, n)
print("c = {}".format(c))
print("n = {}".format(n))
'''
c = 4876198060325558549288995522100507087517821034108816602164382070749684285584225421889164875913824962554132279846256774271230741598793103772088831581334775807966395144586271639023739926023422461534946692758208303683848234357028505178292070426362296226890794270835780238370200672015289469862799153558118626538
n = 22496691787129427749959005524646018077441588595947356500541791402307996665819440265849843924260051516521718141146431339445253436586359746245186586849516881880135888115635970343512176471451755147483038942057104297542535022428306408447982927962678529654674038001433905787928883880082539446749721026403230355477
'''
和
*******************************
bound = 2**128
prec = 400
ring = RealField(prec)
data3 = ring(data1 / data2)
#data3 = 0.576745262648089166053295786066675247383735995449723064673392221201629992787992198615151331712300834922059228957126784067
*******************************
大概分析一下,p和q是512bit的大素数,明文先与pad**3进行异或以后rsa加密,所以本题关键的两个问题一个就是求解p和q,另一个就是求解pad。
首先求解pad想到的是应用连分数攻击,找到分子分母128bit的渐进分数逼近data3:
#sage exp
data3 = 0.576745262648089166053295786066675247383735995449723064673392221201629992787992198615151331712300834922059228957126784067
c = continued_fraction(data3)
print(c)
alist = c.convergents()
print(alist)
for i in alist:
a = str(i).split('/')
if len(a)>1 and gcd(int(a[0]),int(a[1])) == 1 and is_prime(int(a[0])) and is_prime(int(a[1])) and int(a[0]).bit_length()==128 and int(a[1]).bit_length()==128:
print(a)
#['182219017730986958273958989689968387899', '315943674845875518476789636594922239111']
如此一来pad问题就解决了。接下来需要求p和q。先去factordb查了一波没查到结果,只能想办法硬算,近似算法具体算法参考以下这篇:
【zer0pts CTF 2022】 Anti-Fermat(p、q生成不当)_Paintrain的博客-优快云博客
针对本题的话根据p+q1<<512
可以得到近似p=(iroot(pow(2,1024)-4*n,2)[0]+pow(2,512))//2+1145141919810
然后用coppersmith方法攻击p值的低位原理参考这篇:
所以解密脚本为:
#sage exp
from Crypto.Util.number import *
import gmpy2
c = 4876198060325558549288995522100507087517821034108816602164382070749684285584225421889164875913824962554132279846256774271230741598793103772088831581334775807966395144586271639023739926023422461534946692758208303683848234357028505178292070426362296226890794270835780238370200672015289469862799153558118626538
n = 22496691787129427749959005524646018077441588595947356500541791402307996665819440265849843924260051516521718141146431339445253436586359746245186586849516881880135888115635970343512176471451755147483038942057104297542535022428306408447982927962678529654674038001433905787928883880082539446749721026403230355477
e=65537
#estimate p
px=(gmpy2.iroot(pow(2,1024)-4*n,2)[0]+pow(2,512))//2+1145141919810
print(px)
p=int(px)
P.<x>=PolynomialRing(Zmod(n)) #对p进一步爆破
for i in range(100,1000):
f=x+ZZ(((p>>i)<<i)) #注意加上整数环ZZ,因为x是个环内的数,不然会报错,不信你可以试试
root=f.small_roots(X=2^i,beta=0.4)
if root!=[]:
p=root[0]+ZZ(((p>>i)<<i))
break
print(p)
q=ZZ(n)//ZZ(p)
phi=ZZ((p-1)*(q-1))
d=gmpy2.invert(e,phi)
m=ZZ(pow(c,d,n))
print(m)
data1=182219017730986958273958989689968387899
data2=315943674845875518476789636594922239111
pad = data1 * data2
print(pad**3)
#190813940127169285428485324804754938788990669565404586938424781084071030386363403117434253462457023978333955353156254005360622226335647610163254072330538141918676938868012557681771059410152661947776076466998765803516367248870831928
#190813940127169285428485324804754938788990669565404586938424781084071030386363403117434253462457023978333955353156254005360622226315064447374106848135025311597743809754751326596877994873102973248296727123176719173187699013097440069
mm=m^^(pad**3)
#mm=56006392793427429214108738999096395450496940694719089841200007225830160331551005145390312324435424381
flag=long_to_bytes(mm)
print(flag)