또 뭐하지
[Dreamhack] STREAMer-Prototype 본문
728x90
풀이
#!/usr/bin/env python3
from cipher import STREAM
import random
if __name__ == "__main__":
with open("flag", "rb") as f:
flag = f.read()
assert flag[:3] == b'DH{' and flag[-1:] == b'}'
seed = random.getrandbits(16)
stream = STREAM(seed, 16)
print(f"encrypted flag > {stream.encrypt(flag).hex()}")
문제의 prob.py 코드를 살펴보면 flag를 암호화하는 것을 확인할 수 있다. 이때 seed를 랜덤 16비트로 사용하고 있고, 그 seed를 STREAM 암호에 입력하고 있는 걸 확인할 수 있다. 이제 STREAM 암호를 확인해보자.
class STREAM:
def __init__(self, seed, size):
self.state = self.num2bits(seed, size)
def num2bits(self, num, size):
assert num < (1 << size)
return bin(num)[2:].zfill(size)
def bits2num(self, bits):
return int('0b' + bits, 2)
def shift(self):
new_bit = self.state[-1]
self.state = new_bit + self.state[:-1]
return new_bit
def getNbits(self, num):
sequence = ""
for _ in range(num):
sequence += self.shift()
return sequence
def encrypt(self, plaintext):
ciphertext = b""
for p in plaintext:
stream = self.bits2num(self.getNbits(8))
c = p ^ stream
ciphertext += bytes([c])
return ciphertext
def decrypt(self, ciphertext):
plaintext = b""
for c in ciphertext:
stream = self.bits2num(self.getNbits(8))
p = c ^ stream
plaintext += bytes([p])
return plaintext
if __name__ == "__main__":
import os
for seed in range(0x100):
Alice = STREAM(seed, 16)
Bob = STREAM(seed, 16)
plaintext = os.urandom(128)
ciphertext = Alice.encrypt(plaintext)
assert plaintext == Bob.decrypt(ciphertext)
cipher.py를 통해 STREAM 암호를 확인해보면 암호화되는 방식은 아래와 같다.
1. 입력된 seed를 통해 self.state를 정의
2. getNbits에서 stream이 될 sequence를 생성
3. 이때, sequence는 self.state를 맨 하위 비트를 반환하고 right rotate를 시키는 방식으로 생성
4. sequence를 변환하여 stream을 생성하고, 평문과 xor하여 암호화
근데 복호화함수를 제공하고 있다!!!!!!!!
그러면 그냥 seed를 알아내서 복호화함수에 집어넣는 전수조사를 하면 될 것 같다.
from cipher import STREAM
with open('./STREAMer-Prototype/output.txt', 'r') as file:
line = file.readline().strip()
if line.startswith("encrypted flag >"):
encrypted_flag = line.split("encrypted flag >")[1].strip()
# 암호문을 hex 문자열에서 바이트로 변환
ciphertext = bytes.fromhex(encrypted_flag)
# 전수조사 시작
for seed in range(0x10000): # 0부터 65535까지 모든 seed를 시도
stream = STREAM(seed, 16)
decrypted = stream.decrypt(ciphertext)
# 복호화된 결과가 'DH'로 시작하면 출력하고 종료
if decrypted.startswith(b"DH"):
print(f"Found seed: {seed}")
print(f"Decrypted flag: {decrypted}")
break
위와 같이 전수조사 코드를 작성해고 실행시켜보면, 아래와 같이 시드와 복호화된 flag를 얻을 수 있다.
'Write-up > Crypto' 카테고리의 다른 글
[Dreamhack] safeprime (1) | 2024.10.24 |
---|---|
[Dreamhack] What is This??? (0) | 2024.10.04 |
[Dreamhack] No Shift Please! (4) | 2024.09.27 |
[Dreamhack] Double DES (0) | 2024.09.20 |
[Dreamhack] ICM2022 (0) | 2024.09.13 |