e_msb = int(bin(PKEY)[-8:], 2) n_msb = int(bin(PKEY)[2:-8], 2) # for i in tqdm(range(14, 256)): # if i % 2 == 0: # continue # n = (n_msb << 8) + i # print('trying', i) # fs = factor(n) # if len(fs) == 2: # print(i, n, fs)
p = 188473222069998143349386719941755726311 q = 292926085409388790329114797826820624883 n = p * q assert (n >> 8) == n_msb phi = (p - 1) * (q - 1)
for i in tqdm(range(256)): e = (e_msb << 8) + i try: d = pow(e, -1, phi) for j inrange(256): m = pow((ENC << 8) + j, d, n) flag = long_to_bytes(m) if flag.isascii(): print(flag) except: pass # CCTF{6oRYGy&Dc$G2ZS}
Medium
*Derik
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
#!/usr/bin/env python3
from Crypto.Util.number import * from secret import C, e, d, p, q, r, flag
O = [1391526622949983, 2848691279889518, 89200900157319, 31337]
assert isPrime(e) and isPrime(d) and isPrime(p) and isPrime(q) and isPrime(r) assert C[0] * p - C[1] * q >= 0 assert C[2] * q - C[3] * r >= 0 assert C[4] * r - C[5] * p >= 0 assert (C[0] * p - C[1] * q) ** e + (C[2] * q - C[3] * r) ** e + (C[4] * r - C[5] * p) ** e == d * (C[0] * p - C[1] * q) * (C[2] * q - C[3] * r) * (C[4] * r - C[5] * p) assert C[6] * e - C[7] * d == O[3]
n = e * d * p * q * r m = bytes_to_long(flag) c = pow(m, 65537, n) print(f'C = {C}') print(f'c = {c}')
C[6], C[7] 是 10543, 4,而 e
又出現在 exponent 所以應該不大,一個最可能的解是 。這樣的話會變成要解 ,明顯是一條橢圓曲線。透過
sage 轉換之後 enumerate 一下找到全部為正整數的 ,然後反過來得到 之後就可以解出 flag 了。
from itertools import permutations from Crypto.Util.number import long_to_bytes
# fmt: off O = [1391526622949983, 2848691279889518, 89200900157319, 31337] C = [5960650533801939766973431801711817334521794480800845853788489396583576739362531091881299990317357532712965991685855356736023156123272639095501827949743772, 6521307334196962312588683933194431457121496634106944587943458360009084052009954473233805656430247044180398241991916007097053259167347016989949709567530079, 1974144590530162761749719653512492399674271448426179161347522113979158665904709425021321314572814344781742306475435350045259668002944094011342611452228289, 2613994669316609213059728351496129310385706729636898358367479603483933513667486946164472738443484347294444234222189837370548518512002145671578950835894451, 8127380985210701021743355783483366664759506587061015828343032669060653534242331741280215982865084745259496501567264419306697788067646135512747952351628613, 5610271406291656026350079703507496574797593266125358942992954619413518379131260031910808827754539354830563482514244310277292686031300804846114623378588204, 10543, 4] ct = 80607532565510116966388633842290576008441185412513199071132245517888982730482694498575603226192340250444218146275844981580541820190393565327655055810841864715587561905777565790204415381897361016717820490400344469662479972681922265843907711283466105388820804099348169127917445858990935539611525002789966360469324052731259957798534960845391898385316664884009395500706952606508518095360995300436595374193777531503846662413864377535617876584843281151030183895735511854 # fmt: on
# guess, otherwise exponent will be too big e, d = 3, 73 assert C[6] * e - C[7] * d == O[3]
# solve a^3+b^3+c^3=d*a*b*c a, b, c = QQ["a, b, c"].gens() phi = EllipticCurve_from_cubic(a ^ 3 + b ^ 3 + c ^ 3 - d * a * b * c) G = phi.codomain().gen(0)
Mi = matrix([[C[0], -C[1], 0], [0, C[2], -C[3]], [-C[5], 0, C[4]]]).inverse() phii = phi.inverse() for i inrange(-5, 5): print(i) x, y, z = phii(i * G) assert x ^ 3 + y ^ 3 + z ^ 3 == d * x * y * z ifall([x < 0for x in (x, y, z)]): x, y, z = -x, -y, -z ifall([x > 0for x in (x, y, z)]): for perm in permutations((x, y, z)): p, q, r = Mi * vector(perm) mul = lcm(lcm(p.denominator(), q.denominator()), r.denominator()) div = gcd(gcd(p.numerator(), q.numerator()), r.numerator()) p, q, r = [ZZ(mul * i / div) for i in [p, q, r]] assert (C[0] * p - C[1] * q) ** e + (C[2] * q - C[3] * r) ** e + ( C[4] * r - C[5] * p ) ** e == d * (C[0] * p - C[1] * q) * (C[2] * q - C[3] * r) * ( C[4] * r - C[5] * p ) ifall([p.is_integer() and is_pseudoprime(p) for p in (p, q, r)]): print("Found") break else: continue break
n = e * d * p * q * r phi = (e - 1) * (d - 1) * (p - 1) * (q - 1) * (r - 1) d = pow(65537, -1, phi) pt = pow(ct, d, n) print(long_to_bytes(pt))
defmul_barak(m, P, E): if P == (0, 0): return P R = (0, 0) while m != 0: if m & 1: R = add_barak(R, P, E) m = m >> 1 if m != 0: P = add_barak(P, P, E) return R
defrand_barak(E): c, d, p = E whileTrue: y = randint(1, p - 1) K = Zmod(p) P.<x> = PolynomialRing(K) f = x**3 - d*x*y + c + y^3 R = f.roots() try: r = R[0][0] return (r, y) except: continue
p = 73997272456239171124655017039956026551127725934222347 d = 68212800478915688445169020404812347140341674954375635 c = 1 E = (c, d, p)
P = rand_barak(E)
FLAG = flag.lstrip(b'CCTF{').rstrip(b'}') m = bytes_to_long(FLAG) assert m < p Q = mul_barak(m, P, E) print(f'P = {P}') print(f'Q = {Q}')
p = 73997272456239171124655017039956026551127725934222347 d = 68212800478915688445169020404812347140341674954375635 c = 1
F = GF(p)
x, y, z = QQ["x,y,z"].gens() eq = x ^ 3 + y ^ 3 + c * z ^ 3 - d * x * y * z phi = EllipticCurve_from_cubic(eq) E = phi.codomain().change_ring(GF(p)) P = ( 71451574057642615329217496196104648829170714086074852, 69505051165402823276701818777271117086632959198597714, ) Q = ( 40867727924496334272422180051448163594354522440089644, 56052452825146620306694006054673427761687498088402245, )
fx, fy, fz = map(lambda f: f.change_ring(F), phi.defining_polynomials()) phiP = lambda x, y, z=1: E(fx(x, y, z) / fz(x, y, z), fy(x, y, z) / fz(x, y, z)) EP = phiP(*P) EQ = phiP(*Q) x = discrete_log(EQ, EP, operation="+") print(x) od = EP.order() # the generator doesn't have full order print( [ flag for i inrange(E.order() // od) if (flag := long_to_bytes(int(x + od * i))).isascii() ] ) # CCTF{_hE5S!4n_f0rM_0F_3CC!!}
from Crypto.Util.number import * from secret import m, flag
defgenPrime(m, nbit): assert m >= 2 whileTrue: a = getRandomNBitInteger(nbit // m) r = getRandomNBitInteger(m ** 2 - m + 2) p = a ** m + r if isPrime(p): return (p, r)
defgenkey(m, nbit): p, r = genPrime(m, nbit // 2) q, s = genPrime(m, nbit // 2) n = p * q e = r * s return (e, n)
defencrypt(msg, pkey): e, n = pkey m = bytes_to_long(msg) c = pow(m, e, n) return c
e, n = ( 150953688, 373824666550208932851344358703053061405262438259996622188837935528607451817812480600479188884096072016823491996056842120586016323642383543231913508464973502962030059403443181467594283936168384790367731793997013711256520780338341018619858240958105689126133812557401122953030695509876185592917323138313818881164334490044163316692588337720342646339764174333821950301279825316497898035760524780198230860089280791887363472060435443944632303774987556026740232641561706904946900169858650106994947597642013168757868017723456208796677559254390940651802333382820063200360490892131573853635471525711894510477078934343423255983, ) enc = 275574424285842306309073814038154403551700455145115884031072340378743712325975683329051874910297915882286569143815715537085387363420246497061870251520240399514896001311724695996978111559476733709139080970977190150345474341853495386364275702356438666152069791355990718058189043717952080875207858163490627801836274404446661613239167700736337269924479349700031535265765885064606399858172168036794462235707003475360358004643720927563261787867952228496769300443415094124132722170498229611285689671203272698693505808912907778910378274197503048226322090611405601517624884408718689404556983397217070272851442351897456769883 m = 4
defsolve_quadratic(a, b, c): d = b**2 - 4 * a * c r1 = (-b + sqrt(d)) / (2 * a) r2 = (-b - sqrt(d)) / (2 * a) return r1, r2
ab, _ = n.nth_root(4, truncate_mode=True) a4s_b4r = (n - e) % (ab**4) a4b4rs = ab**4 * e a4s, b4r = solve_quadratic(1, -a4s_b4r, a4b4rs) a = gcd(a4s, ab) b = gcd(b4r, ab) s = a4s // a**4 r = b4r // b**4 assert r * s == e p = a**4 + r q = b**4 + s assert p * q == n
for mp in GF(p)(enc).nth_root(e, all=True): for mq in GF(q)(enc).nth_root(e, all=True): m = crt([ZZ(mp), ZZ(mq)], [p, q]) flag = long_to_bytes(m) if flag.isascii(): print(flag) # CCTF{S!mP1E_A7t4cK_0n_SpEc1aL-5trucTur3D_RSA_pR1me5!}
import sys import math import functools from PIL import Image from random import randint import string from secret import flag, key, n
defpad(s, l): whilelen(s) < l: s += string.printable[randint(0, 61)] return s
defsox(n, d): x, y, t = 0, 0, d for s inrange(n - 1): u = 1 & t // 2 v = 1 & t ^ u x, y = spin(2**s, x, y, u, v) x += 2**s * u y += 2**s * v t = t // 4 return x, y
defspin(n, x, y, u, v): if v == 0: if u == 1: x = n - 1 - x y = n - 1 - y x, y = y, x return x, y
defencrypt(msg, key, n): _msg = pad(msg, n ** 2) _msg, _key = [ord(_) for _ in _msg], [ord(_) for _ in key] img = Image.new('RGBA', (n, n), 'darkblue') pix = img.load()
for _ inrange(len(key)): w = len(_key) h = n**2 // w + 1 arr = [[_msg[w*x + y] if w*x + y < n**2elseNonefor x inrange(h)] for y inrange(w)] _conf = sorted([(_key[i], i) for i inrange(w)]) _marshal = [arr[_conf[i][1]] for i inrange(w)] _msg = functools.reduce(lambda a, r: a + _marshal[r], range(w), []) _msg = list(filter(lambda x: x isnotNone, _msg)) _msg = [(_msg[_] + _key[_ % w]) % 256for _ inrange(n**2)]
for d inrange(n**2): x, y = sox(n, d) pix[x,y] = (_msg[d], _msg[d], _msg[d]) keysum = sum(_key) if w > 0else0 orient = keysum % 4 img = img.rotate(90*orient) return img
import sys import math import functools from PIL import Image from random import randint import string import itertools import z3
defpad(s, l): whilelen(s) < l: s += string.printable[randint(0, 61)] return s
defsox(n, d): x, y, t = 0, 0, d for s inrange(n - 1): u = 1 & t // 2 v = 1 & t ^ u x, y = spin(2**s, x, y, u, v) x += 2**s * u y += 2**s * v t = t // 4 return x, y
defspin(n, x, y, u, v): if v == 0: if u == 1: x = n - 1 - x y = n - 1 - y x, y = y, x return x, y
n = 256 img = Image.open("enc.png") img = img.rotate(90 * 1) # guess pix = img.load() msg = [] for d inrange(n**2): x, y = sox(n, d) msg.append(pix[x, y][0])
deftry_conf(conf): key_sym = [z3.BitVec("key_%d" % i, 8) for i inrange(3)] msg_sym = [z3.BitVec("msg_%d" % i, 8) for i inrange(n**2)] msg_arr = msg_sym[:] for _ inrange(len(key_sym)): w = len(key_sym) h = n**2 // w + 1 arr = [ [msg_arr[w * x + y] if w * x + y < n**2elseNonefor x inrange(h)] for y inrange(w) ] _marshal = [arr[conf[i]] for i inrange(w)] msg_arr = functools.reduce(lambda a, r: a + _marshal[r], range(w), []) msg_arr = list(filter(lambda x: x isnotNone, msg_arr)) msg_arr = [(msg_arr[_] + key_sym[_ % w]) % 256for _ inrange(n**2)] sol = z3.Solver() for i inrange(n**2): sol.add(msg_arr[i] == msg[i]) for x, y inzip(msg_sym, b"CCTF{"): sol.add(x == y) if sol.check() == z3.sat: m = sol.model() print([m.eval(x) for x in key_sym]) print(bytes([m.eval(x).as_long() for x in msg_sym])[:100])
for conf in itertools.permutations(range(3)): # correct conf = (1, 2, 0) print(conf) try_conf(conf) # CCTF{3nCrypTioN_8Y_c0lUmn4R_7rAnSp05it!On!}
""" s =p+q ed=1+k*(n'+y-s+1) =1+k*(n-t) t =s-y-1 """
for i in tqdm(range(256)): e = (e_msb << 8) + i k, t = Zmod(e)["k, t"].gens() f = 1 + k * (n_msb * 2**8 - t) rs = small_roots(f, (2**64, 2**1025), m=3, d=4) if rs: print(i, rs) # i = 171 break
rs = [ ( 6823792554575489397, 339429557959585189701831352324590530872763312539010344903142994882560384526456848728524471256411137222762385478052025872755202468572218239287614181033902856793017322338973563489979888570193807877377040282961710845331494163541163584827604616161828513831660392743437795710563167837376965534351712230091159840872, ) ] k, t = map(ZZ, rs[0]) phi = n_msb * 2**8 - t for i in tqdm(range(256)): n = n_msb * 2**8 + i ifpow(2, phi, n) == 1: break d = pow(e, -1, phi)
for i in tqdm(range(256)): m = pow((enc << 8) + i, d, n) flag = long_to_bytes(m) if flag.isascii(): print(flag) # CCTF{aIr_pr3s5urE_d!Ff3rEn7i4L_8eTw3eN_ArEa5!}
cf = continued_fraction(ee / (nn - 2**1025)) for c in cf.convergents(): print(c) if c.denominator() <= 2**64: k = c.numerator() d = c.denominator() if k == 0: continue for i inrange(256): e = ee + i phi = (e * d - 1) // k if (phi >> 1500) == (nn >> 1500): print("try phi", phi) for j inrange(256): n = nn + j ifpow(2, phi, n) == 1: print("found", n, e, d) for i in tqdm(range(256)): m = pow((enc << 8) + i, d, n) flag = long_to_bytes(m) if flag.isascii(): print(flag) exit()
from Crypto.Util.number import * from flag import flag
defbase(n, l): D = [] while n > 0: n, r = divmod(n, l) D.append(r) return''.join(str(d) for d inreversed(D)) or'0'
defasiv_prng(seed): l = len(seed) _seed = base(bytes_to_long(seed), 3) _seed = [int(_) for _ in _seed] _l = len(_seed) R = [[getRandomRange(0, 3) for _ inrange(_l)] for _ inrange(_l**2)] S = [] for r in R: s = 0 for _ inrange(_l): s += (r[_] * _seed[_]) % 3 # s += getRandomRange(0, 3) s %= 3 S.append(s) return R, S
seed = flag.lstrip(b'CCTF{').rstrip(b'}') R, S = asiv_prng(seed)
f = open('output.txt', 'w') f.write(f'R = {R}\nS = {S}') f.close()
一個很奇怪的 RNG,不過一眼就能看出是直接解 linear system 搞定。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
from sage.allimport * from Crypto.Util.number import * from collections import Counter
withopen("output.txt") as f: exec(f.read())
l = len(R[0]) + 5 sol = matrix(Zmod(3), R[:l]).solve_right(vector(S[:l]))
flag = 0 for x in sol: flag = flag * 3 + ZZ(x) print(long_to_bytes(flag))
n, e, a, b = pkey nbit = 256 pp = ZZ["pp"].gen() p = 2 ** (nbit - 1) + pp s = pp + 2 ** (nbit // 2) # guess for t inrange(1000): q = 2 * s + 1 + t f = p * q - n rs = f.roots() if rs: print(t, rs) break p = 2 ** (nbit - 1) + rs[0][0] q = n // p assert p * q == n Z = Zmod(n) E = EllipticCurve(Z, [a, b]) C = E(encx, ency) Ep = EllipticCurve(GF(p), [a, b]) Eq = EllipticCurve(GF(q), [a, b]) od = Ep.order() * Eq.order() d = pow(e, -1, od) M = d * C print(long_to_bytes(int(M.xy()[0])))
import sys from Crypto.Util.number import * from hashlib import sha256 from flag import flag
p = 114863632180633827211184132915225798242263961691870412740605315763112513729991 A = -3 B = 105675527217961035404524512435875047840495516468907806313576241823653895562912 E = EllipticCurve(GF(p), [A, B]) G = E.random_point() _o = E.order() original_msg = 'I love all cryptographers!!!'
defdie(*args): pr(*args) quit()
defpr(*args): s = " ".join(map(str, args)) sys.stdout.write(s + "\n") sys.stdout.flush()
defencrypt(msg, pkey): e, l = randint(1, _o), len(msg) m1, m2 = bytes_to_long(msg[:l // 2]), bytes_to_long(msg[l // 2:]) assert m1 < p and m2 < p e1, e2 = (e * pkey).xy() c1, c2 = m1 * e1 % p, m2 * e2 % p return (c1, c2, e * G)
defsign(msg, skey): _tail = bytes_to_long(sha256(str(skey).encode('utf-8')).digest()) % (1 << 24) whileTrue: K = [randint(1, 2**255) // (1 << 24) + _tail for _ in'__'] r, s = int((K[0] * G).xy()[0]), int((K[1] * G).xy()[1]) if r * s != 0: break h = bytes_to_long(sha256(msg).digest()) t = inverse(K[0], _o) * (h * r - s * skey) % _o return (r, s, t)
defverify(msg, pkey, _sign): r, s, t = [int(_) % _o for _ in _sign] h = bytes_to_long(sha256(msg.encode('utf-8')).digest()) u = int(h * r * inverse(t, _o) % _o) v = int(s * inverse(t, _o) % _o) # u = h * r * inverse(t, _o) % _o # v = s * inverse(t, _o) % _o _R = (u * G - v * pkey).xy()[0] return _R == r
defmain(): border = "|" pr(border*72) pr(border, "Hi all, now it's time to solve a probably simple ECC challenge about", border) pr(border, "encryption and signing in elliptic curves! Follow the questions and ", border) pr(border, "find the secret flag, are you ready!? ", border) pr(border*72)
pkey, skey = keygen(E)
whileTrue: pr("| Options: \n|\t[E]ncrypt a message! \n|\t[G]et the flag \n|\t[P]ublic Key \n|\t[S]ign a message \n|\t[V]erify signature \n|\t[Q]uit") ans = sc().decode().lower().strip() if ans == 'e': pr(border, 'Send your message here: ') _msg = sc() _enc = encrypt(_msg, pkey) pr(border, f'enc = {_enc}') elif ans == 'g': pr(border, 'You should send the valid signature for my given message!') pr(border, 'Send the signature of original message here: ') _sgn = sc().split(b',') try: _sgn = [int(_) for _ in _sgn] if verify(original_msg, pkey, _sgn): die(border, f'Congratz! You got the flag: {flag}') else: pr(border, 'Your signature is not correct!') except: import traceback; traceback.print_exc() pr(border, 'Try to send valid signature!') continue elif ans == 's': pr(border, 'Send your message to sign: ') _msg = sc() iflen(_msg) >= 10: die(border, 'Sorry, I sign only short messages! :/') _sgn = sign(_msg, skey) pr(border, f'sgn = {_sgn}') elif ans == 'v': pr(border, 'Send your signature to verify: ') _sgn = sc().split(b',') try: _sgn = [int(_) for _ in _sgn] pr(border, 'Send your message: ') _msg = sc() if verify(_msg, pkey, _sgn): pr(border, 'Your message successfully verified :)') else: pr(border, 'Verification failed :(') except: pr(border, 'Try to send valid signature!') continue elif ans == 'p': pr(border, f'pkey = {pkey}') pr(border, f'G = {G}') elif ans == 'q': die(border, 'Quitting...') else: die(border, 'You should select valid choice!')
from sage.allimport * from pwn import process, remote, context from Crypto.Util.number import * from hashlib import sha256 import ast, os
p = 114863632180633827211184132915225798242263961691870412740605315763112513729991 A = -3 B = 105675527217961035404524512435875047840495516468907806313576241823653895562912 E = EllipticCurve(GF(p), [A, B]) G = E.random_point() q = E.order() original_msg = "I love all cryptographers!!!" R = Zmod(q)
defsign(msg: bytes): io.sendline(b"s") io.sendline(msg) io.recvuntil(b"sgn = ") r, s, t = ast.literal_eval(io.recvlineS().strip()) h = bytes_to_long(sha256(msg + b"\n").digest()) return h, r, s, t
n_sigs = 16 sigs = [sign(os.urandom(4).hex().encode()) for _ inrange(n_sigs)] PR = PolynomialRing(R, ["d"] + [f"k{i}"for i inrange(n_sigs)]) d, *ks = PR.gens() eqs = [] for (h, r, s, t), k inzip(sigs, ks): eqs.append(t * k - (h * r - s * d)) eqs2 = [f.sylvester_matrix(g, d).det() for f, g inzip(eqs, eqs[1:])]
M, v = Sequence(eqs2).coefficient_matrix() print(vector(v)) L = block_matrix(ZZ, [[M.T.dense_matrix(), 1], [q, 0]]) bounds = [0] * len(eqs2) + [1 << (256 - 24)] * len(ks) + [1] Q = diagonal_matrix([2**512 // b if b else2**1024for b in bounds]) L *= Q L = L.LLL() L /= Q v = L[0] if v[-1] < 0: v = -v print(v) k_sol = vector(ZZ, v[len(eqs2) : -1]) d = ( eqs[0] .subs({ks[0]: k_sol[0]}) .univariate_polynomial() .roots(multiplicities=False)[0] ) assert ( d == eqs[1] .subs({ks[1]: k_sol[1]}) .univariate_polynomial() .roots(multiplicities=False)[0] ) assert d * G == pkey
defsign(msg, skey): _tail = bytes_to_long(sha256(str(skey).encode("utf-8")).digest()) % (1 << 24) whileTrue: K = [randint(1, 2**255) // (1 << 24) + _tail for _ in"__"] r, s = int((K[0] * G).xy()[0]), int((K[1] * G).xy()[1]) if r * s != 0: break h = bytes_to_long(sha256(msg).digest()) t = inverse(K[0], q) * (h * r - s * skey) % q return (r, s, t)
defverify(msg, pkey, _sign): r, s, t = [int(_) % q for _ in _sign] h = bytes_to_long(sha256(msg.encode('utf-8')).digest()) u = h * r * inverse(t, q) % q v = s * inverse(t, q) % q _R = (u * G - v * pkey).xy()[0] return _R == r
> nc 06.cr.yp.toc.tf 33137 |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| | Hi all, I have created a basic and simple cryptography task about | | elliptic curve over rational field. Your mission is to find all | | points Q over E such that 2 * Q = P, such that P is given. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| | Generating parameters, please wait... | Options: | [I]informations | [S]ubmit points | [Q]uit I | E = Elliptic Curve defined by y^2 = x^3 - 76479349401*x over Rational Field | Q = (2740238460026645848168554718863025/9496587522097110856052646144 : -40938233945632940227696869615241088990456963438185/925446596757862314622073825244539026870272 : 1) | Options: | [I]informations | [S]ubmit points | [Q]uit S | Please send the points on elliptic curve one by one:
雖然他看起來符號有打錯,不過應該就是求 的 half point 而已,sage
很簡單就搞定了。
1 2 3 4 5 6 7 8 9
E = EllipticCurve(QQ, [-76479349401, 0]) Q = E( 2740238460026645848168554718863025 / 9496587522097110856052646144, -40938233945632940227696869615241088990456963438185 / 925446596757862314622073825244539026870272, ) for x in Q.division_points(2): print(",".join(map(str, x.xy()))) # CCTF{H4lVin9_pO!ntS_0n_3lLipT1C_cuRve5!}
from Crypto.Util.number import long_to_bytes from Crypto.Cipher import AES from hashlib import md5 from public_values_aux import generate_distortion_map
load("./castryck_decru_shortcut.sage")
x = QQ["x"].gen() P = ( 3799366067639160994711391413511701264777392349807255916259320256251336249666 * x + 633884628131689177031068067897867565283026098415356709331881575255526844055, 3967348484864888240941807454988077684669074109524399477973520952727771366997 * x + 2712354532382043232096058211997452093712477916671679907467703464009558475387, ) Q = ( 560486392227142181240528415381730657098132581407794833013161975335122628946 * x + 3215971074127995409351672272900519761566156375365764079386358523254177565572, 2231746347912007096335360835242707156884468521076802738444724241125548841199 * x + 1147378568798166954853288670809304301194478550602719730593160186622788033023, ) R = ( 2656280316115888204975052029900945854050191685154131031859911335618240136443 * x + 1127449111197960889758916770042950976852995868310602942974825430779982061546, 3477289737920472771668877366806058236254602770820629911886593813749930497839 * x + 4646016633241840360901490323351236375375727836768954121794139000985805816564, ) S = ( 2403139149412141532587482679318245468078604585804423116505024414375742701912 * x + 2772488504607240668919423445309052101443116827322741849326656561794480962717, 3356599382898540527962106232860239304405841217130774924490318752448476310798 * x + 2818004736373436361527915593539097434287090434842750370886675729711731978922, ) # def eq(x, y): # return y^2 -(x^3+6*x^2+1*x) # eqs = [eq(*P) for P in (P, Q, R, S)] # pmul = gcd(eqs[0].resultant(eqs[1]), eqs[2].resultant(eqs[3])) # print(factor(pmul))
p = 4651852759096127491733667803074539573102288457512521355046899661762757394431 a = valuation(p + 1, 2) b = valuation(p + 1, 3) F = GF(p ^ 2, "a", modulus=x ^ 2 + 1) E_start = EllipticCurve(F, [0, 6, 0, 1, 0]) E_start.set_order((p + 1) ^ 2) P, Q, R, S = [E_start(P) for P in (P, Q, R, S)]
a2 = 6 a4 = ( 2070374075904221348548347954672740119972290047985052548426161483408084160515 * x + 896749506444795652787374405713981306103783874504413776724865996633074195878 ) a6 = ( 2497300913991521538985990865799426081199023429830552981773916386651958830387 * x + 4243320791854592301388975795466391442631117041175807728844738724691845270777 ) E_end = EllipticCurve(F, [0, a2, 0, a4, a6]) E_end.set_order((p + 1) ^ 2) _phi_P = ( 76437828586489590038329193939006186966443918785230388533883401536928551274 * x + 1854701339851606878866613257086348330205980107370562791121360193846610915298, 3614996124089236146025194675467338095830005859290616536023140003816221458491 * x + 1308394538776387115295908857102539180825411698539070801598965381200026966383, ) _phi_Q = ( 2350346337927935568113772636838467488287314266120334638991371449749383548230 * x + 3389994457403704259291228848441313337916860864318549296438418403582347527289, 3514523396038039657181009561828298688334341559779027220238590888980836781356 * x + 1132784636339236588815425424619354807485262558088269015122405460656452137103, ) phi_P, phi_Q = [E_end(P) for P in (_phi_P, _phi_Q)]
from Crypto.Util.number import * from flag import flag
defbase(n, l): D = [] while n > 0: n, r = divmod(n, l) D.append(r) return''.join(str(d) for d inreversed(D)) or'0'
defasiv_prng(seed): l = len(seed) _seed = base(bytes_to_long(seed), 3) _l = len(_seed) R = [[getRandomRange(0, 3) for _ inrange(_l)] for _ inrange(_l**2)] S = [] for r in R: s = 0 for _ inrange(_l): b = ((int(r[_]) + int(_seed[_])) % 3) % 2 s = s ^ b S.append(s) print(len(S)) return R, S
seed = flag.lstrip(b'CCTF{').rstrip(b'}') R, S = asiv_prng(seed)
f = open('output.txt', 'w') f.write(f'R = {R}\nS = {S}') f.close()
和 ASIv1 很像,不過它會先 mod 3 再 mod
2,很難處理。這邊的關鍵是想辦法令一個函數 去代表那個運算:
digits = [] for i inrange(l): thing = tuple(sol[i * 3 : (i + 1) * 3]) if thing in inv: digits.append(inv[thing]) else: thing2 = tuple(1 - x for x in thing) digits.append(inv[thing2])
print(long_to_bytes(int("".join(str(s) for s in digits), 3))) # CCTF{4n0Th3R_47tACkER_!n_Vi5A!}
解完這之後我又在想: 如果是先 再 也能解嗎? 如果是這樣的話
encoding () 要怎麼找?
測試了一下也真的可以,一個方法是先隨便選個已知的字串且選定好 ,然後用上面的方法建表並回推出 。另一個是利用 的性質,可知 。在一般情況下 用最簡單的 one hot encoding 的話
,那 。
defbase(n, l): D = [] while n > 0: n, r = divmod(n, l) D.append(r) return"".join(str(d) for d inreversed(D)) or"0"
defasiv_prng(seed, mod): l = len(seed) _seed = base(bytes_to_long(seed), mod) _l = len(_seed) R = [[getRandomRange(0, mod) for _ inrange(_l)] for _ inrange(_l**2)] S = [] for r in R: s = 0 for _ inrange(_l): b = ((int(r[_]) + int(_seed[_])) % mod) % 2 s = s ^^ b S.append(s) return _seed, R, S
# choose encodings mf = matrix(GF(2), mod, mod) for x inrange(mod): for y inrange(mod): mf[x, y] = ((x + y) % mod) % 2 mg = matrix(GF(2), mapping) mh = (mg.inverse() * mf).T assert mg * mh.T == mf inv_table = {} for i inrange(mod): t = tuple(mh[i]) inv_table[t] = i t2 = tuple(1 - x for x in t) inv_table[t2] = i
sv, R, S = asiv_prng(b"flag{test}", mod) l = len(R[0]) RR = [] for row in R: r = [] for x in row: r += mapping[x] RR.append(r)
A = matrix(GF(2), RR) sol = A.solve_right(vector(S)) digits = [] for i inrange(l): thing = tuple(sol[i * mod : (i + 1) * mod]) digits.append(inv_table[thing]) print(long_to_bytes(int("".join(str(s) for s in digits), mod)))