CTF中RSA相关题型总结(持续更新)
e很小时:
import gmpy2
from functools import reduce
from Crypto.Util.number import long_to_bytes
def CRT(items):
N = reduce(lambda x, y: x * y, (i[1] for i in items))
result = 0
for a, n in items:
m = N // n
d, r, s = gmpy2.gcdext(n, m)
if d != 1:
raise Exception("Input not pairwise co-prime")
result += a * s * m
return result % N, N
# e, n, c
e = 0x3
n=[0x52d483c27cd806550fbe0e37a61af2e7cf5e0efb723dfc81174c918a27627779b21fa3c851e9e94188eaee3d5cd6f752406a43fbecb53e80836ff1e185d3ccd7782ea846c2e91a7b0808986666e0bdadbfb7bdd65670a589a4d2478e9adcafe97c6ee23614bcb2ecc23580f4d2e3cc1ecfec25c50da4bc754dde6c8bfd8d1fc16956c74d8e9196046a01dc9f3024e11461c294f29d7421140732fedacac97b8fe50999117d27943c953f18c4ff4f8c258d839764078d4b6ef6e8591e0ff5563b31a39e6374d0d41c8c46921c25e5904a817ef8e39e5c9b71225a83269693e0b7e3218fc5e5a1e8412ba16e588b3d6ac536dce39fcdfce81eec79979ea6872793]
c=[0x10652cdfaa6b63f6d7bd1109da08181e500e5643f5b240a9024bfa84d5f2cac9310562978347bb232d63e7289283871efab83d84ff5a7b64a94a79d34cfbd4ef121723ba1f663e514f83f6f01492b4e13e1bb4296d96ea5a353d3bf2edd2f449c03c4a3e995237985a596908adc741f32365]
data = list(zip(c, n))
x, n = CRT(data)
m = gmpy2.iroot(gmpy2.mpz(x), e)[0].digits()
print(m)
print(long_to_bytes(int(m)).decode())
解形如\(x^2(modp)\equiv r\)的同余方程
V&N2020 公开赛 easy_RSA
from random import randint
from gmpy2 import *
from Crypto.Util.number import *
def getprime(bits):
while 1:
n = 1
while n.bit_length() < bits:
n *= next_prime(randint(1,1000))
if isPrime(n - 1):
return n - 1
m = bytes_to_long(b'flag{************************************}')
p = getprime(505)
q = getPrime(512)
r = getPrime(512)
assert m < q
n = p * q * r
e = 0x10001
d = invert(q ** 2, p ** 2)
c = pow(m, 2, r)
cipher = pow(c, e, n)
print(n)
print(d)
print(cipher)
'''
7941371739956577280160664419383740967516918938781306610817149744988379280561359039016508679365806108722198157199058807892703837558280678711420411242914059658055366348123106473335186505617418956630780649894945233345985279471106888635177256011468979083320605103256178446993230320443790240285158260236926519042413378204298514714890725325831769281505530787739922007367026883959544239568886349070557272869042275528961483412544495589811933856131557221673534170105409
7515987842794170949444517202158067021118454558360145030399453487603693522695746732547224100845570119375977629070702308991221388721952258969752305904378724402002545947182529859604584400048983091861594720299791743887521228492714135449584003054386457751933095902983841246048952155097668245322664318518861440
1618155233923718966393124032999431934705026408748451436388483012584983753140040289666712916510617403356206112730613485227084128314043665913357106301736817062412927135716281544348612150328867226515184078966397180771624148797528036548243343316501503364783092550480439749404301122277056732857399413805293899249313045684662146333448668209567898831091274930053147799756622844119463942087160062353526056879436998061803187343431081504474584816590199768034450005448200
'''
c = pow(m, 2, r)
from sympy.ntheory.residue_ntheory import nthroot_mod
m=nthroot_mod(c,2,r)
完整exp:
from gmpy2 import *
from Crypto.Util.number import *
from sympy.ntheory.residue_ntheory import nthroot_mod
p=102634610559478918970860957918259981057327949366949344137104804864768237961662136189827166317524151288799657758536256924609797810164397005081733039415393
q=7534810196420932552168708937019691994681052660068275906973480617604535381306041583841106383688654426129050931519275383386503174076258645141589911492908993
r=10269028767754306217563721664976261924407940883784193817786660413744866184645984238866463711873380072803747092361041245422348883639933712733051005791543841
e=65537
phi=(p-1)*(q-1)*(r-1)
d=invert(e,phi)
n=p*q*r
cipher=1618155233923718966393124032999431934705026408748451436388483012584983753140040289666712916510617403356206112730613485227084128314043665913357106301736817062412927135716281544348612150328867226515184078966397180771624148797528036548243343316501503364783092550480439749404301122277056732857399413805293899249313045684662146333448668209567898831091274930053147799756622844119463942087160062353526056879436998061803187343431081504474584816590199768034450005448200
c=pow(cipher,d,n)
m=nthroot_mod(c,2,r)
print(long_to_bytes(m))
Rabin RSA:
import gmpy2
import libnum
from Crypto.Util.number import long_to_bytes
p=13934102561950901579
q=14450452739004884887
e = 2
c = 20442989381348880630046435751193745753
n = p*q
# Rebin算法
mp = gmpy2.powmod(c, (p+1)//4, p)
mq = gmpy2.powmod(c, (q+1)//4, q)
gcd1, a, b= gmpy2.gcdext(p, q) # 欧几里得扩展a*p+b*q=gcd1
r=(a*p*mq+b*q*mp)%n
r_=n-r
s=(a*p*mq-b*q*mp)%n
s_=n-s
print(f"r={libnum.n2s(int(r))}")
print(f"r_={libnum.n2s(int(r_))}")
print(f"s={libnum.n2s(int(s))}")
print(f"s_={libnum.n2s(int(s_))}")
pq生成不当:
from Crypto.Util.number import *
import sympy
#from secrets import flag
def get_happy_prime():
p = getPrime(512)
q = sympy.nextprime(p ^ ((1 << 512) - 1))
return p, q
m = bytes_to_long(flag)
p, q = get_happy_prime()
n = p * q
e = 65537
print(n)
print(pow(m, e, n))
# 24852206647750545040640868093921252282805229864862413863025873203291042799096787789288461426555716785288286492530194901130042940279109598071958012303179823645151637759103558737126271435636657767272703908384802528366090871653024192321398785017073393201385586868836278447340624427705360349350604325533927890879
# 14767985399473111932544176852718061186100743117407141435994374261886396781040934632110608219482140465671269958180849886097491653105939368395716596413352563005027867546585191103214650790884720729601171517615620202183534021987618146862260558624458833387692782722514796407503120297235224234298891794056695442287
q等于p取反的下一个素数
则
\[q \approx p \oplus ((1<<512) -1)
\]
则
\[q=(1<<512)-p+r
\]
则
\[p+q \approx (1<<512)
\]
所以我们可以构造
\[n=\sqrt{\big( \frac{p+q}{2} \big) ^2-\big( \frac{p-q}{2} \big)^2}
\]
因此可以求出\(p-q\)的值,因此 \(p=\frac{(p+q)-(p-q)}{2}\)
因此可以求出p的值
exp1:(以p能不能整除n作为判断条件)
from Crypto.Util.number import *
import gmpy2
n=24852206647750545040640868093921252282805229864862413863025873203291042799096787789288461426555716785288286492530194901130042940279109598071958012303179823645151637759103558737126271435636657767272703908384802528366090871653024192321398785017073393201385586868836278447340624427705360349350604325533927890879
c=14767985399473111932544176852718061186100743117407141435994374261886396781040934632110608219482140465671269958180849886097491653105939368395716596413352563005027867546585191103214650790884720729601171517615620202183534021987618146862260558624458833387692782722514796407503120297235224234298891794056695442287
t1=1<<512
p=(2**512+gmpy2.iroot((2**512)**2-4*n,2)[0])//2
p=int(p)
while n%p!=0:
p=gmpy2.next_prime(p)
q=n//p
phi=(p-1)*(q-1)
d=gmpy2.invert(e,phi)
m=pow(c,d,n)
print(long_to_bytes(m))
exp2:(以\(\sqrt{(p+q)^2-4n}\)能不能开方作为判断条件)
from Crypto.Util.number import *
import gmpy2
n=24852206647750545040640868093921252282805229864862413863025873203291042799096787789288461426555716785288286492530194901130042940279109598071958012303179823645151637759103558737126271435636657767272703908384802528366090871653024192321398785017073393201385586868836278447340624427705360349350604325533927890879
c=14767985399473111932544176852718061186100743117407141435994374261886396781040934632110608219482140465671269958180849886097491653105939368395716596413352563005027867546585191103214650790884720729601171517615620202183534021987618146862260558624458833387692782722514796407503120297235224234298891794056695442287
for r in range(10000000000):
t1=(1<<512)-1+r
t2,s=gmpy2.iroot(t1**2-4*n,2)
if s:
p=(t1+t2)//2
q=n//p
d=gmpy2.invert(e,(p-1)*(q-1))
print(long_to_bytes(pow(c,d,n)))
break
\(p^2+ q^2=N\)
使用sagemath的p,q=two_squares(N)
# #sage9.3
# from Crypto.Util.number import *
# flag = b'Kicky_Mu{KFC_v_me_50!!!}'
# p = getPrime(256)
# q = getPrime(256)
# n = p*q^3
# e = 0x10001
# N = pow(p, 2) + pow(q, 2)
# m = bytes_to_long(flag)
# c = pow(m,e,n)
#
# print(c)
# print(N)
from Crypto.Util.number import *
c = 34992437145329058006346797890363070594973075282993832268508442432592383794878795192132088668900695623924153165395583430068203662437982480669703879475321408183026259569199414707773374072930515794134567251046302713509056391105776219609788157691337060835717732824405538669820477381441348146561989805141829340641
N = 14131431108308143454435007577716000559419205062698618708133959457011972529354493686093109431184291126255192573090925119389094648901918393503865225710648658
p,q=two_squares(N)
n = p * pow(q, 3)
e = 0x10001
phi = (p - 1) * (pow(q, 3) - pow(q, 2))
d = inverse(e, phi)
m = pow(c, d, n)
print(long_to_bytes(m))
Coppersmith
已知m的高位,求m
n=10934282759418716864083387149400358148885247110933867252983794425632302624483291838978054379912661191455027376539730843211768681711588034738804296785076819
c=199928678441564572513071545433948014294972061145992950128884609861283198064457810780158231851803305318741555460032075238932950496972965422017125
(m>>72)<<72=584734024210391580014049648429032467639773954048
e=3
在\(Zmod(n)\)下,有\(m^3-c \equiv 0 \rightarrow (m_{high}+x)^3-c\equiv 0\)
exp:
from Crypto.Util.number import *
def phase2(high_m, n, c):
R.<x> = PolynomialRing(Zmod(n), implementation='NTL')
m = high_m + x
M = m((m^3 - c).small_roots()[0])
return M
n = 10934282759418716864083387149400358148885247110933867252983794425632302624483291838978054379912661191455027376539730843211768681711588034738804296785076819
c = 199928678441564572513071545433948014294972061145992950128884609861283198064457810780158231851803305318741555460032075238932950496972965422017125
high_m = 584734024210391580014049648429032467639773954048
M=phase2(high_m, n, c)
print(long_to_bytes(int(M)))
flag{this_is_a_flag}
已知p的高位,求m
n = 22251179507951667208988404735324990388496950479821651652239579051045817986824945842987389922759437945557559748313907295712994332924679954306619009079508267870910149223565520196385455171091011721532290110253401719887456896015127869765120008086727571060297059461651083340986173237394309195529977693665449059967337557768799655172974710341929078477027816362721220950313898766868468203962782247110726810571421671360963619837700834009507913757260784147014841481557088215597539779565493898663380798904766007590175316989637076522379230279938065198199833033309266088268398369881039750675835382713087914092008694800853680890199
c = 13791076590876280345965238373786427523823675722374540431144373789735114060078921115309660269509771288228144711168452947459244770278987545774287579571059845423259662466243727180866431665100157413245622442955953683599217851246153754699865188329020209657227990460455369896960050383820265224545863644175721361758413632638638545353172694886999221882770404353366722168355187142789778530832186215934690392286482192890311329246011772739859918291556448869621490688586398693159275264761107488552610343215662469995425523594866854716852872141401095283180173839653418794273521904566990987307557028155209305585359720312859989634334
(p>>128)<<128 = 150840505999598161819551431768821975459467574249752039047846845481249241887784911457438773307473629946085877682693884024926228559996574370474982369597013808808768450992113314638371133051992554697609546180277873202687064844984114775286878743211353292718680724328420518679703560272767696234210910831061812379648
exp:
from Crypto.Util.number import *
def phase3(high_p, n, c):
R.<x> = PolynomialRing(Zmod(n), implementation='NTL')
p = high_p + x
x0 = p.small_roots(X = 2^128, beta = 0.1,epsilon=0.02)[0]
P = int(p(x0))
Q = n // P
assert n == P*Q
d = inverse_mod(65537, (P-1)*(Q-1))
#print(power_mod(c, d, n))
return power_mod(c,d,n)
n = 22251179507951667208988404735324990388496950479821651652239579051045817986824945842987389922759437945557559748313907295712994332924679954306619009079508267870910149223565520196385455171091011721532290110253401719887456896015127869765120008086727571060297059461651083340986173237394309195529977693665449059967337557768799655172974710341929078477027816362721220950313898766868468203962782247110726810571421671360963619837700834009507913757260784147014841481557088215597539779565493898663380798904766007590175316989637076522379230279938065198199833033309266088268398369881039750675835382713087914092008694800853680890199
c = 13791076590876280345965238373786427523823675722374540431144373789735114060078921115309660269509771288228144711168452947459244770278987545774287579571059845423259662466243727180866431665100157413245622442955953683599217851246153754699865188329020209657227990460455369896960050383820265224545863644175721361758413632638638545353172694886999221882770404353366722168355187142789778530832186215934690392286482192890311329246011772739859918291556448869621490688586398693159275264761107488552610343215662469995425523594866854716852872141401095283180173839653418794273521904566990987307557028155209305585359720312859989634334
high_p = 150840505999598161819551431768821975459467574249752039047846845481249241887784911457438773307473629946085877682693884024926228559996574370474982369597013808808768450992113314638371133051992554697609546180277873202687064844984114775286878743211353292718680724328420518679703560272767696234210910831061812379648
M=phase3(high_p, n, c)
print(M)
print(long_to_bytes(M))
已知p的若干中间位
from Crypto.Util.number import *
flag = b'?'
e = 65537
p, q = getPrime(1024), getPrime(1024)
N = p * q
gift = p&(2**923-2**101)
m = bytes_to_long(flag)
c = pow(m, e, N)
print("N = ",N)
print("gift = ",gift)
print("c = ",c)
"""
N = 12055968471523053394851394038007091122809367392467691213651520944038861796011063965460456285088011754895260428814358599592032865236006733879843493164411907032292051539754520574395252298997379020268868972160297893871261713263196092380416876697472160104980015554834798949155917292189278888914003846758687215559958506116359394743135211950575060201887025032694825084104792059271584351889134811543088404952977137809673880602946974798597506721906751835019855063462460686036567578835477249909061675845157443679947730585880392110482301750827802213877643649659069945187353987713717145709188790427572582689339643628659515017749
p0 = 70561167908564543355630347620333350122607189772353278860674786406663564556557177660954135010748189302104288155939269204559421198595262277064601483770331017282701354382190472661583444774920297367889959312517009682740631673940840597651219956142053575328811350770919852725338374144
c = 2475592349689790551418951263467994503430959303317734266333382586608208775837696436139830443942890900333873206031844146782184712381952753718848109663188245101226538043101790881285270927795075893680615586053680077455901334861085349972222680322067952811365366282026756737185263105621695146050695385626656638309577087933457566501579308954739543321367741463532413790712419879733217017821099916866490928476372772542254929459218259301608413811969763001504245717637231198848196348656878611788843380115493744125520080930068318479606464623896240289381601711908759450672519228864487153103141218567551083147171385920693325876018
"""
exp:
N = 12055968471523053394851394038007091122809367392467691213651520944038861796011063965460456285088011754895260428814358599592032865236006733879843493164411907032292051539754520574395252298997379020268868972160297893871261713263196092380416876697472160104980015554834798949155917292189278888914003846758687215559958506116359394743135211950575060201887025032694825084104792059271584351889134811543088404952977137809673880602946974798597506721906751835019855063462460686036567578835477249909061675845157443679947730585880392110482301750827802213877643649659069945187353987713717145709188790427572582689339643628659515017749
p0 = 70561167908564543355630347620333350122607189772353278860674786406663564556557177660954135010748189302104288155939269204559421198595262277064601483770331017282701354382190472661583444774920297367889959312517009682740631673940840597651219956142053575328811350770919852725338374144
c = 2475592349689790551418951263467994503430959303317734266333382586608208775837696436139830443942890900333873206031844146782184712381952753718848109663188245101226538043101790881285270927795075893680615586053680077455901334861085349972222680322067952811365366282026756737185263105621695146050695385626656638309577087933457566501579308954739543321367741463532413790712419879733217017821099916866490928476372772542254929459218259301608413811969763001504245717637231198848196348656878611788843380115493744125520080930068318479606464623896240289381601711908759450672519228864487153103141218567551083147171385920693325876018
def bivariate(pol, XX, YY, kk=4):
N = pol.parent().characteristic()
f = pol.change_ring(ZZ)
PR, (x, y) = f.parent().objgens()
idx = [(k - i, i) for k in range(kk + 1) for i in range(k + 1)]
monomials = list(map(lambda t: PR(x ** t[0] * y ** t[1]), idx))
# collect the shift-polynomials
g = []
for h, i in idx:
if h == 0:
g.append(y ** h * x ** i * N)
else:
g.append(y ** (h - 1) * x ** i * f)
# construct lattice basis
M = Matrix(ZZ, len(g))
for row in range(M.nrows()):
for col in range(M.ncols()):
h, i = idx[col]
M[row, col] = g[row][h, i] * XX ** h * YY ** i
# LLL
B = M.LLL()
PX = PolynomialRing(ZZ, 'xs')
xs = PX.gen()
PY = PolynomialRing(ZZ, 'ys')
ys = PY.gen()
# Transform LLL-reduced vectors to polynomials
H = [(i, PR(0)) for i in range(B.nrows())]
H = dict(H)
for i in range(B.nrows()):
for j in range(B.ncols()):
H[i] += PR((monomials[j] * B[i, j]) / monomials[j](XX, YY))
# Find the root
poly1 = H[0].resultant(H[1], y).subs(x=xs)
poly2 = H[0].resultant(H[2], y).subs(x=xs)
poly = gcd(poly1, poly2)
x_root = poly.roots()[0][0]
poly1 = H[0].resultant(H[1], x).subs(y=ys)
poly2 = H[0].resultant(H[2], x).subs(y=ys)
poly = gcd(poly1, poly2)
y_root = poly.roots()[0][0]
return x_root, y_root
PR = PolynomialRing(Zmod(N), names='x,y')
x, y = PR.gens()
pol = 2 ** 923 * x + y + p0
x, y = bivariate(pol, 2 ** 101, 2 ** 101)
p = 2 ** 923 * x + y + p0
q = N // p
print(p)
print(q)
phi=(p-1)*(q-1)
e=65537
d=inverse(e,phi)
m=pow(c,d,N)
print(long_to_bytes(int(m)))