from output import * from itertools import product from math import gcd from tqdm import tqdm
h1, h2 = hints
for a, b in product(range(2**12), repeat=2): q = gcd(a * h1 - b * h2, n) if q != 1and q < n: print(q, n) break q = 131749193259488372734882395267267400452018470526669557625739671139987328020291297864452866159092612057179256194270162132453379915244109293125925735503860433762913331882646107732350881847176645056234707603429859084687993766987515407413263165507571230913665811470277548803428982720272589512297691853544766981321 p = n // q e = 0x10001 d = pow(e, -1, (p - 1) * (q - 1)) m = pow(c, d, n) flag = m.to_bytes(1024, "big").strip(b"\x00") print(flag) # DUCTF{gcd_1s_a_g00d_alg0r1thm_f0r_th3_t00lbox}
apbq rsa ii
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
from Crypto.Util.number import getPrime, bytes_to_long from random import randint
p = getPrime(1024) q = getPrime(1024) n = p * q e = 0x10001
hints = [] for _ inrange(3): a, b = randint(0, 2**312), randint(0, 2**312) hints.append(a * p + b * q)
FLAG = open('flag.txt', 'rb').read().strip() c = pow(bytes_to_long(FLAG), e, n) print(f'{n = }') print(f'{c = }') print(f'{hints = }')
from sage.allimport * from Crypto.Util.number import getPrime, bytes_to_long from random import randint from itertools import product, combinations from output import *
h1, h2, h3 = hints L = matrix(hints).T.augment(matrix.identity(3)) L[:, 0] *= n L = L.LLL() for v in L: print(v) print([x.bit_length() for x in v])
# the expected vector is (a1*a3*b1-a1*a2*b3, -a1*a3*b1+a1**2*b3, a1*a2*b1-a1**2*b2) # but we can see that a1 divides all of them # assuming gcd(gcd((a1*a3*b2-a1*a2*b3), (-a1*a3*b1+a1**2*b3)), (a1*a2*b1-a1**2*b2)) == 1 here # the shortest vector should be (a3*b2-a2*b3, -a3*b1+a1*b3, a2*b1-a1*b2)
_, t, u, v = L[0] # therefore this should hold # assert abs(a3*b2 - a2*b3) == abs(t) # assert abs(a3*b1 - a1*b3) == abs(u) # assert abs(a2*b1 - a1*b2) == abs(v) a1s, a2s, a3s, b1s, b2s, b3s = QQ["a1,a2,a3,b1,b2,b3"].gens() for sign in product((-1, 1), repeat=3): I = ideal( [ a3s * b2s - a2s * b3s + sign[0] * t, a3s * b1s - a1s * b3s + sign[1] * u, a2s * b1s - a1s * b2s + sign[2] * v, ] ) if I.dimension() != -1: print(sign) print("dim", I.dimension())
defstep2(f): # this f is in the form of k1*a1+k2*a2+k3*a3==0 # for some reason, k1*b1+k2*b2+k3*b3==0 also holds # use LLL to find it print("=" * 40) print(f) L = matrix(f.coefficients()).T.augment(matrix.identity(3)) L[:, 0] *= n L = L.LLL() print(L[0]) print(L[1]) v1 = L[0] v2 = L[1] xs = [] for c1, c2 in product((-2, -1, 0, 1, 2), repeat=2): v = c1 * v1 + c2 * v2 _, x1, x2, x3 = v ifall([0 <= x <= 2**312for x in (x1, x2, x3)]): xs.append((x1, x2, x3)) # we don't know which one is correct pair of (a1, a2, a3) and (b1, b2, b3) # just try all combinations for g1, g2 in combinations(xs, 2): a1r, a2r, a3r = g1 b1r, b2r, b3r = g2 q = gcd(a2r * h1 - a1r * h2, n) if1 < q < n: p = n // q e = 0x10001 d = inverse_mod(e, (p - 1) * (q - 1)) m = pow(c, d, n) flag = int(m).to_bytes(1024, "big").strip(b"\x00") print(flag) exit()
deffnv1(s): h = 0xcbf29ce484222325 for b in s: h *= 0x00000100000001b3 h &= 0xffffffffffffffff h ^= b return h
TARGET = 0x1337133713371337
print("Welcome to FNV!") print(f"Please enter a string in hex that hashes to 0x{TARGET:016x}:") s = bytearray.fromhex(input()) if fnv1(s) == TARGET: print('Well done!') print(os.getenv('FLAG')) else: print('Try again... :(')
uint64_t start = 0xcbf29ce484222325; uint64_t end = 0x1337133713371337;
// meet in the middle attack 8 bytes // 4 bytes forward, 4 bytes backward uint64_t *tblptr = tbl; for (uint8_t a = 0; a < 256; a++) { printf("a: %d\n", a); for (uint8_t b = 0; b < 256; b++) { for (uint8_t c = 0; c < 256; c++) { for (uint8_t d = 0; d < 256; d++) { uint64_t s = start; fnv_forward(&s, a); fnv_forward(&s, b); fnv_forward(&s, c); fnv_forward(&s, d); *tblptr = s; tblptr++; if (d == 255) break; } if (c == 255) break; } if (b == 255) break; } if (a == 255) break; } printf("done part 1\n");
std::sort(tbl, tblend); printf("done sort\n");
for (uint8_t a = 0; a < 256; a++) { printf("a: %d\n", a); for (uint8_t b = 0; b < 256; b++) { for (uint8_t c = 0; c < 256; c++) { for (uint8_t d = 0; d < 256; d++) { uint64_t s = end; fnv_backward(&s, a); fnv_backward(&s, b); fnv_backward(&s, c); fnv_backward(&s, d); uint64_t *f = std::lower_bound(tbl, tblend, s); if (f != tblend && *f == s) { printf("found %lx\n", s); printf("a: %d, b: %d, c: %d, d: %d\n", a, b, c, d); } if (d == 255) break; } if (c == 255) break; } if (b == 255) break; } if (a == 255) break; } return0; } // g++ brute.cpp -Wall -o brute -Ofast -march=native -mtune=native && ./brute
from hashlib import md5 as md5 import subprocess from tempfile import TemporaryDirectory import os, pickle from tqdm import trange from sage.allimport * from binteger import Bin from pwn import remote
deffn(inp): h = md5() ret = bytes([0] * 16) for b in inp: h.update(bytes([b])) ret = bytes([a ^ b for a, b inzip(ret, h.digest())]) return ret
defxor(x, y): returnbytes([a ^ b for a, b inzip(x, y)])
withopen("data.pkl", "rb") as f: ms, xs = pickle.load(f)
cur = byt2bv(fn(b"".join([ma for ma, mb in ms])), 128) mat = matrix(GF(2), [byt2bv(x, 128) for x in xs]) assert mat.rank() == 128 target = byt2bv(b"h" * 16, 128) # cur+?*mat=target sol = mat.solve_left(target - cur) print(sol) msg = b"" for v, ma, mb inzip(sol, *zip(*ms)): if v == 0: msg += ma else: msg += mb print(fn(msg))