from typing import List, Tuple from utils import * class WeakRNG: """Simple class for weak RNG""" def __init__(self) -> None: self.rstate = 0 self.maxn = 255 self.a = 0 # Set this to correct value self.b = 0 # Set this to correct value self.p = 257 def init_state(self, rstate: int) -> None: """Initialise rstate""" self.rstate = rstate # Set this to some value self.update_state() def update_state(self) -> None: """Update state""" self.rstate = (self.a * self.rstate + self.b) % self.p def get_prg_byte(self) -> int: """Return a new PRG byte and update PRG state""" b = self.rstate & 0xFF self.update_state() return b def main() -> None: # Initialise weak rng wr = WeakRNG() wr.init_state(0) # Print ciphertext CH = "a432109f58ff6a0f2e6cb280526708baece6680acc1f5fcdb9523129434ae9f6ae9edc2f224b73a8" print("Full ciphertext in hexa:", CH) # Print known plaintext pknown = "Let all creation" nb = len(pknown) print("Known plaintext:", pknown) pkh = str_2_hex(pknown) print("Plaintext in hexa:", pkh) # Obtain first nb bytes of RNG gh = hexxor(pkh, CH[0 : nb * 2]) print(gh) gbytes = [] for i in range(nb): gbytes.append(ord(hex_2_str(gh[2 * i : 2 * i + 2]))) print("Bytes of RNG: ") print(gbytes) # Break the LCG here: # TODO 1: Find a and b, and set them in the RNG # TODO 2: Predict/generate rest of RNG bytes # TODO 3: Decrypt plaintext # TODO 4: Print the full plaintext p = ... print("Full plaintext is:", p) if __name__ == "__main__": main()