2021. 10. 11. 18:57, CTF/Crypto
$\textsf{fake[LEN-LEN//3:LEN]} = 0$. Therefore $\textsf{key[LEN-LEN//3:LEN]}$ can be recovered(Index is ignored).
For $\textsf{fake[i]} \text{ for } i < \textsf{LEN-LEN//3}$, those value is linear combination of $\textsf{key[i+1:LEN]}$. It is enough to check whether which remaining value is a linear combination of $\textsf{key[i+1:LEN]}$.
There might be a false positive, so I was planning to bruteforce last four or five recovered keybits but fortunately there was no false positive.
def keygen(ln):
# Generate a linearly independent key
arr = [ 1 << i for i in range(ln) ]
for i in range(ln):
for j in range(i):
if random.getrandbits(1):
arr[j] ^= arr[i]
for i in range(ln):
for j in range(i):
if random.getrandbits(1):
arr[ln - 1 - j] ^= arr[ln - 1 - i]
return arr
def gen_keystream(key):
ln = len(key)
assert ln > 50
# Generate some fake values based on the given key...
fake = [0] * ln
for i in range(ln - ln // 3):
arr = list(range(i + 1, ln))
random.shuffle(arr)
for j in arr[:ln // 3]:
fake[i] ^= key[j]
# Generate the keystream
res = []
for i in range(ln):
t = random.getrandbits(1)
if t:
res.append((t, [fake[i], key[i]]))
else:
res.append((t, [key[i], fake[i]]))
# Shuffle!
random.shuffle(res)
keystream = [v[0] for v in res]
public = [v[1] for v in res]
return keystream, public
def xor(a, b):
return [x ^ y for x, y in zip(a, b)]
def recover_keystream(key, public):
st = set(key)
keystream = []
for v0, v1 in public:
if v0 in st:
keystream.append(0)
elif v1 in st:
keystream.append(1)
else:
assert False, "Failed to recover the keystream"
return keystream
def bytes_to_bits(inp):
res = []
for v in inp:
res.extend(list(map(int, format(v, '08b'))))
return res
def bits_to_bytes(inp):
res = []
for i in range(0, len(inp), 8):
res.append(int(''.join(map(str, inp[i:i+8])), 2))
return bytes(res)
def rank_check(basis, t, LEN):
for i in range(LEN-1,-1,-1):
if t & (1<<i):
if basis[i] == 0:
return False
t ^= basis[i]
return t == 0
def add_basis(basis,t,LEN):
for j in range(LEN-1, -1, -1):
if t & (1 << j):
if basis[j] == 0:
basis[j] = t
return None
else:
t ^= basis[j]
def solve():
f = open('output.txt')
enc = int(f.readline(), 16)
pub = eval(f.readline()) # len 616
LEN = len(pub)
keystream = [0]*LEN
vis = [0]*LEN
basis = [0]*LEN
############# BASIS
for i in range(LEN):
if pub[i][0] == 0:
vis[i] = True
keystream[i] = 1
add_basis(basis,pub[i][1],LEN)
if pub[i][1] == 0:
vis[i] = True
keystream[i] = 0
add_basis(basis,pub[i][0],LEN)
for cur in range(LEN//3, LEN):
for i in range(LEN):
if vis[i]: continue
if rank_check(basis, pub[i][0], LEN):
vis[i] = True
add_basis(basis, pub[i][1], LEN)
keystream[i] = 1
print("now ", cur, "keystream", i, keystream[i])
break
if rank_check(basis, pub[i][1], LEN):
vis[i] = True
add_basis(basis, pub[i][0], LEN)
print("now ", cur, "keystream", i, keystream[i])
break
else:
print("!!!!!",i)
return None
print(keystream)
z = 0
for i in range(LEN):
if keystream[i]: z ^= (1<<(LEN-1-i))
print(long_to_bytes(z^enc))
solve()
'CTF > Crypto' 카테고리의 다른 글
[zer0pts CTF 2022] CurveCrypto (0) | 2022.03.22 |
---|---|
[zer0pts CTF 2022] Anti-Fermat (0) | 2022.03.22 |
[Codegate 2022] PrimeGenerator (0) | 2022.02.28 |
[2021 PBCTF] Alkaloid Stream (2) | 2021.10.11 |
[2019 X-MAS CTF] Santa Knows Crypto (0) | 2019.12.14 |
[2019 X-MAS CTF] Hashed Presents (0) | 2019.12.14 |
Comments