curve = NIST256p n = curve.order private_key = SigningKey.from_secret_exponent(random.randrange(1, n), curve=curve) d = private_key.privkey.secret_multiplier print(f'd = {d}') public_key = private_key.get_verifying_key()
messages = [ b"Hello player, welcome to L3HCTF 2025!", b"This is a crypto challenge, as you can probably tell.", b"It's about ECDSA, a very... robust algorithm.", b"I'm sure there are no implementation flaws whatsoever.", b"Anyway, here are your signatures. Good luck!", f"Oh, and the flag is L3HCTF{{{d}}}. Don't tell anyone!".encode(), ] nonce_generator = FlawedNonceGenerator(n) f = open('signatures.txt', 'w')
for i inrange(6): k = nonce_generator.generate_nonce() message = messages[i] h = int.from_bytes(hashlib.sha256(message).digest(), 'big') R = k * curve.generator r = R.x() % n s_inv = pow(k, -1, n) s = (s_inv * (h + d * r)) % n f.write(f"(h:{h},r:{r},s:{s}),\n")
[x + 69788518200564789389321144350462685453109604718076361366049302823767256812650, k + 20259192668456929166524619606713276345602588639715480059091270804733464402770, a + 5429358627696695589699281230327408089193738662340759874540258774415727222303, b + 44568864543157323131751489652584342118296318663514348237122188472367311256223, c + 43731216038486108514267049101526725549282472663927075875243047123834915417678]
h = [sig[i][0] for i inrange(len(sig))] r = [sig[i][1] for i inrange(len(sig))] s = [sig[i][2] for i inrange(len(sig))]
curve = NIST256p print(curve) n = curve.order g = curve.generator print(f'n = {n}')
PR.<x,k,a,b,c> = PolynomialRing(Zmod(n))
eqs = [] for i inrange(6): eq = ((h[i] + x * r[i])) - s[i]*k k = (a * k**2 + b * k + c) eqs.append(eq) I = PR.ideal(eqs) G = I.groebner_basis() print(G)
x = -int(G[0].coefficients()[1])%n print(f"L3HCTF{{{x}}}")
import gmpy2 from gmpy2 import * from Crypto.Util.number import * from random import randint from gmpy2 import invert from scret import flag 0 defmyfunction(num): output = 0 output=num**3 return output
whileTrue: p = random_prime(2**(p_bits), lbound=2**(p_bits-1)) q = random_prime(2**(q_bits), lbound=2**(q_bits-1)) if p != q and p > q and p < 2*q: break N = p * q phi = (p**4 - 1) * (q**4 - 1)
d_bits = 1024 d_bound = 2**d_bits
whileTrue: d_small = randint(2, d_bound) d = phi - d_small if gcd(d, phi) == 1: if d_small.bit_length() == 1021: break
e = inverse_mod(d, phi) return N, e
defencrypt(m, N, e): n = 4 r = 2 R = Integers(N) P = PolynomialRing(R, 't') t = P.gen() Q = P.quotient(t**n - r)
m_poly = Q([m, 0, 0, 0])
c_poly = m_poly ** e
return c_poly.lift()
if __name__ == "__main__": N, e = generate_vulnerable_key() m = int.from_bytes(flag, 'big') c = encrypt(m, N, e)
# N = 99697845285265879829811232968100099666254250525000506525475952592468738395250956460890611762459685140661035795964867321445992110528627232335703962897072608767840783176553829502743629914407970206513639916759403399986924602596286330464348286080258986075962271511105387188070309852907253486162504945490429185609 # e = 74900336437853271512557457581304251523854378376434438153117909482138661618901386551154807447783262736408028580620771857416463085746907317126876189023636958838207330193074215769008709076254356539808209005917645822989554532710565445155350102802675594603406077862472881027575871589046600011223990947361848608637247276816477996863812313225929441545045479384803449990623969591150979899801722841101938868710054151839628803383603849632857020369527380816687165487370957857737696187061619496102857237814447790678611448197153594917852504509869007597997670022501500067854210261136878917620198551551460145853528269270832725348151160651020188255399136483482428499340574623409209151124687319668989144444549871527949104436734300277004316939985015286758651969045396343970037328043635061226100170529991733947365830164811844853806681198818875837903563263114249814483901121700854712406832325690101810786429930813776784979083590353027191492894890551838308899148551566437532914838098811643805243593419063566975400775134981190248113477610235165151367913498299241375039256652674679958159505112725441797566678743542054295794919839551675786573113798857814005058856054462008797386322048089657472710775620574463924678367455233801970310210504653908307254926827 # c = 98460941530646528059934657633016619266170844887697553075379408285596784682803952762901219607460711533547279478564732097775812539176991062440097573591978613933775149262760936643842229597070673855940231912579258721734434631479496590694499265794576610924303262676255858387586947276246725949970866534023718638879
defencrypt(m, N, e): n = 4 r = 2 R = Integers(N) P = PolynomialRing(R, 't') t = P.gen() Q = P.quotient(t**n - r)
m_poly = Q([m, 0, 0, 0]) c_poly = m_poly ** e
return c_poly.lift()
R = Integers(N):定义模N的整数环Z/NZ
P = PolynomialRing(R, 't'):在环R上构造多项式环(Z/NZ)[t]
Q = P.quotient(t**n - r):构造商环Q=(t4−2)(Z/NZ)[t]
在Q中满足 t4=2 (因为模掉了理想 ⟨t4−2⟩)
m_poly = Q([m, 0, 0, 0]):将m嵌入商环Q中的元素:
mpoly=m+0∗t+0∗t2+0∗t3
这本质上是常数多项式(仅常数项非零)
c_poly = m_poly ** e:
在商环Q中进行指数运算,但由于mpoly是常数多项式,运算简化为cpoly=me(在商环Q中)
所以等价于RSA的c=memodn
此处edsmall=−1modϕ,所以解密时m=c−dsmallmodn
题解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
from Crypto.Util.number import * from gmpy2 import *
N = 99697845285265879829811232968100099666254250525000506525475952592468738395250956460890611762459685140661035795964867321445992110528627232335703962897072608767840783176553829502743629914407970206513639916759403399986924602596286330464348286080258986075962271511105387188070309852907253486162504945490429185609 e = 74900336437853271512557457581304251523854378376434438153117909482138661618901386551154807447783262736408028580620771857416463085746907317126876189023636958838207330193074215769008709076254356539808209005917645822989554532710565445155350102802675594603406077862472881027575871589046600011223990947361848608637247276816477996863812313225929441545045479384803449990623969591150979899801722841101938868710054151839628803383603849632857020369527380816687165487370957857737696187061619496102857237814447790678611448197153594917852504509869007597997670022501500067854210261136878917620198551551460145853528269270832725348151160651020188255399136483482428499340574623409209151124687319668989144444549871527949104436734300277004316939985015286758651969045396343970037328043635061226100170529991733947365830164811844853806681198818875837903563263114249814483901121700854712406832325690101810786429930813776784979083590353027191492894890551838308899148551566437532914838098811643805243593419063566975400775134981190248113477610235165151367913498299241375039256652674679958159505112725441797566678743542054295794919839551675786573113798857814005058856054462008797386322048089657472710775620574463924678367455233801970310210504653908307254926827 c = 98460941530646528059934657633016619266170844887697553075379408285596784682803952762901219607460711533547279478564732097775812539176991062440097573591978613933775149262760936643842229597070673855940231912579258721734434631479496590694499265794576610924303262676255858387586947276246725949970866534023718638879