RSA入门¶
RSA学习过程,对常见题型进行了整合
发表于2023年7月6日。于2024年7月15日进行更新,把以前三篇有关RSA的内容整合成一篇,添加了一些题目,并且去除了冗余的内容
一、RSA算法原理简介¶
1.密钥的产生¶
-
选择两个保密的大素数\(p\)和\(q\)
-
计算\(n = p \times q,\phi(n) = (p-1)(q-1)\),其中\(\phi(n)\)是n的欧拉函数值
-
选一整数\(e\),满足\(1 < e < \phi(n)\),且\(gcd(\phi(n),e) = 1\)
-
计算\(d\),满足\(ed \equiv 1 \mod \phi(n)\)。即\(d\)是e在模\(\phi(n)\)下的乘法逆元,因为\(e\)和\(\phi(n)\)互素,所以\(d\)必定存在
-
以\((e,n)\)为公开钥,\((d,n)\)为秘密钥
2.加密¶
加密时,先把明文比特串分组,使得每个分组对应的十进制数\(<n\),即分组长度小于\(log_2n\)。如然后对每个明文分组\(m\),作加密运算:
3.解密¶
对密文分组的解密运算:
4.证明解密的正确性¶
情况1:\(m,n\)互素。由欧拉定理:
即\(c^d \equiv m \mod n\)
情况2:\(m,n\)不互素。
因为\(m,n\)不互素,注意到\(n = pq\),所以此时\(m\)是\(p\)或者\(q\)的倍数。假设\(m\)是\(p\)的倍数,即\(m = tp\)
此时\(gcd(m,q) = 1\),否则\(m\)也是\(q\)的倍数,从而\(m\)是n的倍数,这与明文分组\(m < n\)矛盾。所以不可能
由\(gcd(m,q) = 1\)得
所以
即\(m^{k\phi(n)} \equiv 1 \mod q\),也就是\(m^{k\phi(n)} = kq + 1\)
两边同时乘上\(m = tp\),得\(m^{k\phi(n)+1} \equiv ktpq + m = m+tkn\)
也就是\(m^{k\phi(n)+1} \equiv m \mod n\)
二、基础工具¶
1.yafu¶
使用方法:进入yafu所在的文件夹,输入命令yafu-x64 factor(n)
2.网站分解¶
http://www.factordb.com/index.php
三、密钥生成和读取¶
密钥生成¶
通过Crypto.PublicKey.RSA
中的construct
函数可以生成公钥和私钥。
对于生成公钥,需要两个参数\(n,e\),生成私钥需要\(n,e,d\)
需要配合exprot_Key
使用
生成公钥¶
from Crypto.Util.number import *
from Crypto.PublicKey import RSA
p = getPrime(512)
q = getPrime(512)
n = p*q
e = 65537
a = (n,e)
publickey = RSA.construct(a)
with open("publickey.pem","wb") as f:
f.write(publickey.export_key())
生成私钥¶
必需参数是\(n,e,d\),可添参数是\(p,q\)
from Crypto.Util.number import *
from Crypto.PublicKey import RSA
import gmpy2
p = getPrime(512)
q = getPrime(512)
n = p*q
e = 65537
d = gmpy2.invert(e,(p-1)*(q-1))
a = (n,e)
b = (n,e,int(d))
publickey = RSA.construct(a)
privatekey = RSA.construct(b)
with open("publickey.pem","wb") as f:
f.write(publickey.export_key())
with open("privatekey.pem","wb") as f2:
f2.write(privatekey.export_key())
读取密钥¶
key中有p,q,n,e,d五个属性,一般题目也就给了公钥,所以只有n,e是能读取的
例题1 泄露私钥¶
task
from Crypto.PublicKey import RSA
import libnum
import gmpy2
import uuid
flag = "flag{" + str(uuid.uuid4()) + "}"
print(flag)
m = libnum.s2n(flag)
p = libnum.generate_prime(1024)
q = gmpy2.next_prime(p)
n = p * q
e = 65537
phi = (p - 1) * (q - 1)
d = gmpy2.invert(e, phi)
m = libnum.s2n(flag)
c = pow(m, e, n)
#
c1 = libnum.n2s(int(c))
with open("flag.pem", "wb") as f:
f.write(c1)
## 生成公钥
rsa_components = (int(n), int(e), int(d))
keypair = RSA.construct(rsa_components)
with open('pubckey.pem', 'wb') as f:
f.write(keypair.exportKey())
题目中把d也传入数据了,直接读取d解密即可
from Crypto.PublicKey import RSA
from Crypto.Util.number import *
c = bytes_to_long(open("flag.pem","rb").read())
key = RSA.import_key(open("publickey.pem","rb").read())
e = key.e
n = key.n
d = key.d
print(long_to_bytes(pow(c,d,n)))
## flag{947ce8a3-40ee-46c0-a00e-0026e583f8da}
例题2 OAEP¶
task.py
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
import libnum
import gmpy2
import uuid
flag = "flag{" + str(uuid.uuid4()) + "}"
print(flag)
flag = flag.encode()
p = libnum.generate_prime(1024)
q = gmpy2.next_prime(p)
n = p * q
e = 65537
phi = (p - 1) * (q - 1)
d = gmpy2.invert(e, phi)
#
## 生成公钥
rsa_components = (int(n), int(e), int(d))
keypair = RSA.construct(rsa_components)
with open('prikey2.pem', 'wb') as f:
f.write(keypair.exportKey())
rsa_components = (int(n), e,)
arsa = RSA.construct(rsa_components)
rsakey = RSA.importKey(arsa.exportKey())
rsakey = PKCS1_OAEP.new(rsakey)
c = rsakey.encrypt(flag)
with open("flag2.pem", "wb") as f:
f.write(c)
了解了一下函数
参数含义如下:
key:RSA密钥,可以是公钥或私钥;
hashAlgo:哈希算法,默认为SHA-1;
myfunc:消息生成函数,默认为MGF1;
label:可选的附加数据,默认为空。
key是必需参数
使用PKCS1_OAEP.new
初始化后,可以调用其实例方法encrypt
和decrypt
实现RSA-OAEP算法的加密和解密操作
exp.py
from Crypto.Cipher import PKCS1_OAEP
from Crypto.PublicKey.RSA import *
c = open("flag2.pem","rb").read()
key = import_key(open("prikey2.pem","rb").read())
newkey = PKCS1_OAEP.new(key)
m = newkey.decrypt(c)
print(m).
#flag{04bbaad0-9241-42a4-9fd4-7d6e0d8bc5f1}
攻防世界——cr4-poor-rsa¶
题目给了个无后缀的文件,拖到010发现里面有藏两个文件,于是把后缀改成了zip
打开后得到两个文件,分别是key.pub和flag.b64
key.pub
-----BEGIN PUBLIC KEY-----
ME0wDQYJKoZIhvcNAQEBBQADPAAwOQIyUqmeJJ7nzzwMv5Y6AJZhdyvJzfbh4/v8
bkSgel4PiURXqfgcOuEyrFaD01soulwyQkMCAwEAAQ==
-----END PUBLIC KEY-----
flag.b64
先试着读取公钥,发现n可以分解,于是就按常规流程做了
exp.py
import base64
from Crypto.PublicKey.RSA import *
from Crypto.Util.number import *
import gmpy2
c = base64.b64decode(open("flag.b64","rb").read())
c = bytes_to_long(c)
key = import_key(open("key.pub","rb").read())
p = 863653476616376575308866344984576466644942572246900013156919
q = 965445304326998194798282228842484732438457170595999523426901
n = p*q
e = 65537
d = gmpy2.invert(e,(p-1)*(q-1))
print(long_to_bytes(pow(c,d,n)))
#XCTF{SMALL_PRIMES_ARE_BAD}
四、共模攻击¶
共模攻击:
在对同一明文的加密过程中使用相同的模数n,对同一明文,用不同的密钥e(两个密钥是互素的)进行加密
结果是得到两个不同的c
原理:
通过欧几里得扩展算法我们能得到\(x,y\)满足\(e_1x+e_2y = 1\)
例题1¶
task.py
import libnum
import gmpy2
import uuid
flag = "flag{" + str(uuid.uuid4()) + "}"
m = libnum.s2n(flag)
p = libnum.generate_prime(1024)
q = libnum.generate_prime(1024)
n1 = p * q
n2 = p * q
e1 = 2333
e2 = 23333
m = libnum.s2n(flag)
c1 = pow(m, e1, n1)
c2 = pow(m, e2, n2)
print("n1=", n1)
print("n2=", n2)
print("e1=", e1)
print("e2=", e2)
print("c1=", c1)
print("c2=", c2)
#n1 = 12023886737570921683430494088148056717464277480371493354080633886982376602419433228186314817561301719123238737516332784081267153425832030515178119047675516911098595227477026283152544604891747727831780305507300318674027062554009254728767714650522432836286987070040177863862115871377017779058128916872854380528430193235920536818893053943407063308419618772087299760070707222914961338101044775521373972076936552277418325268112523349134412986872504187930360266568935217397303420305220796347316727211659529079762169876950534044014924448371804442314283893083178368082712851107281302456671010073505430574108861981588149293779
n2 = 12023886737570921683430494088148056717464277480371493354080633886982376602419433228186314817561301719123238737516332784081267153425832030515178119047675516911098595227477026283152544604891747727831780305507300318674027062554009254728767714650522432836286987070040177863862115871377017779058128916872854380528430193235920536818893053943407063308419618772087299760070707222914961338101044775521373972076936552277418325268112523349134412986872504187930360266568935217397303420305220796347316727211659529079762169876950534044014924448371804442314283893083178368082712851107281302456671010073505430574108861981588149293779
e1 = 2333
e2 = 23333
c1 = 1316116662134770690879814362103839780623420120527248536043840592146479052480574077985474161623763978563721124073172820410730492348846200098142706235343164470686127445583938273863894304189618247054649514955176136464273395879832878841555224421879457659795562326746943199675846414637238040550327393009642569894024250271081839428945999237716296592560124669418322569188493036148885333003876760965512925618500360394774816066758106739359762817644284120811162065280330204951295150904138010974815308787047834776406610525102814356091515999954110712767658162496023213125548829820563945272374105274832862682574678195529192009516
c2 =6485241395763328009719746130709898541269729483150505308808259329749145687803066648274311801821624527910483266170666538736992203392620205417714840881369386852010836477498279266591695876758050686740322941452286584178315830797555697887040771666991377055060541491757349967338300117181859105577325308779010792879713808168285776399372981366988860647334022480774711504685240194804912592209253106123423232743785805952113875347267336118332317990496240807273787216894980604742600774512296661048914646776553393778079057461747246478299158814839681875752645552215714984659603917168300453505504140987829883479097467840565806608012
m = pow(c1,x,n) * pow(c2,y,n) % n
exp.py
from Crypto.Util.number import *
import gmpy2
n = 12023886737570921683430494088148056717464277480371493354080633886982376602419433228186314817561301719123238737516332784081267153425832030515178119047675516911098595227477026283152544604891747727831780305507300318674027062554009254728767714650522432836286987070040177863862115871377017779058128916872854380528430193235920536818893053943407063308419618772087299760070707222914961338101044775521373972076936552277418325268112523349134412986872504187930360266568935217397303420305220796347316727211659529079762169876950534044014924448371804442314283893083178368082712851107281302456671010073505430574108861981588149293779
e1 = 2333
e2 = 23333
c1 =1316116662134770690879814362103839780623420120527248536043840592146479052480574077985474161623763978563721124073172820410730492348846200098142706235343164470686127445583938273863894304189618247054649514955176136464273395879832878841555224421879457659795562326746943199675846414637238040550327393009642569894024250271081839428945999237716296592560124669418322569188493036148885333003876760965512925618500360394774816066758106739359762817644284120811162065280330204951295150904138010974815308787047834776406610525102814356091515999954110712767658162496023213125548829820563945272374105274832862682574678195529192009516
c2 =6485241395763328009719746130709898541269729483150505308808259329749145687803066648274311801821624527910483266170666538736992203392620205417714840881369386852010836477498279266591695876758050686740322941452286584178315830797555697887040771666991377055060541491757349967338300117181859105577325308779010792879713808168285776399372981366988860647334022480774711504685240194804912592209253106123423232743785805952113875347267336118332317990496240807273787216894980604742600774512296661048914646776553393778079057461747246478299158814839681875752645552215714984659603917168300453505504140987829883479097467840565806608012
s,x,y = gmpy2.gcdext(e1,e2)
m = (pow(c1,x,n)*pow(c2,y,n))%n
print(long_to_bytes(m))
#flag{01d80670b01b654fe4831a3e81870734}
gcdext(e1,e2)
返回3个元素
第一个元素是\(Boolean\)类型的数据,判断存不存在\(x,y\)使得\(e_1x+e_2y = 1\)
返回得第二个和第三个元素是\(x,y\)
例题2¶
这个例题的情况是\(gcd(e_1,e_2)\ne 1\)
task.py
from Crypto.Util.number import *
from random import getrandbits
import gmpy2
import uuid
while 1:
flag = "flag{" + str(uuid.uuid4()) + "}"
m = bytes_to_long(flag.encode())
p = getPrime(1024)
q = getPrime(1024)
n = p * q
e1 = getrandbits(10)
e2 = getrandbits(10)
if e1 != e2 and gmpy2.gcd(e1,e2) != 1:
break
c1 = pow(m, e1, n)
c2 = pow(m, e2, n)
print("e1 =", e1)
print("e2 =", e2)
print("n =", n)
print("c1 =", c1)
print("c2 =", c2)
这种题目我们还是正常推导,设\(t = gcd(e_1,e_2)\),通过扩展欧几里得算法,有
则
根据t的大小再进行不同的处理,比如t=3,那么可以试着用低加密指数的思路进行处理。
如果t比较大,那么可以再次当作一次RSA进行求解。
本例t = 2,直接开根就行
exp.py
from Crypto.Util.number import *
import gmpy2
e1 = 578
e2 = 392
n = 21792499489446653209359648268647408248484077502636323240941263512972521642966446318685589383376089358615828479732487823375467576966410911798574546152698546172208644494120844910028661801069139412883722092087841337354582470102991346201250757430966278341015814968426027288609918021263801588485143246793300627932938615206724828284751003817198828431954277335825721403220979778254648036632075276172476930299390290573025768956364488376300510746252434716167769851984446036711610150897081622960442923737196929758209816434803424884970510663599653463189492521652184966337230394292288573277654840483815385709060428243829968709733
c1 = 1295899105546936416711955776176786556954959764395004520666273768220642845167647126115394711085928049897436984534359683209799926877399786065216458011526399070534983898250382591372240231327810785046739203554803467534631081973525005181861203752320250219830020069663762443152692331055158533035896110900630817135766754326408199206651276750278716441636585609321276880631239079781048185864263400051324827820941692502756433463495216541801444097560942509859140724554853380906157874504969878938634453309110942314571026225239704634981956565844426060346340677136929914119932647724346392582368980017754022031748246759437397697793
c2 = 6100251841868768392049795926373721745054594119167283623934416754665831830741776139556785242664295441966913393337547165974512844660057299278828165715333417692799802949938590574117892067491764731548261988101287152727657523152041485072722017224763458684855801781252103126948392647769522681887089175624603484575515518773338807587100984947122699045372679023951413797420560947466351031076552444459222063798664625809884979352261000568340687804017980769948161583294444251776973765636460565633962599948356942127522339715718463747197473475842874431177106692482361060930677857750098337273277996678196019443721319477484374253966
t = gmpy2.gcd(e1,e2)
s,x,y = gmpy2.gcdext(e1,e2)
m = gmpy2.iroot((pow(c1,x,n)*pow(c2,y,n))%n,t)
print(long_to_bytes(m[0]))
五、低加密指数攻击¶
原理:
加密指数e很小一般是3,导致出现两个情况
第一种情况:\(m^e < n\) 则 \(c \equiv m^{e} \mod n \longrightarrow c = m^e\) 这种情况下对c开e次方就可以得到m的值
第二种情况:\(m^e > n\)(略大一点点),则\(m^e = k*n + c\)这种情况需要爆破k
例题¶
task.py
import libnum
import gmpy2
import uuid
flag = "flag{" + str(uuid.uuid4()) + "}"
m = libnum.s2n(flag)
print(gmpy2.bit_length(m ** 3))
while True:
p = libnum.generate_prime(504)
q = libnum.generate_prime(504)
n = p * q
phi_n = (p - 1) * (q - 1)
e = 3
if gmpy2.gcd(e, phi_n) == 1 and phi_n%e !=0:
break
c = pow(m, e, n)
print("n=", n)
print("e=", e)
print("c=", c)
#c= 17567615026662297423639652671128685098763112348521263232850922784902991105809108670614334001294254886850775709702759646022208238160649099765454315761185950859820327234504422026634432251632399712621439201146
3091635444512796333373451321795475333496092463760390199602320265733668648810943598505902205569125
n = 1101676297168703265566511587913652821222614528632844563918598090813090976948138058144049294690727841463413972173051671908835164088465174349647584948964206244648736138253802417241570633968307801570794459668533128958442296813160786428069813867034205462528763830205245218089660432399549540588101288362866463
e = 3
exp.py
from Crypto.Util.number import *
import gmpy2
n = 1101676297168703265566511587913652821222614528632844563918598090813090976948138058144049294690727841463413972173051671908835164088465174349647584948964206244648736138253802417241570633968307801570794459668533128958442296813160786428069813867034205462528763830205245218089660432399549540588101288362866463
e = 3
c = 175676150266622974236396526711286850987631123485212632328509227849029911058091086706143340012942548868507757097027596460222082381606490997654543157611859508598203272345044220266344322516323997126214392011463091635444512796333373451321795475333496092463760390199602320265733668648810943598505902205569125
k = 0
t = gmpy2.iroot(c,e)
if t[1]:
print(long_to_bytes(t[0]))
else:
for i in trange() 1:
m = gmpy2.iroot(k*n+c,e)
if m[1]:
print(long_to_bytes(m[0]))
break
else:
k += 1
六、广播攻击¶
原理:
明文\(m\)用相同的密钥\(e\)和不同的模\(n\)进行加密
一般会得到几组不同的\(n\)和\(c\)
第一种情况 多组n之间可能存在公因数¶
例题 BUUCTF-RSA5¶
task.txt
m = xxxxxxxx
e = 65537
========== n c ==========
n = 20474918894051778533305262345601880928088284471121823754049725354072477155873778848055073843345820697886641086842612486541250183965966001591342031562953561793332341641334302847996108417466360688139866505179689516589305636902137210185624650854906780037204412206309949199080005576922775773722438863762117750429327585792093447423980002401200613302943834212820909269713876683465817369158585822294675056978970612202885426436071950214538262921077409076160417436699836138801162621314845608796870206834704116707763169847387223307828908570944984416973019427529790029089766264949078038669523465243837675263858062854739083634207
c = 974463908243330865728978769213595400782053398596897741316275722596415018912929508637393850919224969271766388710025195039896961956062895570062146947736340342927974992616678893372744261954172873490878805483241196345881721164078651156067119957816422768524442025688079462656755605982104174001635345874022133045402344010045961111720151990412034477755851802769069309069018738541854130183692204758761427121279982002993939745343695671900015296790637464880337375511536424796890996526681200633086841036320395847725935744757993013352804650575068136129295591306569213300156333650910795946800820067494143364885842896291126137320
n = 20918819960648891349438263046954902210959146407860980742165930253781318759285692492511475263234242002509419079545644051755251311392635763412553499744506421566074721268822337321637265942226790343839856182100575539845358877493718334237585821263388181126545189723429262149630651289446553402190531135520836104217160268349688525168375213462570213612845898989694324269410202496871688649978370284661017399056903931840656757330859626183773396574056413017367606446540199973155630466239453637232936904063706551160650295031273385619470740593510267285957905801566362502262757750629162937373721291789527659531499435235261620309759
c = 15819636201971185538694880505120469332582151856714070824521803121848292387556864177196229718923770810072104155432038682511434979353089791861087415144087855679134383396897817458726543883093567600325204596156649305930352575274039425470836355002691145864435755333821133969266951545158052745938252574301327696822347115053614052423028835532509220641378760800693351542633860702225772638930501021571415907348128269681224178300248272689705308911282208685459668200507057183420662959113956077584781737983254788703048275698921427029884282557468334399677849962342196140864403989162117738206246183665814938783122909930082802031855
n = 25033254625906757272369609119214202033162128625171246436639570615263949157363273213121556825878737923265290579551873824374870957467163989542063489416636713654642486717219231225074115269684119428086352535471683359486248203644461465935500517901513233739152882943010177276545128308412934555830087776128355125932914846459470221102007666912211992310538890654396487111705385730502843589727289829692152177134753098649781412247065660637826282055169991824099110916576856188876975621376606634258927784025787142263367152947108720757222446686415627479703666031871635656314282727051189190889008763055811680040315277078928068816491
c = 4185308529416874005831230781014092407198451385955677399668501833902623478395669279404883990725184332709152443372583701076198786635291739356770857286702107156730020004358955622511061410661058982622055199736820808203841446796305284394651714430918690389486920560834672316158146453183789412140939029029324756035358081754426645160033262924330248675216108270980157049705488620263485129480952814764002865280019185127662449318324279383277766416258142275143923532168798413011028271543085249029048997452212503111742302302065401051458066585395360468447460658672952851643547193822775218387853623453638025492389122204507555908862
n = 21206968097314131007183427944486801953583151151443627943113736996776787181111063957960698092696800555044199156765677935373149598221184792286812213294617749834607696302116136745662816658117055427803315230042700695125718401646810484873064775005221089174056824724922160855810527236751389605017579545235876864998419873065217294820244730785120525126565815560229001887622837549118168081685183371092395128598125004730268910276024806808565802081366898904032509920453785997056150497645234925528883879419642189109649009132381586673390027614766605038951015853086721168018787523459264932165046816881682774229243688581614306480751
c = 4521038011044758441891128468467233088493885750850588985708519911154778090597136126150289041893454126674468141393472662337350361712212694867311622970440707727941113263832357173141775855227973742571088974593476302084111770625764222838366277559560887042948859892138551472680654517814916609279748365580610712259856677740518477086531592233107175470068291903607505799432931989663707477017904611426213770238397005743730386080031955694158466558475599751940245039167629126576784024482348452868313417471542956778285567779435940267140679906686531862467627238401003459101637191297209422470388121802536569761414457618258343550613
n = 22822039733049388110936778173014765663663303811791283234361230649775805923902173438553927805407463106104699773994158375704033093471761387799852168337898526980521753614307899669015931387819927421875316304591521901592823814417756447695701045846773508629371397013053684553042185725059996791532391626429712416994990889693732805181947970071429309599614973772736556299404246424791660679253884940021728846906344198854779191951739719342908761330661910477119933428550774242910420952496929605686154799487839923424336353747442153571678064520763149793294360787821751703543288696726923909670396821551053048035619499706391118145067
c = 15406498580761780108625891878008526815145372096234083936681442225155097299264808624358826686906535594853622687379268969468433072388149786607395396424104318820879443743112358706546753935215756078345959375299650718555759698887852318017597503074317356745122514481807843745626429797861463012940172797612589031686718185390345389295851075279278516147076602270178540690147808314172798987497259330037810328523464851895621851859027823681655934104713689539848047163088666896473665500158179046196538210778897730209572708430067658411755959866033531700460551556380993982706171848970460224304996455600503982223448904878212849412357
n = 21574139855341432908474064784318462018475296809327285532337706940126942575349507668289214078026102682252713757703081553093108823214063791518482289846780197329821139507974763780260290309600884920811959842925540583967085670848765317877441480914852329276375776405689784571404635852204097622600656222714808541872252335877037561388406257181715278766652824786376262249274960467193961956690974853679795249158751078422296580367506219719738762159965958877806187461070689071290948181949561254144310776943334859775121650186245846031720507944987838489723127897223416802436021278671237227993686791944711422345000479751187704426369
c = 20366856150710305124583065375297661819795242238376485264951185336996083744604593418983336285185491197426018595031444652123288461491879021096028203694136683203441692987069563513026001861435722117985559909692670907347563594578265880806540396777223906955491026286843168637367593400342814725694366078337030937104035993569672959361347287894143027186846856772983058328919716702982222142848848117768499996617588305301483085428547267337070998767412540225911508196842253134355901263861121500650240296746702967594224401650220168780537141654489215019142122284308116284129004257364769474080721001708734051264841350424152506027932
n = 25360227412666612490102161131174584819240931803196448481224305250583841439581008528535930814167338381983764991296575637231916547647970573758269411168219302370541684789125112505021148506809643081950237623703181025696585998044695691322012183660424636496897073045557400768745943787342548267386564625462143150176113656264450210023925571945961405709276631990731602198104287528528055650050486159837612279600415259486306154947514005408907590083747758953115486124865486720633820559135063440942528031402951958557630833503775112010715604278114325528993771081233535247118481765852273252404963430792898948219539473312462979849137
c = 19892772524651452341027595619482734356243435671592398172680379981502759695784087900669089919987705675899945658648623800090272599154590123082189645021800958076861518397325439521139995652026377132368232502108620033400051346127757698623886142621793423225749240286511666556091787851683978017506983310073524398287279737680091787333547538239920607761080988243639547570818363788673249582783015475682109984715293163137324439862838574460108793714172603672477766831356411304446881998674779501188163600664488032943639694828698984739492200699684462748922883550002652913518229322945040819064133350314536378694523704793396169065179
n = 22726855244632356029159691753451822163331519237547639938779517751496498713174588935566576167329576494790219360727877166074136496129927296296996970048082870488804456564986667129388136556137013346228118981936899510687589585286517151323048293150257036847475424044378109168179412287889340596394755257704938006162677656581509375471102546261355748251869048003600520034656264521931808651038524134185732929570384705918563982065684145766427962502261522481994191989820110575981906998431553107525542001187655703534683231777988419268338249547641335718393312295800044734534761692799403469497954062897856299031257454735945867491191
c = 6040119795175856407541082360023532204614723858688636724822712717572759793960246341800308149739809871234313049629732934797569781053000686185666374833978403290525072598774001731350244744590772795701065129561898116576499984185920661271123665356132719193665474235596884239108030605882777868856122378222681140570519180321286976947154042272622411303981011302586225630859892731724640574658125478287115198406253847367979883768000812605395482952698689604477719478947595442185921480652637868335673233200662100621025061500895729605305665864693122952557361871523165300206070325660353095592778037767395360329231331322823610060006
n = 23297333791443053297363000786835336095252290818461950054542658327484507406594632785712767459958917943095522594228205423428207345128899745800927319147257669773812669542782839237744305180098276578841929496345963997512244219376701787616046235397139381894837435562662591060768476997333538748065294033141610502252325292801816812268934171361934399951548627267791401089703937389012586581080223313060159456238857080740699528666411303029934807011214953984169785844714159627792016926490955282697877141614638806397689306795328344778478692084754216753425842557818899467945102646776342655167655384224860504086083147841252232760941
c = 5418120301208378713115889465579964257871814114515046096090960159737859076829258516920361577853903925954198406843757303687557848302302200229295916902430205737843601806700738234756698575708612424928480440868739120075888681672062206529156566421276611107802917418993625029690627196813830326369874249777619239603300605876865967515719079797115910578653562787899019310139945904958024882417833736304894765433489476234575356755275147256577387022873348906900149634940747104513850154118106991137072643308620284663108283052245750945228995387803432128842152251549292698947407663643895853432650029352092018372834457054271102816934
n = 28873667904715682722987234293493200306976947898711255064125115933666968678742598858722431426218914462903521596341771131695619382266194233561677824357379805303885993804266436810606263022097900266975250431575654686915049693091467864820512767070713267708993899899011156106766178906700336111712803362113039613548672937053397875663144794018087017731949087794894903737682383916173267421403408140967713071026001874733487295007501068871044649170615709891451856792232315526696220161842742664778581287321318748202431466508948902745314372299799561625186955234673012098210919745879882268512656931714326782335211089576897310591491
c = 9919880463786836684987957979091527477471444996392375244075527841865509160181666543016317634963512437510324198702416322841377489417029572388474450075801462996825244657530286107428186354172836716502817609070590929769261932324275353289939302536440310628698349244872064005700644520223727670950787924296004296883032978941200883362653993351638545860207179022472492671256630427228461852668118035317021428675954874947015197745916918197725121122236369382741533983023462255913924692806249387449016629865823316402366017657844166919846683497851842388058283856219900535567427103603869955066193425501385255322097901531402103883869
n = 22324685947539653722499932469409607533065419157347813961958075689047690465266404384199483683908594787312445528159635527833904475801890381455653807265501217328757871352731293000303438205315816792663917579066674842307743845261771032363928568844669895768092515658328756229245837025261744260614860746997931503548788509983868038349720225305730985576293675269073709022350700836510054067641753713212999954307022524495885583361707378513742162566339010134354907863733205921845038918224463903789841881400814074587261720283879760122070901466517118265422863420376921536734845502100251460872499122236686832189549698020737176683019
c = 1491527050203294989882829248560395184804977277747126143103957219164624187528441047837351263580440686474767380464005540264627910126483129930668344095814547592115061057843470131498075060420395111008619027199037019925701236660166563068245683975787762804359520164701691690916482591026138582705558246869496162759780878437137960823000043988227303003876410503121370163303711603359430764539337597866862508451528158285103251810058741879687875218384160282506172706613359477657215420734816049393339593755489218588796607060261897905233453268671411610631047340459487937479511933450369462213795738933019001471803157607791738538467
n = 27646746423759020111007828653264027999257847645666129907789026054594393648800236117046769112762641778865620892443423100189619327585811384883515424918752749559627553637785037359639801125213256163008431942593727931931898199727552768626775618479833029101249692573716030706695702510982283555740851047022672485743432464647772882314215176114732257497240284164016914018689044557218920300262234652840632406067273375269301008409860193180822366735877288205783314326102263756503786736122321348320031950012144905869556204017430593656052867939493633163499580242224763404338807022510136217187779084917996171602737036564991036724299
c = 21991524128957260536043771284854920393105808126700128222125856775506885721971193109361315961129190814674647136464887087893990660894961612838205086401018885457667488911898654270235561980111174603323721280911197488286585269356849579263043456316319476495888696219344219866516861187654180509247881251251278919346267129904739277386289240394384575124331135655943513831009934023397457082184699737734388823763306805326430395849935770213817533387235486307008892410920611669932693018165569417445885810825749609388627231235840912644654685819620931663346297596334834498661789016450371769203650109994771872404185770230172934013971
n = 20545487405816928731738988374475012686827933709789784391855706835136270270933401203019329136937650878386117187776530639342572123237188053978622697282521473917978282830432161153221216194169879669541998840691383025487220850872075436064308499924958517979727954402965612196081404341651517326364041519250125036424822634354268773895465698920883439222996581226358595873993976604699830613932320720554130011671297944433515047180565484495191003887599891289037982010216357831078328159028953222056918189365840711588671093333013117454034313622855082795813122338562446223041211192277089225078324682108033843023903550172891959673551
c = 14227439188191029461250476692790539654619199888487319429114414557975376308688908028140817157205579804059783807641305577385724758530138514972962209062230576107406142402603484375626077345190883094097636019771377866339531511965136650567412363889183159616188449263752475328663245311059988337996047359263288837436305588848044572937759424466586870280512424336807064729894515840552404756879590698797046333336445465120445087587621743906624279621779634772378802959109714400516183718323267273824736540168545946444437586299214110424738159957388350785999348535171553569373088251552712391288365295267665691357719616011613628772175
n = 27359727711584277234897157724055852794019216845229798938655814269460046384353568138598567755392559653460949444557879120040796798142218939251844762461270251672399546774067275348291003962551964648742053215424620256999345448398805278592777049668281558312871773979931343097806878701114056030041506690476954254006592555275342579529625231194321357904668512121539514880704046969974898412095675082585315458267591016734924646294357666924293908418345508902112711075232047998775303603175363964055048589769318562104883659754974955561725694779754279606726358588862479198815999276839234952142017210593887371950645418417355912567987
c = 3788529784248255027081674540877016372807848222776887920453488878247137930578296797437647922494510483767651150492933356093288965943741570268943861987024276610712717409139946409513963043114463933146088430004237747163422802959250296602570649363016151581364006795894226599584708072582696996740518887606785460775851029814280359385763091078902301957226484620428513604630585131511167015763190591225884202772840456563643159507805711004113901417503751181050823638207803533111429510911616160851391754754434764819568054850823810901159821297849790005646102129354035735350124476838786661542089045509656910348676742844957008857457
n = 27545937603751737248785220891735796468973329738076209144079921449967292572349424539010502287564030116831261268197384650511043068738911429169730640135947800885987171539267214611907687570587001933829208655100828045651391618089603288456570334500533178695238407684702251252671579371018651675054368606282524673369983034682330578308769886456335818733827237294570476853673552685361689144261552895758266522393004116017849397346259119221063821663280935820440671825601452417487330105280889520007917979115568067161590058277418371493228631232457972494285014767469893647892888681433965857496916110704944758070268626897045014782837
c = 14069112970608895732417039977542732665796601893762401500878786871680645798754783315693511261740059725171342404186571066972546332813667711135661176659424619936101038903439144294886379322591635766682645179888058617577572409307484708171144488708410543462972008179994594087473935638026612679389759756811490524127195628741262871304427908481214992471182859308828778119005750928935764927967212343526503410515793717201360360437981322576798056276657140363332700714732224848346808963992302409037706094588964170239521193589470070839790404597252990818583717869140229811712295005710540476356743378906642267045723633874011649259842
n = 25746162075697911560263181791216433062574178572424600336856278176112733054431463253903433128232709054141607100891177804285813783247735063753406524678030561284491481221681954564804141454666928657549670266775659862814924386584148785453647316864935942772919140563506305666207816897601862713092809234429096584753263707828899780979223118181009293655563146526792388913462557306433664296966331469906428665127438829399703002867800269947855869262036714256550075520193125987011945192273531732276641728008406855871598678936585324782438668746810516660152018244253008092470066555687277138937298747951929576231036251316270602513451
c = 17344284860275489477491525819922855326792275128719709401292545608122859829827462088390044612234967551682879954301458425842831995513832410355328065562098763660326163262033200347338773439095709944202252494552172589503915965931524326523663289777583152664722241920800537867331030623906674081852296232306336271542832728410803631170229642717524942332390842467035143631504401140727083270732464237443915263865880580308776111219718961746378842924644142127243573824972533819479079381023103585862099063382129757560124074676150622288706094110075567706403442920696472627797607697962873026112240527498308535903232663939028587036724
n = 23288486934117120315036919418588136227028485494137930196323715336208849327833965693894670567217971727921243839129969128783853015760155446770590696037582684845937132790047363216362087277861336964760890214059732779383020349204803205725870225429985939570141508220041286857810048164696707018663758416807708910671477407366098883430811861933014973409390179948577712579749352299440310543689035651465399867908428885541237776143404376333442949397063249223702355051571790555151203866821867908531733788784978667478707672984539512431549558672467752712004519300318999208102076732501412589104904734983789895358753664077486894529499
c = 10738254418114076548071448844964046468141621740603214384986354189105236977071001429271560636428075970459890958274941762528116445171161040040833357876134689749846940052619392750394683504816081193432350669452446113285638982551762586656329109007214019944975816434827768882704630460001209452239162896576191876324662333153835533956600295255158377025198426950944040643235430211011063586032467724329735785947372051759042138171054165854842472990583800899984893232549092766400510300083585513014171220423103452292891496141806956300396540682381668367564569427813092064053993103537635994311143010708814851867239706492577203899024
n = 19591441383958529435598729113936346657001352578357909347657257239777540424811749817783061233235817916560689138344041497732749011519736303038986277394036718790971374656832741054547056417771501234494768509780369075443550907847298246275717420562375114406055733620258777905222169702036494045086017381084272496162770259955811174440490126514747876661317750649488774992348005044389081101686016446219264069971370646319546429782904810063020324704138495608761532563310699753322444871060383693044481932265801505819646998535192083036872551683405766123968487907648980900712118052346174533513978009131757167547595857552370586353973
c = 3834917098887202931981968704659119341624432294759361919553937551053499607440333234018189141970246302299385742548278589896033282894981200353270637127213483172182529890495903425649116755901631101665876301799865612717750360089085179142750664603454193642053016384714515855868368723508922271767190285521137785688075622832924829248362774476456232826885801046969384519549385428259591566716890844604696258783639390854153039329480726205147199247183621535172450825979047132495439603840806501254997167051142427157381799890725323765558803808030109468048682252028720241357478614704610089120810367192414352034177484688502364022887
n = 19254242571588430171308191757871261075358521158624745702744057556054652332495961196795369630484782930292003238730267396462491733557715379956969694238267908985251699834707734400775311452868924330866502429576951934279223234676654749272932769107390976321208605516299532560054081301829440688796904635446986081691156842271268059970762004259219036753174909942343204432795076377432107630203621754552804124408792358220071862369443201584155711893388877350138023238624566616551246804054720492816226651467017802504094070614892556444425915920269485861799532473383304622064493223627552558344088839860178294589481899206318863310603
c = 6790553533991297205804561991225493105312398825187682250780197510784765226429663284220400480563039341938599783346724051076211265663468643826430109013245014035811178295081939958687087477312867720289964506097819762095244479129359998867671811819738196687884696680463458661374310994610760009474264115750204920875527434486437536623589684519411519100170291423367424938566820315486507444202022408003879118465761273916755290898112991525546114191064022991329724370064632569903856189236177894007766690782630247443895358893983735822824243487181851098787271270256780891094405121947631088729917398317652320497765101790132679171889
n = 26809700251171279102974962949184411136459372267620535198421449833298448092580497485301953796619185339316064387798092220298630428207556482805739803420279056191194360049651767412572609187680508073074653291350998253938793269214230457117194434853888765303403385824786231859450351212449404870776320297419712486574804794325602760347306432927281716160368830187944940128907971027838510079519466846176106565164730963988892400240063089397720414921398936399927948235195085202171264728816184532651138221862240969655185596628285814057082448321749567943946273776184657698104465062749244327092588237927996419620170254423837876806659
c = 386213556608434013769864727123879412041991271528990528548507451210692618986652870424632219424601677524265011043146748309774067894985069288067952546139416819404039688454756044862784630882833496090822568580572859029800646671301748901528132153712913301179254879877441322285914544974519727307311002330350534857867516466612474769753577858660075830592891403551867246057397839688329172530177187042229028685862036140779065771061933528137423019407311473581832405899089709251747002788032002094495379614686544672969073249309703482556386024622814731015767810042969813752548617464974915714425595351940266077021672409858645427346
思路¶
每两个n求一次公约数,看看是否有不为1的一组n,如果有的话,p就是这个公约数,之后就可以求其他量了
exp.py
from Crypto.Util.number import *
import gmpy2
e = 65537
n = [n0,n1,n2,n3,n4,n5,n6,n7,n8,n9,n10,n11,n12,n13,n14,n15,n16,n17,n18,n19]
c = [c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15,c16,c17,c18,c19]
for i in range(len(n)):
for j in range(len(n)):
if (i!=j):
t = gmpy2.gcd(n[i],n[j])
if t != 1:
p = t
q = n[i] // p
d = gmpy2.invert(e,(p-1)*(q-1))
m = pow(c[i],d,n[i])
print(long_to_bytes(m))
#flag{abdcbe5fd94e23b3de429223ab9c2fdf}
第二种情况 用中国剩余定理¶
简要说明中国剩余定理的作用就是把一个同余式组变成一个同余式,eg:
转换为一个\(C \equiv m ^ e \mod N\),\(N = lcm(n_1,n_2,n_3)\)
例题1¶
task.py
import libnum
import gmpy2
import random
import uuid
flag = "flag{" + str(uuid.uuid4()) + "}"
m = libnum.s2n(flag)
p = libnum.generate_prime(1024)
q = libnum.generate_prime(1024)
n1 = p * q
p = libnum.generate_prime(1024)
q = libnum.generate_prime(1024)
n2 = p * q
p = libnum.generate_prime(1024)
q = libnum.generate_prime(1024)
n3 = p * q
while 1:
e = random.randint(10, 20)
print(e)
if gmpy2.is_prime(e):
break
c1 = pow(m, e, n1)
c2 = pow(m, e, n2)
c3 = pow(m, e, n3)
print("n1=", n1)
print("n2=", n2)
print("n3=", n3)
print("c1=", c1)
print("c2=", c2)
print("c3=", c3)
先根据中国剩余定理求出\(m^e\),这题的e只给范围,要爆破一下
exp.py
from Crypto.Util.number import long_to_bytes
import gmpy2
def Get_Mi(m_list,m): #求衍数
M_list = []
for mi in m_list:
M_list.append(m // mi)
return M_list
def Get_resMi(M_list,m_list): #求乘率
resM_list = []
for i in range(len(M_list)):
resM_list.append(gmpy2.invert(M_list[i],m_list[i]))
return resM_list
def Get_result(a_list):
M_list = Get_Mi(m_list,m)
resM_list = Get_resMi(M_list,m_list)
result = 0
for i in range(len(M_list)):
result += M_list[i]*resM_list[i]*a_list[i]
result %= m
return result
n1 = 16655230929893303490818415854457831426545038662809855283873228642358207995734291242944120042612699642460820594813654718158395826755230956722936107927889550129166619245152453353908373751380196656611349200623414836128383308653618062999595622747482867683840133843768870236300348203389275090871132570173650238774275209757683812077533989960172822335488251744796657926473009279723460304257252876756936524918018903158795894385111046938638194925881670388700872760201130485273663156422785999102754192840209476417602399017445296045070405343876349687582470436774316410697773759057621576657298096301937899052773787116133124199739
n2 = 17197151926745749646602149115445210421300330711044282276861045275221683290586877554048509794473112203880585601275129330843554946888863132721219683639579200702355880529569042889789589005950061966309684759066705732225014741164779016525568884409690021988879475589545329149547046975086877521757237117008484775731784935960191717287332176327498377273179740487245459081737196777751408106728622513560888261855065717079007065635401835089216224111969668029246916986663313301660909538148574652809266532053889578734157117390082522831069594417637550812101652367765364077901612478983024721669687150628356918237152414368862535409859
n3 = 18719461901666732419189610536735130974364055134601694187780706398369536769336080321122034942831217438281120989017698755904233940669427542442488330152862658754609065361849067002424120904308655036927580582916373684567047102601602588472175947665724244201887952599804681827419266055359412641159981152796138695901074514583606207162167385730873921563442166111892785482387108299191119048884993267729877797586421940344366636285656854837470348603688925980178978612114344024951042846249621559376348599687263736342957456838732355009637030035658212442442824658869094581324944034490700706979663405137522294780606800571433058912041
c1 = 3530761236149189046680124371485374220252032991305088864647979778627799354583229731576585900490173357726425570018182390597284149666834264690795437972634538596441103368165128688664787322126097802985602065455316693754513332761284857157982201975554297034291092099307950246864758375115838291339394148547902128382917596947095456178572561422004708150053706114994560773293625641699691472764190426577272488084620105693964419578988589192873196530900413833531923536786853211065167782657153004342018675666293830194703777994380600060782651326623229047839109994778831432598543154184891096335217588164509636922274833553782288823349
c2 = 7557835478962501903223351987016911891266554255050134264644805724502475848487138948948076311894495847429608136390014902405718084026208891531815323418707377349405409096779206918831458396991602033494429461919844309109113047361743133772636443322195238900874786548606687215969337920658068807801603115402783849082788527952834594443136756890747461628705174983562847145588532659589787532039981477468881131005056101092222499397893730056830156407331988257383965698358904379729558105489119604343081747549319382873235286788453435066434264212954607441597606413293491628299838317713381567250093086011058119721189087729804152444980
c3 =8471234074077377509408346140986116360421840978074779990698043926601850838824365885362094731657766299393262223086536737448516669969503891677808275285733096884405583100485903641986516527279324847718603091709062689898441711907846902050004165404073776422495381050861998133576074526490209080137421773440295749900582039873013319584167081936219517593826232230971430937112005615502869367413205660317010303160932970748420125111225082886082306332340892549579826854620461821084886193470846195356695313518639669516456574134135244251956477677377976434266541164893562226872334598362396368708087248848222008201970781942468960022694
m_list= [n1,n2,n3]
a_list= [c1,c2,c3]
m = 1
for i in m_list:
m *= i
result = Get_result(a_list)
for e in range(10,20):
m = gmpy2.iroot(result,e)
if m[1]:
print(long_to_bytes(m[0]))
例题2 鹤城杯2021——Crazy_Tech_RSA¶
task.py
from Crypto.Util.number import *
from Crypto.Util.Padding import *
FLAG = bytes_to_long(pad(b"flag{??????}",64))
def init_key():
p, q = getPrime(512), getPrime(512)
n = p*q
e = 9
while(GCD((p-1)*(q-1),e)!=1):
p, q = getPrime(512), getPrime(512)
n = p*q
d = inverse(e,(p-1)*(q-1))
return n,e,d
n_list=list()
c_list=list()
for i in range(9):
N,e,d=init_key()
n_list.append(N)
c=pow(FLAG,e,N)
c_list.append(pow(FLAG,e,N))
assert(pow(c,d,N)==FLAG)
print("n_list:",n_list)
print("c_list:",c_list)
先用中国剩余定理解出\(m^e\)
再开根号
这道题的e是给出,如果e没有给出的话,需要爆破e
exp.py
from Crypto.Util.number import long_to_bytes
import gmpy2
def Get_Mi(m_list,m): #求衍数
M_list = []
for mi in m_list:
M_list.append(m // mi)
return M_list
def Get_resMi(M_list,m_list): #求乘率
resM_list = []
for i in range(len(M_list)):
resM_list.append(gmpy2.invert(M_list[i],m_list[i]))
return resM_list
def Get_result(a_list):
M_list = Get_Mi(m_list,m)
resM_list = Get_resMi(M_list,m_list)
result = 0
for i in range(len(M_list)):
result += M_list[i]*resM_list[i]*a_list[i]
result %= m
return result
m_list=[71189786319102608575263218254922479901008514616376166401353025325668690465852130559783959409002115897148828732231478529655075366072137059589917001875303598680931962384468363842379833044123189276199264340224973914079447846845897807085694711541719515881377391200011269924562049643835131619086349617062034608799, 92503831027754984321994282254005318198418454777812045042619263533423066848097985191386666241913483806726751133691867010696758828674382946375162423033994046273252417389169779506788545647848951018539441971140081528915876529645525880324658212147388232683347292192795975558548712504744297104487514691170935149949, 100993952830138414466948640139083231443558390127247779484027818354177479632421980458019929149817002579508423291678953554090956334137167905685261724759487245658147039684536216616744746196651390112540237050493468689520465897258378216693418610879245129435268327315158194612110422630337395790254881602124839071919, 59138293747457431012165762343997972673625934330232909935732464725128776212729547237438509546925172847581735769773563840639187946741161318153031173864953372796950422229629824699580131369991913883136821374596762214064774480548532035315344368010507644630655604478651898097886873485265848973185431559958627423847, 66827868958054485359731420968595906328820823695638132426084478524423658597714990545142120448668257273436546456116147999073797943388584861050133103137697812149742551913704341990467090049650721713913812069904136198912314243175309387952328961054617877059134151915723594900209641163321839502908705301293546584147, 120940513339890268554625391482989102665030083707530690312336379356969219966820079510946652021721814016286307318930536030308296265425674637215009052078834615196224917417698019787514831973471113022781129000531459800329018133248426080717653298100515701379374786486337920294380753805825328119757649844054966712377, 72186594495190221129349814154999705524005203343018940547856004977368023856950836974465616291478257156860734574686154136925776069045232149725101769594505766718123155028300703627531567850035682448632166309129911061492630709698934310123778699316856399909549674138453085885820110724923723830686564968967391721281, 69105037583161467265649176715175579387938714721653281201847973223975467813529036844308693237404592381480367515044829190066606146105800243199497182114398931410844901178842049915914390117503986044951461783780327749665912369177733246873697481544777183820939967036346862056795919812693669387731294595126647751951, 76194219445824867986050004226602973283400885106636660263597964027139613163638212828932901192009131346530898961165310615466747046710743013409318156266326090650584190382130795884514074647833949281109675170830565650006906028402714868781834693473191228256626654011772428115359653448111208831188721505467497494581]
a_list=[62580922178008480377006528793506649089253164524883696044759651305970802215270721223149734532870729533611357047595181907404222690394917605617029675103788705320032707977225447998111744887898039756375876685711148857676502670812333076878964148863713993853526715855758799502735753454247721711366497722251078739585, 46186240819076690248235492196228128599822002268014359444368898414937734806009161030424589993541799877081745454934484263188270879142125136786221625234555265815513136730416539407710862948861531339065039071959576035606192732936477944770308784472646015244527805057990939765708793705044236665364664490419874206900, 85756449024868529058704599481168414715291172247059370174556127800630896693021701121075838517372920466708826412897794900729896389468152213884232173410022054605870785910461728567377769960823103334874807744107855490558726013068890632637193410610478514663078901021307258078678427928255699031215654693270240640198, 14388767329946097216670270960679686032536707277732968784379505904021622612991917314721678940833050736745004078559116326396233622519356703639737886289595860359630019239654690312132039876082685046329079266785042428947147658321799501605837784127004536996628492065409017175037161261039765340032473048737319069656, 1143736792108232890306863524988028098730927600066491485326214420279375304665896453544100447027809433141790331191324806205845009336228331138326163746853197990596700523328423791764843694671580875538251166864957646807184041817863314204516355683663859246677105132100377322669627893863885482167305919925159944839, 2978800921927631161807562509445310353414810029862911925227583943849942080514132963605492727604495513988707849133045851539412276254555228149742924149242124724864770049898278052042163392380895275970574317984638058768854065506927848951716677514095183559625442889028813635385408810698294574175092159389388091981, 16200944263352278316040095503540249310705602580329203494665614035841657418101517016718103326928336623132935178377208651067093136976383774189554806135146237406248538919915426183225265103769259990252162411307338473817114996409705345401251435268136647166395894099897737607312110866874944619080871831772376466376, 31551601425575677138046998360378916515711528548963089502535903329268089950335615563205720969393649713416910860593823506545030969355111753902391336139384464585775439245735448030993755229554555004154084649002801255396359097917380427525820249562148313977941413268787799534165652742114031759562268691233834820996, 25288164985739570635307839193110091356864302148147148153228604718807817833935053919412276187989509493755136905193728864674684139319708358686431424793278248263545370628718355096523088238513079652226028236137381367215156975121794485995030822902933639803569133458328681148758392333073624280222354763268512333515]
m = 1
for i in m_list:
m *= i
result = Get_result(a_list)
e = 9
m = gmpy2.iroot(result,e)
if m[1]:
print(long_to_bytes(m[0]))
七、维纳攻击¶
攻击条件:\(d < \frac{1}{3}N^{0.25}\)
原理:
有
因为\(\phi(n) \approx n\)
两边同除\(dn\)有
则
满足勒让德定理(这个定理网上可以搜得到,根据这个定理,不同形式的n是不一样的,比如说这个例子需要\(n=p\times q\)才可使用),因此\(\frac{e}{n}\)可以作为\(\frac{k}{d}\)的收敛子
连分数展开即可
例题¶
task.py
import libnum
import random
import gmpy2
## 生成随机素数
p = libnum.generate_prime(512)
q = libnum.generate_prime(512)
m = "flag{20d6e2da95dcc1fa5f5432a436c4be18}"
## 字符串转数字
m = libnum.s2n(m)
n = p * q
phi_n = (p - 1) * (q - 1)
## 计算d
while True:
nbits = 1024
d = random.getrandbits(nbits // 4)
if (libnum.gcd(d, phi_n) == 1 and 36 * pow(d, 4) < n):
break
## 计算e
e = libnum.invmod(d, phi_n)
c = pow(m, e, n)
print("n=", n)
print("e=", e)
print("c=", c)
exp.py
import gmpy2
import libnum
def continuedFra(x, y):
"""计算连分数
:param x: 分子
:param y: 分母
:return: 连分数列表
"""
cf = []
while y:
cf.append(x // y)
x, y = y, x % y
return cf
def gradualFra(cf):
"""计算传入列表最后的渐进分数
:param cf: 连分数列表
:return: 该列表最后的渐近分数
"""
numerator = 0
denominator = 1
for x in cf[::-1]:
## 这里的渐进分数分子分母要分开
numerator, denominator = denominator, x * denominator + numerator
return numerator, denominator
def solve_pq(a, b, c):
"""使用韦达定理解出pq,x^2−(p+q)∗x+pq=0
:param a:x^2的系数
:param b:x的系数
:param c:pq
:return:p,q
"""
par = gmpy2.isqrt(b * b - 4 * a * c)
return (-b + par) // (2 * a), (-b - par) // (2 * a)
def getGradualFra(cf):
"""计算列表所有的渐近分数
:param cf: 连分数列表
:return: 该列表所有的渐近分数
"""
gf = []
for i in range(1, len(cf) + 1):
gf.append(gradualFra(cf[:i]))
return gf
def wienerAttack(e, n):
"""
:param e:
:param n:
:return: 私钥d
"""
cf = continuedFra(e, n)
gf = getGradualFra(cf)
for d, k in gf:
if k == 0: continue
if (e * d - 1) % k != 0:
continue
phi = (e * d - 1) // k
p, q = solve_pq(1, n - phi + 1, n)
if p * q == n:
return d
n = 113881698992379349039968368927979997900777221951663104697020683691495129639829918739755194174063944178083527489820939138302751895652076620380510013941997706327553964127612610209509889011613768847759318892303231846117914554931459295347697888260576901354448014917692680573408654658384481284699735788978230690197
e = 39068960413447607023613035707248214114819409621234801785480423979473767995171860917209502861408393208940683687475760366491413173744775811644295874981290403938714121977201901942939425294427737703229098649131737380098596135730392902019429964095866394165971291108245774407908011073271822915371753470010435225545
c = 32897925577913728659288168937025744709859960639901500169867896018406263110205704273203287172003057450591000201857719871686024077615520906540631374442504017489026298422189715372129838501090730593164075113452055617571409044743698645392909829425374093273187125709095368164744188182156849031225036001381531504057
d = wienerAttack(e, n)
print(d)
m = pow(c, d, n)
print(libnum.n2s(m).decode())
exp也可以用sagemath写,这里就不展示了
多因子的维纳攻击¶
例题来源:2023NKCTF——complex_matrix
task.py
from Crypto.Util.number import *
import gmpy2 as gy
flag = ''
k = 400
p, q = getPrime(741), getPrime(741)
N = p * q
phi = (p-1) * (q-1)
_flag = bytes_to_long(flag)
p, q = getPrime(1024), getPrime(1024)
d_array = [getPrime(k) for _ in range(4)]
e_array = [inverse(i, phi) for i in d_array]
c = pow(_flag, 65537, N)
print('N:',N)
print('e:',e_array)
print('c:',c)
#N: 71841248095369087024928175623295380241516644434969868335504061065977014103487197287619667598363486210886674500469383623511906399909335989202774281795855975972913438448899231650449810696539722877903606541112937729384851506921675290984316325565141178015123381439392534417225128922398194700511937668809140024838070124095703585627058463137549632965723304713166804084673075651182998654091113119667582720831809458721072371364839503563819080226784026253
#e: [65128799196671634905309494529154568614228788035735808211836905142007976099865571126946706559109393187772126407982007858423859147772762638898854472065889939549916077695303157760259717113616428849798058080633047516455513870697383339784816006154279428812359241282979297285283850338964993773227397528608557211742425548651971558377656644211835094019462699301650412862894391885325969143805924684662849869947172175608502179438901337558870349697233790535, 58756559706647121529575085912021603170286163639572075337348109911506627489265537716060463072086480156516641723700802217411122982693536541892986623158818442274840863016647800896033363360822503445344748132842451806511693779600370832206455202293028402486647422212959763287987847280322100701242139127654031151565924132562837893975505159702015125483479126108892709063135006366792197127007229210558758401679638300464111782814561428899998471531067163715, 34828685390969672139784723764579499920301439564705391196519314224159563070870933754477650614819514127121146216049444888554338415587165719098661141454627820126445291802801256297252654045398330613075575527685542980264993711077876535643646746742646371967302159565887123638001580042027272379341650995728849759541960087953160211696369079708787543303742132161742979856720539914370868829868891655221361545648778590685232034703220732697083024449894197969, 26717968456600556973167180286909817773394160817933525240720067057464671317174201540556176814203780603153696663101158205367554829261808020426363683474848952397963507069306452835776851274959389849223566030857588019845781623271395012194869024566879791449466064832273531795430185178486425688475688634844530106740480643866537205900809400383304665727460014210405339697947582657505028211149470787536144302545259243549176816653560626044921521516818788487]
#c: 39297018404565022956251803918747154798377576057123078716166221329195959669756819453426741569480551313085435037629493881038383709458043802420338889323233368852331387845200216275712388921820794980987541224782392553528127093154957890356084331463340193478391679540506421250562554424770350351514435220782124981277580072039637811543914983033300225131364246910828188727043248991987332274929827173923543187017105236008487756190002204169623313222748976369
存个脚本,来源文章列表 | NSSCTF
exp.py
import gmpy2
import libnum
isdigit = lambda x: ord('0') <= ord(x) <= ord('9')
def my_permutations(g, n):
sub = []
res = []
def dfs(s, prev):
if len(s) == n:
res.append(s[::])
for i in g:
if i in s or i < prev:
continue
s.append(i)
dfs(s, max(prev, i))
s.remove(i)
dfs(sub, 0)
return res
class X3NNY(object):
def __init__(self, exp1, exp2):
self.exp1 = exp1
self.exp2 = exp2
def __mul__(self, b):
return X3NNY(self.exp1 * b.exp1, self.exp2 * b.exp2)
def __repr__(self):
return '%s = %s' % (self.exp1.expand().collect_common_factors(), self.exp2)
class X_Complex(object):
def __init__(self, exp):
i = 0
s = '%s' % exp
while i < len(s):
if isdigit(s[i]):
num = 0
while i < len(s) and isdigit(s[i]):
num = num*10 + int(s[i])
i += 1
if i >= len(s):
self.b = num
elif s[i] == '*':
self.a = num
i += 2
elif s[i] == '/':
i += 1
r = 0
while i < len(s) and isdigit(s[i]):
r = r*10 + int(s[i])
i += 1
self.b = num/r
else:
i += 1
if not hasattr(self, 'a'):
self.a = 1
if not hasattr(self, 'b'):
self.b = 0
def WW(e, d, k, g, N, s):
return X3NNY(e*d*g-k*N, g+k*s)
def GG(e1, e2, d1, d2, k1, k2):
return X3NNY(e1*d1*k2- e2*d2*k1, k2 - k1)
def W(i):
e = eval("e%d" % i)
d = eval("d%d" % i)
k = eval("k%d" % i)
return WW(e, d, k, g, N, s)
def G(i, j):
e1 = eval("e%d" % i)
d1 = eval("d%d" % i)
k1 = eval("k%d" % i)
e2 = eval("e%d" % j)
d2 = eval("d%d" % j)
k2 = eval("k%d" % j)
return GG(e1, e2, d1, d2, k1, k2)
def R(e, sn): ## min u max v
ret = X3NNY(1, 1)
n = max(e)
nn = len(e)
l = set(i for i in range(1, n+1))
debug = ''
u, v = 0, 0
for i in e:
if i == 1:
ret *= W(1)
debug += 'W(%d)' % i
nn -= 1
l.remove(1)
u += 1
elif i > min(l) and len(l) >= 2*nn:
ret *= G(min(l), i)
nn -= 1
debug += 'G(%d, %d)' % (min(l), i)
l.remove(min(l))
l.remove(i)
v += 1
else:
ret *= W(i)
l.remove(i)
debug += 'W(%d)' % i
nn -= 1
u += 1
## print(debug, end = ' ')
return ret, u/2 + (sn - v) * a
def H(n):
if n == 0:
return [0]
if n == 2:
return [(), (1,), (2,), (1, 2)]
ret = []
for i in range(3, n+1):
ret.append((i,))
for j in range(1, i):
for k in my_permutations(range(1, i), j):
ret.append(tuple(k + [i]))
return H(2) + ret
def CC(exp, n):
cols = [0 for i in range(1<<n)]
## split exp
texps = ('%s' % exp.exp1.expand()).strip().split(' - ')
ops = []
exps = []
for i in range(len(texps)):
if texps[i].find(' + ') != -1:
tmp = texps[i].split(' + ')
ops.append(0)
exps.append(tmp[0])
for i in range(1, len(tmp)):
ops.append(1)
exps.append(tmp[i])
else:
ops.append(0)
exps.append(texps[i])
if exps[0][0] == '-':
for i in range(len(exps)):
ops[i] = 1-ops[i]
exps[0] = exps[0][1:]
else:
ops[0] = 1
## find e and N
l = []
for i in range(len(exps)):
tmp = 1 if ops[i] else -1
en = []
j = 0
while j < len(exps[i]):
if exps[i][j] == 'e':
num = 0
j += 1
while isdigit(exps[i][j]):
num = num*10 + int(exps[i][j])
j += 1
tmp *= eval('e%d' % num)
en.append(num)
elif exps[i][j] == 'N':
j += 1
num = 0
if exps[i][j] == '^':
j += 1
while isdigit(exps[i][j]):
num = num*10 + int(exps[i][j])
j += 1
if num == 0:
num = 1
tmp *= eval('N**%d' % num)
else:
j += 1
if tmp == 1 or tmp == -1:
l.append((0, ()))
else:
l.append((tmp, tuple(sorted(en))))
## construct h
mp = H(n)
for val, en in l:
cols[mp.index(en)] = val
## print(cols)
return cols
def EWA(n, elist, NN, alpha):
mp = H(n)
var('a')
S = [X_Complex(n*a)]
cols = [[1 if i == 0 else 0 for i in range(2^n)]]
for i in mp[1:]:
eL, s = R(i, n)
cols.append(CC(eL, n))
S.append(X_Complex(s))
alphaA,alphaB = 0, 0
for i in S:
alphaA = max(i.a, alphaA)
alphaB = max(i.b, alphaB)
## print(alphaA, alphaB)
D = []
for i in range(len(S)):
## print((alphaA-S[i].a), (alphaB - S[i].b))
D.append(
int(NN^((alphaA-S[i].a)*alpha + (alphaB - S[i].b)))
)
kw = {'N': NN}
for i in range(len(elist)):
kw['e%d' % (i+1)] = elist[i]
B = Matrix(ZZ, Matrix(cols).T(**kw)) * diagonal_matrix(ZZ, D)
L = B.LLL(0.5)
v = Matrix(ZZ, L[0])
x = v * B**(-1)
phi = int(x[0,1]/x[0,0]*elist[0])
return phi
def attack(NN, elist, alpha):
phi = EWA(len(elist), elist, NN, alpha)
print(phi)
return phi
NN = 71841248095369087024928175623295380241516644434969868335504061065977014103487197287619667598363486210886674500469383623511906399909335989202774281795855975972913438448899231650449810696539722877903606541112937729384851506921675290984316325565141178015123381439392534417225128922398194700511937668809140024838070124095703585627058463137549632965723304713166804084673075651182998654091113119667582720831809458721072371364839503563819080226784026253
elist = [65128799196671634905309494529154568614228788035735808211836905142007976099865571126946706559109393187772126407982007858423859147772762638898854472065889939549916077695303157760259717113616428849798058080633047516455513870697383339784816006154279428812359241282979297285283850338964993773227397528608557211742425548651971558377656644211835094019462699301650412862894391885325969143805924684662849869947172175608502179438901337558870349697233790535, 58756559706647121529575085912021603170286163639572075337348109911506627489265537716060463072086480156516641723700802217411122982693536541892986623158818442274840863016647800896033363360822503445344748132842451806511693779600370832206455202293028402486647422212959763287987847280322100701242139127654031151565924132562837893975505159702015125483479126108892709063135006366792197127007229210558758401679638300464111782814561428899998471531067163715, 34828685390969672139784723764579499920301439564705391196519314224159563070870933754477650614819514127121146216049444888554338415587165719098661141454627820126445291802801256297252654045398330613075575527685542980264993711077876535643646746742646371967302159565887123638001580042027272379341650995728849759541960087953160211696369079708787543303742132161742979856720539914370868829868891655221361545648778590685232034703220732697083024449894197969, 26717968456600556973167180286909817773394160817933525240720067057464671317174201540556176814203780603153696663101158205367554829261808020426363683474848952397963507069306452835776851274959389849223566030857588019845781623271395012194869024566879791449466064832273531795430185178486425688475688634844530106740480643866537205900809400383304665727460014210405339697947582657505028211149470787536144302545259243549176816653560626044921521516818788487]
c = 39297018404565022956251803918747154798377576057123078716166221329195959669756819453426741569480551313085435037629493881038383709458043802420338889323233368852331387845200216275712388921820794980987541224782392553528127093154957890356084331463340193478391679540506421250562554424770350351514435220782124981277580072039637811543914983033300225131364246910828188727043248991987332274929827173923543187017105236008487756190002204169623313222748976369
alpha = 400 / int(NN).bit_length() #400指的是d的比特
for i in range(1, len(elist)+1):
var("e%d" % i)
var("d%d" % i)
var("k%d" % i)
g, N, s = var('g'), var('N'), var('s')
for i in range(len(elist)):
elist[i] = Integer(elist[i])
phi = attack(NN, elist, alpha)
d = gmpy2.invert(65537, phi)
m = int(pow(c, d, NN))
print(libnum.n2s(m))
## NKCTF{F10w3r_Hav3_r3start_Day_N0_Man_iS_Y0ung_Aga1n}
八、共享素数¶
两个n有相同的因子,直接求公因数就好了
例题¶
task.py
import gmpy2
import libnum
import uuid
flag = "flag{" + str(uuid.uuid4()) + "}"
m = libnum.s2n(flag)
p = libnum.generate_prime(1024)
q1 = libnum.generate_prime(1024)
q2 = libnum.generate_prime(1024)
n1 = p * q1
n2 = p * q2
e = 65537
c1 = pow(m, e, n1)
c2 = pow(m, e, n2)
print("n1=", n1)
print("n2=", n2)
print("c1=", c1)
print("c2=", c2)
exp.py
from Crypto.Util.number import long_to_bytes
import gmpy2
n1 =22036096414750333101406538757625812613248444424049684758772058140377463618250795867832853117902163257003301132932490853355450673043991381637053778653821758783435921283322439267628837074056789021611782010444749024512216306961829453158759193969454712080047205883631153040900193575534288719429526169135614695862857156639195562501217424283401364740789214390377624598500939079307163832197534297642842744345373413423859103414676878739674227554029537817890874031594311152843060524913028526429344172693584167398664817727426767686424415189580527939256633114120720308173788544194669684834369132677253418971615644691719536820433
n2 =17251653165250011947306159769694143433212298910745609670733920118632739529605426957617875166211610794383631191273183964010346725508667657137931394653419082978603166138439632713627832321960586938891805262605225424775586397813147240201440036009395991700175612039074317131837185920131565272816639771739150718839592250080325774556601865770352479323350280393818365902570673799584200153846520860657815432981116910233453207519365604533077996449249223280685559491369393277114405166293011856168173778428700718404816038991911974902005969923746846815798515831172402122367026339135245751136695128279659872423027539333024854133659
c1 =1408937404754902028814920445701404613476983383738408959873219805755187459225302977012340464647741276263048769176603562703588286152102079561897286480939341184453940846603761664643956274520695676061184610702912592321357240109665885587701906369214592438887065694062151546241739122722790261888290706296747328780758965559093085406877315628139811554345214347799361309288949307776501119359571116522001853935560023530705364795364624152061166945046882418058831567088890277747158775876953662285842999920594778445526224560016361787941610542255000514402493843548068271595134879195073239601085319795505131267697387692179944010772
c2 =12175155463891225370775786368564999885751076529394005420368968241428058465831204925081389807872272508968531564921996276054143112205083003561546962102395368677755381589762565680900651699885381615975236663522025080384481537727180649424984636506390139648492522347366656322729441290553251505232488994951243521740296115895651926783520321289129993169836271218322014443396220481361007479796234525990954874013729001502984583162486353287639655447340498584591591009224750835072707121652727119580764546240945763088815277130694950594020142961659318737857067755125666395542079926757603295535345281657293981259718286213812909191174
e = 65537
t = gmpy2.gcd(n1,n2)
if t != 1:
p = t
q = n1 // p
d = gmpy2.invert(e,(p-1)*(q-1))
print(long_to_bytes(pow(c1,d,n1)))
九、dp泄露¶
原理推导¶
左右同乘e得
即
化简得
遍历\(i \in (0,e)\)的所有值,如果\(d_p\times e-1\)能够整除\(i\)则,我们就可以求得\(p-1\)
例题1¶
task.py
import gmpy2
import libnum
import uuid
flag = "flag{" + str(uuid.uuid4()) + "}"
print(flag)
m = libnum.s2n(flag)
p = libnum.generate_prime(1024)
q = libnum.generate_prime(1024)
e = 65537
n = p * q
phi = (p - 1) * (q - 1)
d = gmpy2.invert(e, phi)
print("d=",d)
dp = d % (p - 1)
c = pow(m, e, n)
print("n=", n)
print("e=", e)
print("c=", c)
print("dp=", dp)
exp.py
from Crypto.Util.number import long_to_bytes
import gmpy2
n = 17954000555185130679232377513216924086370205717680723426279833171815673097846434355592747466782173529597978954062272371758852339605432963940809244445748900431763988392120156128524694217746804744076348205536430811607694098089294013508111154514184079159181563040241302764793111632189829652065825442796716027051750043654503172469553222784393034067341575558782690547449884992414106322578261286526556856377419622164651917718772498388922129465042492616904419638034789576380038341882418547113136903862482397767904921157094396562770484669239932933837196899640811033424030302285885080504355934919967693498648701839252087380477
c = 1808490145328726635638705291306162339133116115672167390186563455429486046847680827004544020052978814401354685508506555963361065725012891622174617670820924531959433674273579973778657669162210657120785539629874456938159379512635932223403818177582242406964621317531188027900758868453176575753681627336133481701182056262584118645398172089436811174776978418919803975809158758707062473122656821152108292060156091196577573172937093806159669057467094718771367509856968694209472630329096814023864642219783061245777457366202879949123915168571990229277326042767587009623951348541055835347386485900505749475571895673653225741649
dp =114993440308125678369350484461242628405806013372930792337329972720600942891053460367721272956155528263465552939386621554396883112994907299126303463171544968629898544811159986442249990975328659373544491636958873255689808151391606942912468529923159009459712396428051292828093059494024457367637991626193487727331
e =65537
for i in range(1,e):
t = (dp * e - 1) % i #这是p-1前面的系数
if t == 0:
p = (dp * e - 1) // i + 1
if n % p == 0:
q = n // p
d = gmpy2.invert(e,(p-1)*(q-1))
print(long_to_bytes(pow(c,d,n)))
例题2 e很大¶
task.py
import gmpy2
import libnum
import uuid
flag = "flag{" + str(uuid.uuid4()) + "}"
m = libnum.s2n(flag)
p = libnum.generate_prime(1024)
q = libnum.generate_prime(1024)
e = libnum.generate_prime(128)
n = p * q
phi = (p - 1) * (q - 1)
d = gmpy2.invert(e, phi)
dp = d % (p - 1)
c = pow(m, e, n)
print("n=", n)
print("e=", e)
print("c=", c)
print("dp=", dp)
在e很大的情况下,我们爆破\((0,e)\)的值就显得不现实。需要用其他方法 $$ \because d_p \times e = k(p-1)+1 $$
取一个与\(p\)互素的常数\(a\),则有
然后与n求公因数即可得到p
exp.py
from Crypto.Util.number import getPrime,long_to_bytes
import gmpy2
n= 18150086749964030204952772593650655354407282168407543480518017821905322058792108409169209539752974177937328703466169798097779231540410352308736251888449285307132274903811942187361234788236374036493935354342502760429195828731474432692281516115002087485890105917067613983079156790015275611914738187418424730456416770000646598861170179898016595068557049151791620868027603590052357726580431487083778514163249201637184318559165989454489485258667170883129099757366657203826319909509544670881866298317938263281638296241860739828567999093491297970389142395080780768892194380031018324855383292685388767246393785705551231780899
e= 278817530653170259039233683650169866189
c= 10813189255953686674328168562592345253502176950586624384555229875947895107088800774325110599057171743065073092283651992594106863499561887773348061509184951920329015539552207920010924284253109754443530283215130327152416667309504455641730629770856098336299767661535526880065006664806270833698497579073641076473649621250873969544362062393319711114090739414415757921473984666129110213417578310035188480139392986280529932137364474426391469019554935239234968517869914506321750458197587849623935306068749435995413807906558975073047215241796461878288003366415184144140612947217041288538376514085070670565572628317388808356563
dp= 25015362092988139281045705051525732988903355826221062953430054346210238749256645995431509510448988062597830708438496723137288693056422683942336451600173722142331077900759633024803467824277121463213906905346623305038031660927650043841899168305106293747254814365869018331032172781810238397508103692878400636333
a = getPrime(10)
p = gmpy2.gcd(pow(a,dp*e,n)-a,n) #pow(a,dp*e,n)-a 就是kp
m = pow(c,dp,p)
print(long_to_bytes(m))
q = n // p
d = gmpy2.invert(e,(p-1)*(q-1))
m = pow(c,d,n)
print(long_to_bytes(m))
关于m = pow(c,dp,p)的证明¶
很多题目会出现在mod p下求解的情况,需要注意的是前提条件为\(m < p\),证明如下
所以有
即
例题3 dp高位泄露¶
e
不是很大¶
如果e不大的话,直接爆破k解这个方程即可
e很大¶
task.py
from Crypto.Util.number import *
from secret import flag
m = bytes_to_long(flag)
p = getPrime(512)
q = getPrime(512)
n = p * q
e = getPrime(64)
d = inverse(e,(p-1)*(q-1))
dp = d % (p-1)
leak = dp >> 64 << 64
c = pow(m,e,n)
print(f"n = {n}")
print(f"c = {c}")
print(f"e = {e}")
print(f"leak = {leak}")
"""
n = 108867023585283899312601516631596145998654767437612286040742902945694826711187570537876759789643259431350352590412655898964386234903475482280911808566497936037152171435317938413515356868240854632004961172899360272761406519077380255802700944002126599829184693692273637230349297388495886988988512631044494610227
c = 55610391226438079690691299914193010897347055835338032942001645697966587672596937470425142446679815934940962159432814479063990621696064239924347523289515556844359094065042974221093712989000153444928594999529082105262409273370242062803004814801742763253605838374098344711160380314529928211369000469059015996052
e = 14257237624892167181
leak = 2451130625204471881762267484243564297625381377098677997721378436579042927693972537775392209546509688501306219327699327137859174235486735043842710630825984
"""
k和x都是64bit的值,用二元copper即可
exp
from Crypto.Util.number import *
import gmpy2
import itertools
def small_roots(f, bounds, m=1, d=None):
if not d:
d = f.degree()
print(d)
R = f.base_ring()
N = R.cardinality()
f /= f.coefficients().pop(0)
f = f.change_ring(ZZ)
G = Sequence([], f.parent())
for i in range(m + 1):
base = N ^ (m - i) * f ^ i
for shifts in itertools.product(range(d), repeat=f.nvariables()):
g = base * prod(map(power, f.variables(), shifts))
G.append(g)
B, monomials = G.coefficient_matrix()
monomials = vector(monomials)
factors = [monomial(*bounds) for monomial in monomials]
for i, factor in enumerate(factors):
B.rescale_col(i, factor)
B = B.dense_matrix().LLL()
B = B.change_ring(QQ)
for i, factor in enumerate(factors):
B.rescale_col(i, 1 / factor)
H = Sequence([], f.parent().change_ring(QQ))
for h in filter(None, B * monomials):
H.append(h)
I = H.ideal()
if I.dimension() == -1:
H.pop()
elif I.dimension() == 0:
roots = []
for root in I.variety(ring=ZZ):
root = tuple(R(root[var]) for var in f.variables())
roots.append(root)
return roots
return []
n = 108867023585283899312601516631596145998654767437612286040742902945694826711187570537876759789643259431350352590412655898964386234903475482280911808566497936037152171435317938413515356868240854632004961172899360272761406519077380255802700944002126599829184693692273637230349297388495886988988512631044494610227
c = 55610391226438079690691299914193010897347055835338032942001645697966587672596937470425142446679815934940962159432814479063990621696064239924347523289515556844359094065042974221093712989000153444928594999529082105262409273370242062803004814801742763253605838374098344711160380314529928211369000469059015996052
e = 14257237624892167181
leak = 2451130625204471881762267484243564297625381377098677997721378436579042927693972537775392209546509688501306219327699327137859174235486735043842710630825984
R.<x,y> = PolynomialRing(Zmod(n))
f = e * (leak + x) + (y - 1)
res = small_roots(f,(2^64,2^64),m=1,d=3)
for root in res:
dp_low = root[0]
dp = leak + dp_low
tmp = pow(2,e*dp,n) - 2
p = gmpy2.gcd(tmp,n)
q = n // p
d = inverse(e,(p-1)*(q-1))
m = pow(c,d,n)
print(long_to_bytes(m))
十、dp,dq泄露¶
如果题目给出\(p,q,d_p,d_q\),那么直接在模p和模q下求解即可,如果模不够大,再用中国剩余定理即可
例题1¶
task.py
import gmpy2
import libnum
import uuid
flag = "flag{" + str(uuid.uuid4()) + "}"
print(flag)
m = libnum.s2n(flag)
p = libnum.generate_prime(256)
q = libnum.generate_prime(256)
e = 65537
n = p * q
phi = (p - 1) * (q - 1)
d = gmpy2.invert(e, phi)
print("d=", d)
dp = d % (p - 1)
dq = d % (q - 1)
c = pow(m, e, n)
print("p=", p)
print("q=", q)
print("c=", c)
print("dp=", dp)
print("dq=", dq)
exp.sage
import gmpy2
from Crypto.Util.number import *
p = 112454994630978850005784651276022327545786198205744597431888680937657203192943
q = 111081771780978300442208201256251933100607227308819156491182881723714968913833
c = 7847140580627012782899798457736961376953768684667159008470556786390887805253326211691923724846808704462396746105331991924048819814322540306282164012066426
dp = 99016059099144522019375365089687785694029213535292918424815544402513220169503
dq = 79504900574184798493105575420403885224379864982754477219462523963780735261625
n = p*q
mp = pow(c,dp,p)
mq = pow(c,dq,q)
print(long_to_bytes(mp))
print(long_to_bytes(mq))
m = crt([mp,mq],[p,q])
print(long_to_bytes(m))
十一、考察欧拉函数计算¶
欧拉函数计算方法:
-
\(n = 1\),则\(\phi(n)= 1\)
-
\(n\)是素数,则\(\phi(n) = n - 1\)
-
\(n = p^r\)(\(p\)为素数,\(r\)为大于等于1的整数),则\(\phi(n) = p^{r-1}(p-1)\)
-
\(n = \prod_{i=1}^kp_i\),则\(\phi(n) = \prod_{i=1}^{k}(p_i-1)\)
例题1¶
task.py
import gmpy2
import libnum
import uuid
flag = "flag{" + str(uuid.uuid4()) + "}"
print(flag)
m = libnum.s2n(flag)
p = libnum.generate_prime(512)
n = p ** 5
e = 65537
c = pow(m, e, n)
print("n=", n)
print("e=", e)
print("c=", c)
本题考查\(n = p^r\)
exp.py
from Crypto.Util.number import *
import gmpy2
n = 109671394618534156590716540772306636060550711465455829526382945168271125218007503161807386153286648328529071790130095763349089936429151343426469415497138306284842512691195220650548494501337831207724397925027651025644976364368511262187227825083865690186591571250267479440100917127211656877566179258870510690665025580200477574123634259670039152125607834855408269848826938902407472374892693266119859709658788565014195766992713646832624001067898323913639712284673673557898135411273837250194079399384826384835709060797351332323930309379071015140548478132323474993964925055399350661600068568602468295748573856804293659942047543032878436316918991716636681116631322082919386178460096115355963882313682994343822128626370850455024905542367255179074441679461101331332093019368492643
e = 65537
c = 83166081100602571613112201467626632459949037182633475449066025299006894059443612622701975752551708249083077180755342065457682925338233793688583913228361068561515321097016501900442865692643652803949920987493441500744743553498018003210308290969303190355756775977367324120441564693220728163622472865572357639056734898022442794130514936425334924283145153496702507951466618177405870656868713199816223765264228006032228439676574053839549440372521050502986043855511540855864034336902304414848547480112182226920285820386643015671106933140105835060319823245206934565859078021518312305243997612804935774414840491355098017977514736057368000596388974956265042651277403519473262257945986199408278855335170546242641727930526697102351648388874227840119205560199015181257296591985205818
p = 10186351850605898834333098258639828910824016865517013383611935945131883947448223014077315468253377357594775340263769153442019216205089695821439736926082483
phi = p**5-p**4
d = gmpy2.invert(e,phi)
print(long_to_bytes(pow(c,d,n)))
例题2¶
task.py
import gmpy2
import libnum
import uuid
flag = "flag{" + str(uuid.uuid4()) + "}"
m = libnum.s2n(flag)
p = libnum.generate_prime(512)
q = libnum.generate_prime(512)
n = p ** 3 * q
e = 65537
c = pow(m, e, n)
print("q=", q)
print("n=", n)
print("e=", e)
print("c=", c)
\(\because n = p^{3}×q\)
\(\therefore \phi(n) = (p^{3}-p^{2})×(q-1)\)
exp.py
from Crypto.Util.number import long_to_bytes
import gmpy2
q = 13345672330679418443866848695749753384841350112452462690350565885192764753702964893062035116023096943358384379827500462723016224486435032522188166109529147
n = 4663711063632671446966617442890809468548735750386480905820144168615122369358088158709822723959108989276525102755551604204514586528122441075489492157644479194671784485228731421500391142158401889177506319977349707503678947872777602384171260874359045585814189677748712566088220734735479518470883541166059233676170283938881683675790979128058243582825012415020019043126740915522571217495119060031729061070896580899732991209113679151755713858497630999746612658308778711613697038750661479517187094033129979714688161348844542070263109259258937863241431480105798790363889436471998002323269704182369356300287043940743500087239
e = 65537
c = 4050303218893912343776312253598257474375000778822229482734626960955864773175090306426885201033332266573903303684635688485414725284644108123459136702775991157244389086147955395682206311752151842740679445903864544823592773331496589661187968392779340028173948172003460012051289357755574536619241969492822938688821287700132262703677149526846356206143053559703859606442209340834979412336031660590507709503830013770022485005101363701272279629510056964018618212014677531338026866748075406283893942248599825641124694672878533987994699411744521757385858889763503705242690212615083634186373933214686193717950163215308138805348
p = n // q
phi = (p**3-p**2)*(q-1)
d = gmpy2.invert(e,phi)
print(long_to_bytes(pow(c,d,n)))
例题3¶
task.py
import gmpy2
import libnum
import uuid
flag = "flag{" + str(uuid.uuid4()) + "}"
m = libnum.s2n(flag)
p = libnum.generate_prime(512)
q = gmpy2.next_prime(p)
r = libnum.generate_prime(512)
n = p * q * r
e = 65537
c = pow(m, e, n)
print("r=", r)
print("n=", n)
print("e=", e)
print("c=", c)
r = 12328943069972158868300333965019293732240349172933398867374450193780676916633106046545397891902123683693837126404908611670219604587587151306224914062663729
n = 928445951911850156618541782850215900925329423880533465612155142015978599609287623859912813317551629221695490535012732781489396534420011145723987610606038091488823086647363964394753700158320900867101659445170118179077194271099520502633316318889163873291574934282498061117736456183503867870294570083013883365868242889035609602940685335912371326827533418614992221705810476710807373254363162373986374486325350746366851935451369892949745302442034805629514003196071631
e = 65537
c = 327716655224470059950709685055600963837116578216483343492948888372401723689223347212508532985781828794786448842515029515358422017875793926582832247025212149474404973170422295165602666360784347416812528617973764432916955654602356835327769633635513894485943553309743509322858937973710628023758816806471875016815994664897320150855163109437521642800230902661034555151514311149333258071668655344069451897282357234220538922127548822361859943829665459953651351620958628
exp.py
from Crypto.Util.number import long_to_bytes
import gmpy2
r = 12328943069972158868300333965019293732240349172933398867374450193780676916633106046545397891902123683693837126404908611670219604587587151306224914062663729
n = 928445951911850156618541782850215900925329423880533465612155142015978599609287623859912813317551629221695490535012732781489396534420011145723987610606038091488823086647363964394753700158320900867101659445170118179077194271099520502633316318889163873291574934282498061117736456183503867870294570083013883365868242889035609602940685335912371326827533418614992221705810476710807373254363162373986374486325350746366851935451369892949745302442034805629514003196071631
e = 65537
c = 327716655224470059950709685055600963837116578216483343492948888372401723689223347212508532985781828794786448842515029515358422017875793926582832247025212149474404973170422295165602666360784347416812528617973764432916955654602356835327769633635513894485943553309743509322858937973710628023758816806471875016815994664897320150855163109437521642800230902661034555151514311149333258071668655344069451897282357234220538922127548822361859943829665459953651351620958628
t = gmpy2.iroot(n//r,2)[0]
p = gmpy2.next_prime(t)
q = n // p // r
phi = (p-1)*(q-1)*(r-1)
d = gmpy2.invert(e,phi)
print(long_to_bytes(pow(c,d,n)))
十二、e和phi不互素¶
这种情况在比赛中比较常见。在做这类题目之前,建议先了解sagemath基本使用方法
当\(e\)与\(\phi(n)\)不互素时,则不存在模\(\phi(n)\)的逆元\(d\)使得\(ed \equiv 1(mod \quad \phi(n))\)
处理方式1:¶
这种处理方式是最简单也是最常规的
令\(t = gcd(e,\phi(n))\)
设\(e = e'\times t\),则\(e' = \frac{e}{t}\)
则\(c \equiv m^e \mod n \longrightarrow c \equiv (m ^t)^{e'} \mod n\)
求\(e'\)对应的\(d\),解出\(m^t \equiv c^d \mod n\)
在\(m^t < n\)的情况下开根即可获得\(m\)
例题1¶
task.py
import gmpy2
import libnum
import random
import uuid
flag = "flag{" + str(uuid.uuid4()) + "}"
print(flag)
m = libnum.s2n(flag)
while 1:
e = random.randint(100, 1000)
p = libnum.generate_prime(1024)
q = libnum.generate_prime(1024)
phi_n = (p - 1) * (q - 1)
t = gmpy2.gcd(e, phi_n)
if t == e:
continue
t1 = e // t
if gmpy2.invert(t1, phi_n) and t > 1:
break
n = p * q
c = pow(m, e, n)
print("p=", p)
print("q=", q)
print("e=", e)
print("c=", c)
exp.py
from Crypto.Util.number import *
import gmpy2
p = 171854505164939390402295426493389586289972154851849140728417624619463988154808053805729538974688869671559032639921300088271234681410193379381085714252211392886408792711387524667824537369266846649573070209815436507363007636943912350208275895292853801665488228125846058987049326903498661007035974420392738723323
q = 145951936627745243523384785325963094339728144811023266133546816860787405503371056873662508073284279180417626507724315776654624382665743082805910036891739754019932290977071276850239245644056698685966997752654383650764557358649666141576105936215709831181842086893228254304235678475375978464394818353375373451573
n = p*q
e = 830
c= 4413268199893347044741276120215584703428167052744516280494996526431559720190092261631829389527634625276020346166956540800884139234489942113764564139232948414263452549927818365096023041932432723988241639527832673120924732407691135173154085803338322715604275530735968992726708155724384432557207264839248502158712330572704509492520346044648676055223193900826626346707083590815897507927683083455678855000344499804465073698745769989966769567497677402668725931090596642504740789789740965769347050166069295727209131555338513809368814890255851742010120871635378654904140016065148709710206173069000137023824698858539843753921
phi = (p-1)*(q-1)
t = gmpy2.gcd(e,phi)
if t != 1:
print(t)
e1 = e // t
d = gmpy2.invert(e1,phi)
m = pow(c,d,n)
print(long_to_bytes(gmpy2.iroot(m,t)[0]))
处理方式2:¶
使用sagemath,建立有限域,然后开根,以一个例题简要说明
task.py
from secret import flag
from Crypto.Util.number import *
m = bytes_to_long(flag)
e = 2
p = getPrime(512)
q = getPrime(512)
n = p * q
c = pow(m,e,n)
print(f"c = {c}")
print(f"p = {p}")
print(f"q = {q}")
print(f"n = {n}")
"""
c = 3136716033729406787100895984031132591372408032397380657110411936279557864804613451803228203558942365572618855741582340710496951283998288077886684480798840909615843832888291672118118174611935731391325961
p = 6995170125828760803175021463861846748101755707034027896253692749933464491557662142860042836548188827042797130278821285624095121174944527912522028416084887
q = 12272700813225623560132355056448185486009112345760462061684545263916365691442580749089054915285013385322910087693364777427389347919562222271368766699836367
n = 85849630091910220195429598000499270755938566349764235961421375317755949910077610512936495968854306764812963460054159547290157103999299511719875933657730205460710045409434205381402766954402709130620384187298033137488697869180531872534818830013412093865496100309052022972165149312556870258314510623053681685529
"""
exp.sage
from Crypto.Util.number import *
c = 3136716033729406787100895984031132591372408032397380657110411936279557864804613451803228203558942365572618855741582340710496951283998288077886684480798840909615843832888291672118118174611935731391325961
p = 6995170125828760803175021463861846748101755707034027896253692749933464491557662142860042836548188827042797130278821285624095121174944527912522028416084887
q = 12272700813225623560132355056448185486009112345760462061684545263916365691442580749089054915285013385322910087693364777427389347919562222271368766699836367
n = 85849630091910220195429598000499270755938566349764235961421375317755949910077610512936495968854306764812963460054159547290157103999299511719875933657730205460710045409434205381402766954402709130620384187298033137488697869180531872534818830013412093865496100309052022972165149312556870258314510623053681685529
R.<x> = PolynomialRing(Zmod(p))
f = x^2 - c
res1 = f.roots()
R.<x> = PolynomialRing(Zmod(q))
f = x^2 - c
res2 = f.roots()
for i in res1:
for j in res2:
m = crt([int(i[0]),int(j[0])],[p,q])
print(long_to_bytes(m))
当\(m < p\)的时候,不需要中国剩余定理也能出
两种处理方式的综合¶
例题1——2022ctfshow卷王杯¶
task.py
from Crypto.Util.number import bytes_to_long
from secrets import p,q,r,s,t,flag
n = p * q * r * s * t
e = 2
m = bytes_to_long(os.urandom(500) + flag)
c = pow(m,e,n)
print(p,q,r,s,t,sep='\n')
print(c)
'''
145332367700944303747548912160113939198078051436029477960348968315913956664143693347226702600438608693933768134575289286283267810723137895903153829001826223446477799895493265422562348917012216790077395795861238257357035152687833639085415763850743538206986781418939737511715957738982536382066693822159860701263
116660458253067608044065523310547233337730583902133756095473339390057738510707447906971188577217274861047379404014140178165569604404468897712846876108444468370709141219302291601408652742006268186059762087155933131837323952675627966299810891805398890428420575425160696531236660480933905879208166090591482794763
157931722402853245421436270609912823260313730941283152856444641969403238646482562190531038393124087232554754746464603598717356255570166081501573727336977292059427220330169044611674973569766966838498453232642731737958791706086957762244686953294662693939604300864961637325536379321027705854708492453330690705531
100973451687449518854742673778783266158999451072058606348222018797891147675959983616210003484476577612134482311993701677242007759556951494382833070563369964294544839433671087037596159753825249018950693369209927951667775267086896180395776150188902057785214767230658487267587289809918132337927575673868568976679
93960345071948255233882121683650797512129333868351496468898834736770441398743300745703393838320587998953678254272245400344928586394089488734271897540051673996675973642347859306921527430850673334243441180183460927865980713929789963587608547554858491264614271309608925634272282292964002897650355047792764365447
9144597920381774885442906257311149465702295057238600973973598305004391534618770363098565074541384771979931799878381439264848137810353858418200992191234142740194489573540381681161219332611454834544291634628456257670178843484698324641739324687497388018406214041657278323855749902661752448796122517061920880552011343608609622885787617238758769398972009949575526258430282648817039091284796330585349957724522615105102735930258969562103112238020133587096826386028128471852377225525357348919204333121695432662339443004327748973224423132988376298843862056631045488285859621661802413201793962883794915513510467912312842687601478117040419013468059983777273699192408773551806581458197324620065210523913467414181480875280203580147077789063808832356486197271376615883221558265591069223727607585313240243619515521180600435114131162272519949101464089935441251751426683447701142156416866113627126765919641034042927519834229168536331952275698122511502745177547569813354280565828372968703810158857859460406828090199683324760956105682902577189283246483314689365570862217407333103243336691401424548702387876409228977278498691200028282744239512091373110111792177228979867318546462714521296256938374618636206565791541769138267080789842400796973226733816939794717596194090232425688504890234304977612220790858557639246367437740975495450011676714198668471438814299689325208882261918460708833888406187912527346628912894921059735420931656953236560178909180587372589456926690219114173193202048332172538564489660440225377822914097420807957784201785024166011709377791129
'''
看似白给,其实\(e\)和\(\phi(n)\)不互素
而且在flag前面填充了一些数据,导致\(m^e > n\),所以直接开根号也不可取
本题\(c \equiv m^e \mod n\),等价于m满足下面五个式子:
我们在5个因子下求解,再用中国剩余定理组合即可
exp.sage
from sympy.ntheory.modular import crt
import gmpy2
from Crypto.Util.number import *
p = 145332367700944303747548912160113939198078051436029477960348968315913956664143693347226702600438608693933768134575289286283267810723137895903153829001826223446477799895493265422562348917012216790077395795861238257357035152687833639085415763850743538206986781418939737511715957738982536382066693822159860701263
q = 116660458253067608044065523310547233337730583902133756095473339390057738510707447906971188577217274861047379404014140178165569604404468897712846876108444468370709141219302291601408652742006268186059762087155933131837323952675627966299810891805398890428420575425160696531236660480933905879208166090591482794763
r = 157931722402853245421436270609912823260313730941283152856444641969403238646482562190531038393124087232554754746464603598717356255570166081501573727336977292059427220330169044611674973569766966838498453232642731737958791706086957762244686953294662693939604300864961637325536379321027705854708492453330690705531
s = 100973451687449518854742673778783266158999451072058606348222018797891147675959983616210003484476577612134482311993701677242007759556951494382833070563369964294544839433671087037596159753825249018950693369209927951667775267086896180395776150188902057785214767230658487267587289809918132337927575673868568976679
t = 93960345071948255233882121683650797512129333868351496468898834736770441398743300745703393838320587998953678254272245400344928586394089488734271897540051673996675973642347859306921527430850673334243441180183460927865980713929789963587608547554858491264614271309608925634272282292964002897650355047792764365447
c = 9144597920381774885442906257311149465702295057238600973973598305004391534618770363098565074541384771979931799878381439264848137810353858418200992191234142740194489573540381681161219332611454834544291634628456257670178843484698324641739324687497388018406214041657278323855749902661752448796122517061920880552011343608609622885787617238758769398972009949575526258430282648817039091284796330585349957724522615105102735930258969562103112238020133587096826386028128471852377225525357348919204333121695432662339443004327748973224423132988376298843862056631045488285859621661802413201793962883794915513510467912312842687601478117040419013468059983777273699192408773551806581458197324620065210523913467414181480875280203580147077789063808832356486197271376615883221558265591069223727607585313240243619515521180600435114131162272519949101464089935441251751426683447701142156416866113627126765919641034042927519834229168536331952275698122511502745177547569813354280565828372968703810158857859460406828090199683324760956105682902577189283246483314689365570862217407333103243336691401424548702387876409228977278498691200028282744239512091373110111792177228979867318546462714521296256938374618636206565791541769138267080789842400796973226733816939794717596194090232425688504890234304977612220790858557639246367437740975495450011676714198668471438814299689325208882261918460708833888406187912527346628912894921059735420931656953236560178909180587372589456926690219114173193202048332172538564489660440225377822914097420807957784201785024166011709377791129
e = 2
R.<x> = PolynomialRing(Zmod(p))
f = x^e - c
f = f.monic()
res1 = f.roots()
R.<x> = PolynomialRing(Zmod(q))
f = x^e - c
f = f.monic()
res2 = f.roots()
R.<x> = PolynomialRing(Zmod(r))
f = x^e - c
f = f.monic()
res3 = f.roots()
R.<x> = PolynomialRing(Zmod(s))
f = x^e - c
f = f.monic()
res4 = f.roots()
R.<x> = PolynomialRing(Zmod(t))
f = x^e - c
f = f.monic()
res5 = f.roots()
for i in res1:
for j in res2:
for k in res3:
for a in res4:
for b in res5:
m_list = [int(i[0]),int(j[0]),int(k[0]),int(a[0]),int(b[0])]
a_list= [p,q,r,s,t]
solve = CRT_list(m_list,a_list)
flag = long_to_bytes(solve)
if b'ctfshow' in flag:
print(flag)
## ctfshow{D0_y0u_R3aLly_Kn0w_Ra8IN_alg0RI7HM?}
例题2——2018高校运维挑战赛AzureRSA¶
task.txt
n1=0xcfc59d54b4b2e9ab1b5d90920ae88f430d39fee60d18dddbc623d15aae645e4e50db1c07a02d472b2eebb075a547618e1154a15b1657fbf66ed7e714d23ac70bdfba4c809bbb1e27687163cb09258a07ab2533568192e29a3b8e31a5de886050b28b3ed58e81952487714dd7ae012708db30eaf007620cdeb34f150836a4b723L
e1=0xfae3aL
c1=0x81523a330fb15125b6184e4461dadac7601340960840c5213b67a788c84aecfcdc3caf0bf3e27e4c95bb3c154db7055376981972b1565c22c100c47f3fa1dd2994e56090067b4e66f1c3905f9f780145cdf8d0fea88a45bae5113da37c8879c9cdb8ee9a55892bac3bae11fbbabcba0626163d0e2e12c04d99f4eeba5071cbeaL
n2=0xd45304b186dc82e40bd387afc831c32a4c7ba514a64ae051b62f483f27951065a6a04a030d285bdc1cb457b24c2f8701f574094d46d8de37b5a6d55356d1d368b89e16fa71b6603bd037c7f329a3096ce903937bb0c4f112a678c88fd5d84016f745b8281aea8fd5bcc28b68c293e4ef4a62a62e478a8b6cd46f3da73fa34c63L
e2=0x1f9eaeL
c2=0x4d7ceaadf5e662ab2e0149a8d18a4777b4cd4a7712ab825cf913206c325e6abb88954ebc37b2bda19aed16c5938ac43f43966e96a86913129e38c853ecd4ebc89e806f823ffb802e3ddef0ac6c5ba078d3983393a91cd7a1b59660d47d2045c03ff529c341f3ed994235a68c57f8195f75d61fc8cac37e936d9a6b75c4bd2347L
assert pow(flag,e1,n1)==c1
assert pow(flag,e2,n2)==c2
assert gcd(e1,(p1-1)*(q1-1))==14
assert gcd(e2,(p2-1)*(q2-1))==14
本题两个n均可分解
分解情况如下:
p1 = 12037827528067911684278967221392433256129944002157200272548317200308481572950474775891360447285969682243206009995242277136633522897723532096467191105943909
q1 = 12120327527644543811107783655014863098833219936714394976342507913322405566177432644931575840816861543106701611662013978324877080018872656490603706071067111
p2 = 12120327527644543811107783655014863098833219936714394976342507913322405566177432644931575840816861543106701611662013978324877080018872656490603706071067111
q2 = 12301580698247665838432962460247894405698817646605188562297985838079356879336309758823376086396761749681729993573203954506346863479448531269351981555913253
我们可以发现\(n_1,n_2\)之间存在公因数
设\(e\)和\(\phi(n)\)的公因数为\(t\),则\(e = e't\),\(e' = \frac{e}{t}\),有\(e'd \equiv 1 \mod \phi(n)\)
\(\therefore m^t \equiv c^d \mod n\)
本题\(t = 14\),于是我们有
用中国剩余定理解出其特解\(res\),即\(res \equiv m^{14} \mod lcm(n_1,n_2) \longrightarrow res \equiv m^{14} \mod pq_1q_2\)
把它当作一个\(e=14\)的RSA加密,此时我们计算\(\phi(n) = (p_1 - 1)(q_1-1)(q_2-1)\)
我们分别求\(e = 14\)和\(p_1 -1\),\(q_1-1\),\(q_2-1\)的公因数,结果分别是2,14,2
那么我们转换成\(res \equiv m^{14} \mod p_1q_2\)
我们分别在\(\mod p_1\)和\(\mod q_2\)下用有限域开根求出解,再用中国剩余定理
exp.sage
n1 = 0xcfc59d54b4b2e9ab1b5d90920ae88f430d39fee60d18dddbc623d15aae645e4e50db1c07a02d472b2eebb075a547618e1154a15b1657fbf66ed7e714d23ac70bdfba4c809bbb1e27687163cb09258a07ab2533568192e29a3b8e31a5de886050b28b3ed58e81952487714dd7ae012708db30eaf007620cdeb34f150836a4b723
e1 = 0xfae3a
c1 = 0x81523a330fb15125b6184e4461dadac7601340960840c5213b67a788c84aecfcdc3caf0bf3e27e4c95bb3c154db7055376981972b1565c22c100c47f3fa1dd2994e56090067b4e66f1c3905f9f780145cdf8d0fea88a45bae5113da37c8879c9cdb8ee9a55892bac3bae11fbbabcba0626163d0e2e12c04d99f4eeba5071cbea
n2 = 0xd45304b186dc82e40bd387afc831c32a4c7ba514a64ae051b62f483f27951065a6a04a030d285bdc1cb457b24c2f8701f574094d46d8de37b5a6d55356d1d368b89e16fa71b6603bd037c7f329a3096ce903937bb0c4f112a678c88fd5d84016f745b8281aea8fd5bcc28b68c293e4ef4a62a62e478a8b6cd46f3da73fa34c63
e2 = 0x1f9eae
c2 = 0x4d7ceaadf5e662ab2e0149a8d18a4777b4cd4a7712ab825cf913206c325e6abb88954ebc37b2bda19aed16c5938ac43f43966e96a86913129e38c853ecd4ebc89e806f823ffb802e3ddef0ac6c5ba078d3983393a91cd7a1b59660d47d2045c03ff529c341f3ed994235a68c57f8195f75d61fc8cac37e936d9a6b75c4bd2347
p1 = 12037827528067911684278967221392433256129944002157200272548317200308481572950474775891360447285969682243206009995242277136633522897723532096467191105943909
q1 = 12120327527644543811107783655014863098833219936714394976342507913322405566177432644931575840816861543106701611662013978324877080018872656490603706071067111
p2 = 12120327527644543811107783655014863098833219936714394976342507913322405566177432644931575840816861543106701611662013978324877080018872656490603706071067111
q2 = 12301580698247665838432962460247894405698817646605188562297985838079356879336309758823376086396761749681729993573203954506346863479448531269351981555913253
phi1 = (p1-1)*(q1-1)
phi2 = (p2-1)*(q2-1)
def decrypt(c,e,phi,n):
t = gmpy2.gcd(e,phi)
if t != 1:
e1 = e // t
d = gmpy2.invert(e1,phi)
m = pow(c,d,n)
return m
res1 = decrypt(c1,e1,phi1,n1)
res2 = decrypt(c2,e2,phi2,n2)
res = crt([res1,res2],[n1,n2])
phi = (p1 - 1)*(q2 - 1)
n = p1 * q2
m2 = decrypt(res,14,phi,n)
R.<x> = PolynomialRing(Zmod(p1))
f = x^2 - m2
sol1 = f.roots()
R.<x> = PolynomialRing(Zmod(q2))
f = x^2 - m2
sol2 = f.roots()
for i in sol1:
for j in sol2:
m = crt([int(i[0]),int(j[0])],[p1,q2])
print(long_to_bytes(m))
## EIS{Comm0n_Div15or_plus_CRT_is_so_easy|cb2733b9e69ab3a9bd526fa1}
处理方式3:¶
AMM开根,具体原理可以参考:奇安信攻防社区-有限域上的高次开根AMM算法在RSA上的应用 (butian.net)
例题 2021黑盾杯Crypto1¶
task.txt
e = 1801
c = pow(m,e,p)
c =821562155714228494350968286343241874202753771452745916900616612053610190986294297934462409534126095213198464996196364868528238538372119009517541428785632007137206972918081643841690069171088425923887930051635578719252415693144672179185417101210954906623326286804995637775062840407550493095027500638719998
p =19897846550210846565807788524492364050901480736489979129040638436463635149815428186161001280958415730930156556581274966745574164608778242980049611665461488306439665507971670397595035647317930606555771720849158745264269952668944940061576328219674721623208805067371087817766416300084129945316973502412996143
exp.sage
from Crypto.Util.number import *
import gmpy2
import time
import random
from tqdm import tqdm
e = 1801
c = 821562155714228494350968286343241874202753771452745916900616612053610190986294297934462409534126095213198464996196364868528238538372119009517541428785632007137206972918081643841690069171088425923887930051635578719252415693144672179185417101210954906623326286804995637775062840407550493095027500638719998
p = 19897846550210846565807788524492364050901480736489979129040638436463635149815428186161001280958415730930156556581274966745574164608778242980049611665461488306439665507971670397595035647317930606555771720849158745264269952668944940061576328219674721623208805067371087817766416300084129945316973502412996143
def AMM(o, r, q):
start = time.time()
print('\n----------------------------------------------------------------------------------')
print('Start to run Adleman-Manders-Miller Root Extraction Method')
print('Try to find one {:#x}th root of {} modulo {}'.format(r, o, q))
g = GF(q)
o = g(o)
p = g(random.randint(1, q))
while p ^ ((q-1) // r) == 1:
p = g(random.randint(1, q))
print('[+] Find p:{}'.format(p))
t = 0
s = q - 1
while s % r == 0:
t += 1
s = s // r
print('[+] Find s:{}, t:{}'.format(s, t))
k = 1
while (k * s + 1) % r != 0:
k += 1
alp = (k * s + 1) // r
print('[+] Find alp:{}'.format(alp))
a = p ^ (r**(t-1) * s)
b = o ^ (r*alp - 1)
c = p ^ s
h = 1
for i in range(1, t):
d = b ^ (r^(t-1-i))
if d == 1:
j = 0
else:
print('[+] Calculating DLP...')
j = - discrete_log(a, d)
print('[+] Finish DLP...')
b = b * (c^r)^j
h = h * c^j
c = c ^ r
result = o^alp * h
end = time.time()
print("Finished in {} seconds.".format(end - start))
print('Find one solution: {}'.format(result))
return result
def findAllPRoot(p, e):
print("Start to find all the Primitive {:#x}th root of 1 modulo {}.".format(e, p))
start = time.time()
proot = set()
while len(proot) < e:
proot.add(pow(random.randint(2, p-1), (p-1)//e, p))
end = time.time()
print("Finished in {} seconds.".format(end - start))
return proot
def findAllSolutions(mp, proot, cp, p):
print("Start to find all the {:#x}th root of {} modulo {}.".format(e, cp, p))
start = time.time()
all_mp = set()
for root in proot:
mp2 = mp * root % p
assert(pow(mp2, e, p) == cp)
all_mp.add(mp2)
end = time.time()
print("Finished in {} seconds.".format(end - start))
return all_mp
mp = AMM(c,e,p)
p_proot = findAllPRoot(p, e)
mps = findAllSolutions(mp, p_proot, c, p)
for i in mps:
flag = long_to_bytes(int(i))
if b'flag' in flag:
print(flag)
## flag{Enj01_m1sc_A0d_cr0}
另一种解法:
from Crypto.Util.number import *
e = 1801
c = 821562155714228494350968286343241874202753771452745916900616612053610190986294297934462409534126095213198464996196364868528238538372119009517541428785632007137206972918081643841690069171088425923887930051635578719252415693144672179185417101210954906623326286804995637775062840407550493095027500638719998
p = 19897846550210846565807788524492364050901480736489979129040638436463635149815428186161001280958415730930156556581274966745574164608778242980049611665461488306439665507971670397595035647317930606555771720849158745264269952668944940061576328219674721623208805067371087817766416300084129945316973502412996143
g = pow(2,(p-1) // e,p)
d0 = inverse(e,(p - 1) // e)
m0 = pow(c,d0,p)
for i in range(e):
m = m0 * pow(g,i,p) % p
flag = long_to_bytes(m)
if b"flag" in flag:
print(flag)
没搞懂原理
十三、Rabin¶
简单了解一下Rabin加密体制流程
一年后回头再看,Rabin只是e=2的RSA
密钥生成¶
选取两个大素数\(p,q\),并且满足
即\(p,q\)都是\(4k + 3\)形式的素数
接下来计算\(n = p\times q\),\((p,q)\)作为私钥,\(n\)作为公钥
加密过程¶
解密过程¶
即
根据二次剩余得
\(c^{\frac{p-1}{2}} \equiv 1 \mod p\)同乘c得:\(c^{\frac{p+1}{2}} \equiv c \mod p\),开根号得\(c^{\frac{p+1}{4}} \mod p\),所以\(m_p =c^{\frac{p+1}{4}}\)
同理\(m_q = c^{\frac{q+1}{4}}\)
此时得到两个同余式
再解中国剩余定理即可
例题¶
task.py
import gmpy2
import libnum
import random
import uuid
flag = "flag{" + str(uuid.uuid4()) + "}"
print(flag)
m = libnum.s2n(flag)
p = libnum.generate_prime(512)
q = libnum.generate_prime(512)
n = p * q
e = 2
c = pow(m, e, n)
print("p=", p)
print("q=", q)
print("n=", n)
print("c=", c)
print("e=", e)
exp.py
import gmpy2
from Crypto.Util.number import *
p= 13314362720917602133969793252481444316247612541287913579795797774897851142465370812511985605994998073433561235021924708067874236781706611485522371488232623
q= 10711516497864529822020903304369858958930042711451857859791558135232705853374332295320094676061294774680048276363750484537945067473851592618816785752809803
n= 142617015943661365869136488949628046624950745436416195175536421279851751774402291519010668496730147866462378904972514253007029491632653461771497495733152729212900224242492221133006321373540619376544526943204146111719397605460529531608654329571698129077171108416638061409327725762114841023226929126272738803269
c= 3136716033731857617369889733308430982192049734478834150612954276064433287574994581343168243135342097712334250357890492021703404008556737899236668582163912130637742227325170121650071435166332685070232329
e= 2
inv_p = gmpy2.invert(p, q)
inv_q = gmpy2.invert(q, p)
mp = pow(c, (p + 1) // 4, p)
mq = pow(c, (q + 1) // 4, q)
a = (inv_p * p * mq + inv_q * q * mp) % n
b = n - int(a)
c = (inv_p * p * mq - inv_q * q * mp) % n
d = n - int(c)
## 因为rabin 加密有四种结果,全部列出。
aa = [a, b, c, d]
for i in aa:
print(long_to_bytes(int(i)))
两次有限域开根再中国剩余定理也可以解
exp.sage
import gmpy2
from Crypto.Util.number import *
p = 13314362720917602133969793252481444316247612541287913579795797774897851142465370812511985605994998073433561235021924708067874236781706611485522371488232623
q = 10711516497864529822020903304369858958930042711451857859791558135232705853374332295320094676061294774680048276363750484537945067473851592618816785752809803
n = 142617015943661365869136488949628046624950745436416195175536421279851751774402291519010668496730147866462378904972514253007029491632653461771497495733152729212900224242492221133006321373540619376544526943204146111719397605460529531608654329571698129077171108416638061409327725762114841023226929126272738803269
c = 3136716033731857617369889733308430982192049734478834150612954276064433287574994581343168243135342097712334250357890492021703404008556737899236668582163912130637742227325170121650071435166332685070232329
e = 2
R.<x> = PolynomialRing(Zmod(p))
f = x^2 - c
res1 = f.roots()
R.<x> = PolynomialRing(Zmod(q))
f = x^2 - c
res2 = f.roots()
for i in res1:
for j in res2:
m = crt([int(i[0]),int(j[0])],[p,q])
print(long_to_bytes(int(m)))
多次解Rabin¶
题目来源NSSCTF ROUND#11
from Crypto.Util.number import *
from secret import flag
p = getPrime(512)
q = getPrime(512)
assert p > q
n = p*q
e = 65536
m = bytes_to_long(flag)
num1 = (pow(p,e,n)-pow(q,e,n)) % n
num2 = pow(p-q,e,n)
c = pow(m,e,n)
print("num1=",num1)
print("num2=",num2)
print("n=",n)
print("c=",c)
先当脚本小子
exp.py
from Crypto.Util.number import *
import gmpy2
num1= 134186458247304184975418956047750205959249518467116558944535042073046353646812210914711656218265319503240074967140027248278994209294869476247136854741631971975560846483033205230015783696055443897579440474585892990793595602095853960468928457703619205343030230201261058516219352855127626321847429189498666288452
num2= 142252615203395148320392930915384149783801592719030740337592034613073131106036364733480644482188684184951026866672011061092572389846929838149296357261088256882232316029199097203257003822750826537629358422813658558008420810100860520289261141533787464661186681371090873356089237613080052677646446751824502044253
n= 154128165952806886790805410291540694477027958542517309121222164274741570806324940112942356615458298064007096476638232940977238598879453357856259085001745763666030177657087772721079761302637352680091939676709372354103177660093164629417313468356185431895723026835950366030712541994019375251534778666996491342313
c= 9061020000447780498751583220055526057707259079063266050917693522289697419950637286020502996753375864826169562714946009146452528404466989211057548905704856329650955828939737304126685040898740775635547039660982064419976700425595503919207903099686497044429265908046033565745195837408532764433870408185128447965
tmp = num1+num2
p = gmpy2.gcd(n,tmp)
q = n // p
inv_p = gmpy2.invert(p, q)
inv_q = gmpy2.invert(q, p)
cs = [c]
for i in range(16):
ps = []
for c2 in cs:
r = pow(c2, (p + 1) // 4, p)
s = pow(c2, (q + 1) // 4, q)
x = (r * inv_q * q + s * inv_p * p) % n
y = (r * inv_q * q - s * inv_p * p) % n
if x not in ps:
ps.append(x)
if n - x not in ps:
ps.append(n - x)
if y not in ps:
ps.append(y)
if n - y not in ps:
ps.append(n - y)
cs = ps
for m in cs:
print(long_to_bytes(m))
下面的三个题型将涉及CopperSmith,师傅们可以通读一遍:密码学学习笔记 之 Coppersmith’s Method | Van1sh的小屋 (jayxv.github.io)
十四、m高位泄露¶
这类题目会有两种情况,第一种情况是代码很直白的给出m的高位,第二种情况是利用flag头之类的信息来获取高位
情况1:直接给出m的高位¶
例题¶
task.py
import gmpy2
import libnum
import uuid
flag = "flag{" + str(uuid.uuid4()) + "}"
m = libnum.s2n(flag)
p = libnum.generate_prime(512)
q = libnum.generate_prime(512)
n = p * q
m1 = ((m >> 300) << 300)
e = 3
c = pow(m, e, n)
print("n =", n)
print("c =", c)
print("e =", e)
print("m1 =", m1)
"""
n = 89449659165373664419599666603079125351786161891254199117045952387178298091726343680198833028457552478360463001966084179577576990766724383528486250298768666097882661565765202949881673799125950008229527772973603379916117935790703989917655837756217393025354969853495238961762669326690100145696530290685977278593
c = 175676150266637032446485438802315236532165610668245377791442524569846934587347877260997089793552024464242407355427955652050327122630649033488529560135042402737218074153101020540979958586399761415542047850951996733997549252310811350769808163958303048261417309757780500291307110596781699418188514782424677
e = 3
m1 = 56006392791978632601307849398736624069259692797382051345599538506145258779412417900757721790977933312
"""
exp.sage
from Crypto.Util.number import long_to_bytes
n = 89449659165373664419599666603079125351786161891254199117045952387178298091726343680198833028457552478360463001966084179577576990766724383528486250298768666097882661565765202949881673799125950008229527772973603379916117935790703989917655837756217393025354969853495238961762669326690100145696530290685977278593
c = 175676150266637032446485438802315236532165610668245377791442524569846934587347877260997089793552024464242407355427955652050327122630649033488529560135042402737218074153101020540979958586399761415542047850951996733997549252310811350769808163958303048261417309757780500291307110596781699418188514782424677
e = 3
m1 = 56006392791978632601307849398736624069259692797382051345599538506145258779412417900757721790977933312
R.<x> = PolynomialRing(Zmod(n))
f = (m1 + x)^e - c
res = f.small_roots(X = 2^300,beta = 1)
if res != []:
m = m1 + res[0]
print(long_to_bytes(int(m)))
情况2:利用flag头等已知信息¶
例题——2024XYCTF 反方向的密码 相思¶
task.py
from Crypto.Util.number import *
import hashlib
from secrets import flag
def hash(x):
return hashlib.sha256(x.encode()).digest()
def pad(message):
return message + hash(str(len(message)))
m = bytes_to_long(pad(flag))
p = getStrongPrime(512)
q = getStrongPrime(512)
n = p * q
e = 3
print(pow(m, e, n))
print(n)
## 120440199294949712392334113337541924034371176306546446428347114627162894108760435789068328282135879182130546564535108930827440004987170619301799710272329673259390065147556073101312748104743572369383346039000998822862286001416166288971531241789864076857299162050026949096919395896174243383291126202796610039053
## 143413213355903851638663645270518081058249439863120739973910994223793329606595495141951165221740599158773181585002460087410975579141155680671886930801733174300593785562287068287654547100320094291092508723488470015821072834947151827362715749438612812148855627557719115676595686347541785037035334177162406305243
m可以看为m = bytes_to_long(b"XYCTF{xxxxxxxxxxxxxxxxxxxx}" + pad)
pad可以爆破,所以只需要求解中间未知的字符,就相当于一个m高位和低位泄露的题
exp.sage
from Crypto.Util.number import *
import hashlib
c = 120440199294949712392334113337541924034371176306546446428347114627162894108760435789068328282135879182130546564535108930827440004987170619301799710272329673259390065147556073101312748104743572369383346039000998822862286001416166288971531241789864076857299162050026949096919395896174243383291126202796610039053
n = 143413213355903851638663645270518081058249439863120739973910994223793329606595495141951165221740599158773181585002460087410975579141155680671886930801733174300593785562287068287654547100320094291092508723488470015821072834947151827362715749438612812148855627557719115676595686347541785037035334177162406305243
def hash(x):
return hashlib.sha256(x.encode()).digest()
for i in range(10,40): #i代表{}中未知数的个数
prefix = bytes_to_long(b"XYCTF{") * 256^(32 + 1 + i)
pad = hash(str(i+7))
low = bytes_to_long(b"}" + pad)
R.<x> = PolynomialRing(Zmod(n))
f = (prefix + x*256^33 + low)^3 - c
f = f.monic()
res = f.small_roots(X=256^i)
if res != []:
m = prefix + int(res[0])*256^33 + low
print(long_to_bytes(int(m)))
## XYCTF{!__d3ng__hu0__1@n__3h@n__Chu__!}
十五、p高位泄露¶
这类题目也有两种情况,第一种情况是代码很直白的给出p的高位,第二种情况是利用其他信息获取p的高位
p的高位泄露是有条件的,经过我的不完全准确的统计(以512bit的p为例)
当beta=0.4
时,在未知位数少于等于227bit时,可以恢复p
当beta=0.4,epsilon=0.01
时,在未知位数少于等于248bit时,可以恢复p
例题1¶
task.py
import gmpy2
import libnum
import uuid
flag = "flag{" + str(uuid.uuid4()) + "}"
m = libnum.s2n(flag)
p = libnum.generate_prime(1024)
q = libnum.generate_prime(1024)
n = p * q
e = 65537
p1 = ((p >> 256) << 256)
c = pow(m, e, n)
print("n =", n)
print("c =", c)
print("e =", e)
print("p1 =", p1)
"""
n = 25412529168113241701978154909309452589891277619233574149177682749114694998754065178357796120946044207438029964927062297462478639487054245771692139625849995546462111249773750389956600652870714030563605023702161513442866609937847422556059608499864578170270126239637444959812121589196901129645564580908045557218006330672260617798453633543627607790892960895904087738679492228779277752739734608284915605638138243297198792777112179909034121738317943791638151509031222745851940804609153731748776002638455252820409482251897734211263626398933847861538578761515233197699408866935293343456161438639398890089434015875977218250399
c = 11832017536820850822990089557724269863899815227776358234936663617587241671432348464674233033185082415100398087268764691266148966050993867487703853445199053612975005945065305992972854436834255574224203980327515867976652513642869374642661621841855735886358661741631500029948344306194937625466742946921106659582316643893949403548828556819907948714983462986507817955376793071143086032085845182853003634916425312911434933416448638808160541352834497686975061092257675653110414264672490891200433992043618040530275350634723043175666891682239033429796170154980192829798607191555482341170827932551423162833473892514972387547888
e = 65537
p1 = 174553077493661081676268351785469032783476528521014320107330821253075206651723812600343204348306643031578070226902979453793372875180300634043015175074746912397887970195415967163417566827459210112867899640388623940244194079258961165834045219906954836822089775153665401751146892024327963835455414059781203165184
"""
exp.sage
import gmpy2
from Crypto.Util.number import *
n = 25412529168113241701978154909309452589891277619233574149177682749114694998754065178357796120946044207438029964927062297462478639487054245771692139625849995546462111249773750389956600652870714030563605023702161513442866609937847422556059608499864578170270126239637444959812121589196901129645564580908045557218006330672260617798453633543627607790892960895904087738679492228779277752739734608284915605638138243297198792777112179909034121738317943791638151509031222745851940804609153731748776002638455252820409482251897734211263626398933847861538578761515233197699408866935293343456161438639398890089434015875977218250399
c = 11832017536820850822990089557724269863899815227776358234936663617587241671432348464674233033185082415100398087268764691266148966050993867487703853445199053612975005945065305992972854436834255574224203980327515867976652513642869374642661621841855735886358661741631500029948344306194937625466742946921106659582316643893949403548828556819907948714983462986507817955376793071143086032085845182853003634916425312911434933416448638808160541352834497686975061092257675653110414264672490891200433992043618040530275350634723043175666891682239033429796170154980192829798607191555482341170827932551423162833473892514972387547888
e = 65537
p_high = 174553077493661081676268351785469032783476528521014320107330821253075206651723812600343204348306643031578070226902979453793372875180300634043015175074746912397887970195415967163417566827459210112867899640388623940244194079258961165834045219906954836822089775153665401751146892024327963835455414059781203165184
R.<x> = PolynomialRing(Zmod(n))
f = p_high + x
res = f.small_roots(X = 2^256,beta = 0.4)
if res != []:
p = p_high + int(res[0])
q = n // p
d = gmpy2.invert(e,(p-1)*(q-1))
m = pow(c,d,n)
print(long_to_bytes(int(m)))
例题2——2023LitCTF Babyxor¶
task.py
from Crypto.Util.number import *
from secret import flag
m = bytes_to_long(flag)
assert len(flag)==32
p = getPrime(512)
q = getPrime(512)
n = p*q
e = 65537
c1 = p^m
c2 = pow(m,e,n)
print(f'n = {n}')
print(f'c1 = {c1}')
print(f'c2 = {c2}')
"""
n = 139167681803392690594490403105432649693546256181767408269202101512534988406137879788255103631885736461742577594980136624933914700779445704490217419248411578290305101891222576080645870988658334799437317221565839991979543660824098367011942169305111105129234902517835649895908656770416774539906212596072334423407
c1 = 11201139662236758800406931253538295757259990870588609533820056210585752522925690049252488581929717556881067021381940083808024384402885422258545946243513996
c2 = 112016152270171196606652761990170033221036025260883289104273504703557624964071464062375228351458191745141525003775876044271210498526920529385038130932141551598616579917681815276713386113932345056134302042399379895915706991873687943357627747262597883603999621939794450743982662393955266685255577026078256473601
"""
因为flag长度为32,转为int的值为256bit,因为p为512的数,所以p ^ m
的高256bit和p的高256bit是一样的,间接告诉我们p的高位
这个未知位数不太满足我们前面说的攻击条件,差了8位,因此需要做一点爆破
exp.sage
import gmpy2
from tqdm import *
from Crypto.Util.number import *
n = 139167681803392690594490403105432649693546256181767408269202101512534988406137879788255103631885736461742577594980136624933914700779445704490217419248411578290305101891222576080645870988658334799437317221565839991979543660824098367011942169305111105129234902517835649895908656770416774539906212596072334423407
c1 = 11201139662236758800406931253538295757259990870588609533820056210585752522925690049252488581929717556881067021381940083808024384402885422258545946243513996
c2 = 112016152270171196606652761990170033221036025260883289104273504703557624964071464062375228351458191745141525003775876044271210498526920529385038130932141551598616579917681815276713386113932345056134302042399379895915706991873687943357627747262597883603999621939794450743982662393955266685255577026078256473601
e = 65537
pbits = 512
p_high = c1 >> 256
for i in trange(2**8):
p4 = p_high << 8 #这里需要先爆破8位,使得知道264位以后再恢复p
p4 = p4 + i
kbits = pbits - p4.nbits()
p4 = p4 << kbits
R.<x> = PolynomialRing(Zmod(n))
f = x + p4
res = f.small_roots(X=2^kbits, beta=0.4, epsilon=0.01)
if res != []:
p = p4 + int(x[0])
q = n // p
d = gmpy2.invert(e,(p-1)*(q-1))
m = pow(c2,d,n)
print(long_to_bytes(int(m)))
break
#LitCTF{oh!!!!coppersmith_is_fun}
例题3¶
有些题目不一定给出高位,还有可能给出低位,甚至给出部分高位和部分低位。其本质是一样的,我们只需要改变多项式即可
task.py
from secret import flag
from Crypto.Util.number import *
p, q = getPrime(1024), getPrime(1024)
N = p * q
p0 = p ^ (bytes_to_long(flag)<<444)
m = bytes_to_long(flag)
c = pow(m, 65537, N)
print(len(flag))
print('c=',c)
print('N=',N)
print('p0=',p0)
## 54
## c= 6187845844052645335477666563187579997555293403110620879123121166924703361821847984760733842049752886698011561451715570810292323756091403783920480396052120046379755571530451812078574368413924390017994278703794257118954968480994077586245800902748815905644287545189605031883291488844527496906890127546594960138582150272568163575590734246290813150131949296550974206595456421136190026954855755623761557179760444906148376433584795779131477110538212742401420633087881506416368853221110426491868881029814841479615979710066371796507692025126150957315754738584387325388998533227577023142894876376702128870643448600352603905149
## N= 14195810221536708489210274086946022255792382922322850338983263099316341767896809249586174293795778082892237356582757544364274847341220303582304283372889068290282580493623042441421715338444710303281638639785784613434328659529884972238348336971186339482788748316527376410510261228354155806341136524162787121212184386900663470590652770503564816948407257603737938414126069053610568675347826390537145556511048774030823322301932088595499671755944744816524811272617200683384649389274196659297432212847319503330409792704612575414010711158873031786577877685578976140462539734553598745329712188216200905451774357282278403189943
## p0= 111984935426070810628244029907949697819351004665202173622240566580193974673163315128983603277856218378729883402496424467491406698035050254407170555432448523469880166015507303737468316933545613178461925283040643344197452758878116752692499745309765526523083790825015522124083482964296662782850606081657447935191
因为m左移444位,这样子m后面444位都是0,所以异或之后,不影响p低位444值
根据flag长度是54,转成int数据就432bit,左移444位后是876位,异或之后,p的高(1024 - 876) = 148位也是不变的。所以我们有了p的部分高位和低位
还是利用coppersmith,改个多项式即可
exp.sage
import gmpy2
from Crypto.Util.number import *
p0 = 111984935426070810628244029907949697819351004665202173622240566580193974673163315128983603277856218378729883402496424467491406698035050254407170555432448523469880166015507303737468316933545613178461925283040643344197452758878116752692499745309765526523083790825015522124083482964296662782850606081657447935191
c = 6187845844052645335477666563187579997555293403110620879123121166924703361821847984760733842049752886698011561451715570810292323756091403783920480396052120046379755571530451812078574368413924390017994278703794257118954968480994077586245800902748815905644287545189605031883291488844527496906890127546594960138582150272568163575590734246290813150131949296550974206595456421136190026954855755623761557179760444906148376433584795779131477110538212742401420633087881506416368853221110426491868881029814841479615979710066371796507692025126150957315754738584387325388998533227577023142894876376702128870643448600352603905149
n = 14195810221536708489210274086946022255792382922322850338983263099316341767896809249586174293795778082892237356582757544364274847341220303582304283372889068290282580493623042441421715338444710303281638639785784613434328659529884972238348336971186339482788748316527376410510261228354155806341136524162787121212184386900663470590652770503564816948407257603737938414126069053610568675347826390537145556511048774030823322301932088595499671755944744816524811272617200683384649389274196659297432212847319503330409792704612575414010711158873031786577877685578976140462539734553598745329712188216200905451774357282278403189943
e = 65537
phigh = p0 >> 876 <<876
tmp = int("1" * 444,2)
plow = p0 & tmp
R.<x> = PolynomialRing(Zmod(n))
f = phigh + x*2**444 + plow
f = f.monic()
res = f.small_roots(X=2^432,beta=0.4)
if res != []:
p = int(phigh + res[0]*2**444+plow)
print("p =",p)
q = n // p
d = gmpy2.invert(e,(p-1)*(q-1))
m = pow(c,d,n)
print(long_to_bytes(int(m)))
十六、d低位泄露¶
攻击条件:e在可爆破范围,并且已知d的低位
推导:
即
假设我们知道d的低L位,并且记为\(d_{low}\),我们对上式同模\(2^L\),于是有
两边同时乘上p得到
此时上式只有k和p是未知的,因为\(0 < k < e\),所以可对k进行爆破,解同余式得到p的低位,再用coppersmith恢复p
例题¶
task.py
import gmpy2
import libnum
import uuid
flag = "flag{" + str(uuid.uuid4()) + "}"
m = libnum.s2n(flag)
while True:
p = libnum.generate_prime(512)
q = libnum.generate_prime(512)
n = p * q
phi_n = (p - 1) * (q - 1)
e = 3
if gmpy2.gcd(e, phi_n) == 1:
break
d = gmpy2.invert(e, phi_n)
d1 = d & ((1 << 486) - 1)
c = pow(m, e, n)
print("n =", n)
print("e =", e)
print("c =", c)
print("dlow =", d1)
"""
n = 52742121495363456830645578439066440260525635701449452038623040460534514676940962601979528301396249463310635013618692939847284377316096998174539886900202801371512846078230196507601167693580439935790730812348102969592553942497201279143623565409782692807615767067494338127711608771029145341503069929345973282553
e = 3
c = 175676150266403096249431407570554929021369604168136874268275844375181688894753012319267533769923727863698572157250017689244151605424698000831986135513112136594197978237874400825236288135820643994889528170234514127521418132167932446836545721803621236277931291609749528037915073270452302613264065194049125
dlow = 8681746171122274095992828774600905650260279086049883317863420271848455130773826835383939352151607850521826888046119078445911475580784484455485323
"""
exp.sage
from Crypto.Util.number import long_to_bytes,inverse
from tqdm import *
n = 52742121495363456830645578439066440260525635701449452038623040460534514676940962601979528301396249463310635013618692939847284377316096998174539886900202801371512846078230196507601167693580439935790730812348102969592553942497201279143623565409782692807615767067494338127711608771029145341503069929345973282553
e = 3
c = 175676150266403096249431407570554929021369604168136874268275844375181688894753012319267533769923727863698572157250017689244151605424698000831986135513112136594197978237874400825236288135820643994889528170234514127521418132167932446836545721803621236277931291609749528037915073270452302613264065194049125
dlow = 8681746171122274095992828774600905650260279086049883317863420271848455130773826835383939352151607850521826888046119078445911475580784484455485323
def get_full_p(p_low,n,pbits):
kbits = p_low.bit_length()
R.<x> = PolynomialRing(Zmod(n))
f = x * 2^kbits + p_low
f = f.monic()
res = f.small_roots(X = 2^(pbits-kbits),beta=0.4)
if res != []:
p = int(res[0]) * 2^kbits + p_low
return p
for k in trange(e):
var('p')
f1 = e*dlow*p - (k*n*p - k*p^2 - k*n + (k+1)*p)
roots = solve_mod(f1,2^486)
if roots != []:
for root in roots:
if int(root[0]).bit_length() == 486:
p = get_full_p(int(root[0]),n,512)
if p:
q = n // p
d = inverse(3,(p-1)*(q-1))
m = pow(c,d,n)
print(long_to_bytes(m))
break
2023强网拟态决赛——BadRSA¶
task.py
from Crypto.Util.number import *
f = open('flag.txt','rb')
m = bytes_to_long(f.readline().strip())
p = getPrime(512)
q = getPrime(512)
e = getPrime(8)
n = p*q
phi = (p-1)*(q-1)
d = inverse(e,phi)
leak = d & ((1<<265) - 1)
print(f'e = {e}')
print(f'leak = {leak}')
print(f'n = {n}')
c = pow(m,e,n)
print(f'c = {c}')
'''
e = 149
leak = 6001958312144157007304943931113872134090201010357773442954181100786589106572169
n = 88436063749749362190546240596734626745594171540325086418270903156390958817492063940459108934841028734921718351342152598224670602551497995639921650979296052943953491639892805985538785565357751736799561653032725751622522198746331856539251721033316195306373318196300612386897339425222615697620795751869751705629
c = 1206332017436789083799133504302957634035030644841294494992108068042941783794804420630684301945366528832108224264145563741764232409333108261614056154508904583078897178425071831580459193200987943565099780857889864631160747321901113496943710282498262354984634755751858251005566753245882185271726628553508627299
'''
由\(ed \equiv 1 \mod \phi(n)\)
即\(ed = k(p-1)(q-1) + 1\)
两边同时模\(2^{265}\),得\(ed_0 \equiv k(p-1)(q-1) + 1 \mod 2^{265}\),这里\(d_0 = leak\)
\(\therefore ed_0 \equiv k(pq - p - q + 1) + 1 \mod 2^{265}\)
再同乘\(p\),得到\(ed_0p \equiv knp - kp^2 - kn + kp + p \mod 2^{265}\)
因为\(d \approx 1023bit\)
所以\(k < e\)
爆破\(k\),解方程得到\(p\)的低位,然后用copper恢复\(p\)
要调copper的参数,解方程得到的只有\(p\)的低265位,还差247位
exp.sage
from Crypto.Util.number import *
import gmpy2
e = 149
d0 = 6001958312144157007304943931113872134090201010357773442954181100786589106572169
n = 88436063749749362190546240596734626745594171540325086418270903156390958817492063940459108934841028734921718351342152598224670602551497995639921650979296052943953491639892805985538785565357751736799561653032725751622522198746331856539251721033316195306373318196300612386897339425222615697620795751869751705629
c = 1206332017436789083799133504302957634035030644841294494992108068042941783794804420630684301945366528832108224264145563741764232409333108261614056154508904583078897178425071831580459193200987943565099780857889864631160747321901113496943710282498262354984634755751858251005566753245882185271726628553508627299
for k in range(1,e):
var("p")
temp = e*d0*p
f = (k*n*p - k*p^2 - k*n + k*p + p) - temp == 0
roots = solve_mod([f],2^265)
if roots != []:
for root in roots:
plow = int(root[0])
## print(plow)
## 55136429770900518182274612434328885021714880080534773062619965935822096183916139
R.<x> = PolynomialRing(Zmod(n))
f1 = x*2^265 + plow
f1 = f1.monic()
res = f1.small_roots(X=2^247,beta=0.5,epsilon = 0.01)
if res != []:
print(res)
## [188210689227294472160085325314952069542671020803828390144430392548173787275]
p = int(res[0])*2^265 + plow
print("p =",p)
## p = 11158174168280917736979570452068827611755694573672250873587467083259280584739528118050085070475912733864211083865201596017044398008278425498714490994488939
q = n // p
d = gmpy2.invert(e,(p-1)*(q-1))
m = pow(c,d,n)
print(long_to_bytes(int(m)))
## flag{827ccb0eea8a706c4c34a16891f84e7b}
break
这里beta = 0.5
是因为,对于度(即最大次方)为\(d\)的多项式,要求根小于\(n^{\frac{\beta^2}{d} - \epsilon}\),而且要求因子\(p > n^{\beta}\)
此题\(d = 1\),经过计算我们要求的根的上界为\(2^{247}\),\(\frac{247}{1024} = 0.2412\),所以取beta = 0.5
可以恢复p。界这个东西感觉有点玄学,只能多做题多感受了
十七、Franklin-Reiter相关消息攻击¶
攻击条件:
当Alice使用同一公钥对两个具有线性关系的消息\(M_1,M_2\)进行加密,并将加密后的消息\(C_1,C_2\)发送给了Bob,我们就可能可以获得对应的消息\(M_1,M_2\)。假设模数为\(N\),\(M_1,M_2\)的线性关系如下:
\(M_1 \equiv f(M_2) \mod N\)
其中\(f\)为一个线性函数,比如\(f = ax+b\)
存脚本就好了
例题1¶
task.py
from secret import flag
from Crypto.Util.number import *
m1 = bytes_to_long(flag)
N = getPrime(512)*getPrime(512)
e = 17
c1 = pow(m1, e, N)
a = getRandomNBitInteger(512)
b = getRandomNBitInteger(512)
m2 = a * m1 + b
c2 = pow(m2, e, N)
print(N, a, b, c1, c2, sep="\n")
## 51296885372346449295388453471330409021784141081351581975478435681552082076338697136130122011636685327781785488670769096434920591920054441921039812310126089859349902066456998315283909435249794317277620588552441456327265553018986591779396701680997794937951231970194353001576159809798153970829987274504038146741
## 13256631249970000274738888132534852767685499642889351632072622194777502848070957827974250425805779856662241409663031192870528911932663995606616763982320967
## 12614470377409090738391280373352373943201882741276992121990944593827605866548572392808272414120477304486154096358852845785437999246453926812759725932442170
## 18617698095122597355752178584860764221736156139844401400942959000560180868595058572264330257490645079792321778926462300410653970722619332098601515399526245808718518153518824404167374361098424325296872587362792839831578589407441739040578339310283844080111189381106274103089079702496168766831316853664552253142
## 14091361528414093900688440242152327115109256507133728799758289918462970724109343410464537203689727409590796472177295835710571700501895484300979622506298961999001641059179449655629481072402234965831697915939034769804437452528921599125823412464950939837343822566667533463393026895985173157447434429906021792720
exp.sage
import libnum
n = 51296885372346449295388453471330409021784141081351581975478435681552082076338697136130122011636685327781785488670769096434920591920054441921039812310126089859349902066456998315283909435249794317277620588552441456327265553018986591779396701680997794937951231970194353001576159809798153970829987274504038146741
a = 13256631249970000274738888132534852767685499642889351632072622194777502848070957827974250425805779856662241409663031192870528911932663995606616763982320967
b = 12614470377409090738391280373352373943201882741276992121990944593827605866548572392808272414120477304486154096358852845785437999246453926812759725932442170
c1 = 18617698095122597355752178584860764221736156139844401400942959000560180868595058572264330257490645079792321778926462300410653970722619332098601515399526245808718518153518824404167374361098424325296872587362792839831578589407441739040578339310283844080111189381106274103089079702496168766831316853664552253142
c2 = 14091361528414093900688440242152327115109256507133728799758289918462970724109343410464537203689727409590796472177295835710571700501895484300979622506298961999001641059179449655629481072402234965831697915939034769804437452528921599125823412464950939837343822566667533463393026895985173157447434429906021792720
e = 17
def franklinReiter(n,e,c1,c2,a,b):
PR.<x> = PolynomialRing(Zmod(n))
g1 = x^e - c1
g2 = (a*x+b)^e - c2
def gcd(g1, g2):
while g2:
g1, g2 = g2, g1 % g2
return g1.monic()
return -gcd(g1, g2)[0]
m = franklinReiter(n,e,c1,c2,a,b)
print(libnum.n2s(int(m)))
例题2——SICTFround2 签到题来咯¶
task.py
from secret import flag
from Crypto.Util.number import *
m = bytes_to_long(flag)
p = getPrime(1024)
q = getPrime(1024)
e = getPrime(10)
n = p*q
c1 = pow(114*m+2333,e,n)
c2 = pow(514*m+4555,e,n)
print(f'n = {n}')
print(f'c1 = {c1}')
print(f'c2 = {c2}')
'''
n = 18993579800590288733556762316465854395650778003397512624355925069287661487515652428099677335464809283955351330659278915073219733930542167360381688856732762552737791137784222098296804826261681852699742456526979985201331982720936091963830799430264680941164508709453794113576607749669278887105809727027129736803614327631979056934906547015919204770702496676692691248702461766117271815398943842909579917102217310779431999448597899109808086655029624478062317317442297276087073653945439820988375066353157221370129064423613949039895822016206336117081475698987326594199181180346821431242733826487765566154350269651592993856883
c1 = 3089900890429368903963127778258893993015616003863275300568951378177309984878857933740319974151823410060583527905656182419531008417050246901514691111335764182779077027419410717272164998075313101695833565450587029584857433998627248705518025411896438130004108810308599666206694770859843696952378804678690327442746359836105117371144846629293505396610982407985241783168161504309420302314102538231774470927864959064261347913286659384383565379900391857812482728653358741387072374314243068833590379370244368317200796927931678203916569721211768082289529948017340699194622234734381555103898784827642197721866114583358940604520
c2 = 6062491672599671503583327431533992487890060173533816222838721749216161789662841049274959778509684968479022417053571624473283543736981267659104310293237792925201009775193492423025040929132360886500863823523629213703533794348606076463773478200331006341206053010168741302440409050344170767489936681627020501853981450212305108039373119567034948781143698613084550376070802084805644270376620484786155554275798939105737707005991882264123315436368611647275530607811665999620394422672764116158492214128572456571553281799359243174598812137554860109807481900330449364878168308833006964726761878461761560543284533578701661413931
'''
本题未知e,爆破一下e即可
exp.sage
## sage
import libnum
from Crypto.Util.number import *
n =
c1 =
c2 =
E = []
for i in range(2^9,2^10):
if isPrime(i):
E.append(i)
def franklinReiter(n,e,c1,c2):
PR.<x> = PolynomialRing(Zmod(n))
g1 = (114*x + 2333)^e - c1
g2 = (514*x + 4555)^e - c2
def gcd(g1, g2):
while g2:
g1, g2 = g2, g1 % g2
return g1.monic()
return -gcd(g1, g2)[0]
## print(E)
for e in E:
m = franklinReiter(n,e,c1,c2)
flag = long_to_bytes(int(m))
if b'SICTF' in flag:
print(flag)
break
else:
continue
例题3——2023领航杯 RSA3¶
在前面的例子中,加密指数都不太大,脚本运行起来都算快。接下来这道例题,加密指数e为65537,如果不使用更优的方法,会很浪费时间
task.py
from Crypto.Util.number import *
from secret import flag
m = bytes_to_long(flag)
p1, q1 = getPrime(512), getPrime(512)
n1 = p1*q1
e = 65537
p2, q2 = getPrime(512), getPrime(512)
n2 = p2*q2
print(f'n1 = {n1}')
print(f'n2 = {n2}')
print(f'c1 = {pow(m,e,n2)}')
print(f'c2 = {pow(n1-m,e,n2)}')
## n1 = 52579135273678950581073020233998071974221658902576724000130040488018033110534210901239397446395736563148970863970460542205225993317478251099451639165369081820130823165642873594136020122857712288395352930384057524510346112486008850200845915783772351449146183974239444691330777565342525218070680067550270554767
## n2 = 68210568831848267339414957973218186686176324296418282565773310695862151827108036984694027795077376921170907068110296451176263520249799154781062517066423984526868547296781709439425857993705489037768605485740968600877866332458671029054092942851472208033494968784822459369206497698469167909174346042658361616469
## c1 = 42941712708129054668823891960764339394032538100909746015733801598044118605733969558717842106784388091495719003761324737091667431446354282990525549196642753967283958283202592037329821712755519455155110675327321252333824912095517427885925854391047828862338332559137577789387455868761466777370476884779752953853
## c2 = 62704043252861638895370674827559804184650708692227789532879941590038911799857232898692335429773480889624046167792573885125945511356456073688435911975161053231589019934427151230924004944847291434167067905803180207183209888082275583120633408232749119300200555327883719466349164062163459300518993952046873724005
参考:HALF-GCD算法的阐述_half gcd_Entropy Increaser的博客-CSDN博客
多项式 gcd 的正确姿势:Half-GCD 算法 - whx1003 - 博客园 (cnblogs.com)
脚本来源:rkm0959_implements/Half_GCD/code.sage at main · rkm0959/rkm0959_implements (github.com)
我们引入使用了HGCD算法的Franklin-Reiter相关消息攻击的脚本
exp.sage
from Crypto.Util.number import *
import sys
def HGCD(a, b):
if 2 * b.degree() <= a.degree() or a.degree() == 1:
return 1, 0, 0, 1
m = a.degree() // 2
a_top, a_bot = a.quo_rem(x^m)
b_top, b_bot = b.quo_rem(x^m)
R00, R01, R10, R11 = HGCD(a_top, b_top)
c = R00 * a + R01 * b
d = R10 * a + R11 * b
q, e = c.quo_rem(d)
d_top, d_bot = d.quo_rem(x^(m // 2))
e_top, e_bot = e.quo_rem(x^(m // 2))
S00, S01, S10, S11 = HGCD(d_top, e_top)
RET00 = S01 * R00 + (S00 - q * S01) * R10
RET01 = S01 * R01 + (S00 - q * S01) * R11
RET10 = S11 * R00 + (S10 - q * S11) * R10
RET11 = S11 * R01 + (S10 - q * S11) * R11
return RET00, RET01, RET10, RET11
def GCD(a, b):
print(a.degree(), b.degree())
q, r = a.quo_rem(b)
if r == 0:
return b
R00, R01, R10, R11 = HGCD(a, b)
c = R00 * a + R01 * b
d = R10 * a + R11 * b
if d == 0:
return c.monic()
q, r = c.quo_rem(d)
if r == 0:
return d
return GCD(d, r)
sys.setrecursionlimit(500000)
e = 65537
n1 =
n2 =
c1 =
c2 =
R.<x> = PolynomialRing(Zmod(n2))
f = x^e - c1
g = (n1 - x)^e - c2
res = GCD(f,g)
m = -res.monic().coefficients()[0]
print(m)
flag = long_to_bytes(int(m))
print(flag)
#CnHongKe{Fr4nkl1n_R31ter_4nd_gcD}
十八、Boneh-Durfee攻击¶
攻击条件:\(d < N^{0.292}\)
存脚本即可
exp.sage
from __future__ import print_function
import time
############################################
## Config
##########################################
"""
Setting debug to true will display more informations
about the lattice, the bounds, the vectors...
"""
debug = True
"""
Setting strict to true will stop the algorithm (and
return (-1, -1)) if we don't have a correct
upperbound on the determinant. Note that this
doesn't necesseraly mean that no solutions
will be found since the theoretical upperbound is
usualy far away from actual results. That is why
you should probably use `strict = False`
"""
strict = False
"""
This is experimental, but has provided remarkable results
so far. It tries to reduce the lattice as much as it can
while keeping its efficiency. I see no reason not to use
this option, but if things don't work, you should try
disabling it
"""
helpful_only = True
dimension_min = 7 ## stop removing if lattice reaches that dimension
############################################
## Functions
##########################################
## display stats on helpful vectors
def helpful_vectors(BB, modulus):
nothelpful = 0
for ii in range(BB.dimensions()[0]):
if BB[ii,ii] >= modulus:
nothelpful += 1
print(nothelpful, "/", BB.dimensions()[0], " vectors are not helpful")
## display matrix picture with 0 and X
def matrix_overview(BB, bound):
for ii in range(BB.dimensions()[0]):
a = ('%02d ' % ii)
for jj in range(BB.dimensions()[1]):
a += '0' if BB[ii,jj] == 0 else 'X'
if BB.dimensions()[0] < 60:
a += ' '
if BB[ii, ii] >= bound:
a += '~'
print(a)
## tries to remove unhelpful vectors
## we start at current = n-1 (last vector)
def remove_unhelpful(BB, monomials, bound, current):
## end of our recursive function
if current == -1 or BB.dimensions()[0] <= dimension_min:
return BB
## we start by checking from the end
for ii in range(current, -1, -1):
## if it is unhelpful:
if BB[ii, ii] >= bound:
affected_vectors = 0
affected_vector_index = 0
## let's check if it affects other vectors
for jj in range(ii + 1, BB.dimensions()[0]):
## if another vector is affected:
## we increase the count
if BB[jj, ii] != 0:
affected_vectors += 1
affected_vector_index = jj
## level:0
## if no other vectors end up affected
## we remove it
if affected_vectors == 0:
print("* removing unhelpful vector", ii)
BB = BB.delete_columns([ii])
BB = BB.delete_rows([ii])
monomials.pop(ii)
BB = remove_unhelpful(BB, monomials, bound, ii-1)
return BB
## level:1
## if just one was affected we check
## if it is affecting someone else
elif affected_vectors == 1:
affected_deeper = True
for kk in range(affected_vector_index + 1, BB.dimensions()[0]):
## if it is affecting even one vector
## we give up on this one
if BB[kk, affected_vector_index] != 0:
affected_deeper = False
## remove both it if no other vector was affected and
## this helpful vector is not helpful enough
## compared to our unhelpful one
if affected_deeper and abs(bound - BB[affected_vector_index, affected_vector_index]) < abs(bound - BB[ii, ii]):
print("* removing unhelpful vectors", ii, "and", affected_vector_index)
BB = BB.delete_columns([affected_vector_index, ii])
BB = BB.delete_rows([affected_vector_index, ii])
monomials.pop(affected_vector_index)
monomials.pop(ii)
BB = remove_unhelpful(BB, monomials, bound, ii-1)
return BB
## nothing happened
return BB
"""
Returns:
* 0,0 if it fails
* -1,-1 if `strict=true`, and determinant doesn't bound
* x0,y0 the solutions of `pol`
"""
def boneh_durfee(pol, modulus, mm, tt, XX, YY):
"""
Boneh and Durfee revisited by Herrmann and May
finds a solution if:
* d < N^delta
* |x| < e^delta
* |y| < e^0.5
whenever delta < 1 - sqrt(2)/2 ~ 0.292
"""
## substitution (Herrman and May)
PR.<u, x, y> = PolynomialRing(ZZ)
Q = PR.quotient(x*y + 1 - u) ## u = xy + 1
polZ = Q(pol).lift()
UU = XX*YY + 1
## x-shifts
gg = []
for kk in range(mm + 1):
for ii in range(mm - kk + 1):
xshift = x^ii * modulus^(mm - kk) * polZ(u, x, y)^kk
gg.append(xshift)
gg.sort()
## x-shifts list of monomials
monomials = []
for polynomial in gg:
for monomial in polynomial.monomials():
if monomial not in monomials:
monomials.append(monomial)
monomials.sort()
## y-shifts (selected by Herrman and May)
for jj in range(1, tt + 1):
for kk in range(floor(mm/tt) * jj, mm + 1):
yshift = y^jj * polZ(u, x, y)^kk * modulus^(mm - kk)
yshift = Q(yshift).lift()
gg.append(yshift) ## substitution
## y-shifts list of monomials
for jj in range(1, tt + 1):
for kk in range(floor(mm/tt) * jj, mm + 1):
monomials.append(u^kk * y^jj)
## construct lattice B
nn = len(monomials)
BB = Matrix(ZZ, nn)
for ii in range(nn):
BB[ii, 0] = gg[ii](0, 0, 0)
for jj in range(1, ii + 1):
if monomials[jj] in gg[ii].monomials():
BB[ii, jj] = gg[ii].monomial_coefficient(monomials[jj]) * monomials[jj](UU,XX,YY)
## Prototype to reduce the lattice
if helpful_only:
## automatically remove
BB = remove_unhelpful(BB, monomials, modulus^mm, nn-1)
## reset dimension
nn = BB.dimensions()[0]
if nn == 0:
print("failure")
return 0,0
## check if vectors are helpful
if debug:
helpful_vectors(BB, modulus^mm)
## check if determinant is correctly bounded
det = BB.det()
bound = modulus^(mm*nn)
if det >= bound:
print("We do not have det < bound. Solutions might not be found.")
print("Try with highers m and t.")
if debug:
diff = (log(det) - log(bound)) / log(2)
print("size det(L) - size e^(m*n) = ", floor(diff))
if strict:
return -1, -1
else:
print("det(L) < e^(m*n) (good! If a solution exists < N^delta, it will be found)")
## display the lattice basis
if debug:
matrix_overview(BB, modulus^mm)
## LLL
if debug:
print("optimizing basis of the lattice via LLL, this can take a long time")
BB = BB.LLL()
if debug:
print("LLL is done!")
## transform vector i & j -> polynomials 1 & 2
if debug:
print("looking for independent vectors in the lattice")
found_polynomials = False
for pol1_idx in range(nn - 1):
for pol2_idx in range(pol1_idx + 1, nn):
## for i and j, create the two polynomials
PR.<w,z> = PolynomialRing(ZZ)
pol1 = pol2 = 0
for jj in range(nn):
pol1 += monomials[jj](w*z+1,w,z) * BB[pol1_idx, jj] / monomials[jj](UU,XX,YY)
pol2 += monomials[jj](w*z+1,w,z) * BB[pol2_idx, jj] / monomials[jj](UU,XX,YY)
## resultant
PR.<q> = PolynomialRing(ZZ)
rr = pol1.resultant(pol2)
## are these good polynomials?
if rr.is_zero() or rr.monomials() == [1]:
continue
else:
print("found them, using vectors", pol1_idx, "and", pol2_idx)
found_polynomials = True
break
if found_polynomials:
break
if not found_polynomials:
print("no independant vectors could be found. This should very rarely happen...")
return 0, 0
rr = rr(q, q)
## solutions
soly = rr.roots()
if len(soly) == 0:
print("Your prediction (delta) is too small")
return 0, 0
soly = soly[0][0]
ss = pol1(q, soly)
solx = ss.roots()[0][0]
#
return solx, soly
def example():
############################################
## How To Use This Script
##########################################
#
## The problem to solve (edit the following values)
#
## the modulus
N = 0xc2fd2913bae61f845ac94e4ee1bb10d8531dda830d31bb221dac5f179a8f883f15046d7aa179aff848db2734b8f88cc73d09f35c445c74ee35b01a96eb7b0a6ad9cb9ccd6c02c3f8c55ecabb55501bb2c318a38cac2db69d510e152756054aaed064ac2a454e46d9b3b755b67b46906fbff8dd9aeca6755909333f5f81bf74db
## the public exponent
e = 0x19441f679c9609f2484eb9b2658d7138252b847b2ed8ad182be7976ed57a3e441af14897ce041f3e07916445b88181c22f510150584eee4b0f776a5a487a4472a99f2ddc95efdd2b380ab4480533808b8c92e63ace57fb42bac8315fa487d03bec86d854314bc2ec4f99b192bb98710be151599d60f224114f6b33f47e357517
## the hypothesis on the private exponent (the theoretical maximum is 0.292)
delta = .18 ## this means that d < N^delta
#
## Lattice (tweak those values)
#
## you should tweak this (after a first run), (e.g. increment it until a solution is found)
m = 4 ## size of the lattice (bigger the better/slower)
## you need to be a lattice master to tweak these
t = int((1-2*delta) * m) ## optimization from Herrmann and May
X = 2*floor(N^delta) ## this _might_ be too much
Y = floor(N^(1/2)) ## correct if p, q are ~ same size
#
## Don't touch anything below
#
## Problem put in equation
P.<x,y> = PolynomialRing(ZZ)
A = int((N+1)/2)
pol = 1 + x * (A + y)
#
## Find the solutions!
#
## Checking bounds
if debug:
print("=== checking values ===")
print("* delta:", delta)
print("* delta < 0.292", delta < 0.292)
print("* size of e:", int(log(e)/log(2)))
print("* size of N:", int(log(N)/log(2)))
print("* m:", m, ", t:", t)
## boneh_durfee
if debug:
print("=== running algorithm ===")
start_time = time.time()
solx, soly = boneh_durfee(pol, e, m, t, X, Y)
## found a solution?
if solx > 0:
print("=== solution found ===")
if False:
print("x:", solx)
print("y:", soly)
d = int(pol(solx, soly) / e)
print("private key found:", d)
else:
print("=== no solution was found ===")
if debug:
print(("=== %s seconds ===" % (time.time() - start_time)))
if __name__ == "__main__":
example()
例题 2023楚慧杯——so large e¶
task.py
from Crypto.Util.number import *
from Crypto.PublicKey import RSA
from flag import flag
import random
m = bytes_to_long(flag)
p = getPrime(512)
q = getPrime(512)
n = p*q
e = random.getrandbits(1024)
assert size(e)==1024
phi = (p-1)*(q-1)
assert GCD(e,phi)==1
d = inverse(e,phi)
assert size(d)==269
pub = (n, e)
PublicKey = RSA.construct(pub)
with open('pub.pem', 'wb') as f :
f.write(PublicKey.exportKey())
c = pow(m,e,n)
print('c =',c)
print(long_to_bytes(pow(c,d,n)))
#c = 6838759631922176040297411386959306230064807618456930982742841698524622016849807235726065272136043603027166249075560058232683230155346614429566511309977857815138004298815137913729662337535371277019856193898546849896085411001528569293727010020290576888205244471943227253000727727343731590226737192613447347860
提取公钥得到n,e
发现\(\frac{d}{n} = 0.26269\)
多半就是boneh_durfee攻击手段
改改example()函数的delta
和m
即可
delta
就是\(\frac{d}{n}\)的大小
exp
#sage
from __future__ import print_function
import time
############################################
## Config
##########################################
"""
Setting debug to true will display more informations
about the lattice, the bounds, the vectors...
"""
debug = True
"""
Setting strict to true will stop the algorithm (and
return (-1, -1)) if we don't have a correct
upperbound on the determinant. Note that this
doesn't necesseraly mean that no solutions
will be found since the theoretical upperbound is
usualy far away from actual results. That is why
you should probably use `strict = False`
"""
strict = False
"""
This is experimental, but has provided remarkable results
so far. It tries to reduce the lattice as much as it can
while keeping its efficiency. I see no reason not to use
this option, but if things don't work, you should try
disabling it
"""
helpful_only = True
dimension_min = 7 ## stop removing if lattice reaches that dimension
############################################
## Functions
##########################################
## display stats on helpful vectors
def helpful_vectors(BB, modulus):
nothelpful = 0
for ii in range(BB.dimensions()[0]):
if BB[ii,ii] >= modulus:
nothelpful += 1
print(nothelpful, "/", BB.dimensions()[0], " vectors are not helpful")
## display matrix picture with 0 and X
def matrix_overview(BB, bound):
for ii in range(BB.dimensions()[0]):
a = ('%02d ' % ii)
for jj in range(BB.dimensions()[1]):
a += '0' if BB[ii,jj] == 0 else 'X'
if BB.dimensions()[0] < 60:
a += ' '
if BB[ii, ii] >= bound:
a += '~'
print(a)
## tries to remove unhelpful vectors
## we start at current = n-1 (last vector)
def remove_unhelpful(BB, monomials, bound, current):
## end of our recursive function
if current == -1 or BB.dimensions()[0] <= dimension_min:
return BB
## we start by checking from the end
for ii in range(current, -1, -1):
## if it is unhelpful:
if BB[ii, ii] >= bound:
affected_vectors = 0
affected_vector_index = 0
## let's check if it affects other vectors
for jj in range(ii + 1, BB.dimensions()[0]):
## if another vector is affected:
## we increase the count
if BB[jj, ii] != 0:
affected_vectors += 1
affected_vector_index = jj
## level:0
## if no other vectors end up affected
## we remove it
if affected_vectors == 0:
print("* removing unhelpful vector", ii)
BB = BB.delete_columns([ii])
BB = BB.delete_rows([ii])
monomials.pop(ii)
BB = remove_unhelpful(BB, monomials, bound, ii-1)
return BB
## level:1
## if just one was affected we check
## if it is affecting someone else
elif affected_vectors == 1:
affected_deeper = True
for kk in range(affected_vector_index + 1, BB.dimensions()[0]):
## if it is affecting even one vector
## we give up on this one
if BB[kk, affected_vector_index] != 0:
affected_deeper = False
## remove both it if no other vector was affected and
## this helpful vector is not helpful enough
## compared to our unhelpful one
if affected_deeper and abs(bound - BB[affected_vector_index, affected_vector_index]) < abs(bound - BB[ii, ii]):
print("* removing unhelpful vectors", ii, "and", affected_vector_index)
BB = BB.delete_columns([affected_vector_index, ii])
BB = BB.delete_rows([affected_vector_index, ii])
monomials.pop(affected_vector_index)
monomials.pop(ii)
BB = remove_unhelpful(BB, monomials, bound, ii-1)
return BB
## nothing happened
return BB
"""
Returns:
* 0,0 if it fails
* -1,-1 if `strict=true`, and determinant doesn't bound
* x0,y0 the solutions of `pol`
"""
def boneh_durfee(pol, modulus, mm, tt, XX, YY):
"""
Boneh and Durfee revisited by Herrmann and May
finds a solution if:
* d < N^delta
* |x| < e^delta
* |y| < e^0.5
whenever delta < 1 - sqrt(2)/2 ~ 0.292
"""
## substitution (Herrman and May)
PR.<u, x, y> = PolynomialRing(ZZ)
Q = PR.quotient(x*y + 1 - u) ## u = xy + 1
polZ = Q(pol).lift()
UU = XX*YY + 1
## x-shifts
gg = []
for kk in range(mm + 1):
for ii in range(mm - kk + 1):
xshift = x^ii * modulus^(mm - kk) * polZ(u, x, y)^kk
gg.append(xshift)
gg.sort()
## x-shifts list of monomials
monomials = []
for polynomial in gg:
for monomial in polynomial.monomials():
if monomial not in monomials:
monomials.append(monomial)
monomials.sort()
## y-shifts (selected by Herrman and May)
for jj in range(1, tt + 1):
for kk in range(floor(mm/tt) * jj, mm + 1):
yshift = y^jj * polZ(u, x, y)^kk * modulus^(mm - kk)
yshift = Q(yshift).lift()
gg.append(yshift) ## substitution
## y-shifts list of monomials
for jj in range(1, tt + 1):
for kk in range(floor(mm/tt) * jj, mm + 1):
monomials.append(u^kk * y^jj)
## construct lattice B
nn = len(monomials)
BB = Matrix(ZZ, nn)
for ii in range(nn):
BB[ii, 0] = gg[ii](0, 0, 0)
for jj in range(1, ii + 1):
if monomials[jj] in gg[ii].monomials():
BB[ii, jj] = gg[ii].monomial_coefficient(monomials[jj]) * monomials[jj](UU,XX,YY)
## Prototype to reduce the lattice
if helpful_only:
## automatically remove
BB = remove_unhelpful(BB, monomials, modulus^mm, nn-1)
## reset dimension
nn = BB.dimensions()[0]
if nn == 0:
print("failure")
return 0,0
## check if vectors are helpful
if debug:
helpful_vectors(BB, modulus^mm)
## check if determinant is correctly bounded
det = BB.det()
bound = modulus^(mm*nn)
if det >= bound:
print("We do not have det < bound. Solutions might not be found.")
print("Try with highers m and t.")
if debug:
diff = (log(det) - log(bound)) / log(2)
print("size det(L) - size e^(m*n) = ", floor(diff))
if strict:
return -1, -1
else:
print("det(L) < e^(m*n) (good! If a solution exists < N^delta, it will be found)")
## display the lattice basis
if debug:
matrix_overview(BB, modulus^mm)
## LLL
if debug:
print("optimizing basis of the lattice via LLL, this can take a long time")
BB = BB.LLL()
if debug:
print("LLL is done!")
## transform vector i & j -> polynomials 1 & 2
if debug:
print("looking for independent vectors in the lattice")
found_polynomials = False
for pol1_idx in range(nn - 1):
for pol2_idx in range(pol1_idx + 1, nn):
## for i and j, create the two polynomials
PR.<w,z> = PolynomialRing(ZZ)
pol1 = pol2 = 0
for jj in range(nn):
pol1 += monomials[jj](w*z+1,w,z) * BB[pol1_idx, jj] / monomials[jj](UU,XX,YY)
pol2 += monomials[jj](w*z+1,w,z) * BB[pol2_idx, jj] / monomials[jj](UU,XX,YY)
## resultant
PR.<q> = PolynomialRing(ZZ)
rr = pol1.resultant(pol2)
## are these good polynomials?
if rr.is_zero() or rr.monomials() == [1]:
continue
else:
print("found them, using vectors", pol1_idx, "and", pol2_idx)
found_polynomials = True
break
if found_polynomials:
break
if not found_polynomials:
print("no independant vectors could be found. This should very rarely happen...")
return 0, 0
rr = rr(q, q)
## solutions
soly = rr.roots()
if len(soly) == 0:
print("Your prediction (delta) is too small")
return 0, 0
soly = soly[0][0]
ss = pol1(q, soly)
solx = ss.roots()[0][0]
#
return solx, soly
def example():
############################################
## How To Use This Script
##########################################
#
## The problem to solve (edit the following values)
#
## the modulus
N = 116518679305515263290840706715579691213922169271634579327519562902613543582623449606741546472920401997930041388553141909069487589461948798111698856100819163407893673249162209631978914843896272256274862501461321020961958367098759183487116417487922645782638510876609728886007680825340200888068103951956139343723
e = 113449247876071397911206070019495939088171696712182747502133063172021565345788627261740950665891922659340020397229619329204520999096535909867327960323598168596664323692312516466648588320607291284630435682282630745947689431909998401389566081966753438869725583665294310689820290368901166811028660086977458571233
## the public exponent
## the hypothesis on the private exponent (the theoretical maximum is 0.292)
delta = .27 ## this means that d < N^delta
#
## Lattice (tweak those values)
#
## you should tweak this (after a first run), (e.g. increment it until a solution is found)
m = 5 ## size of the lattice (bigger the better/slower)
## you need to be a lattice master to tweak these
t = int((1-2*delta) * m) ## optimization from Herrmann and May
X = 2*floor(N^delta) ## this _might_ be too much
Y = floor(N^(1/2)) ## correct if p, q are ~ same size
#
## Don't touch anything below
#
## Problem put in equation
P.<x,y> = PolynomialRing(ZZ)
A = int((N+1)/2)
pol = 1 + x * (A + y)
#
## Find the solutions!
#
## Checking bounds
if debug:
print("=== checking values ===")
print("* delta:", delta)
print("* delta < 0.292", delta < 0.292)
print("* size of e:", int(log(e)/log(2)))
print("* size of N:", int(log(N)/log(2)))
print("* m:", m, ", t:", t)
## boneh_durfee
if debug:
print("=== running algorithm ===")
start_time = time.time()
solx, soly = boneh_durfee(pol, e, m, t, X, Y)
## found a solution?
if solx > 0:
print("=== solution found ===")
if False:
print("x:", solx)
print("y:", soly)
d = int(pol(solx, soly) / e)
print("private key found:", d)
else:
print("=== no solution was found ===")
if debug:
print(("=== %s seconds ===" % (time.time() - start_time)))
if __name__ == "__main__":
example()
例题 2023领航杯 bd¶
task.py
from Crypto.Util.number import *
from secret import flag
p = getPrime(512)
q = getPrime(512)
n = p * q
d = getPrime(299)
e = inverse(d,(p-1)*(q-1))
m = bytes_to_long(flag)
c = pow(m,e,n)
hint1 = p >> (512-70)
hint2 = q >> (512-70)
print(f"n = {n}")
print(f"e = {e}")
print(f"c = {c}")
print(f"hint1 = {hint1}")
print(f"hint2 = {hint2}")
"""
n = 73337798113265277242402875272164983073482378701520700321577706460042584510776095519204866950129951930143711572581533177043149866218358557626070702546982947219557280493881836314492046745063916644418320245218549690820002504737756133747743286301499039227014032044403571945455215839074583290324966069724343874361
e = 42681919079074901709680276679968298324860328305878264036188155781983964226653746568102282190906458519960811259171162918944726137301701132135900454469634110653076655027353831375989861927565774719655974876907429954299669710134188543166679161864800926130527741511760447090995444554722545165685959110788876766283
c = 35616516401097721876690503261383371143934066789806504179229622323608172352486702183654617788750099596415052166506074598646146147151595929618406796332682042252530491640781065608144381326123387506000855818316664510273026302748073274714692374375426255513608075674924804166600192903250052744024508330641045908599
hint1 = 740477612377832718425
hint2 = 767891335159501447918
"""
这是一种利用上p,q高位的boneh-durfee,论文:367.pdf (iacr.org)
对大佬实验的脚本进行修改:Codes of the manuscript---Practical Attacks on Small Private Exponent RSA---New Records and New Insi - Pastebin.com
这类题没太搞懂原理,只能当个脚本小子先
exp
import time
time.clock = time.time
debug = True
strict = False
helpful_only = True
dimension_min = 7 ## 如果晶格达到该尺寸,则停止移除
## 显示有用矢量的统计数据
def helpful_vectors(BB, modulus):
nothelpful = 0
for ii in range(BB.dimensions()[0]):
if BB[ii,ii] >= modulus:
nothelpful += 1
print(nothelpful, "/", BB.dimensions()[0], " vectors are not helpful")
## 显示带有 0 和 X 的矩阵
def matrix_overview(BB, bound):
for ii in range(BB.dimensions()[0]):
a = ('%02d ' % ii)
for jj in range(BB.dimensions()[1]):
a += '0' if BB[ii,jj] == 0 else 'X'
if BB.dimensions()[0] < 60:
a += ' '
if BB[ii, ii] >= bound:
a += '~'
#print (a)
## 尝试删除无用的向量
## 从当前 = n-1(最后一个向量)开始
def remove_unhelpful(BB, monomials, bound, current):
## 我们从当前 = n-1(最后一个向量)开始
if current == -1 or BB.dimensions()[0] <= dimension_min:
return BB
## 开始从后面检查
for ii in range(current, -1, -1):
## 如果它没有用
if BB[ii, ii] >= bound:
affected_vectors = 0
affected_vector_index = 0
## 让我们检查它是否影响其他向量
for jj in range(ii + 1, BB.dimensions()[0]):
## 如果另一个向量受到影响:
## 我们增加计数
if BB[jj, ii] != 0:
affected_vectors += 1
affected_vector_index = jj
## 等级:0
## 如果没有其他载体最终受到影响
## 我们删除它
if affected_vectors == 0:
#print ("* removing unhelpful vector", ii)
BB = BB.delete_columns([ii])
BB = BB.delete_rows([ii])
monomials.pop(ii)
BB = remove_unhelpful(BB, monomials, bound, ii-1)
return BB
## 等级:1
#如果只有一个受到影响,我们会检查
## 如果它正在影响别的向量
elif affected_vectors == 1:
affected_deeper = True
for kk in range(affected_vector_index + 1, BB.dimensions()[0]):
## 如果它影响哪怕一个向量
## 我们放弃这个
if BB[kk, affected_vector_index] != 0:
affected_deeper = False
## 如果没有其他向量受到影响,则将其删除,并且
## 这个有用的向量不够有用
#与我们无用的相比
if affected_deeper and abs(bound - BB[affected_vector_index, affected_vector_index]) < abs(bound - BB[ii, ii]):
#print ("* removing unhelpful vectors", ii, "and", affected_vector_index)
BB = BB.delete_columns([affected_vector_index, ii])
BB = BB.delete_rows([affected_vector_index, ii])
monomials.pop(affected_vector_index)
monomials.pop(ii)
BB = remove_unhelpful(BB, monomials, bound, ii-1)
return BB
## nothing happened
return BB
"""
Returns:
* 0,0 if it fails
* -1,-1 如果 "strict=true",并且行列式不受约束
* x0,y0 the solutions of `pol`
"""
def boneh_durfee(pol, modulus, mm, tt, XX, YY):
"""
Boneh and Durfee revisited by Herrmann and May
在以下情况下找到解决方案:
* d < N^delta
* |x|< e^delta
* |y|< e^0.5
每当 delta < 1 - sqrt(2)/2 ~ 0.292
"""
## substitution (Herrman and May)
PR.<u, x, y> = PolynomialRing(ZZ) #多项式环
Q = PR.quotient(x*y + 1 - u) ## u = xy + 1
polZ = Q(pol).lift()
UU = XX*YY + 1
## x-移位
gg = []
for kk in range(mm + 1):
for ii in range(mm - kk + 1):
xshift = x^ii * modulus^(mm - kk) * polZ(u, x, y)^kk
gg.append(xshift)
gg.sort()
## 单项式 x 移位列表
monomials = []
for polynomial in gg:
for monomial in polynomial.monomials(): #对于多项式中的单项式。单项式():
if monomial not in monomials: ## 如果单项不在单项中
monomials.append(monomial)
monomials.sort()
## y-移位
for jj in range(1, tt + 1):
for kk in range(floor(mm/tt) * jj, mm + 1):
yshift = y^jj * polZ(u, x, y)^kk * modulus^(mm - kk)
yshift = Q(yshift).lift()
gg.append(yshift) ## substitution
## 单项式 y 移位列表
for jj in range(1, tt + 1):
for kk in range(floor(mm/tt) * jj, mm + 1):
monomials.append(u^kk * y^jj)
## 构造格 B
nn = len(monomials)
BB = Matrix(ZZ, nn)
for ii in range(nn):
BB[ii, 0] = gg[ii](0, 0, 0)
for jj in range(1, ii + 1):
if monomials[jj] in gg[ii].monomials():
BB[ii, jj] = gg[ii].monomial_coefficient(monomials[jj]) * monomials[jj](UU,XX,YY)
#约化格的原型
if helpful_only:
## #自动删除
BB = remove_unhelpful(BB, monomials, modulus^mm, nn-1)
## 重置维度
nn = BB.dimensions()[0]
if nn == 0:
print ("failure")
return 0,0
## 检查向量是否有帮助
if debug:
helpful_vectors(BB, modulus^mm)
## 检查行列式是否正确界定
det = BB.det()
bound = modulus^(mm*nn)
if det >= bound:
print ("We do not have det < bound. Solutions might not be found.")
print ("Try with highers m and t.")
if debug:
diff = (log(det) - log(bound)) / log(2)
print ("size det(L) - size e^(m*n) = ", floor(diff))
if strict:
return -1, -1
else:
print ("det(L) < e^(m*n) (good! If a solution exists < N^delta, it will be found)")
## display the lattice basis
if debug:
matrix_overview(BB, modulus^mm)
## LLL
if debug:
print ("optimizing basis of the lattice via LLL, this can take a long time")
#BB = BB.BKZ(block_size=25)
BB = BB.LLL()
if debug:
print ("LLL is done!")
## 替换向量 i 和 j ->多项式 1 和 2
if debug:
print ("在格中寻找线性无关向量")
found_polynomials = False
for pol1_idx in range(nn - 1):
for pol2_idx in range(pol1_idx + 1, nn):
## 对于i and j, 构造两个多项式
PR.<w,z> = PolynomialRing(ZZ)
pol1 = pol2 = 0
for jj in range(nn):
pol1 += monomials[jj](w*z+1,w,z) * BB[pol1_idx, jj] / monomials[jj](UU,XX,YY)
pol2 += monomials[jj](w*z+1,w,z) * BB[pol2_idx, jj] / monomials[jj](UU,XX,YY)
## 结果
PR.<q> = PolynomialRing(ZZ)
rr = pol1.resultant(pol2)
if rr.is_zero() or rr.monomials() == [1]:
continue
else:
print ("found them, using vectors", pol1_idx, "and", pol2_idx)
found_polynomials = True
break
if found_polynomials:
break
if not found_polynomials:
print ("no independant vectors could be found. This should very rarely happen...")
return 0, 0
rr = rr(q, q)
## solutions
soly = rr.roots()
if len(soly) == 0:
print ("Your prediction (delta) is too small")
return 0, 0
soly = soly[0][0]
ss = pol1(q, soly)
solx = ss.roots()[0][0]
return solx, soly
def example():
############################################
## 随机生成数据
##########################################
#start_time =time.perf_counter
start =time.clock()
size = 512
length_N = 2*size
ss = 0
s = 70
M = 1 ## the number of experiments
delta = 299/1024
for i in range(M):
## p = random_prime(2^size,None,2^(size-1))
## q = random_prime(2^size,None,2^(size-1))
## if(p<q):
## temp=p
## p=q
## q=temp
N = 73337798113265277242402875272164983073482378701520700321577706460042584510776095519204866950129951930143711572581533177043149866218358557626070702546982947219557280493881836314492046745063916644418320245218549690820002504737756133747743286301499039227014032044403571945455215839074583290324966069724343874361
e = 42681919079074901709680276679968298324860328305878264036188155781983964226653746568102282190906458519960811259171162918944726137301701132135900454469634110653076655027353831375989861927565774719655974876907429954299669710134188543166679161864800926130527741511760447090995444554722545165685959110788876766283
hint1 = 740477612377832718425 ## p高位
hint2 = 767891335159501447918 ## q高位
## print ("p真实高",s,"比特:", int(p/2^(512-s)))
## print ("q真实高",s,"比特:", int(q/2^(512-s)))
## N = p*q;
## 解密指数d的指数( 最大0.292)
m = 7 ## 格大小(越大越好/越慢)
t = round(((1-2*delta) * m)) ## 来自 Herrmann 和 May 的优化
X = floor(N^delta) ##
Y = floor(N^(1/2)/2^s) ## 如果 p、 q 大小相同,则正确
for l in range(int(hint1),int(hint1)+1):
print('\n\n\n l=',l)
pM=l;
p0=pM*2^(size-s)+2^(size-s)-1;
q0=N/p0;
qM=int(q0/2^(size-s))
A = N + 1-pM*2^(size-s)-qM*2^(size-s);
#A = N+1
P.<x,y> = PolynomialRing(ZZ)
pol = 1 + x * (A + y) #构建的方程
## Checking bounds
#if debug:
#print ("=== 核对数据 ===")
#print ("* delta:", delta)
#print ("* delta < 0.292", delta < 0.292)
#print ("* size of e:", ceil(log(e)/log(2))) ## e的bit数
## print ("* size of N:", len(bin(N))) ## N的bit数
#print ("* size of N:", ceil(log(N)/log(2))) ## N的bit数
#print ("* m:", m, ", t:", t)
## boneh_durfee
if debug:
##print ("=== running algorithm ===")
start_time = time.time()
solx, soly = boneh_durfee(pol, e, m, t, X, Y)
if solx > 0:
#print ("=== solution found ===")
if False:
print ("x:", solx)
print ("y:", soly)
d_sol = int(pol(solx, soly) / e)
ss=ss+1
print ("=== solution found ===")
print ("p的高比特为:",l)
print ("q的高比特为:",qM)
print ("d=",d_sol)
if debug:
print("=== %s seconds ===" % (time.time() - start_time))
#break
print("ss=",ss)
#end=time.process_time
end=time.clock()
print('Running time: %s Seconds'%(end-start))
if __name__ == "__main__":
example()
十九、一些和数论推导相关的题目¶
1.hint = pow(ap+b,q,n)¶
task.py
import libnum
import gmpy2
import uuid
from Crypto.Util.number import *
flag = "flag{" + str(uuid.uuid4()) + "}"
m = libnum.s2n(flag)
e = 65537
p = getPrime(1024)
q = getPrime(1024
n = p * q
c = pow(m, e, n)
hint = pow(2020 * p + 2021, q, n)
print(f'n={n}')
print(f'c={c}')
print(f'hint={hint}')
把hint展开
模\(p\)能得到
两边同时取p次方
即
p = gcd(pow(2021,n,n) - hint,n)
exp
from Crypto.Util.number import *
import gmpy2
n = 27020725261160598541077357737650775795182555998856810737571508044949928734067444441660366270392732456051807439301564552672200975582350577967001486740668193835704559129378410828266554536148151615878808327988333060924165410762016082268322936465413880236634083213834739549234631742766416876749808978934944262651307600621868854944164060642189749365967978497831698002669974744487926082412272998646851047638183126945784060957075393737537570645086672473571281053798891685646561828588448040073373363454584468753860529849749093081434144360661566815886630699933232263079413562069476421802192735693386029862725050469209845710383
c = 10188807385387617708190575473905502994151677148079820873886980571555051900701810208218351138721306416600688313703084580808183634201231599134123549448962443376514560489130860694363901933597676373555599555647232128717993571185822894818704143675318690577221330618533739592165564396729937983659337232822442555504262694675199751730664450120569727835850996566436129543730932040989365233424791093843941154003052950306359994891955336607690065213304872738280674213630736611351982705373394299097653653497017756036211550125607093109216729483090391729134062236908282557149575812220142872855836932590459512028618076264332235518829
hint = 15179972145975733285419381814235528011288991423484121653543845156913121513320504879647666067298415751234264897435338898933073713420024176276221164394369781676781604128149168834126855517212300158864797800121336042194751965268493010327202598446572764475343894613152062609436699715193914479572113800212525965140106015838636914979735618606768207651697548364440806425770871133439416876157686985836939255598747973339866125864303982956813846287509191028829738926404992619459242904729015823730553526572575372668559669124599614613391797015393641171177282129497503752370800088634017972208535899870704612274473042064675033593148
e = 65537
p = gmpy2.gcd(pow(2021,n,n)-hint,n)
q = n // p
d = gmpy2.invert(e,(p-1)*(q-1))
m = pow(c,d,n)
print(long_to_bytes(m))
2.hint = pow(ap+b,e,n)¶
task.py
import gmpy2
import libnum
import uuid
flag = "flag{" + str(uuid.uuid4()) + "}"
print(flag)
m = libnum.s2n(flag)
p = libnum.generate_prime(512)
q = libnum.generate_prime(512)
e = 65537
n = p * q
h = 20211102
hc = pow(h + p * 1111, e, n)
c = pow(m, e, n)
print("hc=", hc)
print("n=", n)
print("c=", c)
hc = 71505320953946158049530109094654497075489963071106175336722892393493112481336409391299522595724154571954223093317880494307263262649833222750675105885636892419350501821324979706283867758665536771783209816719106279467902518895579024290387800216711663670572861182058425925280993190282267615052256942516011995207
n = 76856511192427852645963041043072791148703422665129663050712492700760489247788743818199589072069758934570218804936479267319288093436111548055922916898782764333246946326823653877357695179165138863843657328764265204547147092074499832221138997131011222722917338444675582832114206750168113207646100633238664244737
c = 39246179387125192271554620313966311736032348078183121707012959204367908070472764506984235827179206718838172586811066682034907967943722841257765922283692526422653916506577810629430853963448057701574209912936660396486847365579797147723437378122880075493171892191049105237005801787649587080840600670585409293046
两边模p得到
p = gcd(pow(b,e,n)-hint,n)
exp
from Crypto.Util.number import *
import gmpy2
hint = 71505320953946158049530109094654497075489963071106175336722892393493112481336409391299522595724154571954223093317880494307263262649833222750675105885636892419350501821324979706283867758665536771783209816719106279467902518895579024290387800216711663670572861182058425925280993190282267615052256942516011995207
n = 76856511192427852645963041043072791148703422665129663050712492700760489247788743818199589072069758934570218804936479267319288093436111548055922916898782764333246946326823653877357695179165138863843657328764265204547147092074499832221138997131011222722917338444675582832114206750168113207646100633238664244737
c = 39246179387125192271554620313966311736032348078183121707012959204367908070472764506984235827179206718838172586811066682034907967943722841257765922283692526422653916506577810629430853963448057701574209912936660396486847365579797147723437378122880075493171892191049105237005801787649587080840600670585409293046
e = 65537
b = 20211102
p = gmpy2.gcd(pow(b,e,n)-hint,n)
q = n // p
d = gmpy2.invert(e,(p-1)*(q-1))
m = pow(c,d,n)
print(long_to_bytes(m))
3.q = inverse(e,p)¶
task.py
import gmpy2
import libnum
import uuid
flag = "flag{" + str(uuid.uuid4()) + "}"
m = libnum.s2n(flag)
e = 65537
while 1:
p = libnum.generate_prime(512)
q = libnum.invmod(e, p)
if gmpy2.is_prime(q):
break
n=p*q
c=pow(m,e,n)
print("n=",n)
print("c=",c)
所以有
两边同时乘\(p\)
这个k和e差不多大,在e不太大的情况下可以枚举k解这个方程
还有个方法就是
从\(en = kp^2 + 1\),凑出\(4ken + 1 = (2kp+1)^2\)
所以\(p = \frac{(4ken+1)^{\frac{1}{2}}-1}{2k}\)
exp.py
from Crypto.Util.number import *
import gmpy2
n = 58204114420266684815970658378327773998564393394613074044159240444415512492622689982761518905542522328879289101538953676661805875053162972893258897360344016406294652339343767887745752686437325346837603712186500309908703326587069304255508650910107794737000566778637055164127273830551001009133332601839918695739
c = 43430611858598126654595145883807180034546121754009334579568652220639483233618841529702503298293207886941913478597477904682701187000781983315547295293641024286170190626012102497319037012751300959255076727985925313853559910457404758461819072120343343943528618993507783981659418177044469142912677141806591464788
e = 65537
for k in range(1,e):
t = gmpy2.iroot((4*k*e*n + 1),2)
if t[1]:
p = (t[0]-1) // (2*k)
q = n // p
d = gmpy2.invert(e,(p-1)*(q-1))
m = pow(c,d,n)
print(long_to_bytes(m))
break
4.pow(m,p,n)和pow(m,q,n)¶
task.py
import libnum
import uuid
flag = "flag{" + str(uuid.uuid4()) + "}"
m=libnum.s2n(flag)
p=libnum.generate_prime(512)
q=libnum.generate_prime(512)
n=p*q
x=pow(m,p,n)
y=pow(m,q,n)
print("n=",n)
print("x=",x)
print("y=",y)
由费马小定理得
同理
即
相乘之后得到
再次化简
然后用copper解
exp.sage
from Crypto.Util.number import *
n = 119168018353396473071220326930634033296857570351877525203349067654228903288865563346158289110924833018314600851680403536994000145188490252887831026813814036968773088160020677568623347649228357482873911613625537196000702331852604517461327776409524836030721808860499640682583008287503643735346752806150919473547
x = 20889450245206188360163017466832661797042512279294313816641964974342193835127401896327018708629718120262511077145232274218469726065543657294173612852238031375768722870519066517281989421725687761586428233882899166319861093186744865410310768961853709659722549327714475931676224727563796969392665870925936060875
y = 32080707538492572190029237251694217148237404571842762312567934187316746458298295007401945958852986479911593108750816992042333214302313415615710205763277908672519589955718578006218124903939275787171888825356704546781455848117466648569999021535956085557973651213126679157398458139672913801297571585910183741493
R.<m> = PolynomialRing(Zmod(n))
f = x*y - m^2 - m*(x - m + y - m)
f = f.monic()
root = f.small_roots(X=2^336)
if root != []:
print(long_to_bytes(int(root[0])))
5.leak = d + p¶
task.py
from Crypto.Util.number import *
import uuid
flag = "flag{" + str(uuid.uuid4()) + "}"
m = bytes_to_long(flag.encode())
p = getPrime(512)
q = getPrime(512)
n = p * q
e = 65537
d = inverse(e,(p-1)*(q-1))
leak = d + p
c = pow(m,e,n)
print(f"leak = {leak}")
print(f"c = {c}")
print(f"n = {n}")
同时乘上e
则
p = gcd(pow(2,e*leak,n) - pow(2,e+1,n),n)
exp.py
from Crypto.Util.number import *
import gmpy2
leak = 43773730595208010615167769243389712919043986781372553925103531305753192121900940758872887224717935746491356121136709395293427821519713664465479239343568683512805566797519940659245386786069452631897152582632812964236464253538638932777814445952543179981728372597574240011522586022744496408528369815424689627714
c = 32609109759602838902299290553935199233727818772965249106067660946940666082748851189532358246129713630287421754985189526470019256048805899987261287835158990237267846168718587057488187109882012577904592602367187436017302897260666096753156638501800052563311351183911829268477864436682312113353547663292164618797
n = 73687428902140845363357908478989818544523419338611246958530518113252515978963884581173646615800353308789787478447973996695401703969420384980841285031836556985268236880854319562700104921035182736733530699304849659644263120110205601793351720111745179867010541532557489688430577820860370652773129870929371931513
e = 65537
p = gmpy2.gcd(pow(2,leak * e,n) - pow(2,e + 1,n),n)
q = n // p
d = gmpy2.invert(e,(p-1)*(q-1))
m = pow(c,d,n)
print(long_to_bytes(m))
接下来三个题型来源于2023 数据安全产业人才能力挑战赛---math_exam
6.leak = (n + p) % (q-1)¶
task.py
import libnum
import uuid
flag = "flag{" + str(uuid.uuid4()) + "}"
m=libnum.s2n(flag)
p=libnum.generate_prime(512)
q=libnum.generate_prime(512)
if p <= q:
p, q = q, p
e = 0x10001
n = p * q
c = pow(m, e, n)
leak = (n + p) % (q-1)
print(f'{e = }')
print(f'{c = }')
print(f'{n = }')
print(f'{leak = }')
#e = 65537
#c = 846622880180923496523897101093587388412673197929101816777894080453907929979417582433675846206418833989406082027835614960931951892393700870678469052366477889491688459558189367255658278968722099012534045477993924284003153851171132420751750724394405070269223797513951991873714156884423926582172189394011114952
#n = 159452716285492879108396025652299064897348745847754101475050126796260046052685162344131542880739092630022413124977374334652652450809186959288635651980201026825896903174847709657312399801033678426271413442323084354665643010763178857967804623680894444913369256168333223214048037661178587978535722147091129404833
#leak = 2669103705669857828725305123419482758456336465207378766363532584323475128597302561377245054918781031448710846825859151788151496659511563529987056456136018
即
题目确定了\(p > q\)
再联立\(n = p \times q\)解方程即可分解n
exp.py
from Crypto.Util.number import *
from sympy import solve,symbols
import gmpy2
e = 65537
c = 846622880180923496523897101093587388412673197929101816777894080453907929979417582433675846206418833989406082027835614960931951892393700870678469052366477889491688459558189367255658278968722099012534045477993924284003153851171132420751750724394405070269223797513951991873714156884423926582172189394011114952
n = 159452716285492879108396025652299064897348745847754101475050126796260046052685162344131542880739092630022413124977374334652652450809186959288635651980201026825896903174847709657312399801033678426271413442323084354665643010763178857967804623680894444913369256168333223214048037661178587978535722147091129404833
leak = 2669103705669857828725305123419482758456336465207378766363532584323475128597302561377245054918781031448710846825859151788151496659511563529987056456136018
p = symbols('p')
q = symbols('q')
eq1 = 2*(p-q+1) - leak
eq2 = p*q - n
solution = solve((eq1,eq2),(p,q))
print(solution)
p = int(solution[1][0])
q = int(solution[1][1])
d = gmpy2.invert(e,(p-1)*(q-1))
m = pow(c,d,n)
print(long_to_bytes(m))
7.leak = d + p + q¶
task.py
import libnum
import uuid
flag = "flag{" + str(uuid.uuid4()) + "}"
m=libnum.s2n(flag)
p=libnum.generate_prime(512)
q=libnum.generate_prime(512)
e = 0x10001
n = p * q
c = pow(m, e, n)
d=libnum.invmod(e,(p-1)*(q-1))
leak = d+p+q
print(f'{e = }')
print(f'{c = }')
print(f'{n = }')
print(f'{leak = }')
#e = 65537
#c = 65194823373091792824101730983124740337276083358867621564067880339279446092377567969207237986613196892737474455781661885696122256698478429450971196633786693648866129636737262041654769618993094832127875251068775632567036646408374963058703320605733921797230106462440860984746880466416824674570639694481298708147
#n = 101929257180069933443442160085713121307068880188090652033345240568607589666231813199686824369361640378636124324844158355533056421197926269617986872835671463371353540696806173813019752742218460997272803573114119876536384486655117245296360474103378827486280279523273344156760793016731778663058274770626116861407
#leak = 87007773233816810147344015772388866522443114032719766646343787373996588014373656496789294836431302130125588646180886383013958151442324020038131736683796464202667423644714259545194662934238144990354387370533656134036753530002005551694211595695927699196016268145816389892292091218491443784193805171731592693841
则
因为\(\phi(n) = n - (p+q) + 1\)
exp.py
from Crypto.Util.number import *
c = 65194823373091792824101730983124740337276083358867621564067880339279446092377567969207237986613196892737474455781661885696122256698478429450971196633786693648866129636737262041654769618993094832127875251068775632567036646408374963058703320605733921797230106462440860984746880466416824674570639694481298708147
n = 101929257180069933443442160085713121307068880188090652033345240568607589666231813199686824369361640378636124324844158355533056421197926269617986872835671463371353540696806173813019752742218460997272803573114119876536384486655117245296360474103378827486280279523273344156760793016731778663058274770626116861407
leak = 87007773233816810147344015772388866522443114032719766646343787373996588014373656496789294836431302130125588646180886383013958151442324020038131736683796464202667423644714259545194662934238144990354387370533656134036753530002005551694211595695927699196016268145816389892292091218491443784193805171731592693841
m = pow(c,leak - n - 1,n)
print(long_to_bytes(m))
8.leak = pow(p,q,n) + pow(q,p,n) % n¶
task.py
import libnum
import uuid
flag = "flag{" + str(uuid.uuid4()) + "}"
m=libnum.s2n(flag)
p=libnum.generate_prime(512)
q=libnum.generate_prime(512)
e = 0x10001
n = p * q
c = pow(m, e, n)
leak = (pow(p, q, n) + pow(q, p, n)) % n
print(f'{e = }')
print(f'{c = }')
print(f'{n = }')
print(f'{leak = }')
由费马小定理得
即
然后
或者解方程
exp.py
from Crypto.Util.number import *
import gmpy2
e = 65537
c = 59662555342583061013008608133060203475725526601468647442902301335538953096485921516133656618941085620436784211565880744663573927593670579237831797055934897166262528476227281479029026508166848256301828084036716500159067642101104810756620735383857351274773983199968924981397675373272878756685629789497697821620
n = 83332115751539889489689110273690067288993797655970253065863170986174973047785854940017477990345318506407680986257706329521142524295434171889087917406552261883625775754882538291980506944585738241124811588555071095223782766762626040473256423491630224616140407276984106458673447870374272906086783555489477673207
leak = 18881487897809480964326513919135880296801378921812225600834164247018332292886076618571738627353925482046410714540439662613766662197119044934743578662330528
p_q = gmpy2.iroot(leak ** 2 - 4 * n,2)[0]
p = (leak + p_q) // 2
q = n // p
d = gmpy2.invert(e,(p-1)*(q-1))
m = pow(c,d,n)
print(long_to_bytes(m))
2023数据安全产业人才能力挑战赛——math_exam¶
task.py
import os
from Crypto.Util.number import *
from secret import flag
bits = 512
def pad(msg, length):
pad_length = length - len(msg) - 1
pad_data = os.urandom(pad_length)
return msg + b'\x00' + pad_data
def unpad(msg):
return msg.split(b"\x00")[0]
def challenge1(m):
p, q = [getPrime(bits) for i in range(2)]
if p <= q:
p, q = q, p
e = 0x10001
n = p * q
c = pow(m, e, n)
leak = (n + p) % (q-1)
print('-------- challenge 1 --------')
print(f'{e = }')
print(f'{c = }')
print(f'{n = }')
print(f'{leak = }')
def challenge2(m):
p, q = [getPrime(bits) for i in range(2)]
e = 0x10001
n = p * q
d = inverse(e, (p-1)*(q-1))
c = pow(m, e, n)
leak = d + p + q
print('-------- challenge 2 --------')
print(f'{e = }')
print(f'{c = }')
print(f'{n = }')
print(f'{leak = }')
def challenge3(m):
p, q = [getPrime(bits) for i in range(2)]
e = 0x10001
n = p * q
c = pow(m, e, n)
leak = (pow(p, q, n) + pow(q, p, n)) % n
print('-------- challenge 3 --------')
print(f'{e = }')
print(f'{c = }')
print(f'{n = }')
print(f'{leak = }')
assert len(flag) == 42
ms = []
for i in range(0, 42, 14):
ms.append(bytes_to_long(pad(flag[i:i+14], bits//4-1)))
m1, m2, m3 = ms
challenge1(m1)
challenge2(m2)
challenge3(m3)
"""
-------- challenge 1 --------
e = 65537
c = 112742443814287255411540092433156061065388404049949520959549377871297566383025041892192679147481155020865118811016470498351633875090973546567374001852295013083192495299811476604405637385307524194793969533646755764136014187430115618114840780368311166911900457224593131166970676797547489278410997707815915932756
n = 121127425328043404860413278637978444801342472819958112597540188142689720655042880213001676368390521140660355813910726809125567752172921410143437643574528335234973793653775043030021036875866776532570781661875022102733555943967261003246543180935987772711036868216508554536086688819118597075508026787867088355603
leak = 216638862637129382765636503118049146067015523924032194492700294200289728064297722088882791754351329407138196573832392846467607399504585045028165699421278
-------- challenge 2 --------
e = 65537
c = 7964477910021153997178145480752641882728907630831216554750778499596527781702830885213467912351097301767341858663701574005489585561370961723264247818377063081744522471774208105250855114831033452448184392499682147532404562876275189577321587660597603848038824026981539659156304028998137796242331160312370913038
n = 140571013522095816880929287025269553867630639381779595547026503691829940612178900269986625350464874598461222087427155791855120339533208468121389480964471710028253589422629569889402475311387750348466199387760629889238062977271925350490110043385800605640905324122017637306715108727700910035925728362455954862209
leak = 58442382248753295429370894053397615609981110383986887405127350139482893508400422595729520437678203735054593866306478994471465948872565590901376309380029015549809468112086393107585011072503638322671608471684607214064187044372418770555236721845694224676090744181562673509234801011420696349507624867568099759003
-------- challenge 3 --------
e = 65537
c = 54161995127842474543974770981473422085334044100057089719350274921419091368361244533281599379235907845996678762379778310924192757650322930707785543132446159092950451255660204858292974657119337026589911330412367633761103944916751660957776230135927005700707688661350641600954072696774954805514477330339449799540
n = 88207747624007183083381863279444163105330473097729276113333026679597864128605555600000789783468271680476780366740448641311570797876037993255307716167149079618302706650018518487351604778857406170722209469765782625409279109832638886179654096975665134276856272488090272822541461702907181545730309689190333058151
leak = 19596671928335648228117128090384865424885102632642665068992144783391306491716530155291726644158221224616817878768426330717188403310818678195631582453246848
"""
exp.py
from sympy import symbols,solve
from Crypto.Util.number import *
import gmpy2
e = 65537
c1 =
n1 =
leak1 =
p1 = symbols('p1')
q1 = symbols('q1')
eq1 = 2*(p1-q1+1)-leak1
eq2 = p1 * q1- n1
solution1 = solve((eq1,eq2),(p1,q1))
p1,q1 = int(solution1[1][0]),int(solution1[1][1])
d1 = gmpy2.invert(e,(p1-1)*(q1-1))
m1 = pow(c1,d1,n1)
flag1 = long_to_bytes(m1)[:14]
c2 =
n2 =
leak2 =
tmp = leak2 - n2 -1
m2 = pow(c2,tmp,n2)
flag2 = long_to_bytes(m2)[:14]
c3 =
n3 =
leak3 =
p3 = symbols('p3')
q3 = symbols('q3')
eq3 = p3 + q3 - leak3
eq4 = p3 * q3 - n3
solution3 = solve((eq3,eq4),(p3,q3))
p3,q3 = int(solution3[0][0]),int(solution3[0][1])
d3 = gmpy2.invert(e,(p3-1)*(q3-1))
m3 = pow(c3,d3,n3)
flag3 = long_to_bytes(m3)[:14]
flag = flag1 + flag2 + flag3
print(flag)
二十、剪枝相关¶
1.gift = p ^ q¶
题目来源:2023陕西省技能大赛——奇怪得asr
task.py
from Crypto.Util.number import *
key = 'flag{**********}'
bits = 1024
msg = bytes_to_long(key.encode())
e = 65537
p = getPrime(bits)
q = getPrime(bits)
n = p * q
def encrypt1(msg, e, n):
c = pow(msg, e, n)
return c
seed = p ^ q
a = getPrime(bits)
b = getPrime(bits)
n1 = getPrime(bits)
def encrypt2(seed):
enc = []
for i in range(10):
seed = (a * seed + b) % n1
enc.append(seed)
return enc
c = encrypt1(msg, e, n)
enc = encrypt2(seed)
print("n = ", n)
print("c = ", c)
print("n1 = ", n1)
print("enc = ", enc)
n = 24044063028844014127418595700558729326190738802687551098858513077613750188240082663594575453404975706225242363463089392757425008423696150244560748490108425645064339883915929498539109384801415313004805586193044292137299902797522618277016789979196782551492020031695781792205215671106103568559626617762521687128199445018651010056934305055040748892733145467040663073395258760159451903432330506383025685265502086582538667772105057401245864822281535425692919273252955571196166824113519446568745718898654447958192533288063735350717599092500158028352667339959012630051251024677881674246253876293205648190626145653304572328397
c = 14883053247652228283811442762780942186987432684268901119544211089991663825267989728286381980568977804079766160707988623895155236079459150322336701772385709429870215701045797411519212730389048862111088898917402253368572002593328131895422933030329446097639972123501482601377059155708292321789694103528266681104521268192526745361895856566384239849048923482217529011549596939269967690907738755747213669693953769070736092857407573675987242774763239531688324956444305397953424851627349331117467417542814921554060612622936755420459029769026126293588814831034143264949347763031994934813475762839410192390466491651507733968227
n1 = 137670797028117726329534659376416493367957852768263083700434198723955223922183386928456013703791817601151754417828367188186912209697081337658512940425529211281290630976671911327606706953154608427885071841566358882014021242768190762103365969320014710368160869517966437591299370072284930202718943785099916898209
enc = [101737402423360536260958229788866250367716256968287178187558336481872788309727545478736771692477306412259739856568227009850831432381180909815512654609798228982433082928392936844193974517574281026029228179913579225687286945054175762659252515268270399329404664775893089132101252158524000295899895962104782878103, 37355684997487259669354747104430314505839306993101096210478266975184357608742619438151118843905165289324251734149329596611854110739738607745107961453008343886403511257039401245484528985856920723694142989180291902939107642020398816995584650913417698279936585230648639613028793148102494100898288564799111024672, 58677759595639211550435023449462812079890625834313820227189340593596480924226619376872336960357021314847975570175387751632125898437020801920862764666175594874885587518469384576361008639967382152477408865298759987606155830674598034578657554841283906976808719095766296677147076808250022898199866472085742989883, 61841632061818470036288407041172200048676249787061823756736224887116113640875444187463656719652972233582538657844183320242896612625995507633237074900538692102956750184024574603018257213912795847625926653585010890014291951218199774765624860625726555381815237888483974246173727262881650634287497285246796321130, 7618244158597756867387754433401378508070531356170836765779245254233413235386172690733378371343899289510629513166609513857423499004879497768588665836034791151090648182168421570449377835494883902907064269417199065924565304966242954268460876762295575715334403142360198583318323418975108290758222653083011275844, 106276841058222138994123556391380518368163552919305398852484130331884811278068151915582752795463570013359693610495645946230044828403849434903415989487924763756589202218361370725532394478569304449884620166937809374355282324069422109879874964479199929174533104879048175102339134830614476339153367475243140156049, 54574757236475194407137831004617398270525645136836468973535243574661043352422598443323384197261529289829451787586618886007968913414366545291507686451774653217577858375086817168124727394445167274831801876424578654786480330913650363551771258617533162477541882336257099777912519011890593910515860435759936717781, 15567087904962670212229825713697043597876172881256160613623383896576159414077875401117959132252949501643234465895697270909085179587988268864498823765197994781747034644583869111599516151129007414228897958635533561248099927507725880289417298814703767549313482346652043188826434944367260731729064673486516315207, 10757138067445225320504771816863593606847219020279502671965413470243269270456133564739090471033889069283122519782525412134604896073598293410977787230108853737796640474070194546344190858079847734817109910030714675258996740807873872365037296486121580542250452443305370358407408558223735250474249180772656905880, 68097848963949068260912124852455363245291187860801223898468533992003737157497436432969031551088942445561676359631354280979357356539429863946694570097104716411407829017684705171462511875250672979623888463245258237680782731827727876526411531354910982579164963119481534453651300645314177478026462894232377307020]
先通过LCG求出seed,然后剪枝得到p,q。LCG就不过多赘述了
exp.py
from Crypto.Util.number import *
import sys
sys.setrecursionlimit(3000)
gift = 39428646082513135314545544161912595458975375891528176714825766497155482031976852156313956476772023258684487799640179241987139554034654104867011313090105438798561154654679825702410748780286094326639330840289843154525176685892323447168072417654823748596238888125898914210332775882916911771786984574407163323116
N = 24044063028844014127418595700558729326190738802687551098858513077613750188240082663594575453404975706225242363463089392757425008423696150244560748490108425645064339883915929498539109384801415313004805586193044292137299902797522618277016789979196782551492020031695781792205215671106103568559626617762521687128199445018651010056934305055040748892733145467040663073395258760159451903432330506383025685265502086582538667772105057401245864822281535425692919273252955571196166824113519446568745718898654447958192533288063735350717599092500158028352667339959012630051251024677881674246253876293205648190626145653304572328397
c = 14883053247652228283811442762780942186987432684268901119544211089991663825267989728286381980568977804079766160707988623895155236079459150322336701772385709429870215701045797411519212730389048862111088898917402253368572002593328131895422933030329446097639972123501482601377059155708292321789694103528266681104521268192526745361895856566384239849048923482217529011549596939269967690907738755747213669693953769070736092857407573675987242774763239531688324956444305397953424851627349331117467417542814921554060612622936755420459029769026126293588814831034143264949347763031994934813475762839410192390466491651507733968227
## 低位往高位爆
def findp(p,q):
if len(p) == 1024:
pp = int(p,2)
if N % pp == 0:
print("p = ",pp)
print("q = ",N // pp)
qq = N // pp
d = inverse(65537,(pp-1)*(qq-1))
m = pow(c,d,N)
print(long_to_bytes(m))
return
else:
l = len(p)
pp = int(p,2)
qq = int(q,2)
if (pp ^ qq) % (2 ** l) == gift % (2 ** l) and pp * qq % (2 ** l) == N % (2**l):
findp('1' + p,'1' + q)
findp('1' + p,'0' + q)
findp('0' + p,'1' + q)
findp('0' + p,'0' + q)
findp('1','1')
## flag{y0u_kn0w_Pruning_and_lcg}
2.gift = p ^ (q >> 16)¶
题目来源:2023DASCTF暑期挑战赛——EzRSA
task.py
from Crypto.Util.number import *
from secret import secret, flag
def encrypt(m):
return pow(m, e, n)
assert flag == b"dasctf{" + secret + b"}"
e = 11
p = getPrime(512)
q = getPrime(512)
n = p * q
P = getPrime(512)
Q = getPrime(512)
N = P * Q
gift = P ^ (Q >> 16)
print(N, gift, pow(n, e, N))
print(encrypt(bytes_to_long(secret)),
encrypt(bytes_to_long(flag)))
N = 75000029602085996700582008490482326525611947919932949726582734167668021800854674616074297109962078048435714672088452939300776268788888016125632084529419230038436738761550906906671010312930801751000022200360857089338231002088730471277277319253053479367509575754258003761447489654232217266317081318035524086377
gift = 8006730615575401350470175601463518481685396114003290299131469001242636369747855817476589805833427855228149768949773065563676033514362512835553274555294034
pow(n,e,N) = 14183763184495367653522884147951054630177015952745593358354098952173965560488104213517563098676028516541915855754066719475487503348914181674929072472238449853082118064823835322313680705889432313419976738694317594843046001448855575986413338142129464525633835911168202553914150009081557835620953018542067857943
pow(secret,e,n) = 69307306970629523181683439240748426263979206546157895088924929426911355406769672385984829784804673821643976780928024209092360092670457978154309402591145689825571209515868435608753923870043647892816574684663993415796465074027369407799009929334083395577490711236614662941070610575313972839165233651342137645009
pow(flag,e,n) = 46997465834324781573963709865566777091686340553483507705539161842460528999282057880362259416654012854237739527277448599755805614622531827257136959664035098209206110290879482726083191005164961200125296999449598766201435057091624225218351537278712880859703730566080874333989361396420522357001928540408351500991
思路很清晰,先分解N,解RSA得到n,再富兰克林相关消息攻击求解flag。
这里只展示剪枝分解N
exp
import sys
from tqdm import *
sys.setrecursionlimit(3000)
gift = 8006730615575401350470175601463518481685396114003290299131469001242636369747855817476589805833427855228149768949773065563676033514362512835553274555294034
N = 75000029602085996700582008490482326525611947919932949726582734167668021800854674616074297109962078048435714672088452939300776268788888016125632084529419230038436738761550906906671010312930801751000022200360857089338231002088730471277277319253053479367509575754258003761447489654232217266317081318035524086377
## 低位往高位爆
def findp(p,q):
if len(p) == 512:
pp = int(p,2)
if N % pp == 0:
print("p = ",pp)
print("q = ",N // pp)
else:
l = len(p)
pp = int(p,2)
qq = int(q,2)
if (pp ^ (qq >> 16)) % (2 ** l) == gift % (2 ** l) and pp * qq % (2 ** l) == N % (2 ** l):
findp('1' + p,'1' + q)
findp('1' + p,'0' + q)
findp('0' + p,'1' + q)
findp('0' + p,'0' + q)
for i in trange(2**16,2**17):
findp('1',bin(i)[2:])
"""
p = 8006847171912577069085166877758626954304824756138758266557706391662987806065132448544117840031499707938227955094109779732609035310252723066470330862622641
q = 9366986529377069783394625848920106951220134111548343265311677163992169555436421569730703291128771472885865288798344038000984911921843088200997725324682297
"""
3.不会取名字¶
题目来源:2024HDCTF——ezrsa
task.py
from Crypto.Util.number import *
import random
import hashlib
from secret import flag
gen1 = lambda bits=1024, rand=lambda n: bytes(random.getrandbits(1) for _ in range(n)): (getPrime(bits//2, randfunc=rand), getPrime(bits//2, randfunc=rand))
gen2 = lambda alpha=512, K=500, T=getPrime(506): next(((p, q, T) for q, r in [(getPrime(alpha), getPrime(alpha))] for k in range(2, K+1) if (isPrime(p := r + (k * q - r) % T))), None)
p1,q1=gen1()
p2, q2, T = gen2()
assert flag == "DASCTF{" + hashlib.md5(str(p1 + p2 + q1 + q2).encode()).hexdigest() + "}"
print(p1*q1)
print((p2*q2,T))
## 44945076854246685060397710825960160082061127479194994041436997195972585701097443198954359213635892234058786065342178389181538153413878118039445271277476379366294977408981257175008890470376094381644530106799352839565803317977637572325347776636285703517680754624094985374606187797141657688145287340444623176193
## (57784854392324291351358704449756491526369373648574288191576366413179694041729248864428194536249209588548791706980878177790271653262097539281383559433402738548851606776347237650302071287124974607439996041713554182180186588308614458904981542909792071322939678815174962366963098166320441995961513884899917498099, 150514823288951667574011681197229106951781617714873679347685702558528178681176081082658953342482323349796111911103531429615442550000291753989779754337491)
这里仅对gen1()这部分讲解
gen1()
,关键就是把getPrime(bits,randfunc=None)
改成了getPrime(bits,randfunc=rand)
我不太清楚randfunc
起到什么作用,自己打印几组数据发现,gen1
生成的素数每8bit只有2个情况,分别是
00000000 00000001
而高8位必定是10000000
通过这个性质,再利用p * q % 2**l == n % 2**l
,写一个剪枝就可以爆出来
exp.py
from tqdm import *
n1 = 44945076854246685060397710825960160082061127479194994041436997195972585701097443198954359213635892234058786065342178389181538153413878118039445271277476379366294977408981257175008890470376094381644530106799352839565803317977637572325347776636285703517680754624094985374606187797141657688145287340444623176193
def find(p,q,l):
if l == 504:
pp = int("10000000"+ p,2)
qq = int("10000000"+ q,2)
if n1 % pp == 0:
print(f"p1 = {pp}")
print(f"q1 = {qq}")
return
else:
pp = int(p,2)
qq = int(q,2)
if pp * qq % 2**l == n1 % 2**l:
find("00000001" + p,"00000001" + q,l+8)
find("00000001" + p,"00000000" + q,l+8)
find("00000000" + p,"00000001" + q,l+8)
find("00000000" + p,"00000000" + q,l+8)
find("00000001","00000001",8)
4.不会取名字¶
题目来源:2024osuCTF
task.py
from Crypto.Util.number import isPrime,bytes_to_long
import random
import os
def getWYSIprime():
while True:
digits = [random.choice("727") for _ in range(272)]
prime = int("".join(digits))
if isPrime(prime):
return prime
## RSA encryption using the WYSI primes
p = getWYSIprime()
q = getWYSIprime()
n = p * q
e = 65537
flag = bytes_to_long(os.getenv("FLAG",b"osu{fake_flag_for_testing}"))
ciphertext = pow(flag,e,n)
print(f"n = {n}")
print(f"e = {e}")
print(f"ciphertext = {ciphertext}")
"""
n = 2160489795493918825870689458820648828073650907916827108594219132976202835249425984494778310568338106260399032800745421512005980632641226298431130513637640125399673697368934008374907832728004469350033174207285393191694692228748281256956917290437627249889472471749973975591415828107248775449619403563269856991145789325659736854030396401772371148983463743700921913930643887223704115714270634525795771407138067936125866995910432010323584269926871467482064993332990516534083898654487467161183876470821163254662352951613205371404232685831299594035879
e = 65537
ciphertext = 2087465275374927411696643073934443161977332564784688452208874207586196343901447373283939960111955963073429256266959192725814591103495590654238320816453299972810032321690243148092328690893438620034168359613530005646388116690482999620292746246472545500537029353066218068261278475470490922381998208396008297649151265515949490058859271855915806534872788601506545082508028917211992107642670108678400276555889198472686479168292281830557272701569298806067439923555717602352224216701010790924698838402522493324695403237985441044135894549709670322380450
"""
素数由7
or 2
组成,所以剪枝就好了,和二进制的01没什么区别
exp.py
from Crypto.Util.number import *
import itertools
import gmpy2
n = 2160489795493918825870689458820648828073650907916827108594219132976202835249425984494778310568338106260399032800745421512005980632641226298431130513637640125399673697368934008374907832728004469350033174207285393191694692228748281256956917290437627249889472471749973975591415828107248775449619403563269856991145789325659736854030396401772371148983463743700921913930643887223704115714270634525795771407138067936125866995910432010323584269926871467482064993332990516534083898654487467161183876470821163254662352951613205371404232685831299594035879
e = 65537
ciphertext = 2087465275374927411696643073934443161977332564784688452208874207586196343901447373283939960111955963073429256266959192725814591103495590654238320816453299972810032321690243148092328690893438620034168359613530005646388116690482999620292746246472545500537029353066218068261278475470490922381998208396008297649151265515949490058859271855915806534872788601506545082508028917211992107642670108678400276555889198472686479168292281830557272701569298806067439923555717602352224216701010790924698838402522493324695403237985441044135894549709670322380450
def findp(p,q):
l = len(p)
if l == 272 and n % int(p) == 0:
q = n // int(p)
print(f"p = {p}")
print(f"q = {q}")
else:
table = ["2","7"]
for i,j in itertools.product(table,repeat=2):
pp = int(i + p)
qq = int(j + q)
if pp * qq % 10**l == n % 10**l:
findp(i+p,j+q)
## findp("7","7")
p = 27777727727777722777277277777272772727772722777777277777277772227772772772227272727777772772772727227772777277727777777222777777277727772272272777772722727722777727277727727777777772772777772777277772222727227777777222727777772772272727777222777777277777727272772272272277
q = 77777772777772222722727222227777272777772777772277727772722777777777227277727272772727277277272772727227272772772222277777772727727772722772777272727777272722772777277777277777277777727777277277777277777272772772777777727772727277727777772772777772272772272222227777777227
d = gmpy2.invert(e,(p-1)*(q-1))
m = pow(ciphertext,d,n)
print(long_to_bytes(m))
## osu{h4v3_y0u_3v3r_n0t1c3d_th4t_727_1s_pr1m3?}
这四种其实感觉都算是一个类型的。还有很多类型的剪枝可以参考:Crypto趣题-剪枝 | 糖醋小鸡块的blog (tangcuxiaojikuai.xyz)
5.剪枝高位泄露¶
改编自2024XYCTF——铜匠——part3
task.py
from Crypto.Util.number import *
from uuid import uuid4
flag = "flag{" + str(uuid4()) + "}"
m = bytes_to_long(flag.encode())
e = 65537
p = getPrime(512)
q = getPrime(512)
n = p * q
n = p * q
c = pow(m,e,n)
hint = (p ^ q) >> 200
print(f"c = {c}")
print(f"hint = {hint}")
print(f"n = {n}")
"""
c = 131369115652458166734046676308463999858958566061027321031978783010359641091133329180071403453658128376834077573719048417128188606423319316139110362434662107918020440100011984923813248515798307240829242781364796147914413916010985480344221078382648887106771447184119879293816004142774768308105423590006218154095
hint = 1418156189500701046118843280016917462701888775284481310064968961841401532967678842766145628051
n = 149674440332297459310104619359509309480607215578927485825557593606756533602713173946403283163260154493438427348209708307170391308942988466700336664636266655214819841710712761463985437035510015805275916279554381867547108324810390610671268389247357987728963839572199589558858271355105026004101888297456720686127
"""
原理参考:2023-鹏城杯-wp-crypto | 糖醋小鸡块的blog (tangcuxiaojikuai.xyz)
exp
from Crypto.Util.number import *
c = 77362292774939745985127248740136531356798680244461718641182309736632869439528624490319564705732587035892746550259989967311639940839352531540590481816143399815777578738222244349541298856970218973629828183402846736572747940317185733010901816452760815595925525717774150109667814870300394441913855689875810419726
hint = 3952699881526141586582096584337236735424573202916336803978009509888494841237961467284222140708
n = 101811981048263163700430054305833461232304464649339483324456752139265661172425623344370861924802283149319747333342558424458871624320190755682987168048547266046556603061770039238687342160962557147928318419071351955573359146111983095312306624896541836196196950684743489047140141567937687816622755267268993977151
e = 65537
leak = hint << 200
leak = bin(leak)[2:].zfill(512)
leakbits = 200 ## 缺失的位数
def findp(pp,qq,l):
p_Min = int(pp + (512-l)*"0",2)
p_Max = int(pp + (512-l)*"1",2)
q_Min = int(qq + (512-l)*"0",2)
q_Max = int(qq + (512-l)*"1",2)
if(l == 512 - leakbits):
R.<x> = PolynomialRing(Zmod(n))
phigh = p_Min
f = phigh + x
root = f.small_roots(X=2^leakbits, beta=0.499)
if root != []:
p = phigh + int(root[0])
q = n // p
d = inverse(e,(p-1)*(q-1))
m = pow(c,d,n)
print(long_to_bytes(m))
if (p_Max * q_Max < n) or (p_Min * q_Min > n):
return
## 以下是根据异或来操作的
if leak[l] == '0':
findp(pp + '1',qq + '1',l+1)
findp(pp + '0',qq + '0',l+1)
if leak[l] == '1':
findp(pp + '1',qq + '0',l+1)
findp(pp + '0',qq + '1',l+1)
findp('1','1',1)
二十一、一些分解n常用的方法¶
1.费马分解¶
简单来说,费马分解干了这样一件事:
从\(a = \sqrt{n}\)开始,逐步增加,直到发现\(a^2 - n\)是一个平方数,就找到了正确的\(a,b\),然后就可以计算\(p = a +b ,q = a -b\)
从这个思想可以发现,这个算法的效率取决于\(\frac{p+q}{2}\)和\(\sqrt{n}\)的差距,所以当\(p,q\)接近的时候,用费马分解可以很快计算出\(p,q\)
这里给出一个脚本
from math import isqrt
def fermat(n):
a = isqrt(n)
b2 = a * a - n
b = isqrt(n)
count = 0
while b * b != b2:
a = a + 1
b2 = a * a - n
b = isqrt(b2)
count += 1
p = a + b
q = a - b
assert n == p * q
return p, q
例题——MoeCTF2023 |p-q|¶
task.py
with open("flag.txt","rb") as fs:
flag = fs.read().strip()
assert len(flag) == 72
m = int.from_bytes(flag,"big")
from Crypto.Util.number import getPrime, isPrime
def next_prime(p):
while True:
p += 2
if isPrime(p):
return p
p = getPrime(2048)
q = next_prime(p)
n = p * q
e = 65537
c = pow(m,e,n)
print("n =",n)
print("c =",c)
## n = 329960318345010350458589325571454799968957932130539403944044204698872359769449414256378111233592533561892402020955736786563103586897940757198920737583107357264433730515123570697570757034221232010688796344257587359198400915567115397034901247038275403825404094129637119512164953012131445747740645183682571690806238508035172474685818036517880994658466362305677430221344381425792427288500814551334928982040579744048907401043058567486871621293983772331951723963911377839286050368715384227640638031857101612517441295926821712605955984000617738833973829140899288164786111118033301974794123637285172303688427806450817155786233788027512244397952849209700013205803489334055814513866650854230478124920442832221946442593769555237909177172933634236392800414176981780444770542047378630756636857018730168151824307814244094763132088236333995807013617801783919113541391133267230410179444855465611792191833319172887852945902960736744468250550722314565805440432977225703650102517531531476188269635151281661081058374242768608270563131619806585194608795817118466680430500830137335634289617464844004904410907221482919453859885955054140320857757297655475489972268282336250384384926216818756762307686391740965586168590784252524275489515352125321398406426217
## c = 307746143297103281117512771170735061509547958991947416701685589829711285274762039205145422734327595082350457374530975854337055433998982493020603245187129916580627539476324521854057990929173492940833073106540441902619425074887573232779899379436737429823569006431370954961865581168635086246592539153824456681688944066925973182272443586463636373955966146029489121226571408532284480270826510961605206483011204059402338926815599691009406841471142048842308786000059979977645988396524814553253493672729395573658564825709547262230219183672493306100392069182994445509803952976016630731417479238769736432223194249245020320183199001774879893442186017555682902409661647546547835345461056900610391514595370600575845979413984555709077635397717741521573798309855584473259503981955303774208127361309229536010653615696850725905168242705387575720694946072789441481191449772933265705810128547553027708513478130258801233619669699177901566688737559102165508239876805822898509541232565766265491283807922473440397456701500524925191214292669986798631732639221198138026031561329502985577205314190565609214349344303324429408234237832110076900414483795318189628198913032900272406887003325858236057373096880675754802725017537119549989304878960436575670784578550
这里p,q是相邻的素数,可以直接开根号分解,也可以用费马分解
exp.py
from math import isqrt
from Crypto.Util.number import *
def fermat(n):
a = isqrt(n)
b2 = a * a - n
b = isqrt(n)
count = 0
while b * b != b2:
a = a + 1
b2 = a * a - n
b = isqrt(b2)
count += 1
p = a + b
q = a - b
assert n == p * q
return p, q
n =
c =
p,q = fermat(n)
d = inverse(65537,(p-1)*(q-1))
m = pow(c,d,n)
print(long_to_bytes(m))
2.p-1光滑¶
原理没了解,就存个脚本吧
脚本来源:RSA攻击:Smooth攻击_p-1光滑攻击-CSDN博客
import gmpy2
def Pollards_p_1(N):
a = 2 ## 为了快速计算以及满足费马小定理条件
n = 2 ## 从1开始没必要
while True:
a = pow(a, n, N) ## 递推计算a^B!
res = gmpy2.gcd(a - 1, N) ## 尝试计算p
if res != 1 and res != N: ## 满足条件后返回
return res
n += 1
例题——NCTF2019 childRSA¶
task.py
from random import choice
from Crypto.Util.number import isPrime, sieve_base as primes
from flag import flag
def getPrime(bits):
while True:
n = 2
while n.bit_length() < bits:
n *= choice(primes)
if isPrime(n + 1):
return n + 1
e = 0x10001
m = int.from_bytes(flag.encode(), 'big')
p, q = [getPrime(2048) for _ in range(2)]
n = p * q
c = pow(m, e, n)
## n = 32849718197337581823002243717057659218502519004386996660885100592872201948834155543125924395614928962750579667346279456710633774501407292473006312537723894221717638059058796679686953564471994009285384798450493756900459225040360430847240975678450171551048783818642467506711424027848778367427338647282428667393241157151675410661015044633282064056800913282016363415202171926089293431012379261585078566301060173689328363696699811123592090204578098276704877408688525618732848817623879899628629300385790344366046641825507767709276622692835393219811283244303899850483748651722336996164724553364097066493953127153066970594638491950199605713033004684970381605908909693802373826516622872100822213645899846325022476318425889580091613323747640467299866189070780620292627043349618839126919699862580579994887507733838561768581933029077488033326056066378869170169389819542928899483936705521710423905128732013121538495096959944889076705471928490092476616709838980562233255542325528398956185421193665359897664110835645928646616337700617883946369110702443135980068553511927115723157704586595844927607636003501038871748639417378062348085980873502535098755568810971926925447913858894180171498580131088992227637341857123607600275137768132347158657063692388249513
## c = 26308018356739853895382240109968894175166731283702927002165268998773708335216338997058314157717147131083296551313334042509806229853341488461087009955203854253313827608275460592785607739091992591431080342664081962030557042784864074533380701014585315663218783130162376176094773010478159362434331787279303302718098735574605469803801873109982473258207444342330633191849040553550708886593340770753064322410889048135425025715982196600650740987076486540674090923181664281515197679745907830107684777248532278645343716263686014941081417914622724906314960249945105011301731247324601620886782967217339340393853616450077105125391982689986178342417223392217085276465471102737594719932347242482670320801063191869471318313514407997326350065187904154229557706351355052446027159972546737213451422978211055778164578782156428466626894026103053360431281644645515155471301826844754338802352846095293421718249819728205538534652212984831283642472071669494851823123552827380737798609829706225744376667082534026874483482483127491533474306552210039386256062116345785870668331513725792053302188276682550672663353937781055621860101624242216671635824311412793495965628876036344731733142759495348248970313655381407241457118743532311394697763283681852908564387282605279108
exp.py
import gmpy2
from Crypto.Util.number import *
def Pollards_p_1(N):
a = 2 ## 为了快速计算以及满足费马小定理条件
n = 2 ## 从1开始没必要
while True:
a = pow(a, n, N) ## 递推计算a^B!
res = gmpy2.gcd(a - 1, N) ## 尝试计算p
if res != 1 and res != N: ## 满足条件后返回
return res
n += 1
n =
c =
p = Pollards_p_1(n)
q = n // p
d = inverse(65537,(p-1)*(q-1))
m = pow(c,d,n)
print(long_to_bytes(m))
## NCTF{Th3r3_ar3_1ns3cure_RSA_m0duli_7hat_at_f1rst_gl4nce_appe4r_t0_be_s3cur3}
3.p+1光滑¶
脚本来源:
def lucas(c, d, N):
x = c ## a1
y = (c**2 - 2) % N ## a2
for bit in bin(d)[3:]: ## 快速乘(从高到低位)--我个人理解
if bit == '1':
x = (x*y - c) % N ## 下标对应a_{x+y},其次保证a_{2k-1}=a_{k}a_{k-1}-a_{0}成立
y = (y**2 - 2) % N ## 使得y翻倍--正常的快速幂流程
else:
y = (x*y - c) % N ## 保证a_{2k-1}=a_{k}a_{k-1}-a_{0}成立
x = (x**2 - 2) % N ## a_{k} 翻倍
return x #返回a_{ed}
才疏学浅,没找到例题
4.已知phi和n分解n¶
如果是两个因子的,\(n = p\times q\),那么直接联立方程就可以解
如果是多因子的话,就没这么容易了,以NKCTF2023的ezRSA为例
例题——NKCTF2023 ezRSA¶
task.py
from Crypto.Util.number import *
from secret import flag
m1 = bytes_to_long(flag[:len(flag)//3])
m2 = bytes_to_long(flag[len(flag)//3:])
def gen():
prime_list = []
for i in range(4):
prime_list.append(getPrime(512))
return sorted(prime_list)
prime_list = gen()
p,q,r,t = prime_list[0],prime_list[3],prime_list[1],prime_list[2]
e = 65537
n = p*q*r*t
phi = (p-1)*(q-1)*(r-1)*(t-1)
c1 = pow(m1,e,p*q)
p1 = getPrime(512)
q1 = getPrime(512)
N = p1*q1
c2 = pow(m2,p1,N)
c3 = pow(m2,q1,N)
print(f'n = {n}')
print(f'phi = {phi}')
print(f'c1 = {c1}')
print(f'N = {N}')
print(f'c2 = {c2}')
print(f'c3 = {c3}')
'''
n = 8836130216343708623415307573630337110573363595188748983290313549413242332143945452914800845282478216810685733227137911630239808895196748125078747600505626165666334675100147790578546682128517668100858766784733351894480181877144793496927464058323582165412552970999921215333509253052644024478417393146000490808639363681195799826541558906527985336104761974023394438549055804234997654701266967731137282297623426318212701157416397999108259257077847307874122736921265599854976855949680133804464839768470200425669609996841568545945133611190979810786943246285103031363790663362165522662820344917056587244701635831061853354597
phi = 8836130216343708623415307573630337110573363595188748983290313549413242332143945452914800845282478216810685733227137911630239808895196748125078747600505622503351461565956106005118029537938273153581675065762015952483687057805462728186901563990429998916382820576211887477098611684072561849314986341226981300596338314989867731725668312057134075244816223120038573374383949718714549930261073576391501671722900294331289082826058292599838631513746370889828026039555245672195833927609280773258978856664434349221972568651378808050580665443131001632395175205804045958846124475183825589672204752895252723130454951830966138888560
c1 = 78327207863361017953496121356221173288422862370301396867341957979087627011991738176024643637029313969241151622985226595093079857523487726626882109114134910056673489916408854152274726721451884257677533593174371742411008169082367666168983943358876017521749198218529804830864940274185360506199116451280975188409
N = 157202814866563156513184271957553223260772141845129283711146204376449001653397810781717934720804041916333174673656579086498762693983380365527400604554663873045166444369504886603233275868192688995284322277504050322927511160583280269073338415758019142878016084536129741435221345599028001581385308324407324725353
c2 = 63355788175487221030596314921407476078592001060627033831694843409637965350474955727383434406640075122932939559532216639739294413008164038257338675094324172634789610307227365830016457714456293397466445820352804725466971828172010276387616894829328491068298742711984800900411277550023220538443014162710037992032
c3 = 9266334096866207047544089419994475379619964393206968260875878305040712629590906330073542575719856965053269812924808810766674072615270535207284077081944428011398767330973702305174973148018082513467080087706443512285098600431136743009829009567065760786940706627087366702015319792328141978938111501345426931078
'''
exp.py
from math import gcd
from math import isqrt
from random import randrange
from gmpy2 import is_prime
def factorize(N, phi):
"""
Recovers the prime factors from a modulus if Euler's totient is known.
This method only works for a modulus consisting of 2 primes!
:param N: the modulus
:param phi: Euler's totient, the order of the multiplicative group modulo N
:return: a tuple containing the prime factors, or None if the factors were not found
"""
s = N + 1 - phi
d = s ** 2 - 4 * N
p = int(s - isqrt(d)) // 2
q = int(s + isqrt(d)) // 2
return p, q
def factorize_multi_prime(N, phi):
"""
Recovers the prime factors from a modulus if Euler's totient is known.
This method works for a modulus consisting of any number of primes, but is considerably be slower than factorize.
More information: Hinek M. J., Low M. K., Teske E., "On Some Attacks on Multi-prime RSA" (Section 3)
:param N: the modulus
:param phi: Euler's totient, the order of the multiplicative group modulo N
:return: a tuple containing the prime factors
"""
prime_factors = set()
factors = [N]
while len(factors) > 0:
## Element to factorize.
N = factors[0]
w = randrange(2, N - 1)
i = 1
while phi % (2 ** i) == 0:
sqrt_1 = pow(w, phi // (2 ** i), N)
if sqrt_1 > 1 and sqrt_1 != N - 1:
## We can remove the element to factorize now, because we have a factorization.
factors = factors[1:]
p = gcd(N, sqrt_1 + 1)
q = N // p
if is_prime(p):
prime_factors.add(p)
elif p > 1:
factors.append(p)
if is_prime(q):
prime_factors.add(q)
elif q > 1:
factors.append(q)
## Continue in the outer loop
break
i += 1
return tuple(prime_factors)
n =
phi =
prime_list = sorted(factorize_multi_prime(n,phi))
p,q,r,s = prime_list[0],prime_list[3],prime_list[1],prime_list[2]
5.已知e,d分解n¶
import random
import gmpy2
def divide_pq(e, d, n):
k = e*d - 1
while True:
g = random.randint(2, n-1)
t = k
while True:
if t % 2 != 0:
break
t //= 2
x = pow(g, t, n)
if x > 1 and gmpy2.gcd(x-1, n) > 1:
p = gmpy2.gcd(x-1, n)
return (p, n//p)
二十二、不知道叫什么分类的题目¶
给出p + q低位¶
题目改编自2024XYCTF——铜匠——part2
task.py
from Crypto.Util.number import *
from uuid import uuid4
flag = "flag{" + str(uuid4()) + "}"
m = bytes_to_long(flag.encode())
e = 65537
p = getPrime(1024)
q = getPrime(1024)
n = p * q
c = pow(m, e, n)
hint = (p + q) & ((1 << 624) - 1)
print(f"c = {c}")
print(f"hint = {hint}")
print(f"n = {n}")
"""
c = 15315623227108436291858457034857784719507552879018189851637500530704870673436079954784519165863568569923075589417879105802430194799540543536178163710092884414704414320471378011034947694757321045648672645088739109820484000260862752393231610482665197130322211444656668269314857325584729333799747940039582233403795688967132390847508527859286606080564369696319857802230684766189133382904414261588681956483620140766886760632093938290509495921191051004955960321224324525865371027175220422824090922909186107029324403060456677201122370380708945945621513853659281202197178155661602947407740113932985040400431009519035927170893
hint = 24765551240982534917083490896297931130347202481167225145278716583234238038819431100154290815134734511033735464993876484465992525732351399544319245104113383110187111270727627683278542339074
n = 17551595965847360101001559529386245228497232313421489853434901311116953087050954433040038840788997073271446971526589676430781788129026667353632541062149232552031818920006832783397173014011531311807992794738323157382559849771809561200626834225824761208921248849766951980339089458227127422515917026821919873970760316856393212652571020677585627719682906485373773819364730302897222175047226443095023421963275036185038777190349527562337069435775581997139041749482233185668100893166822768561406331106814954573421744711888039361670837655170604347860448702902142977569791794645486978083071644858164529311966931143494605467581
"""
由题意知\(hint \equiv p+q \mod 2^{624}\)
除此之外还可以得到\(n_{low} \equiv p\times q \mod 2^{624}\)
于是有\(n_{low} \equiv p(hint - p) \mod 2^{624}\),解这个方程,然后得到p的低位,再用coppersmith
exp.sage
from Crypto.Util.number import *
c =
hint =
n =
e = 65537
n_low = n % 2^624
var('p')
f = p * (hint - p) - n_low
res = solve_mod(f,2^624)
for i in res:
plow = int(i[0])
R.<x> = PolynomialRing(Zmod(n))
f2 = x * 2^624 + plow
f2 = f2.monic()
root = f2.small_roots(X = 2^400,beta=0.4)
if root != []:
p = int(root[0])*2^624 + plow
q = n // p
d = inverse(e,(p-1)*(q-1))
m = pow(c,d,n)
print(long_to_bytes(m))
给出p + q高位¶
题目改编自2023贵阳大数据安全精英赛——childrsa
task.py
from Crypto.Util.number import *
from uuid import uuid4
flag = "flag{" + str(uuid4()) + "}"
m = bytes_to_long(flag.encode())
e = 65537
p = getPrime(1024)
q = getPrime(1024)
n = p * q
c = pow(m,e,n)
hint = (p + q) >> 400
print(f"c = {c}")
print(f"hint = {hint}")
print(f"n = {n}")
"""
c = 9968814618309288374765866491408679544255429893255485341540355195679112942954793887247314436025657932769746362042585414910893400260770578028623836705800055045072907439444477587736093915786634848757052762926680474130492661750432044025559425178180215747669943104929529122332455902347039817592660193268467698523220383789551009222998925658852390205657636722754375420684776093364112335355059660951403603124371637134722485720098467185512008162108300224681045740170399118079432119176169258163078208915377786922862558709935512780853980376778422910630993460815435812492821018759585591884031366023668940372754253922297009332299
hint = 105339843160443546161059100165057877716740618426298713183228594499797346255161510101279378179555206038228997256205578377516899889823785206924887213498045434452190147663923551839494492842528
n = 18082068933780051996564597024915927694586996785675007728934595064379707482865414885175435323040864143693167921685287351955951750372213399691641808639756160589090710830417826035004009898533761679036070970158874299127191974011618903726273713888134189317545858033157115955525192756551460792306555827664839412205373639439765940037587708927072607585261515428021124875200073775443189376478576573477677951404802079319347815808709279487553524912259078196698834492416001870786404364835221144821510700252279703537618579227763205158431798627532437072037863851605556234186314341793234064284447561153310642226744523000217117902339
"""
我们可以联立\(p+q\)的高位和\(n = p \times q\)解方程组,此时解出来的\(p\)和正确的\(p\)高位是一样的,最后再用coppersmith去解低400位
实际测试发现,解方程可能存在误差,所以最后用copper处理低405位
Exp
from Crypto.Util.number import *
c =
hint =
n =
e = 65537
R.<x> = PolynomialRing(RealField(2048))
f = x * ((hint << 400) - x) - n
res = f.roots()
for root in res:
phigh = int(root[0]) >> 405 << 405
PR.<x> = PolynomialRing(Zmod(n))
f1 = phigh + x
res1 = f1.small_roots(X = 2^405,beta=0.4)
if res1 != []:
p = phigh + int(res1[0])
q = n // p
d = inverse(e,(p-1)*(q-1))
m = pow(c,d,n)
print(long_to_bytes(m))
已知p^2 + q^2分解n = p*q¶
利用sagemath自带函数two_squares()
,甚至有three_squares()
二十三、私钥文件提取参数¶
常考的就是PKCS1形式的私钥文件,参考:参考文章
先生成私钥文件
from Crypto.Util.number import *
from Crypto.PublicKey import RSA
p = getPrime(1024)
q = getPrime(1024)
n = p*q
e = 65537
d = inverse(e,(p-1)*(q-1))
print(f"n = {n}")
print(f"e = {e}")
print(f"p = {p}")
print(f"q = {q}")
print(f"dp = {d % (p-1)}")
print(f"dq = {d % (q-1)}")
print(f"inv = {inverse(p,q)}")
privatekey = RSA.construct((n,e,int(d)))
with open("privatekey.pem","wb") as f2:
f2.write(privatekey.export_key())
得到
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAhgPB1hHIr7An3HDG1dqJo8UQu+5oOLOA119z0rZESozrr1ox
3g0Ku86t1X1OpbawWr8cFzXgYsDtgZPWhEExbsU/qHGZXewo8ofe/4Sa/s1DOpUm
ZIFsM/YAtWEex+aTwA9FT+6EZ3OYJatmY9iq9ewnAjeCdBwll04C8vT9Ke73Xndn
B8tTtL2S4hIcuz7vVd1HTZSfQ+ousLUM5OuTe0361NFqp4RFhhHjtM9cuvyaPaMF
vRFoemXyCH8pfxgl4llFSBJitPAeLBxHpV9PjlLBp4kYIzPrYDMp1AF2seQyvb8W
NujFcu0ZvOZRuHxULiUT2RI2srZ6eyAoq7RXiwIDAQABAoIBAE/yw9tqZpfw9ga7
PNNteTk7Ih2LP5+77nwN1LH6zEjRQvUsUJ2QmDusM+YtyBJyJ0krw51RJdikEcyA
nrPtlIjpoW1iv8TZUyBE0FMND848NAQp4GqLDzr8YjXSh6NnufMU6RujRlfVDQpD
82RTaMInLKpU5T1RYVefUYERiEpQCJjzDd2fb1UlCJx6XZguTXTsqCmhr7Lr6xN1
WvSdTY2a7cPxnusggrCaiYxoCjJQRPl+Z4O33gHkXNbZnch5YlEQui1+fanofKuk
lK3mAbqBwo/lfXXAu5GbhMdIZ6Iw68vAiFJQtuwvOYE1h6sN3EHsjnfkbfgC+uu4
1QQfAvECgYEAyBFidz8w3ijHW+XDcH20JhHxEMAmFTUf0fXI11x3ECk+6c2yAH1v
DHM4rr3KHspVhEJzyNVsVBg1I4JF5gSkPWsygjdoyMPqjQ9M0YP2Qho6iiiz20c3
w+K9cBezTNtDn+N/gqOrJLBGOpru1zwpfroS4ie76QNpAUZ83OQUVrkCgYEAq3sG
B0rZvn3+LbQ3S/AlydpnZYf6e85FUt3fQukRBI4vLl6SpOMJSZfQQUnM+P09t2z7
rH3w4QLOYbfEndt1I/MMhfWb7a96I/Cfw9mW48RIUrk4MUtV/Pq7bKz0vzq/DBnA
44nAsa46bb9ysjJ6+fcnLWNLWz4O9+vBeFaGPmMCgYB+vnSwsrmUpCTX1REhPKFZ
1NfxEqmNmeAUtS6NMKjE9jxDBeqUYOJu8regC9/17ZyLc0XCn2JHTCat3iPF+n7J
4hVXZR7ewS7gOiciPAVQDymyyOJYMh/j2srELl+KewW2TvtCmckcLwfurKROenCX
Ne4sk5t5nI1zH2KO1XcFEQKBgH9DeD/lPyBu5TsKKpfDDGh4HJBvkGhdt3k+jLld
u3GEDGP/cBnLHVNuxfIOUX7ggvMkgMuNVD3KFVzUQ6lb+93IPZ0VoLmPp7gQlqGF
VMSJIZuzNo7u+Ewd0QdgfOuHL85NNqgnzciQI3DbysWRTU9CK+M1c/GtZvJ8F0O2
Az89AoGAILpBAbTHYaBpdXrN4axCm9wbJzEJlk0Pv9BvNXly5LiU/xJsgppP/gmP
9NmUN8QKmp3dmxM9Ub36DYGpZRyPKbKfjKQfSraLXwokr7aIm4jc7Ow0NBBgTsfS
EaqTgYiY9axcqaYS9I5iyfQZt9Kl/hJX6aT9s2M+DQfchzaFWkQ=
-----END RSA PRIVATE KEY-----
解base64再转16进制得到下面的内容
30 82 04 a2 02 01 00 02 82 01 01 00 86 03 c1 d6 11 c8 af b0 27 dc 70 c6 d5 da 89 a3 c5 10 bb ee 68 38 b3 80 d7 5f 73 d2 b6 44 4a 8c eb af 5a 31 de 0d 0a bb ce ad d5 7d 4e a5 b6 b0 5a bf 1c 17 35 e0 62 c0 ed 81 93 d6 84 41 31 6e c5 3f a8 71 99 5d ec 28 f2 87 de ff 84 9a fe cd 43 3a 95 26 64 81 6c 33 f6 00 b5 61 1e c7 e6 93 c0 0f 45 4f ee 84 67 73 98 25 ab 66 63 d8 aa f5 ec 27 02 37 82 74 1c 25 97 4e 02 f2 f4 fd 29 ee f7 5e 77 67 07 cb 53 b4 bd 92 e2 12 1c bb 3e ef 55 dd 47 4d 94 9f 43 ea 2e b0 b5 0c e4 eb 93 7b 4d fa d4 d1 6a a7 84 45 86 11 e3 b4 cf 5c ba fc 9a 3d a3 05 bd 11 68 7a 65 f2 08 7f 29 7f 18 25 e2 59 45 48 12 62 b4 f0 1e 2c 1c 47 a5 5f 4f 8e 52 c1 a7 89 18 23 33 eb 60 33 29 d4 01 76 b1 e4 32 bd bf 16 36 e8 c5 72 ed 19 bc e6 51 b8 7c 54 2e 25 13 d9 12 36 b2 b6 7a 7b 20 28 ab b4 57 8b 02 03 01 00 01 02 82 01 00 4f f2 c3 db 6a 66 97 f0 f6 06 bb 3c d3 6d 79 39 3b 22 1d 8b 3f 9f bb ee 7c 0d d4 b1 fa cc 48 d1 42 f5 2c 50 9d 90 98 3b ac 33 e6 2d c8 12 72 27 49 2b c3 9d 51 25 d8 a4 11 cc 80 9e b3 ed 94 88 e9 a1 6d 62 bf c4 d9 53 20 44 d0 53 0d 0f ce 3c 34 04 29 e0 6a 8b 0f 3a fc 62 35 d2 87 a3 67 b9 f3 14 e9 1b a3 46 57 d5 0d 0a 43 f3 64 53 68 c2 27 2c aa 54 e5 3d 51 61 57 9f 51 81 11 88 4a 50 08 98 f3 0d dd 9f 6f 55 25 08 9c 7a 5d 98 2e 4d 74 ec a8 29 a1 af b2 eb eb 13 75 5a f4 9d 4d 8d 9a ed c3 f1 9e eb 20 82 b0 9a 89 8c 68 0a 32 50 44 f9 7e 67 83 b7 de 01 e4 5c d6 d9 9d c8 79 62 51 10 ba 2d 7e 7d a9 e8 7c ab a4 94 ad e6 01 ba 81 c2 8f e5 7d 75 c0 bb 91 9b 84 c7 48 67 a2 30 eb cb c0 88 52 50 b6 ec 2f 39 81 35 87 ab 0d dc 41 ec 8e 77 e4 6d f8 02 fa eb b8 d5 04 1f 02 f1 02 81 81 00 c8 11 62 77 3f 30 de 28 c7 5b e5 c3 70 7d b4 26 11 f1 10 c0 26 15 35 1f d1 f5 c8 d7 5c 77 10 29 3e e9 cd b2 00 7d 6f 0c 73 38 ae bd ca 1e ca 55 84 42 73 c8 d5 6c 54 18 35 23 82 45 e6 04 a4 3d 6b 32 82 37 68 c8 c3 ea 8d 0f 4c d1 83 f6 42 1a 3a 8a 28 b3 db 47 37 c3 e2 bd 70 17 b3 4c db 43 9f e3 7f 82 a3 ab 24 b0 46 3a 9a ee d7 3c 29 7e ba 12 e2 27 bb e9 03 69 01 46 7c dc e4 14 56 b9 02 81 81 00 ab 7b 06 07 4a d9 be 7d fe 2d b4 37 4b f0 25 c9 da 67 65 87 fa 7b ce 45 52 dd df 42 e9 11 04 8e 2f 2e 5e 92 a4 e3 09 49 97 d0 41 49 cc f8 fd 3d b7 6c fb ac 7d f0 e1 02 ce 61 b7 c4 9d db 75 23 f3 0c 85 f5 9b ed af 7a 23 f0 9f c3 d9 96 e3 c4 48 52 b9 38 31 4b 55 fc fa bb 6c ac f4 bf 3a bf 0c 19 c0 e3 89 c0 b1 ae 3a 6d bf 72 b2 32 7a f9 f7 27 2d 63 4b 5b 3e 0e f7 eb c1 78 56 86 3e 63 02 81 80 7e be 74 b0 b2 b9 94 a4 24 d7 d5 11 21 3c a1 59 d4 d7 f1 12 a9 8d 99 e0 14 b5 2e 8d 30 a8 c4 f6 3c 43 05 ea 94 60 e2 6e f2 b7 a0 0b df f5 ed 9c 8b 73 45 c2 9f 62 47 4c 26 ad de 23 c5 fa 7e c9 e2 15 57 65 1e de c1 2e e0 3a 27 22 3c 05 50 0f 29 b2 c8 e2 58 32 1f e3 da ca c4 2e 5f 8a 7b 05 b6 4e fb 42 99 c9 1c 2f 07 ee ac a4 4e 7a 70 97 35 ee 2c 93 9b 79 9c 8d 73 1f 62 8e d5 77 05 11 02 81 80 7f 43 78 3f e5 3f 20 6e e5 3b 0a 2a 97 c3 0c 68 78 1c 90 6f 90 68 5d b7 79 3e 8c b9 5d bb 71 84 0c 63 ff 70 19 cb 1d 53 6e c5 f2 0e 51 7e e0 82 f3 24 80 cb 8d 54 3d ca 15 5c d4 43 a9 5b fb dd c8 3d 9d 15 a0 b9 8f a7 b8 10 96 a1 85 54 c4 89 21 9b b3 36 8e ee f8 4c 1d d1 07 60 7c eb 87 2f ce 4d 36 a8 27 cd c8 90 23 70 db ca c5 91 4d 4f 42 2b e3 35 73 f1 ad 66 f2 7c 17 43 b6 03 3f 3d 02 81 80 20 ba 41 01 b4 c7 61 a0 69 75 7a cd e1 ac 42 9b dc 1b 27 31 09 96 4d 0f bf d0 6f 35 79 72 e4 b8 94 ff 12 6c 82 9a 4f fe 09 8f f4 d9 94 37 c4 0a 9a 9d dd 9b 13 3d 51 bd fa 0d 81 a9 65 1c 8f 29 b2 9f 8c a4 1f 4a b6 8b 5f 0a 24 af b6 88 9b 88 dc ec ec 34 34 10 60 4e c7 d2 11 aa 93 81 88 98 f5 ac 5c a9 a6 12 f4 8e 62 c9 f4 19 b7 d2 a5 fe 12 57 e9 a4 fd b3 63 3e 0d 07 dc 87 36 85 5a 44
对其格式化
30 82 04 a2
02 01
00
02 82 01 01
00 86 03 c1 d6 11 c8 af b0 27 dc 70 c6 d5 da 89 a3 c5 10 bb ee 68 38 b3 80 d7 5f 73 d2 b6 44 4a 8c eb af 5a 31 de 0d 0a bb ce ad d5 7d 4e a5 b6 b0 5a bf 1c 17 35 e0 62 c0 ed 81 93 d6 84 41 31 6e c5 3f a8 71 99 5d ec 28 f2 87 de ff 84 9a fe cd 43 3a 95 26 64 81 6c 33 f6 00 b5 61 1e c7 e6 93 c0 0f 45 4f ee 84 67 73 98 25 ab 66 63 d8 aa f5 ec 27 02 37 82 74 1c 25 97 4e 02 f2 f4 fd 29 ee f7 5e 77 67 07 cb 53 b4 bd 92 e2 12 1c bb 3e ef 55 dd 47 4d 94 9f 43 ea 2e b0 b5 0c e4 eb 93 7b 4d fa d4 d1 6a a7 84 45 86 11 e3 b4 cf 5c ba fc 9a 3d a3 05 bd 11 68 7a 65 f2 08 7f 29 7f 18 25 e2 59 45 48 12 62 b4 f0 1e 2c 1c 47 a5 5f 4f 8e 52 c1 a7 89 18 23 33 eb 60 33 29 d4 01 76 b1 e4 32 bd bf 16 36 e8 c5 72 ed 19 bc e6 51 b8 7c 54 2e 25 13 d9 12 36 b2 b6 7a 7b 20 28 ab b4 57 8b
02 03
01 00 01
02 82 01 00
4f f2 c3 db 6a 66 97 f0 f6 06 bb 3c d3 6d 79 39 3b 22 1d 8b 3f 9f bb ee 7c 0d d4 b1 fa cc 48 d1 42 f5 2c 50 9d 90 98 3b ac 33 e6 2d c8 12 72 27 49 2b c3 9d 51 25 d8 a4 11 cc 80 9e b3 ed 94 88 e9 a1 6d 62 bf c4 d9 53 20 44 d0 53 0d 0f ce 3c 34 04 29 e0 6a 8b 0f 3a fc 62 35 d2 87 a3 67 b9 f3 14 e9 1b a3 46 57 d5 0d 0a 43 f3 64 53 68 c2 27 2c aa 54 e5 3d 51 61 57 9f 51 81 11 88 4a 50 08 98 f3 0d dd 9f 6f 55 25 08 9c 7a 5d 98 2e 4d 74 ec a8 29 a1 af b2 eb eb 13 75 5a f4 9d 4d 8d 9a ed c3 f1 9e eb 20 82 b0 9a 89 8c 68 0a 32 50 44 f9 7e 67 83 b7 de 01 e4 5c d6 d9 9d c8 79 62 51 10 ba 2d 7e 7d a9 e8 7c ab a4 94 ad e6 01 ba 81 c2 8f e5 7d 75 c0 bb 91 9b 84 c7 48 67 a2 30 eb cb c0 88 52 50 b6 ec 2f 39 81 35 87 ab 0d dc 41 ec 8e 77 e4 6d f8 02 fa eb b8 d5 04 1f 02 f1
02 81 81 00
c8 11 62 77 3f 30 de 28 c7 5b e5 c3 70 7d b4 26 11 f1 10 c0 26 15 35 1f d1 f5 c8 d7 5c 77 10 29 3e e9 cd b2 00 7d 6f 0c 73 38 ae bd ca 1e ca 55 84 42 73 c8 d5 6c 54 18 35 23 82 45 e6 04 a4 3d 6b 32 82 37 68 c8 c3 ea 8d 0f 4c d1 83 f6 42 1a 3a 8a 28 b3 db 47 37 c3 e2 bd 70 17 b3 4c db 43 9f e3 7f 82 a3 ab 24 b0 46 3a 9a ee d7 3c 29 7e ba 12 e2 27 bb e9 03 69 01 46 7c dc e4 14 56 b9
02 81 81 00
ab 7b 06 07 4a d9 be 7d fe 2d b4 37 4b f0 25 c9 da 67 65 87 fa 7b ce 45 52 dd df 42 e9 11 04 8e 2f 2e 5e 92 a4 e3 09 49 97 d0 41 49 cc f8 fd 3d b7 6c fb ac 7d f0 e1 02 ce 61 b7 c4 9d db 75 23 f3 0c 85 f5 9b ed af 7a 23 f0 9f c3 d9 96 e3 c4 48 52 b9 38 31 4b 55 fc fa bb 6c ac f4 bf 3a bf 0c 19 c0 e3 89 c0 b1 ae 3a 6d bf 72 b2 32 7a f9 f7 27 2d 63 4b 5b 3e 0e f7 eb c1 78 56 86 3e 63
02 81 80
7e be 74 b0 b2 b9 94 a4 24 d7 d5 11 21 3c a1 59 d4 d7 f1 12 a9 8d 99 e0 14 b5 2e 8d 30 a8 c4 f6 3c 43 05 ea 94 60 e2 6e f2 b7 a0 0b df f5 ed 9c 8b 73 45 c2 9f 62 47 4c 26 ad de 23 c5 fa 7e c9 e2 15 57 65 1e de c1 2e e0 3a 27 22 3c 05 50 0f 29 b2 c8 e2 58 32 1f e3 da ca c4 2e 5f 8a 7b 05 b6 4e fb 42 99 c9 1c 2f 07 ee ac a4 4e 7a 70 97 35 ee 2c 93 9b 79 9c 8d 73 1f 62 8e d5 77 05 11
02 81 80
7f 43 78 3f e5 3f 20 6e e5 3b 0a 2a 97 c3 0c 68 78 1c 90 6f 90 68 5d b7 79 3e 8c b9 5d bb 71 84 0c 63 ff 70 19 cb 1d 53 6e c5 f2 0e 51 7e e0 82 f3 24 80 cb 8d 54 3d ca 15 5c d4 43 a9 5b fb dd c8 3d 9d 15 a0 b9 8f a7 b8 10 96 a1 85 54 c4 89 21 9b b3 36 8e ee f8 4c 1d d1 07 60 7c eb 87 2f ce 4d 36 a8 27 cd c8 90 23 70 db ca c5 91 4d 4f 42 2b e3 35 73 f1 ad 66 f2 7c 17 43 b6 03 3f 3d
02 81 80
20 ba 41 01 b4 c7 61 a0 69 75 7a cd e1 ac 42 9b dc 1b 27 31 09 96 4d 0f bf d0 6f 35 79 72 e4 b8 94 ff 12 6c 82 9a 4f fe 09 8f f4 d9 94 37 c4 0a 9a 9d dd 9b 13 3d 51 bd fa 0d 81 a9 65 1c 8f 29 b2 9f 8c a4 1f 4a b6 8b 5f 0a 24 af b6 88 9b 88 dc ec ec 34 34 10 60 4e c7 d2 11 aa 93 81 88 98 f5 ac 5c a9 a6 12 f4 8e 62 c9 f4 19 b7 d2 a5 fe 12 57 e9 a4 fd b3 63 3e 0d 07 dc 87 36 85 5a 44
再通过OpenSSL来查看一下密钥的各参数情况
Private-Key: (2048 bit, 2 primes)
modulus:
00:86:03:c1:d6:11:c8:af:b0:27:dc:70:c6:d5:da:
89:a3:c5:10:bb:ee:68:38:b3:80:d7:5f:73:d2:b6:
44:4a:8c:eb:af:5a:31:de:0d:0a:bb:ce:ad:d5:7d:
4e:a5:b6:b0:5a:bf:1c:17:35:e0:62:c0:ed:81:93:
d6:84:41:31:6e:c5:3f:a8:71:99:5d:ec:28:f2:87:
de:ff:84:9a:fe:cd:43:3a:95:26:64:81:6c:33:f6:
00:b5:61:1e:c7:e6:93:c0:0f:45:4f:ee:84:67:73:
98:25:ab:66:63:d8:aa:f5:ec:27:02:37:82:74:1c:
25:97:4e:02:f2:f4:fd:29:ee:f7:5e:77:67:07:cb:
53:b4:bd:92:e2:12:1c:bb:3e:ef:55:dd:47:4d:94:
9f:43:ea:2e:b0:b5:0c:e4:eb:93:7b:4d:fa:d4:d1:
6a:a7:84:45:86:11:e3:b4:cf:5c:ba:fc:9a:3d:a3:
05:bd:11:68:7a:65:f2:08:7f:29:7f:18:25:e2:59:
45:48:12:62:b4:f0:1e:2c:1c:47:a5:5f:4f:8e:52:
c1:a7:89:18:23:33:eb:60:33:29:d4:01:76:b1:e4:
32:bd:bf:16:36:e8:c5:72:ed:19:bc:e6:51:b8:7c:
54:2e:25:13:d9:12:36:b2:b6:7a:7b:20:28:ab:b4:
57:8b
publicExponent: 65537 (0x10001)
privateExponent:
4f:f2:c3:db:6a:66:97:f0:f6:06:bb:3c:d3:6d:79:
39:3b:22:1d:8b:3f:9f:bb:ee:7c:0d:d4:b1:fa:cc:
48:d1:42:f5:2c:50:9d:90:98:3b:ac:33:e6:2d:c8:
12:72:27:49:2b:c3:9d:51:25:d8:a4:11:cc:80:9e:
b3:ed:94:88:e9:a1:6d:62:bf:c4:d9:53:20:44:d0:
53:0d:0f:ce:3c:34:04:29:e0:6a:8b:0f:3a:fc:62:
35:d2:87:a3:67:b9:f3:14:e9:1b:a3:46:57:d5:0d:
0a:43:f3:64:53:68:c2:27:2c:aa:54:e5:3d:51:61:
57:9f:51:81:11:88:4a:50:08:98:f3:0d:dd:9f:6f:
55:25:08:9c:7a:5d:98:2e:4d:74:ec:a8:29:a1:af:
b2:eb:eb:13:75:5a:f4:9d:4d:8d:9a:ed:c3:f1:9e:
eb:20:82:b0:9a:89:8c:68:0a:32:50:44:f9:7e:67:
83:b7:de:01:e4:5c:d6:d9:9d:c8:79:62:51:10:ba:
2d:7e:7d:a9:e8:7c:ab:a4:94:ad:e6:01:ba:81:c2:
8f:e5:7d:75:c0:bb:91:9b:84:c7:48:67:a2:30:eb:
cb:c0:88:52:50:b6:ec:2f:39:81:35:87:ab:0d:dc:
41:ec:8e:77:e4:6d:f8:02:fa:eb:b8:d5:04:1f:02:
f1
prime1:
00:c8:11:62:77:3f:30:de:28:c7:5b:e5:c3:70:7d:
b4:26:11:f1:10:c0:26:15:35:1f:d1:f5:c8:d7:5c:
77:10:29:3e:e9:cd:b2:00:7d:6f:0c:73:38:ae:bd:
ca:1e:ca:55:84:42:73:c8:d5:6c:54:18:35:23:82:
45:e6:04:a4:3d:6b:32:82:37:68:c8:c3:ea:8d:0f:
4c:d1:83:f6:42:1a:3a:8a:28:b3:db:47:37:c3:e2:
bd:70:17:b3:4c:db:43:9f:e3:7f:82:a3:ab:24:b0:
46:3a:9a:ee:d7:3c:29:7e:ba:12:e2:27:bb:e9:03:
69:01:46:7c:dc:e4:14:56:b9
prime2:
00:ab:7b:06:07:4a:d9:be:7d:fe:2d:b4:37:4b:f0:
25:c9:da:67:65:87:fa:7b:ce:45:52:dd:df:42:e9:
11:04:8e:2f:2e:5e:92:a4:e3:09:49:97:d0:41:49:
cc:f8:fd:3d:b7:6c:fb:ac:7d:f0:e1:02:ce:61:b7:
c4:9d:db:75:23:f3:0c:85:f5:9b:ed:af:7a:23:f0:
9f:c3:d9:96:e3:c4:48:52:b9:38:31:4b:55:fc:fa:
bb:6c:ac:f4:bf:3a:bf:0c:19:c0:e3:89:c0:b1:ae:
3a:6d:bf:72:b2:32:7a:f9:f7:27:2d:63:4b:5b:3e:
0e:f7:eb:c1:78:56:86:3e:63
exponent1:
7e:be:74:b0:b2:b9:94:a4:24:d7:d5:11:21:3c:a1:
59:d4:d7:f1:12:a9:8d:99:e0:14:b5:2e:8d:30:a8:
c4:f6:3c:43:05:ea:94:60:e2:6e:f2:b7:a0:0b:df:
f5:ed:9c:8b:73:45:c2:9f:62:47:4c:26:ad:de:23:
c5:fa:7e:c9:e2:15:57:65:1e:de:c1:2e:e0:3a:27:
22:3c:05:50:0f:29:b2:c8:e2:58:32:1f:e3:da:ca:
c4:2e:5f:8a:7b:05:b6:4e:fb:42:99:c9:1c:2f:07:
ee:ac:a4:4e:7a:70:97:35:ee:2c:93:9b:79:9c:8d:
73:1f:62:8e:d5:77:05:11
exponent2:
7f:43:78:3f:e5:3f:20:6e:e5:3b:0a:2a:97:c3:0c:
68:78:1c:90:6f:90:68:5d:b7:79:3e:8c:b9:5d:bb:
71:84:0c:63:ff:70:19:cb:1d:53:6e:c5:f2:0e:51:
7e:e0:82:f3:24:80:cb:8d:54:3d:ca:15:5c:d4:43:
a9:5b:fb:dd:c8:3d:9d:15:a0:b9:8f:a7:b8:10:96:
a1:85:54:c4:89:21:9b:b3:36:8e:ee:f8:4c:1d:d1:
07:60:7c:eb:87:2f:ce:4d:36:a8:27:cd:c8:90:23:
70:db:ca:c5:91:4d:4f:42:2b:e3:35:73:f1:ad:66:
f2:7c:17:43:b6:03:3f:3d
coefficient:
20:ba:41:01:b4:c7:61:a0:69:75:7a:cd:e1:ac:42:
9b:dc:1b:27:31:09:96:4d:0f:bf:d0:6f:35:79:72:
e4:b8:94:ff:12:6c:82:9a:4f:fe:09:8f:f4:d9:94:
37:c4:0a:9a:9d:dd:9b:13:3d:51:bd:fa:0d:81:a9:
65:1c:8f:29:b2:9f:8c:a4:1f:4a:b6:8b:5f:0a:24:
af:b6:88:9b:88:dc:ec:ec:34:34:10:60:4e:c7:d2:
11:aa:93:81:88:98:f5:ac:5c:a9:a6:12:f4:8e:62:
c9:f4:19:b7:d2:a5:fe:12:57:e9:a4:fd:b3:63:3e:
0d:07:dc:87:36:85:5a:44
经过对比可以知道,结构为
RSAPrivateKey ::= SEQUENCE {
version Version,
modulus INTEGER, -- n
publicExponent INTEGER, -- e
privateExponent INTEGER, -- d
prime1 INTEGER, -- p
prime2 INTEGER, -- q
exponent1 INTEGER, -- d mod (p-1)
exponent2 INTEGER, -- d mod (q-1)
coefficient INTEGER -- (inverse of q) mod p
}
2048bit的私钥文件和1024bit的私钥文件对比
2048 | 02820101(n) | 0203(e) | 028201(d) | 028181(p) | 028181(q) | 028180(d % (p-1)) | 028180(d % (q-1)) | 028180(invert(q,p)) |
---|---|---|---|---|---|---|---|---|
1024 | 028181(n) | 0203(e) | 028180(d) | 024100(p) | 024100(q) | 0240 | 0240 | 0240 |
这个表也没权威性,找参数就找02这样的分隔符就好了。
NSSCTFRound16——break¶
题目给出如下文件:
pri-break.pem
Bc8tSTrvGJm2oYuCzIz+Yg4nwwKBgQDiYUawe5Y+rPbFhVOMVB8ZByfMa4LjeSDd
Z23jEGvylBHSeyvFCQq3ISUE40k1D2XmmeaZML3a1nUn6ORIWGaG2phcwrWLkR6n
ubVmb1QJSzgzmFHGnL56KHByZxD9q6DPB+o6gGWt8/6ddBl2NIZU/1btdPQgojfA
XXJFzR92RQKBgQC7qlB0U7m2U4FdG9eelSd+WSKNUVllZAuHji7jgh7Ox6La9xN5
miGZ1yvP44yX218OJ9Zi08o6vIrM6Eil45KzTtGm4iuIn8CMpox+5eUtoxyvxa9r
s2Wu+IRZN9zCME+p+qI8/TG27dIyDzsdgNqcUo8ESls7uW5/FEA7bYTCiQKBgQC7
1KybeB+kZ0zlfIdi8tVOpeI+uaHDbdh3+/5wHUsD3hmfg7VAag0q/2RA1vkB/oG1
QVLVHl0Yu0I/1/u5jyeakrtClAegAsvlrK+3i321rGS4YpTPb3SX1P/f3GZ7o7Ds
touA+NHk8IL9T7xkmJYw5h/RLG32ucH6aU6MXfLR5QKBgD/skfdFxGWxhHk6U1mS
27IM9jJNg9xLz5nxzkqPPhLn+rdgIIuTuQtv++eEjEP++7ZV10rg5yKVJd/bxy8H
2IN7aQo7kZWulHTQDZMFwgOhn0u6glJi+qC8bWzYDFOQSFrY9XQ3vwKMspqm+697
xM+dMUW0LML6oUE9ZjEiAY/5
-----END PRIVATE KEY-----
cipher.txt
6081370370545409218106271903400346695565292992689150366474451604281551878507114813906275593034729563149286993189430514737137534129570304832172520820901940874698337733991868650159489601159238582002010625666203730677577976307606665760650563172302688129824842780090723167480409842707790983962415315804311334507726664838464859751689906850572044873633896253285381878416855505301919877714965930289139921111644393144686543207867970807469735534838601255712764863973853116693691206791007433101433703535127367245739289103650669095061417223994665200039533840922696282929063608853551346533188464573323230476645532002621795338655
cipher中这个值是2046bit,可以推出n是2048bit的
这个私钥文件的内容转成16进制得到
05 cf 2d 49 3a ef 18 99 b6 a1 8b 82 cc 8c fe 62 0e 27 c3
02 81 81 00
e2 61 46 b0 7b 96 3e ac f6 c5 85 53 8c 54 1f 19 07 27 cc 6b 82 e3 79 20 dd 67 6d e3 10 6b f2 94 11 d2 7b 2b c5 09 0a b7 21 25 04 e3 49 35 0f 65 e6 99 e6 99 30 bd da d6 75 27 e8 e4 48 58 66 86 da 98 5c c2 b5 8b 91 1e a7 b9 b5 66 6f 54 09 4b 38 33 98 51 c6 9c be 7a 28 70 72 67 10 fd ab a0 cf 07 ea 3a 80 65 ad f3 fe 9d 74 19 76 34 86 54 ff 56 ed 74 f4 20 a2 37 c0 5d 72 45 cd 1f 76 45
02 81 81 00
bb aa 50 74 53 b9 b6 53 81 5d 1b d7 9e 95 27 7e 59 22 8d 51 59 65 64 0b 87 8e 2e e3 82 1e ce c7 a2 da f7 13 79 9a 21 99 d7 2b cf e3 8c 97 db 5f 0e 27 d6 62 d3 ca 3a bc 8a cc e8 48 a5 e3 92 b3 4e d1 a6 e2 2b 88 9f c0 8c a6 8c 7e e5 e5 2d a3 1c af c5 af 6b b3 65 ae f8 84 59 37 dc c2 30 4f a9 fa a2 3c fd 31 b6 ed d2 32 0f 3b 1d 80 da 9c 52 8f 04 4a 5b 3b b9 6e 7f 14 40 3b 6d 84 c2 89
02 81 81 00
bb d4 ac 9b 78 1f a4 67 4c e5 7c 87 62 f2 d5 4e a5 e2 3e b9 a1 c3 6d d8 77 fb fe 70 1d 4b 03 de 19 9f 83 b5 40 6a 0d 2a ff 64 40 d6 f9 01 fe 81 b5 41 52 d5 1e 5d 18 bb 42 3f d7 fb b9 8f 27 9a 92 bb 42 94 07 a0 02 cb e5 ac af b7 8b 7d b5 ac 64 b8 62 94 cf 6f 74 97 d4 ff df dc 66 7b a3 b0 ec b6 8b 80 f8 d1 e4 f0 82 fd 4f bc 64 98 96 30 e6 1f d1 2c 6d f6 b9 c1 fa 69 4e 8c 5d f2 d1 e5
02 81 80
3f ec 91 f7 45 c4 65 b1 84 79 3a 53 59 92 db b2 0c f6 32 4d 83 dc 4b cf 99 f1 ce 4a 8f 3e 12 e7 fa b7 60 20 8b 93 b9 0b 6f fb e7 84 8c 43 fe fb b6 55 d7 4a e0 e7 22 95 25 df db c7 2f 07 d8 83 7b 69 0a 3b 91 95 ae 94 74 d0 0d 93 05 c2 03 a1 9f 4b ba 82 52 62 fa a0 bc 6d 6c d8 0c 53 90 48 5a d8 f5 74 37 bf 02 8c b2 9a a6 fb af 7b c4 cf 9d 31 45 b4 2c c2 fa a1 41 3d 66 31 22 01 8f f9
我们已知\(q,d_p,d_q,q^{-1}\)
直接用\(m = c^{d_p} \mod p\)解即可
exp
from Crypto.Util.number import *
q = 0xe26146b07b963eacf6c585538c541f190727cc6b82e37920dd676de3106bf29411d27b2bc5090ab7212504e349350f65e699e69930bddad67527e8e448586686da985cc2b58b911ea7b9b5666f54094b38339851c69cbe7a2870726710fdaba0cf07ea3a8065adf3fe9d741976348654ff56ed74f420a237c05d7245cd1f7645
dp = 0xbbaa507453b9b653815d1bd79e95277e59228d515965640b878e2ee3821ecec7a2daf713799a2199d72bcfe38c97db5f0e27d662d3ca3abc8acce848a5e392b34ed1a6e22b889fc08ca68c7ee5e52da31cafc5af6bb365aef8845937dcc2304fa9faa23cfd31b6edd2320f3b1d80da9c528f044a5b3bb96e7f14403b6d84c289
dq = 0xbbd4ac9b781fa4674ce57c8762f2d54ea5e23eb9a1c36dd877fbfe701d4b03de199f83b5406a0d2aff6440d6f901fe81b54152d51e5d18bb423fd7fbb98f279a92bb429407a002cbe5acafb78b7db5ac64b86294cf6f7497d4ffdfdc667ba3b0ecb68b80f8d1e4f082fd4fbc64989630e61fd12c6df6b9c1fa694e8c5df2d1e5
inv = 0x3fec91f745c465b184793a535992dbb20cf6324d83dc4bcf99f1ce4a8f3e12e7fab760208b93b90b6ffbe7848c43fefbb655d74ae0e7229525dfdbc72f07d8837b690a3b9195ae9474d00d9305c203a19f4bba825262faa0bc6d6cd80c5390485ad8f57437bf028cb29aa6fbaf7bc4cf9d3145b42cc2faa1413d663122018ff9
c = 6081370370545409218106271903400346695565292992689150366474451604281551878507114813906275593034729563149286993189430514737137534129570304832172520820901940874698337733991868650159489601159238582002010625666203730677577976307606665760650563172302688129824842780090723167480409842707790983962415315804311334507726664838464859751689906850572044873633896253285381878416855505301919877714965930289139921111644393144686543207867970807469735534838601255712764863973853116693691206791007433101433703535127367245739289103650669095061417223994665200039533840922696282929063608853551346533188464573323230476645532002621795338655
m = pow(c,dq,q)
print(long_to_bytes(m))
## flag{oi!_you_find___what_i_Wa1t_talK_y0n!!!}
2022蓝帽杯——corrupted_key¶
task.py
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
from secret import flag
key = RSA.generate(1024)
open("flag.enc",'wb').write(PKCS1_OAEP.new(key.publickey()).encrypt(flag))
open('priv.pem','wb').write(key.exportKey('PEM'))
priv.pem
-----BEGIN RSA PRIVATE KEY-----
MIICXgIBAAKBgQDXFSUGqpzsBeUzXWtG9UkUB8MZn9UQkfH2Aw03YrngP0nJ3NwH
UFTgzBSLl0tBhUvZO07haiqHbuYgBegO+Aa3qjtksb+bH6dz41PQzbn/l4Pd1fXm
dJmtEPNh6TjQC4KmpMQqBTXF52cheY6GtFzUuNA7DX51wr6HZqHoQ73GQQIDAQAB
yQvOzxy6szWFheigQdGxAkEA4wFss2CcHWQ8FnQ5w7k4uIH0I38khg07HLhaYm1c
zUcmlk4PgnDWxN+ev+vMU45O5eGntzaO3lHsaukX9461mA==
-----END RSA PRIVATE KEY-----
把已有的内容进行解码,可以得到\(n,e\),inverse(q,p),以及\(d_q\)的低120位
30 82 02 5e
02 01
00
02 81 81 00
d7 15 25 06 aa 9c ec 05 e5 33 5d 6b 46 f5 49 14 07 c3 19 9f d5 10 91 f1 f6 03 0d 37 62 b9 e0 3f 49 c9 dc dc 07 50 54 e0 cc 14 8b 97 4b 41 85 4b d9 3b 4e e1 6a 2a 87 6e e6 20 05 e8 0e f8 06 b7 aa 3b 64 b1 bf 9b 1f a7 73 e3 53 d0 cd b9 ff 97 83 dd d5 f5 e6 74 99 ad 10 f3 61 e9 38 d0 0b 82 a6 a4 c4 2a 05 35 c5 e7 67 21 79 8e 86 b4 5c d4 b8 d0 3b 0d 7e 75 c2 be 87 66 a1 e8 43 bd c6 41
02 03
01 00 01
c9 0b ce cf 1c ba b3 35 85 85 e8 a0 41 d1 b1
02 41 00
e3 01 6c b3 60 9c 1d 64 3c 16 74 39 c3 b9 38 b8 81 f4 23 7f 24 86 0d 3b 1c b8 5a 62 6d 5c cd 47 26 96 4e 0f 82 70 d6 c4 df 9e bf eb cc 53 8e 4e e5 e1 a7 b7 36 8e de 51 ec 6a e9 17 f7 8e b5 98
两边同乘e
即
枚举k,解方程即求出所有\(q\)的低120位的可能取值
两边同乘q得到
即
然后用coper求解
exp.sage
#sage
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
from gmpy2 import *
from tqdm import *
n = 0xd7152506aa9cec05e5335d6b46f5491407c3199fd51091f1f6030d3762b9e03f49c9dcdc075054e0cc148b974b41854bd93b4ee16a2a876ee62005e80ef806b7aa3b64b1bf9b1fa773e353d0cdb9ff9783ddd5f5e67499ad10f361e938d00b82a6a4c42a0535c5e76721798e86b45cd4b8d03b0d7e75c2be8766a1e843bdc641
e = 0x10001
inv = 0xe3016cb3609c1d643c167439c3b938b881f4237f24860d3b1cb85a626d5ccd4726964e0f8270d6c4df9ebfebcc538e4ee5e1a7b7368ede51ec6ae917f78eb598
d_low = 0xc90bcecf1cbab3358585e8a041d1b1
q_low = []
c = open("flag.enc",'rb').read()
for i in trange(1,e):
try:
q0 = invert(i, 2 ** 120) * (e * d_low + i - 1) % 2 ^ 120
q_low.append(q0)
except:
continue
PR.<x> = PolynomialRing(Zmod(n))
for i in trange(len(q_low)-1,-1,-1):
f = inv * (2^120*x + int(q_low[i]))^2 - (2^120*x + int(q_low[i]))
f = f.monic()
root = f.small_roots(X = 2^(512-120))
if root:
q = 2^120 * int(root[0]) + int(q_low[i])
p = n // q
if p * q == n:
d = gmpy2.invert(e, (p - 1) * (q - 1))
print("p = ",p)
print("q = ",q)
print("d = ",d)
key = RSA.construct((int(n),int(e),int(d),int(p),int(q)))
newkey = PKCS1_OAEP.new(key)
flag = newkey.decrypt(c)
print(flag)
break
2024CISCN——ezrsa¶
task.py
from Crypto.Util.number import *
from Crypto.PublicKey import RSA
import random
from secret import flag
m = bytes_to_long(flag)
key = RSA.generate(1024)
passphrase = str(random.randint(0,999999)).zfill(6).encode()
output = key.export_key(passphrase=passphrase).split(b'\n')
for i in range(7, 15):
output[i] = b'*' * 64
with open("priv.pem", 'wb') as f:
for line in output:
f.write(line + b'\n')
with open("enc.txt", 'w') as f:
f.write(str(key._encrypt(m)))
priv.pem
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,435BF84C562FE793
9phAgeyjnJYZ6lgLYflgduBQjdX+V/Ph/fO8QB2ZubhBVOFJMHbwHbtgBaN3eGlh
WiEFEdQWoOFvpip0whr4r7aGOhavWhIfRjiqfQVcKZx4/f02W4pcWVYo9/p3otdD
ig+kofIR9Ky8o9vQk7H1eESNMdq3PPmvd7KTE98ZPqtIIrjbSsJ9XRL+gr5a91gH
****************************************************************
****************************************************************
****************************************************************
****************************************************************
****************************************************************
****************************************************************
****************************************************************
****************************************************************
hQds7ZdA9yv+yKUYv2e4de8RxX356wYq7r8paBHPXisOkGIVEBYNviMSIbgelkSI
jLQka+ZmC2YOgY/DgGJ82JmFG8mmYCcSooGL4ytVUY9dZa1khfhceg==
-----END RSA PRIVATE KEY-----
类似蓝帽杯2022的corrupted_key
不一样的是,这题得到的pem文件内容是加密的
根据代码
找到Crypto下的源代码
RSA.py
发现关键代码
如果passphrase存在,则随机生成一个salt,然后使用PKBDF1方法加密两次拼接得到key。
此时使用的加密方式为3des,模式为cbc,iv为salt
由此我们可以根据passphrase的生成方式来爆破出唯一的passphrase
根据私钥的格式,开头一定是3082,再根据n为1024bit,那么在私钥中n的格式为028181,加密参数e大概率为65537,即0x10001
那么其在私钥中则为 0203010001。
解密后存在如下特征的明文,那么当前的passphrase为所求
from Crypto.Cipher import DES3
from Crypto.Protocol.KDF import PBKDF1
from Crypto.Hash import MD5
import base64
enc1 = "9phAgeyjnJYZ6lgLYflgduBQjdX+V/Ph/fO8QB2ZubhBVOFJMHbwHbtgBaN3eGlhWiEFEdQWoOFvpip0whr4r7aGOhavWhIfRjiqfQVcKZx4/f02W4pcWVYo9/p3otdDig+kofIR9Ky8o9vQk7H1eESNMdq3PPmvd7KTE98ZPqtIIrjbSsJ9XRL+gr5a91gH"
enc2 = "hQds7ZdA9yv+yKUYv2e4de8RxX356wYq7r8paBHPXisOkGIVEBYNviMSIbgelkSIjLQka+ZmC2YOgY/DgGJ82JmFG8mmYCcSooGL4ytVUY9dZa1khfhceg=="
salt = bytes.fromhex("435bf84c562fe793")
dict = [str(i).zfill(6).encode() for i in range(0,1000000)]
for passphrase in dict:
key = PBKDF1(passphrase, salt, 16, 1, MD5)
key += PBKDF1(key + passphrase, salt, 8, 1, MD5)
cipher = DES3.new(key, DES3.MODE_CBC, salt)
data = cipher.decrypt(base64.b64decode(enc1)).hex()
if data.startswith("3082") and "028181" in data and "0203010001" in data:
print(data)
print(passphrase)
data2 = cipher.decrypt(base64.b64decode(enc2)).hex()
print(data2)
break
得到
30 82 02 5c
02 01
00
02 81 81 00
a1 8f 01 1b eb ac ce da 1c 68 12 73 0b 9e 62 72 0d 3c bd 68 57 af 2c f8 43 18 60 f5 dc 83 c5 52 0f 24 2f 3b e7 c9 e9 6d 7f 96 b4 18 98 ff 00 0f db 7e 43 ef 6f 1e 71 7b 2b 79 00 f3 56 60 a2 1d 1b 16 b5 18 49 be 97 a0 b0 f7 cb cf 5c fe 0f 00 37 0c ce 61 93 fe fa 1f ed 97 b3 7b d3 67 a6 73 56 51 62 ce 17 b0 22 57 08 c0 32 96 1d 17 5b bc 2c 82 9b f2 e1 6e ab c7 e0 88 1f ec a0 97 5c 81
02 03
01 00 01
6a 03 30 64 c5 a0 dff c8 f2 36 3b 34 0e 50 24 05 f1 52 c4 29 87 1a 7a cd d2 8b e1 b6 43 b4 65 28 00 b8 8a 3d 23 cc 57 47 7d 75 dd 55 55 b6 35 16 76 16 ef 5c 60 9d 69 ce 3c 2a ed cb 03 b6 2f 92 9b bc d8 91 ca dc 0b a0 31 ae 6f ec 8a 21 16 d0 80 80 80 80 80 80 80 8
再根据私钥格式提取n,e,dq,inv
因为本题中中间部分的私钥文件缺失,而且加密是cbc的,导致enc2第一块解密的结果错误,需要去掉,也就是说正确的dq只有48bit
因此得到
n = 0xa18f011bebacceda1c6812730b9e62720d3cbd6857af2cf8431860f5dc83c5520f242f3be7c9e96d7f96b41898ff000fdb7e43ef6f1e717b2b7900f35660a21d1b16b51849be97a0b0f7cbcf5cfe0f00370cce6193fefa1fed97b37bd367a673565162ce17b0225708c032961d175bbc2c829bf2e16eabc7e0881feca0975c81
e = 65537
dq_leak= 0x8f2363b340e5
inv = 0x5f152c429871a7acdd28be1b643b4652800b88a3d23cc57477d75dd5555b635167616ef5c609d69ce3c2aedcb03b62f929bbcd891cadc0ba031ae6fec8a2116d
k可以爆破,但不知道q,所以没办法构造1元coppersmith
同乘kq
此时会有个突兀的q,不好处理,我们再同乘k,得到
得到两个式子:
恢复出dq之后,\(q = (ed_q + k - 1) // k\)
from tqdm import *
from Crypto.Util.number import *
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
n = 0xa18f011bebacceda1c6812730b9e62720d3cbd6857af2cf8431860f5dc83c5520f242f3be7c9e96d7f96b41898ff000fdb7e43ef6f1e717b2b7900f35660a21d1b16b51849be97a0b0f7cbcf5cfe0f00370cce6193fefa1fed97b37bd367a673565162ce17b0225708c032961d175bbc2c829bf2e16eabc7e0881feca0975c81
e = 65537
dq_leak= 0x8f2363b340e5
inv = 0x5f152c429871a7acdd28be1b643b4652800b88a3d23cc57477d75dd5555b635167616ef5c609d69ce3c2aedcb03b62f929bbcd891cadc0ba031ae6fec8a2116d
c = 55149764057291700808946379593274733093556529902852874590948688362865310469901900909075397929997623185589518643636792828743516623112272635512151466304164301360740002369759704802706396320622342771513106879732891498365431042081036698760861996177532930798842690295051476263556258192509634233232717503575429327989
def coppersmith(k):
R.<x> = PolynomialRing(Zmod(n))
tmp = e * (x * 2^48 + dq_leak) + k - 1 ## kq
f = inv * tmp^2 - k*tmp
f = f.monic()
x0 = f.small_roots(X=2^464,beta=1,epsilon=0.09)
return x0
for k in trange(1,e):
x0 = coppersmith(k)
if x0 != []:
dq = int(x0[0]) * 2^48 + dq_leak
q = (e*dq + k - 1) // k
## print(f"k = {k}")
## k = 47794
p = n // q
d = inverse(e,(p-1)*(q-1))
m = pow(c,d,n)
print(long_to_bytes(int(m)))
## b'flag{df4a4054-23eb-4ba4-be5e-15b247d7b819}'
break
参考:20220709-蓝帽杯-CryptoSecWriteUp | 4XWi11's Blog
在求出q后,其实pow(c,dq,q)
也能出flag,不用求p