magic random


random data is hard to find, so sometimes people generate random data from random data!

intro puzzle

Challenge script:
import random

def lcg(state, multiplier, increment, modulus):
  return (multiplier * state + increment) % modulus

def xor(key, plaintext): # performs a XOR operation on the key and the plaintext
    return bytes([keybyte ^ ptbyte for keybyte, ptbyte in zip(key, plaintext)])

def to_bytes(x): # converts number to 4 bytes (base 10 -> base256)
    return x.to_bytes(4, "big")

def from_bytes(x): # converts 4 bytes to number (base256 -> base 10)
    return int.from_bytes(x, "big")

# reads the content of the secret.png file
SECRET_IMAGE = open("secret.png", "rb").read()

modulus = 0xfffffffb
multiplier = random.randrange(0, modulus) # generates multiplier, increment, state which are in the range of 0 - p
increment = random.randrange(0, modulus)
state = random.randrange(0, modulus)

# generates a one time pad using the LCG to generate bytes
otp = b""
while len(otp) < len(image):
    state = lcg(state, multiplier, increment, modulus)
    otp += to_bytes(state)

print(xor(SECRET_IMAGE, otp).hex())
Output:
8744e97298ef7cc1ab909824f356472717bbecaeddca0abf187f30adfa7bd8a438eb099b12466e4cdfd515e98d9f0bc51fa55e59d4e2a963a706261c1c0fcceaac2634794387f588ba8fa62c4b168b7f45de2c3954301c4653c8d2cfab246fd6adc212399eddd999b1d748541c8532aa3c0f22ddc99a0fd4958e836a87d5c12f563decdb33211a14389b2a945995829b07eb0924480d4f665835d66d61a4785a8964d10d50d7f6f690f5965d38ed141c4838c76a81b9a0df48939d17e59f0d82139e5110856d7033811de19f68b1f51e5aa980d2cb60ba0c5957d5384a1fc6837ead7bf869ddacffe71774a1a66d310cd11b9a123502980a9dac32469302fb234ece786c5d066a5dc3823585d7927e53f405294a2bc8686a6396337c2c9ad6736e69295e94e8e320dcebb2c7ea541e8457d61f43c1dabdaa3d31ea94950f8afb0f7937f8cbb11f807ea247db91e5fa1fd3a9686a01e62127e286811b1e42a6c6321e6273be69a8053c2e0c57587e6b96f8d595d4ebb2db4589e60e18931d7acacbb9146d03c7525ad9910a41d79a7b1e23be3fa8673a49d66c9b0017a62dcf2594dd843390419898ce458256898e49615b8cf6257b2b0b2fcde8639f0b879c745aeabf3492ddfd67639bfc2c91713f430d268da2e851d4d6e5fa72db736b10ca0a8fec3bc035eb086fa3903b523cf15d6241c19ece36008bfd5d80814744b17f8b1da27082ad01709044dd96e7adb91fee5e3c41d28288847be8b412f31b4e83de16e1f49eb366d549c4fa6a0cdacdf3362c620859754d225b5a161d1b90271accde0cab1f243308c39bfc8ec3ba3b65bb5b21e4fc9089c7d4f13cf5a5f3f53ea56c98620ad45b51c3386d66d9a8ed3911fa6af786917e900aa57a6a599cd2c7b1e9e9f1fdeefceef14c8607cdf327ec7386cf21e1ae1779d02f6d45d1d32b290cfac9089524f6178986228be808629d2221984b51267bb5e28ac363422393a710d6f0097a9e06e647222f27c09d0de49578f4878000f6cd152ebb83b5d89adaf3df4fa837ba6073d86dedc8ea9de93c5c1036dad9ec0513e91ef80a8e2bf96466706f893c63cca1b5fc32960fcaae91333186595e5a127d75c667f688633a2380219810ae5b419e11b4ac0b17959628399f2b30e44bc09b9bdb6b625efac71bb9d22bae3c08508cbde105ef505217db69a37dd708190a949751962d30a66b835df4acadc68f5aaef0c014f54871af6bed7da6fe86b3b84dbe3202d9f0d12ae880a4ecdfc9ed92a69d97775e7b4d94b03f1fbfccd3b591b5e21b84d09d9e4990aa65159649e9b04ae8bb0e47c2f045b6b45d00a37a37e3d91f813a42e58114a6c0d86e25a5b313e589fa91d8