2021. 10. 11. 18:49, CTF/Crypto
Let $\textsf{LEN}$ be a key bit length.
Since $\textsf{fake[LEN-1]} = 0$, we can search the value $\textsf{fake[LEN-1]}$ in pubkey. Then $\textsf{key[LEN-1]}$ is immediately recovered.
$\textsf{fake[LEN-2]} = \textsf{key[LEN-1]}$, also possible to find $\textsf{fake[LEN-2]}$ in pubkey. Then $\textsf{key[LEN-2]}$ is recovered.
By similar logic, if we know $\textsf{key[i...LEN-1]}$, then $\textsf{fake[i-1]}$ is recovered which derives to earn $\textsf{key[i-1]}$.
This is all.
from Crypto.Util.number import *
import random
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)
# Generate some fake values based on the given key...
fake = [0] * ln
for i in range(ln):
for j in range(ln // 3):
if i + j + 1 >= ln:
break
fake[i] ^= key[i + j + 1]
# 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 solve():
f = open('output.txt')
enc = int(f.readline(), 16)
pub = eval(f.readline())
key_recover = [0]*600
fake_recover = [0]*600
keystream = [0]*600
vis = [0]*600
for i in range(599,-1,-1):
vv = 0
for j in range(i+1, min(i+201, 600)):
vv ^= key_recover[j]
print(vv)
for j in range(600):
if vis[j]: continue
if pub[j][0] == vv:
keystream[j] = 1
key_recover[i] = pub[j][1]
fake_recover[i] = pub[j][0]
vis[j] = 1
break
if pub[j][1] == vv:
keystream[j] = 0
key_recover[i] = pub[j][0]
fake_recover[i] = pub[j][1]
vis[j] = 1
break
else:
print("wrong",i)
assert(0)
z = 0
for i in range(600):
if keystream[i]: z ^= (1<<(599-i))
print(hex(z))
print(long_to_bytes(z^enc))
solve()
'CTF > Crypto' 카테고리의 다른 글
[zer0pts CTF 2022] Anti-Fermat (0) | 2022.03.22 |
---|---|
[Codegate 2022] PrimeGenerator (0) | 2022.02.28 |
[2021 PBCTF] Steroid 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 |
[2019 X-MAS CTF] DeFUNct Ransomware (0) | 2019.12.14 |
Comments