2024MOECTF Crypto Week2
第二周就开始接触一些简单的数论知识了,还有一些很有趣的题目,比如反素数,可能回过头看看觉得没什么(但深挖一下都很有内容吧,大佬手下留情了呜呜呜),当时做得还是很累,这就是学习的常态吗
大白兔
from Crypto.Util.number import *
flag = b'moectf{xxxxxxxxxx}'
m = bytes_to_long(flag)
e1 = 12886657667389660800780796462970504910193928992888518978200029826975978624718627799215564700096007849924866627154987365059524315097631111242449314835868137
e2 = 12110586673991788415780355139635579057920926864887110308343229256046868242179445444897790171351302575188607117081580121488253540215781625598048021161675697
def encrypt(m , e1 , e2):
p = getPrime(512)
q = getPrime(512)
N = p*q
c1 = pow((3*p + 7*q),e1,N)
c2 = pow((2*p + 5*q),e2,N)
e = 65537
c = pow(m , e , N)
return c
print(encrypt(m ,e1 , e2))
'''
N = 107840121617107284699019090755767399009554361670188656102287857367092313896799727185137951450003247965287300048132826912467422962758914809476564079425779097585271563973653308788065070590668934509937791637166407147571226702362485442679293305752947015356987589781998813882776841558543311396327103000285832158267
c1 = 15278844009298149463236710060119404122281203585460351155794211733716186259289419248721909282013233358914974167205731639272302971369075321450669419689268407608888816060862821686659088366316321953682936422067632021137937376646898475874811704685412676289281874194427175778134400538795937306359483779509843470045
c2 = 21094604591001258468822028459854756976693597859353651781642590543104398882448014423389799438692388258400734914492082531343013931478752601777032815369293749155925484130072691903725072096643826915317436719353858305966176758359761523170683475946913692317028587403027415142211886317152812178943344234591487108474
c = 21770231043448943684137443679409353766384859347908158264676803189707943062309013723698099073818477179441395009450511276043831958306355425252049047563947202180509717848175083113955255931885159933086221453965914552773593606054520151827862155643433544585058451821992566091775233163599161774796561236063625305050
'''
我们可以看到N是难以分解的,给出的c1和c2要我们求出p和q。
算一算吧!
又知道
由二项式展开可以舍掉含有$$p*q$$因式的项,则有
希望消掉q,不妨两边幂方再展开:
两式相减有
记左式为M,则有:
那么M必为p的倍数,也就是说:
利用这个公式快速得到p后,剩下就是一把梭哈
from Crypto.Util.number import *
import gmpy2
e1 = 12886657667389660800780796462970504910193928992888518978200029826975978624718627799215564700096007849924866627154987365059524315097631111242449314835868137
e2 = 12110586673991788415780355139635579057920926864887110308343229256046868242179445444897790171351302575188607117081580121488253540215781625598048021161675697
e=65537
N = 107840121617107284699019090755767399009554361670188656102287857367092313896799727185137951450003247965287300048132826912467422962758914809476564079425779097585271563973653308788065070590668934509937791637166407147571226702362485442679293305752947015356987589781998813882776841558543311396327103000285832158267
c1 = 15278844009298149463236710060119404122281203585460351155794211733716186259289419248721909282013233358914974167205731639272302971369075321450669419689268407608888816060862821686659088366316321953682936422067632021137937376646898475874811704685412676289281874194427175778134400538795937306359483779509843470045
c2 = 21094604591001258468822028459854756976693597859353651781642590543104398882448014423389799438692388258400734914492082531343013931478752601777032815369293749155925484130072691903725072096643826915317436719353858305966176758359761523170683475946913692317028587403027415142211886317152812178943344234591487108474
c = 21770231043448943684137443679409353766384859347908158264676803189707943062309013723698099073818477179441395009450511276043831958306355425252049047563947202180509717848175083113955255931885159933086221453965914552773593606054520151827862155643433544585058451821992566091775233163599161774796561236063625305050
p = GCD((pow(5,e1*e2,N)*pow(c1,e2,N) - pow(7,e1*e2,N)*pow(c2,e1,N))%N,N)
q=N//p
print(long_to_bytes(pow(c,gmpy2.invert(e,(p-1)*(q-1)),N)))
#moectf{Sh4!!0w_deeb4t0_P01arnova}
More_secure_RSA
from Crypto.Util.number import *
flag = b'moectf{xxxxxxxxxxxxxxxxx}'
m = bytes_to_long(flag)
p = getPrime(1024)
q = getPrime(1024)
n = p * q
e = 0x10001
c = pow(m, e, n)
print(f'c = {c}')
print(f'n = {n}')
'''
Oh,it isn't secure enough!
'''
r = getPrime(1024)
n = n * r
c = pow(m, e, n)
print(f'C = {c}')
print(f'N = {n}')
'''
c = 12992001402636687796268040906463852467529970619872166160007439409443075922491126428847990768804065656732371491774347799153093983118784555645908829567829548859716413703103209412482479508343241998746249393768508777622820076455330613128741381912099938105655018512573026861940845244466234378454245880629342180767100764598827416092526417994583641312226881576127632370028945947135323079587274787414572359073029332698851987672702157745794918609888672070493920551556186777642058518490585668611348975669471428437362746100320309846155934102756433753034162932191229328675448044938003423750406476228868496511462133634606503693079
n = 16760451201391024696418913179234861888113832949815649025201341186309388740780898642590379902259593220641452627925947802309781199156988046583854929589247527084026680464342103254634748964055033978328252761138909542146887482496813497896976832003216423447393810177016885992747522928136591835072195940398326424124029565251687167288485208146954678847038593953469848332815562187712001459140478020493313651426887636649268670397448218362549694265319848881027371779537447178555467759075683890711378208297971106626715743420508210599451447691532788685271412002723151323393995544873109062325826624960729007816102008198301645376867
C = 1227033973455439811038965425016278272592822512256148222404772464092642222302372689559402052996223110030680007093325025949747279355588869610656002059632685923872583886766517117583919384724629204452792737574445503481745695471566288752636639781636328540996436873887919128841538555313423836184797745537334236330889208413647074397092468650216303253820651869085588312638684722811238160039030594617522353067149762052873350299600889103069287265886917090425220904041840138118263873905802974197870859876987498993203027783705816687972808545961406313020500064095748870911561417904189058228917692021384088878397661756664374001122513267695267328164638124063984860445614300596622724681078873949436838102653185753255893379061574117715898417467680511056057317389854185497208849779847977169612242457941087161796645858881075586042016211743804958051233958262543770583176092221108309442538853893897999632683991081144231262128099816782478630830512
N = 1582486998399823540384313363363200260039711250093373548450892400684356890467422451159815746483347199068277830442685312502502514973605405506156013209395631708510855837597653498237290013890476973370263029834010665311042146273467094659451409034794827522542915103958741659248650774670557720668659089460310790788084368196624348469099001192897822358856214600885522908210687134137858300443670196386746010492684253036113022895437366747816728740885167967611021884779088402351311559013670949736441410139393856449468509407623330301946032314939458008738468741010360957434872591481558393042769373898724673597908686260890901656655294366875485821714239821243979564573095617073080807533166477233759321906588148907331569823186970816432053078415316559827307902239918504432915818595223579467402557885923581022810437311450172587275470923899187494633883841322542969792396699601487817033616266657366148353065324836976610554682254923012474470450197
'''
这是一道多素数RSA问题,随着质因数增加,RSA加密强度其实是降低,但可以有效减小生成密钥和解密的计算量,因此在现实中也有应用。
我们可以得到N的一个质因数r,到此我们就可以进行解密了:
即$$M^e-C=kN=kpqr$$
则
又r为素数,故有:
因此
其中d是e模r的逆元
from Crypto.Util.number import *
import gmpy2
c = 12992001402636687796268040906463852467529970619872166160007439409443075922491126428847990768804065656732371491774347799153093983118784555645908829567829548859716413703103209412482479508343241998746249393768508777622820076455330613128741381912099938105655018512573026861940845244466234378454245880629342180767100764598827416092526417994583641312226881576127632370028945947135323079587274787414572359073029332698851987672702157745794918609888672070493920551556186777642058518490585668611348975669471428437362746100320309846155934102756433753034162932191229328675448044938003423750406476228868496511462133634606503693079
n = 16760451201391024696418913179234861888113832949815649025201341186309388740780898642590379902259593220641452627925947802309781199156988046583854929589247527084026680464342103254634748964055033978328252761138909542146887482496813497896976832003216423447393810177016885992747522928136591835072195940398326424124029565251687167288485208146954678847038593953469848332815562187712001459140478020493313651426887636649268670397448218362549694265319848881027371779537447178555467759075683890711378208297971106626715743420508210599451447691532788685271412002723151323393995544873109062325826624960729007816102008198301645376867
C = 1227033973455439811038965425016278272592822512256148222404772464092642222302372689559402052996223110030680007093325025949747279355588869610656002059632685923872583886766517117583919384724629204452792737574445503481745695471566288752636639781636328540996436873887919128841538555313423836184797745537334236330889208413647074397092468650216303253820651869085588312638684722811238160039030594617522353067149762052873350299600889103069287265886917090425220904041840138118263873905802974197870859876987498993203027783705816687972808545961406313020500064095748870911561417904189058228917692021384088878397661756664374001122513267695267328164638124063984860445614300596622724681078873949436838102653185753255893379061574117715898417467680511056057317389854185497208849779847977169612242457941087161796645858881075586042016211743804958051233958262543770583176092221108309442538853893897999632683991081144231262128099816782478630830512
N = 1582486998399823540384313363363200260039711250093373548450892400684356890467422451159815746483347199068277830442685312502502514973605405506156013209395631708510855837597653498237290013890476973370263029834010665311042146273467094659451409034794827522542915103958741659248650774670557720668659089460310790788084368196624348469099001192897822358856214600885522908210687134137858300443670196386746010492684253036113022895437366747816728740885167967611021884779088402351311559013670949736441410139393856449468509407623330301946032314939458008738468741010360957434872591481558393042769373898724673597908686260890901656655294366875485821714239821243979564573095617073080807533166477233759321906588148907331569823186970816432053078415316559827307902239918504432915818595223579467402557885923581022810437311450172587275470923899187494633883841322542969792396699601487817033616266657366148353065324836976610554682254923012474470450197
r=N//n
e=65537
d=gmpy2.invert(e,r-1)
m=pow(C,d,r)
print(long_to_bytes(m))
#moectf{th3_a1g3br4_is_s0_m@gic!}
ezlegendre
from sympy import *
from Crypto.Util.number import *
p = getPrime(128)
a = randprime(2, p)
FLAG = b'moectf{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}'
def encrypt_flag(flag):
ciphertext = []
plaintext = ''.join([bin(i)[2:].zfill(8) for i in flag])
for bit in plaintext:
e = randprime(2, p)
n = pow(int(bit) + a, e , p)
ciphertext.append(n)
return ciphertext
print(encrypt_flag(FLAG))
'''
p = 303597842163255391032954159827039706827
a = 34032839867482535877794289018590990371
[278121435714344315140568219459348432240]
'''
这道题是把flag逐字转换为二进制后拼接并逐位加密,a和p已经告诉我们,问题在于随机数e是未知的,如果知道,也许可以逐位解出。
我们会想到对每一个列表元素分别爆破e求解,但电脑表示它要爆了。
这实际上是离散对数问题,与大数分解难题、椭圆曲线求解难题同为公钥加密的三大支柱。
在网上可以搜到有些题通过直接求解离散对数的非预期解,但这道题似乎计算量并不允许。
又搜到利用勒德让符号方法的预期解,结合标题ezlegendre或许这正是这道题的解法。
首先有:
因为
如果bit为0,则
有解,反之bit为1,这样我们可以求出整个二进制串。
以下进行推导:
如果$$bit=0$$
两边同时幂方则有
这是因为e是奇数
这样我们就把离散对数问题转化为了单纯容易的乘法计算了,若 n不满足上式,说明其对应的bit为1
from sympy import *
from Crypto.Util.number import *
p = 303597842163255391032954159827039706827
a = 34032839867482535877794289018590990371
ciphertext=[]
plaintext=''
for i in ciphertext:
if(pow(i,(p-1)//2,p)-p==-1):
plaintext+='0'
else:
plaintext+='1'
flag = ''
for i in range(0, len(plaintext), 8):
flag += chr(int(plaintext[i: i+8], 2))
print(flag)
#moectf{minus_one_1s_n0t_qu4dr4tic_r4sidu4_when_p_mod_f0ur_equ41_to_thr33}
当然官方wp是说a+1是p的二次剩余,那就直接判断i是否为二次剩余,如果是,则输出1。
这里掉坑了,python取模永远是非负数,等于-1的话要手动减去p。
new_system
from random import randint
from Crypto.Util.number import getPrime,bytes_to_long
flag = b'moectf{???????????????}'
gift = bytes_to_long(flag)
def parametergenerate():
q = getPrime(256)
gift1 = randint(1, q)
gift2 = (gift - gift1) % q
x = randint(1, q)
assert gift == (gift1 + gift2) % q
return q , x , gift1, gift2
def encrypt(m , q , x):
a = randint(1, q)
c = (a*x + m) % q
return [a , c]
q , x , gift1 , gift2 = parametergenerate()
print(encrypt(gift1 , q , x))
print(encrypt(gift2 , q , x))
print(encrypt(gift , q , x))
print(f'q = {q}')
'''
[48152794364522745851371693618734308982941622286593286738834529420565211572487, 21052760152946883017126800753094180159601684210961525956716021776156447417961]
[48649737427609115586886970515713274413023152700099032993736004585718157300141, 6060718815088072976566240336428486321776540407635735983986746493811330309844]
[30099883325957937700435284907440664781247503171217717818782838808179889651361, 85333708281128255260940125642017184300901184334842582132090488518099650581761]
q = 105482865285555225519947662900872028851795846950902311343782163147659668129411
'''
一道简单的消元解方程,不用管x是多少,直接就可以消掉了……
from random import randint
from Crypto.Util.number import getPrime,bytes_to_long,long_to_bytes
import gmpy2
a1=48152794364522745851371693618734308982941622286593286738834529420565211572487
c1=21052760152946883017126800753094180159601684210961525956716021776156447417961
a2=48649737427609115586886970515713274413023152700099032993736004585718157300141
c2=6060718815088072976566240336428486321776540407635735983986746493811330309844
a=30099883325957937700435284907440664781247503171217717818782838808179889651361
c=85333708281128255260940125642017184300901184334842582132090488518099650581761
q = 105482865285555225519947662900872028851795846950902311343782163147659668129411
t=(a*(c1+c2)-(a1+a2)*c)%q
s=(a-a1-a2)%q
d=gmpy2.invert(s,q)
g=(t*d)%q
print(long_to_bytes(g))
#b'moectf{gift_1s_present}'
RSA_revenge
from Crypto.Util.number import getPrime, isPrime, bytes_to_long
from secret import flag
def emirp(x):
y = 0
while x !=0:
y = y*2 + x%2
x = x//2
return y
while True:
p = getPrime(512)
q = emirp(p)
if isPrime(q):
break
n = p*q
e = 65537
m = bytes_to_long(flag)
c = pow(m,e,n)
print(f"{n = }")
print(f"{c = }")
"""
n = 141326884939079067429645084585831428717383389026212274986490638181168709713585245213459139281395768330637635670530286514361666351728405851224861268366256203851725349214834643460959210675733248662738509224865058748116797242931605149244469367508052164539306170883496415576116236739853057847265650027628600443901
c = 47886145637416465474967586561554275347396273686722042112754589742652411190694422563845157055397690806283389102421131949492150512820301748529122456307491407924640312270962219946993529007414812671985960186335307490596107298906467618684990500775058344576523751336171093010950665199612378376864378029545530793597
"""
这道题的q和p是有关系的。
我们知道对于二进制数,乘2代表左移一位,模2代表右移一位。因此不难发现q其实是p的二进制逆序数,而且还是素数。
其实函数名字就在提示我们了,emirp正是prime的逆序。
既然知道p与q的关系,自然的想法是遍历p并找到对应的q,且二者乘积等于n。
怎么爆破呢?
因为p和q相反,我们进行判定时一定需要p和q两个数,如果仅仅从低位到高位或者高位到低位爆破,二者乘积一开始只为512位,而n的大小介于1023~1024位之间,这样效率很低。
因此我们考虑从两端同时爆破,这样p和q一开始就有512位相乘,效率应当更好。
from Crypto.Util.number import getPrime, isPrime, bytes_to_long,long_to_bytes
import gmpy2
n = 141326884939079067429645084585831428717383389026212274986490638181168709713585245213459139281395768330637635670530286514361666351728405851224861268366256203851725349214834643460959210675733248662738509224865058748116797242931605149244469367508052164539306170883496415576116236739853057847265650027628600443901
c = 47886145637416465474967586561554275347396273686722042112754589742652411190694422563845157055397690806283389102421131949492150512820301748529122456307491407924640312270962219946993529007414812671985960186335307490596107298906467618684990500775058344576523751336171093010950665199612378376864378029545530793597
def factor(a,b,k):
if k==256:
if a*b==n:
print([a,b])
return a,b
else:
for i in range(2):
for j in range(2):
a1=a+i*(2**k)+j*(2**(511-k))
b1=b+j*(2**k)+i*(2**(511-k))
if a1*b1>n:
continue
if (a1+2**(511-k))*(b1+2**(511-k))<n :
continue
if (a1*b1)%(2**(k+1))!=n%(2**(k+1)):
continue
factor(a1,b1,k+1)
factor(0,0,0)
p=12119998731259483292178496920109290754181396164390285597126378297678818779092115139911720576157973310671490865211601201831597946479039132512609504866583931
q=11660635291534613230423193509391946961264539191735481147071890944740311229658362673314192872117237108949853531941630122241060679012089130178372253390640871
phi=(p-1)*(q-1)
e=65537
d=gmpy2.invert(e,phi)
m=pow(c,d,n)
print(long_to_bytes(m))
#b'moectf{WA!y0u@er***g00((d))}'