引言
马上开学了,摸了
打了DASCTF八月赛,比赛结束前1小时参赛,结果解题最多的题没做出来(啊这)
[DASCTF八月赛 2021]easymath
比赛的时候没做出来,后来Pheonix大佬告诉了我解法
给的代码很短:
assert(len(open('flag.txt', 'rb').read()) < 50)
assert(str(int.from_bytes(open('flag.txt', 'rb').read(), byteorder='big') << 10000).endswith(
'1862790884563160582365888530869690397667546628710795031544304378154769559410473276482265448754388655981091313419549689169381115573539422545933044902527020209259938095466283008'))
做到时候很疑惑,把给的数字转换成二进制也就五百多位,哪来左移10000位呢
也可以有这样的关系式:
e
n
d
=
f
l
a
g
∗
2
10000
m
o
d
1
0
175
end = flag * 2^{10000}\space mod \space 10^{175}
end=flag∗210000 mod 10175
其中175是给的结尾部分的十进制位数,模
1
0
175
10^{175}
10175的目的是为了求
2
10000
2^{10000}
210000的逆元,得到flag
解密代码如下:
from Crypto.Util.number import *
end = 1862790884563160582365888530869690397667546628710795031544304378154769559410473276482265448754388655981091313419549689169381115573539422545933044902527020209259938095466283008
# end = flag*2**{10000} mod 10^{175}
t = inverse(2**10000, 10**175)
m = long_to_bytes(((end * t) % 10**175) // GCD(2**10000, 10**175))
print(m)
结果为:
这里值得注意的是,如果用t = gmpy2.invert(2**10000, 10**175)
,则会报错:
那为什么用Crypto.Util.number
库的inverse
就行呢?还有,为什么要除GCD(2**10000, 10**175)
呢?
模逆元的定义中有这样一段话:
整数 a 对模数 n 之模逆元存在的充分必要条件是 a 和 n 互素,若此模逆元存在,在模数 n 下的除法可以用和对应模逆元的乘法来达成,此概念和实数除法的概念相同
本题中
1
0
175
10^{175}
10175和
2
10000
2^{10000}
210000显然不互素,inverse
先分离出了GCD(2**10000, 10**175)
,才可以进行模逆元计算,因此最后要除GCD(2**10000, 10**175)
[DASCTF八月赛 2021]let’s play with rsa~
加密代码如下:
from sympy import isprime,nextprime
from Crypto.Util.number import getPrime as getprime ,long_to_bytes,bytes_to_long,inverse
flag='flag{***************}'
def play():
p=getprime(1024)
q=getprime(1024)
n=p*q
e=65537
print "Hello,let's play rsa~\n"
print 'Now,I make some numbers,wait a second\n'
n1=getprime(200)
n2=getprime(200)
number=n1*n2
print "Ok,i will send two numbers to you,one of them was encoded.\n"
print "Encode n1:%d,\n"%(pow(n1,e,n))
print "And n2:%d.\n"%n2
print "Information that can now be made public:the public key (n,e):(%d,%d)\n"%(n,e)
while True:
try:
c=int(raw_input("ok,now,tell me the value of the number (encode it for safe):"))
except:
print "Sorry,the input is illeagal, and the integer is accept~"
else:
break
d=inverse(e,(p-1)*(q-1))
m=pow(c,d,n)
if m==number:
print "It's easy and interesting,didn't it?\n"
print "This is the gift for you :"+flag
else:
print "Emmmmm,there is something wrong, bye~\n"
if __name__ == '__main__':
play()
先随机生成了两个数n1,n2
,然后给了我们pow(n1,e,n)
和n2
,让我们传进去一个c
使得c
最后RSA解密后与n1*n2
相等
那直接把n2
加密之后和pow(n1,e,n)
相乘,传进去不就行了吗(啊这)
生成c
代码如下:
c1 =
n2 =
n =
e = 65537
c2 = pow(n2, e, n)
print(c1*c2 % n)
把结果传入即可
[DASCTF八月赛 2021]ezRSA
加密代码如下:
from secret import flag
from Crypto.Util.number import *
from random import getrandbits
from hashlib import sha256
class EzRsa:
def __init__(self):
self.E = 0x10001
self.P = getPrime(1024)
self.Q = getPrime(1024)
while GCD((self.P-1)*(self.Q-1), self.E) != 1:
self.Q = getPrime(1024)
self.N = self.P*self.Q
def encrypt(self):
f = getrandbits(32)
c = pow(f, self.E, self.N)
return (f, c)
def encrypt_flag(self, flag):
f = bytes_to_long(flag)
c = pow(f, self.E, self.N)
return c
def proof():
seed = getrandbits(32)
print(seed)
sha = sha256(str(seed).encode()).hexdigest()
print(f"sha256({seed>>18}...).hexdigest() = {sha}")
sha_i = input("plz enter seed: ")
if sha256(sha_i.encode()).hexdigest() != sha:
exit(0)
if __name__ == "__main__":
proof()
print("welcome to EzRsa")
print("""
1. Get flag
2. Encrypt
3. Insert
4. Exit
""")
A = EzRsa()
coin = 5
while coin > 0:
choose = input("> ")
if choose == "1":
print(
f"pow(flag,e,n) = {A.encrypt_flag(flag)}\ne = 0x10001")
exit(0)
elif choose == "2":
f, c = A.encrypt()
print(f"plain = {f}\ncipher = {c}")
coin -= 1
elif choose == "3":
q = getrandbits(1024)
n = A.P*q
f = getrandbits(32)
c = pow(f, 0x10001, n)
print(f"plain = {f}\ncipher = {c}")
coin -= 1
elif choose == "4":
print("bye~")
else:
print("wrong input")
print("Now you get the flag right?")
输入1,能得到加密后的flag和e
输入2,用EzRsa
中的公钥记为nt
,随机加密一个数,得到明文和密文
输入3,用EzRsa
中的p和一个随机生成的q生成新的公钥记为nk
,随机加密一个数,得到明文和密文
我们可以利用明文,e和密文得到公钥
由于有四次机会,可以得到一对nt
和一对nk
,由此得到输入2中的
n
1
=
g
c
d
(
n
t
1
,
n
t
2
)
n1 = gcd(nt1, nt2)
n1=gcd(nt1,nt2)和输入3中的
n
2
=
g
c
d
(
n
k
1
,
n
k
2
)
n2 = gcd(nk1, nk2)
n2=gcd(nk1,nk2),由于n1
和n2
有公因子p,得到
p
=
g
c
d
(
n
1
,
n
2
)
p = gcd(n1,n2)
p=gcd(n1,n2),所以可以分解EzRsa
中的n,得到flag
至于proof()
部分,不知道为什么,他把seed
都print出来了,直接复制就行了
解密代码如下:
from Crypto.Util.number import *
import gmpy2
ck1 = 10802736552802052334675431350693279487373514975583856720432908395157316583920875453552436496142443616668241018608905018877443641691597372943993746940796864088947110039691619330329829547914610310034042851600736815309651502714085552791205969637596625163884286216655679274373500381744546328590741571307166491219684988090657352142159038206188374695832891006030375956054657085966865212601720744964287594027579678929262839778089899170206998082556473498244863021611505400743727905185153354589976465321853027253539821633361185313034408565005594026376244077003811333923401071515437065293484027335646730805732706266190998912717
mk1 = 3467298486
ck2 = 7952426014817800345542743164212370465256522007694059040467262294139883798321376411423890059270181570060140439911489431487610048706425767050670076985945266595950167706634614499687295626618973683170430839755441335740665931270096392149318526814329218978695464692209823256428215580327499120933284877331428541567646264394511614834203230064225146095541013932153997347325545390454756521012184772766523934716861371813919366599810016530328522084402639154774851578047016291472426451432937369700785642186037817214135023341172743718729742706979406927034574357730393647164709577350234290575266246455335325036550238459460266826777
mk2 = 2637805758
ct1 = 5258297249437233269252734235581546483712740587856019368263741383010451771667214261941296958987255470129584667269164992391194597613632284942804492915958705615338348819026219002542835081068188830987745841778711674448286841103336689060336238552664704124260432965541782948103450178133013110447584887798935485919036836447185053522888046907188507552263118079180956315895262605349789171527309529542909346214121425645357866293754412692643751802750793196774012389022291591637648327944593680206557486483425679654293733112064106916782478544290625173885362276421903124336254498078544284381979906370583318057836106074195007704645
mt1 = 4018514725
ct2 = 2216710613849759291749271001172813296813995296942937937269459242162726262423838768504690540899513401365048563136110961705376280976325200801225641366994647978361247640072336671999168903599506081309580038964520354319361272932687736277969229054373565318758544270975463383927123441762751596885765477383664317818484566431143004646542531904764815747154445292706021915390615940095755639417784345435399786628193680479805174721200711052159068548732143161630778867220968156180570439298242013424813121308759181410582014316563549742660719169563010989100847264028027523510004333399915674385321042096844588069039993247180371045195
mt2 = 3768336235
e = 0x10001
c = 2409589959567577978959459059612176821685774169484662256361511224239193757207995235364470043362762616376254680228672727010474530311597231338182077689977346876997505890770280261284937438407769714519654847286916170373152881118623219276049395838329185415833388821874689670453791866822667341256546099953050403653918769534241514590069310425374668208283548693974017032984604264320169879760335946006653980827443567622501985484127746767154218399238266814865552396320059488020365523603371608242845046716068485196590482585388538864834136370002751749734914128047230447149334621639953462809629563555690666798206156581413136941807
nk1 = pow(mk1, e) - ck1
nk2 = pow(mk2, e) - ck2
n1 = gmpy2.gcd(nk1, nk2)
print(n1)
nt1 = pow(mt1, e) - ct1
nt2 = pow(mt2, e) - ct2
n2 = gmpy2.gcd(nt1, nt2)
print(n2)
p = gmpy2.gcd(n1, n2)
print(p)
print(gmpy2.is_prime(p))
q = n1 // p
print(q)
print(gmpy2.is_prime(q))
phi = (p-1)*(q-1)
d = inverse(e, phi)
m = pow(c, d, p*q)
print(long_to_bytes(m))
另外,发现Crypto.Util.number
中的GCD()
函数比gmpy2
的gcd()
计算较大数时慢很多
结语
希望继续坚持