from Crypto.Util.number import * from gmpy2 import * import random, os from hashlib import sha1 from random import randrange flag=b'' x = bytes_to_long(flag)
defgen_key(): whileTrue: q = getPrime(160) p = 2 * getPrime(1024-160) * q+1 if isPrime(p): break h = random.randint(1, p - 1) g = powmod(h,(p-1)//q, p) y=pow(g,x,p) return p,q,g,y defcry(): a = p = getPrime(512) q = getPrime(512) d = getPrime(280) n = p * q e = inverse(d, (p - 1) * (q - 1)) c = pow(a, e, n) return n,e,c
而关于a的信息就是一个RSA加密结果,而在这个RSA加密中由于d较小,所以可以用boneh and durfee攻击得到d,然后就可以解密出a了。题目名字的not wiener也就用在这里,因为d的界大概是0.273,超过了wiener要求的$ \frac{1}{3}n^{\frac{1}{4}}$,但是却又小于boneh and durfee要求的理论上界0.292,而且并不极限所以不怎么需要调参数就能跑出来。
from sage.allimport * import itertools from hashlib import * from Crypto.Util.number import * from random import randint import ecdsa from math import ceil from secret import secret,hint,flag,my_own_prime
classRandom_EC(): def__init__(self,state = None,Gen_Curve = True): if state == None: self.state = getRandomNBitInteger(512) else: self.state = state if Gen_Curve: self.int_curve()
# get the confirmed curve else: Curve, P, Q = CURVE self.Curve = Curve self.g = Curve.gen(0) self.P = P self.Q = Q
defint_getkey(self): # To get the right random key t = int((self.state * self.Q).x()) self.int_updade() return t%(2**250)
defRSA_reinforce(self,key: int): p = my_own_prime(512) q = my_own_prime(512) n = p * q leak = p + q e = 16542764952 c = pow(key, e, n) return (c, n, leak)
defset_pri_key(self, d: int) -> None: self.pri_key = d self.pub_key = d * self.gen
defsign(self, msg: bytes, K_time:int) -> tuple:
if K_time == 0: K = long_to_bytes(self.Random.Random_key(self.Curve_length)) k = int(sha256(K).hexdigest(), 16) else: k = K_time
P = k * self.gen r = int(P.x()) k_v = int(inverse(k, self.order)) e = int(sha256(msg).hexdigest(), 16) s = (e + self.pri_key * r) * k_v % self.order # print('k = ',k) return r, s, k
e = int(sha256(msg).hexdigest(), 16) w = int(inverse(s, self.order)) u1 = e * w % self.order u2 = r * w % self.order P = u1 * self.gen + u2 * self.pub_key returnint(r) == int(P.x())
definto_secret(self, msg: int) -> tuple: # sage E = EllipticCurve(GF(int(NIST384p.curve.p())),[int(NIST384p.curve.a()), int(NIST384p.curve.b())]) Point = E.lift_x(msg) Key = self.Random.Random_key(self.Curve_length) returnint(Key)*Point
if __name__ == '__main__': hint = b"****************************************************" flag = bytes_to_long(flag) hint = bytes_to_long(hint) secret = bytes_to_long(secret)
for i inrange(250): SIGN = ECDSA()
Hint = SIGN.Random.RSA_reinforce(hint) m1 = b'A typical Dual ec prng vulnerability applied to NSA, you can find its source in past papers.' m2 = b'Hope you have learned a good foundation of ECDSA, it can help you better answer and understand this problem.' C = flag^^secret into_secret = SIGN.into_secret(secret) sign1 = SIGN.sign(m1,0) sign2 = SIGN.sign(m2,sign1[2])
def__init__(self,state = None,Gen_Curve = True): if state == None: self.state = getRandomNBitInteger(512) else: self.state = state if Gen_Curve: self.int_curve()
from Crypto.Util.number import * from gmpy2 import iroot from hashlib import sha256 from tqdm import * from math import ceil
#part1 get hint if(0): c,n,leak = (12351774260625362799610458605055557349668978169954248709224197283033722650641969191523420968152180626844781310599988085824706330561484553939064653937267598659731237154241515349280967639128615784193195725170343153328247947729351564102666060302013802359410482179324719156651832539747622404434096773119440083329, 122908984806235457892414635852036332676574434804833208576141668077475917235411535511069143359388659946159724740722593181625712110278669227640297497485641848470391938438894136564046632275052354217712453952532772368082733299695485759213723305738760035793602060420638500827652832664161031815519780589765520132973, 22333858470427703056488469739724305644350178024239032705153649807913901449803887198889611591209527103787726531081225700412575986297091811550954958064297166) e = 16542764952 p_q = iroot(leak^2-4*n,2)[0] p = (leak + p_q) // 2 q = n // p cq = pow(c,inverse(e//24,q-1),q) PR.<x> = Zmod(q)[] f = x^24 - cq resq = f.roots() for i in resq: print(long_to_bytes(int(i[0]))) #hint: Anything greater than 2^15 is really that's too big
#结合hint在2^15内爆破,发现第201组数据有异常:32309*Q = P if(0): withopen(r"E:\vscode\py\crypto\春秋杯冬季赛 2023\ez_ECCc_output.txt","r") as f: for j in trange(250): for t inrange(6): exec(f.readline()) f.readline() P = NIST_256_CURVE(P) Q = NIST_256_CURVE(Q) q0 = Q for i inrange(2^15): if(q0 == P): print(j,i) print(P) q0 += Q
#part3 get pri C = 28370462154406144789913243909256020527531135264361458510233553021695306448248185548876492600895007348961847185821989 pub_key = (23063531651133054044852146745751828065565652508316078757465526964945889829041322577333868291426745685755660447945768 , 38213774544479557349161813523787259744626407961805163166366401345392394160489749007540120063131112167181615738936602) P = (99376526638506705902714648195970871631891150648967956889439656483745513799077, 49286347987713888387330453808791204691290920954467279402308313223992253330920) Q = (95979043517822469787247449840043678535429394578371796773017425344169131078878, 94108817998367868965643129518919867199519351407755146103464278196693149407197) r1,s1 = (32594514971850903210957109229029032596013744664454613348001968983388557886022626485537652491952756966982681985873826, 33822531453262141722363336331985371357432586409495680846477948429687072595338746861106767975593900234281162130620713) r2,s2 = (32594514971850903210957109229029032596013744664454613348001968983388557886022626485537652491952756966982681985873826, 30963116078493244587396392437563800584802728459796510243236725881496588593849796130551914519859427419450232539678279) into_secret = (12219467168510963191933866108724307399115854676119007622103880230537250338471252977689989738440080704914043187805666 , 15140655916234412794356873631237108843402057349206472869810848889771783263614142207164313273971781373595696054566462) e1 = int(sha256(b"A typical Dual ec prng vulnerability applied to NSA, you can find its source in past papers.").hexdigest(), 16) e2 = int(sha256(b"Hope you have learned a good foundation of ECDSA, it can help you better answer and understand this problem.").hexdigest(), 16) P = NIST_256_CURVE(P) Q = NIST_256_CURVE(Q) into_secret = NIST_384_CURVE(into_secret)
#shared-k attack r = r1 = r2 o = NIST_384_ORDER pri = (e2*s1-e1*s2)*inverse(r1*s2-r2*s1,o) % o
d = 32309 assert d*Q==P
#part4 Dual_EC backdoor defint_getkey(state): # To get the right random key t = int((state * Q)[0]) return t%(2**250)
defRandom_key(n,state): temp = state out = 0 number = ceil(n/250) for i inrange(number): out = (out<<250) + int_getkey(temp) temp = int((temp*P)[0]) return out % (2^n)
for i inrange(2^6): r = i*2^250 + pri try: R = NIST_256_CURVE.lift_x(r) S = d*R state = int(S[0]) key = Random_key(384,state) secret = int((inverse(key,o)*into_secret)[0]) flag = long_to_bytes(int(secret^^C)) if(b"flag"in flag): print(flag) except: pass
Please firstly pay attention to the file named as "task.py". The real flag is a little strange. However, there is no need to be messy in your mind just because of the "appearance" of the flag. Just be self-confident!
print("Parameters are initialized to: \n phi:%s\n" % hex(wild_phi), " e:%s" % hex(wild_e)) print("But they are wild and crazy!") print("We have to give them a lesson!") print("------")
parameters = train.train(wild_phi, wild_e, n, r, phi0) trained_phi = parameters[0] trained_e = parameters[1] print("Parameters are trained to: \n phi:%s\n" % hex(trained_phi), " e:%s" % hex(trained_e)) print("After training, the two naughty parameters are more and more normal.") print("It's closer to your target!") print("------")
parameters = valid.valid(trained_phi, trained_e, n) y_valid = parameters[0] print("The encrypted output in validation set is %s" % hex(y_valid)) print("After validation, the model is more and more stable.") print("To test the real flag!") print("------")
The significant parameter n: 0x81c5f040bfaea676120cd62c36ba7afb303561504bbf8609afa3da60fb6202ca875b0bd2a06143ebcd16fa615557ff159d97909160d68e1938b3ecaf57709b3d2698476b6dd203811b6a2ec6a6e2a7e213ab719bcd3ab49bb864b10e9c78ea3f501c0e2213dfe431043bb6f0cc2e8d77bfb43869b843af1a99ae81b87811e101 The unique parameter r: 0x4f37fe985d13ffde9867fa0063f68dea79196408b1404eadf03ea59297d629c2183a4a6a6647b6c4c99dd43bae8c4fa4691a608d20170fd42b18aef7efb3ae01cd3 ------ Parameters are initialized to: phi:0x81c5f040bfaea676120cd62c36ba7afb303561504bbf8609afa3da60fb6202ca875b0bd2a06143ebcd16fa615557ff159d97909160d68e1938b3ecaf57709648d78eb17edb46dda768a97d57e6bd1c48657393b7c0d9c574c38cc0a3545ce7d209ade33b8ac6b31a41fe9f4ed62b4ddd7b99859b74915f2031dd2f5f0499a2f8 e:0x2ebad696da6dda845bf03fdf34ee73d4849800de9267a5baa3c068e2d33a74727d00002fbfea775e5233087a9039d267130aa924a4f7fed3576f6ff7b8e1b2e8 But they are wild and crazy! We have to give them a lesson! ------ The loss is -0x5144bdad7cc24f5348c5752dda0ff5fa7d72e36370d5af55eb6f590ac0764b843a06ee1a4651b8f3a6c878df56f1678454e58eaf0ede9a1eb0503dce6a1303b69e33bbaad112abb051a28d51a9fee629e89400a338bd02998568d044852f11e05572fc4a0ddacdf7342048295a4025394e77e973621a77ea5bbdb06af2cb72b2f8298e2cd16736454fd066d3d96a4f77cd094cd783ead17024de981df7ade84aa8c282b1ec6f8ec6ec4752727387ef637ba2a4eed8f83c77d5db14d297de8098 Parameters are trained to: phi:0x81c5f040bfaea676120cd62c36ba7afb303561504bbf8609afa3da60fb6202ca875b0bd2a06143ebcd16fa615557ff159d97909160d68e1938b3ecaf57709b3bb712fdcba325655f111918472d4353a66854ccda50b63a1047278c15a4b39cde898d054db87092958c7c05f8fa566dcd969b1ff4b7d1935c375a4af3bfc341b0 e:0x2c22193ad9abcca2f67552fc76dd07b3ef883f3d755c95119cdf82bb6a07c970fd37e582bb49250d8efaa29b8a59c82059165c654206a9d7261f6b45a90dc69 After training, the two naughty parameters are more and more normal. It's closer to your target! ------ The encrypted output in validation set is 0x775cbee546e7579f0a69645b59f72f5c8ff0c538dd9a6e755969dee2ffb8748073c089557801dfb8bfae15baba9a909f3addac142ad928ac7cc453c72166dda235128de12965df4308997416e054ab1ab9af55c60533c7374096aa2d05339900b3e14f7148930bf083eb1eb9fa22b9a997f85b39501d3a9bdfa08e3389b8f2fe After validation, the model is more and more stable. To test the real flag! ------ The final output is 0x29289e3d9275147b885b5061637564cbee3e4d9f48e52694e594f020e49da9b24d9246b2437fb2221fa86ca1a277f3fdd7ab5cad4738a02b66d47703ef816844a84c6c209c8251e8961c9ba2c791649e022627f86932d9700c3b1dc086e8b2747d0a5604955387a935464d3866dd4100b2f3d57603c728761d1d8ef7fdbdcbee 0x2b0059f88454e0e36269c809b5d5b6b28e5bab3c87b20f9e55635239331100a0a582241e7a385034698b61ebf24b519e868617ff67974cc907cc61be38755737f9a6dbeb7890ff55550b1af1ecf635112fcaaa8b07a3972b3c6728cbcf2a3973a4d7bd92affec7e065e0ae83cd36858e6d983785a3668a8b82709d78a69796af ------
n = 0x81c5f040bfaea676120cd62c36ba7afb303561504bbf8609afa3da60fb6202ca875b0bd2a06143ebcd16fa615557ff159d97909160d68e1938b3ecaf57709b3d2698476b6dd203811b6a2ec6a6e2a7e213ab719bcd3ab49bb864b10e9c78ea3f501c0e2213dfe431043bb6f0cc2e8d77bfb43869b843af1a99ae81b87811e101 r = 0x4f37fe985d13ffde9867fa0063f68dea79196408b1404eadf03ea59297d629c2183a4a6a6647b6c4c99dd43bae8c4fa4691a608d20170fd42b18aef7efb3ae01cd3