for key in F[1:]: flag = "" for c in enc: i = ALPHABET.index(c) ii = F.index(F[i] / key) flag += ALPHABET[ii] if flag.endswith("=="): print(base64.b64decode(flag)) break
其實就如 flag 所說的,這個也只是 substitution cipher,只是是在 finite
field 中的版本而已。
for a inrange(256): for b inrange(256): key = key_prefix + bytes([a, b]) xpt = decrypt_ecb(ct, key) enc1 = xor(xpt, pt) iv = xor(decrypt_ecb(enc1, key), pt) flag = decrypt(enc_flag, iv, key) ifall(20 <= x < 127for x in flag): print(flag)
Symbols
這題只給了你一個圖片,裡面有很多數學符號,看起來像是 substitution
cipher。
我的解法是用 Detexify 去查
symbol 的 LaTeX command,然後可以注意到 command 的第一個字元應該就是
flag 的字元,所以最後找出了 CCTF{Play_with_LaTeX}。
medium-easy
Rima
這題是把 flag 變為 0 1 陣列,然後做一些移位的加法去
encode,不過他的程式碼很難讀所以我也放棄去理解那個 code,直接上 z3
就能解了。
f = [Int(f"f_{i}") for i inrange(8 * 32 - 1)] f0 = list(f)
f.insert(0, 0) for i inrange(len(f) - 1): f[i] += f[i + 1]
a = next_prime(len(f)) b = next_prime(a)
g, h = [[_ for i inrange(x) for _ in f] for x in [a, b]]
c = next_prime(len(f) >> 2)
for _ in [g, h]: for __ inrange(c): _.insert(0, 0) for i inrange(len(_) - c): _[i] += _[i + c]
sol = Solver() for x in f0: sol.add(Or(x == 0, x == 1)) sol.add(And([x == y for x, y inzip(g, gg)])) sol.add(And([x == y for x, y inzip(h, hh)])) assert sol.check() == sat m = sol.model() f = [m.eval(x).as_long() for x in f0] f = int("".join(map(str, f))[::-1], 2) print(long_to_bytes(f))
Hyper Normal
這題會先把 flag encode 成一個 的矩陣
然後打亂,假設 flag 的字元是 ,那麼矩陣
會先變為:
from sage.allimport * from functools import reduce from operator import and_ import random
p = 8443
deftranspose(x): result = [[x[j][i] for j inrange(len(x))] for i inrange(len(x[0]))] return result
defvsum(u, v): assertlen(u) == len(v) l, w = len(u), [] for i inrange(l): w += [(u[i] + v[i]) % p] return w
defsprod(a, u): w = [] for i inrange(len(u)): w += [a * u[i] % p] return w
defencrypt(msg): l = len(msg) hyper = [ord(m) * (i + 1) for (m, i) inzip(list(msg), range(l))] V, W = [], [] for i inrange(l): v = [0] * i + [hyper[i]] + [0] * (l - i - 1) V.append(v) random.shuffle(V) # V = [V[1],V[0],V[3],V[2]] print(V) for _ inrange(l): R, v = [random.randint(0, 126) for _ inrange(l)], [0] * l for j inrange(l): v = vsum(v, sprod(R[j], V[j])) W.append(v) print(R, v) random.shuffle(transpose(W)) return W
l = len(W) Z = GF(p) W = Matrix(Z, W)
ccand = [] for k inrange(l): cand = [set() for _ inrange(l)] for i inrange(1, 126): v = vector(x / i for x in W[k]) for j inrange(len(v)): cand[j].add(v[j]) ccand.append(cand)
tccand = transpose(ccand) flag = "" for i inrange(l): # tccand[i] = tccand[i][1::2] # without this line: CCTF{0w_f1Nd_th3_4lL_3I9EnV4Lu35_iN_FiN173_Fi3lD5 ???} # with this line: CCTF{H0w_f1Nd_th3_4l _3I9EnV4Lu35_iN_FiN173_Fi3lD5!???} # so we have the full flag
ss = tccand[i][0] j = 1 whilelen(ss) > 1: ss = ss & tccand[i][j] j += 1 iflen(ss) > 0: c = list(ss)[0] // (i + 1) else: c = ord(" ") flag += chr(c) print(flag)
n = 98027132963374134222724984677805364225505454302688777506193468362969111927940238887522916586024601699661401871147674624868439577416387122924526713690754043 c = 42066148309824022259115963832631631482979698275547113127526245628391950322648581438233116362337008919903556068981108710136599590349195987128718867420453399
k = 246389259423689900229483388850933720271363907782961941639413620688310657308991195363798484778005049234253341752674411282663124201840620584781830032437353134292733496201534415265400175632719346764031781179041636 # xy-x+y-b=0 # (y-1)(x+1)=b-1 b = 992752253935874779143952218845275961347009322164731344882417010624071055636710540798045985678351986133613
# big factors are factored using FactorDB f1 = 1357459302115148222329561139218955500171643099 f2 = 17258104558019725087 f3 = 2035395403834744453
defdivs(f): # copied from sage output = [1] for p, e in f: prev = output[:] pn = 1 for i inrange(e): pn *= p output.extend(a * pn for a in prev) output.sort() return output
for d in divs(fs): x, y = d - 1, (b - 1) // d + 1 assert (y - 1) * (x + 1) == b - 1 flag = long_to_bytes(x) + long_to_bytes(y) ifb"CCTF"in flag: print(flag) break
d = ( 83818189125408135328873033373544374818199783983 * 34388019287720328558025059428347529 * 10803954241 ) assert d < mn assert (l + 1) % d == 0 e = (l + 1) // d assert e < mn assert e * d % phi(k1) == 1 assert e * d % phi(k2) == 1 assert e * d % phi(k3) == 1
withopen("output.txt") as f: lines = [line.strip() for line in f.readlines() if"="notin line] vecs = [[int(x) for x in line[1:-1].split(" ") if x] for line in lines] E = matrix(GF(p), vecs[:11]) LUL = matrix(GF(p), vecs[11:22]) L1S2L = matrix(GF(p), vecs[22:33]) R1S8 = matrix(GF(p), vecs[33:44])
U = L1S2L * LUL ^ -1 S2 = LUL * U R = (R1S8 * S2 ^ -4) ^ -1 A = U ^ -1 * E - R print(A)
io = remote("05.cr.yp.toc.tf", 14010) io.sendlineafter(b"Options", b"G") io.recvuntil(b"Parameters = ") n, f, v = ast.literal_eval(io.recvlineS().strip()) assert f % 2 == 0 g = pow(48763, n, n * n) x = pow(g, f // 2, n * n) y = n * n - x assertpow(x, f, n * n) == 1 assertpow(y, f, n * n) == 1 print(x) print(y) io.sendlineafter(b"Options", b"R") io.sendlineafter(b"comma: ", f"{x},{y}".encode()) print(io.recvallS())
e = 65537 a = 769 b = 90 # (p - a)**2 + (q - b)**2 == k**7 k = 533349483431826854866479442416204129077526048835547852310509534957185 c = 4478819143432789024587861603523572305269547479550443133641110109373270566470025946722977115602647046295004476694988416461505550664119915082335497331912881526446940124404687029541487759747406116312872601161581904176763818623358120927587871262018474674411074996384180525486478668863914557062661081721929081678057785839028975581815732964462013512812566725502749216649190469493027431158255717939171221374546082898410798277258418126725070247145397363980604758633071972900958843430904130 p, q = var("p q") assume(p, "integer") assume(q, "integer") sol = solve(p ** 2 + q ** 2 == k, p, q) sol = [(Integer(p), Integer(q)) for p, q in sol if p > 0and q > 0]
defmul(r, s): # https://en.m.wikipedia.org/wiki/Brahmagupta%E2%80%93Fibonacci_identity a, b = r c, d = s x1 = a * c - b * d y1 = a * d + b * c x2 = a * c + b * d y2 = a * d - b * c return (abs(x1), abs(y1)), (abs(x2), abs(y2))
defsqr(r): return mul(r, r)[0]
for r in sol: r2 = sqr(r) r4 = sqr(r2) for r3 in mul(r, r2): for r7 in mul(r4, r3): p, q = r7 assert p ^ 2 + q ^ 2 == k ^ 7 p += a q += b if isPrime(p) and isPrime(q): print(p, q) n = p * q phi = (p - 1) * (q - 1) d = inverse_mod(e, phi) m = power_mod(c, d, n) print(long_to_bytes(m)) exit()
whileTrue: a, b, p = gen_anomalous(160) q = nextPrime(p) mxq = max([p for p, e in factor(EllipticCurve(GF(q), [a, b]).order())]) if mxq < 2 ^ 40: print(a, b) print(p, q) break print(log(mxq, 2).n())
a, b = ( 823375435824563939268788611110428744408176719161, 128395071361889866257668408194030595816566744161, ) p, q = ( 890662999704698873790151198748536866796172800897, 890662999704698873790151198748536866796172800963, ) Ep = EllipticCurve(GF(p), [a, b]) Eq = EllipticCurve(GF(q), [a, b])
assert Ep.order() == p
defsmart_attack(P, G, p): # https://crypto.stackexchange.com/a/70508 E = G.curve() Eqp = EllipticCurve(Qp(p, 2), [ZZ(t) + randint(0, p) * p for t in E.a_invariants()])
P_Qps = Eqp.lift_x(ZZ(G.xy()[0]), all=True) for P_Qp in P_Qps: if GF(p)(P_Qp.xy()[1]) == G.xy()[1]: break
Q_Qps = Eqp.lift_x(ZZ(P.xy()[0]), all=True) for Q_Qp in Q_Qps: if GF(p)(Q_Qp.xy()[1]) == P.xy()[1]: break
from Crypto.Util.number import * from pwn import remote from sage.matrix.matrix2 import Matrix import ast
defresultant(f1, f2, var): # Copied from https://jsur.in/posts/2021-07-19-google-ctf-2021-crypto-writeups#h1 return Matrix.determinant(f1.sylvester_matrix(f2, var))
io = remote("03.cr.yp.toc.tf", 25010) io.sendlineafter(b"Options", b"S") io.recvuntil(b"p = ") p = int(io.recvlineS().strip()) io.recvuntil(b"r = ") r = int(io.recvlineS().strip()) io.sendlineafter(b"Options", b"P") io.recvuntil(b"pubkey = ") pubkey = ast.literal_eval(io.recvlineS().strip()) print(p, r) print([hex(x) for x in pubkey])
ks = [pow(r, c + 1, p) for c inrange(0, 5)] Z = Zmod(p) PP = PolynomialRing(Z, "s,x1,x2") s, *xs = PP.gens() f1 = ks[0] * s - (pubkey[0] + xs[0]) f2 = ks[1] * s - (pubkey[1] + xs[1]) f = PP.remove_var(s)(resultant(f1, f2, s)) print(f) load("~/workspace/coppersmith.sage") xs = small_roots(f, (2 ** 40, 2 ** 40), m=4, d=2)[0] s = Z(pubkey[0] + xs[0]) / ks[0] assert s == Z(pubkey[1] + xs[1]) / ks[1] print(s) U = [pow(r, c + 1, p) * s % p for c inrange(0, 5)] S = [int(bin(u)[2:][-32:], 2) for u in U] print([hex(x) for x in S])
defsign(msg, privkey, d): msg = msg.encode("utf-8") l = len(msg) // 4 M = [bytes_to_long(msg[4 * i : 4 * (i + 1)]) for i inrange(l)] q = int(next_prime(max(M))) sign = [M[i] * privkey[i] % q for i inrange(l)] return sign
p = 512156828103365901048559505103237592010730651992953680223000172094095757203886681225415426450387040031253612295400192069437985566674257501701743368686395531 u = 278331424202715529007235225803083105831898177238768088959896273495587346471193489462465390715976004916539200837444755811532762335472120306642106779851779895 v = 256568421561256620412008753530664775781745915184311927713911832406042827934333342438038088202080460367979454347035971495645785213472938457309904032230294302 w = 291075584404341211571864039572762475831612407000784732318354539887997569888845019102264165940156056600333692694871997403708476839090241830333179131216949773 ca, cb, cc = ( 287555353447321752440570170565916634951105240901098656962539161570704086923490274350537706807786632105173520254109700863175418950150190301275461066194290273, 61323835393791353232128681044112245885676777670178659696073015541712435637029773641799576432645407470518574659302988690944012552307615441231640649288656467, 24320377817820710179555605271052810810335284586923974087878926553551229844983654115310868607990402619355506091875700785511303195656702348392817435407241231, )
Z = Zmod(p)
r = discrete_log(Z(ca), Z(u)) print(r) s = discrete_log(Z(cb), Z(v)) print(s) wrs = Z(w) ** (r + s) m = Z(cc) / wrs print(long_to_bytes(m))
defsolve_xy(): P = PolynomialRing(QQ, "x,y") x, y = P.gens() I = P.ideal([y ^ 2 + x - s1, y ^ 4 - x * y ^ 2 + x ^ 2 - s2]) V = I.variety() for sol in V: yield (Integer(sol[x]), Integer(sol[y]))
defsolve_z(x, y): P = PolynomialRing(ZZ, "z") z = P.gen() f = x ^ 4 + y ^ 5 + x * y * z - k2 rs = f.roots() iflen(rs) > 0: return Integer(rs[0][0])
for x, y in solve_xy(): z = solve_z(x, y) if z isNone: continue print(x, y, z) assert2 * z ** 5 - x ** 3 + y * z == k1 assert x ** 4 + y ** 5 + x * y * z == k2 assert y ** 6 + 2 * z ** 5 + z * y == k3 p = nextPrime(x ** 2 + z ** 2 + y ** 2 << 76) print(p) q = nextPrime(z ** 2 + y ** 3 - y * x * z ^^ 67) print(q) n, e = p * q, 31337 d = inverse_mod(e, (p - 1) * (q - 1)) print(long_to_bytes(power_mod(c, d, n)))
from sage.allimport * from Crypto.Util.number import *
n = 43216667049953267964807040003094883441902922285265979216983383601881964164181 U = 18230294945466842193029464818176109628473414458693455272527849780121431872221 V = 13100009444194791894141652184719316024656527520759416974806280188465496030062 W = 5543957019331266247602346710470760261172306141315670694208966786894467019982
p = 190116434441822299465355144611018694747 q = n // p
Ep = EllipticCurve(GF(p), [0, U, 0, V, W]) Eq = EllipticCurve(GF(q), [0, U, 0, V, W]) Gp = Ep( 6907136022576092896571634972837671088049787669883537619895520267229978111036, 35183770197918519490131925119869132666355991678945374923783026655753112300226, ) Gq = Eq( 6907136022576092896571634972837671088049787669883537619895520267229978111036, 35183770197918519490131925119869132666355991678945374923783026655753112300226, ) sGp = Ep( 14307615146512108428634858855432876073550684773654843931813155864728883306026, 4017273397399838235912099970694615152686460424982458188724369340441833733921, ) sGq = Eq( 14307615146512108428634858855432876073550684773654843931813155864728883306026, 4017273397399838235912099970694615152686460424982458188724369340441833733921, )
deffind_embedding_degree(E): p = E.base().order() n = E.order() if p == n: # anomalous curve return0 for k inrange(1, 13): if (p ** k - 1) % n == 0: return k
defsmart_attack(P, G, p): # https://crypto.stackexchange.com/a/70508 E = G.curve() Eqp = EllipticCurve(Qp(p, 2), [ZZ(t) + randint(0, p) * p for t in E.a_invariants()])
P_Qps = Eqp.lift_x(ZZ(G.xy()[0]), all=True) for P_Qp in P_Qps: if GF(p)(P_Qp.xy()[1]) == G.xy()[1]: break
Q_Qps = Eqp.lift_x(ZZ(P.xy()[0]), all=True) for Q_Qp in Q_Qps: if GF(p)(Q_Qp.xy()[1]) == P.xy()[1]: break
print( gcd( resultant(resultant(P, tQ, c), resultant(sP, Q, c), d), resultant(resultant(P, Q, c), resultant(sP, tQ, c), d), ) ) # Then factordb get p = 903968861315877429495243431349919213155709
defresultant(f1, f2, var): # Copied from https://jsur.in/posts/2021-07-19-google-ctf-2021-crypto-writeups#h1 return Matrix.determinant(f1.sylvester_matrix(f2, var))
p = 903968861315877429495243431349919213155709 P.<c, d> = GF(p)[]
defpoint(u, v): return u ** 2 + v ** 2 - c ** 2 * (1 + d * u ** 2 * v ** 2) P = point( 398011447251267732058427934569710020713094, 548950454294712661054528329798266699762662, ) Q = point( 139255151342889674616838168412769112246165, 649791718379009629228240558980851356197207, ) sP = point( 730393937659426993430595540476247076383331, 461597565155009635099537158476419433012710, ) tQ = point( 500532897653416664117493978883484252869079, 620853965501593867437705135137758828401933, ) dd = resultant(P,Q,c).univariate_polynomial().roots()[0][0] cc = resultant(P,Q,d).univariate_polynomial().roots()[0][0] print(cc, dd)
現在 都有了,問題在於
sage 的 EllipticCurve 不支援 Edwards Curve。其實去 wiki
就能查到一句話 Every Edwards curve is birationally equivalent to
an elliptic curve in Weierstrass
form,所以代表有辦法把曲線轉換成 Weierstrass form 之後讓 sage
來處理。
我首先是在這邊有找到把
形式的 Edwards Curve 轉換回 Weierstrass form
的公式,問題在於這條曲線有多出一個參數 。之後繼續查下去可以發現這種有
參數形式的是另外兩個人發明的,去找到了他們原本的 paper 就在第五頁看到了
和 互相轉換的公式。
defphi_factor(n, phi): # n=pq # phi=(p-1)(q-1)=n-(p+q)+1 ppq = n - phi + 1 # (x-p)(x-q)=x^2-(p+q)x+n a = 1 b = -ppq c = n D = b ^ 2 - 4 * a * c if is_square(D): sD = sqrt(D) return (-b + sD) / (2 * a), (-b - sD) / (2 * a)
for c in continued_fraction(n1 / n2).convergents(): # n1 / n2 ~= x / k x = c.numer() k = c.denom() if k.nbits() < 250or x.nbits() < 250: continue if k.nbits() > 260or x.nbits() > 260: break if gcd(k, e) != 1: continue cc = crt([-inverse_mod(k, e), 0], [e, x]) # phi = cc (mod ex) s = cc + ((n1 - cc) // (e * x) - 10) * (e * x) # bruteforce phi ~= n1 for i inrange(20): res = phi_factor(n1, s) if res: print(res) p, r = res d = inverse_mod(e, (p - 1) * (r - 1)) m = power_mod(enc1, d, n1) print(long_to_bytes(m)) phi2 = k * (p - 1) * (r - 1) // x q, s = phi_factor(n2, phi2) print((q, s)) d2 = inverse_mod(e, (p - 1) * (r - 1)) m2 = power_mod(enc2, d2, n2) print(long_to_bytes(m2)) exit() s += e * x