import random, os, signal from Crypto.Util.number import long_to_bytes as l2b, bytes_to_long as b2l from secret import FLAG ROUNDS = 3 USED_STATES = [] _ROL_ = lambda x, i : ((x << i) | (x >> (N-i))) & (2**N - 1) N = 128 def handler(signum, frame): print("\n\nToo slow, don't try to do sneaky things.") exit() def validate_state(state): if not all(0 < s < 2**N-1 for s in user_state[-2:]) or not all(0 <= s < N for s in user_state[:4]): print('Please, make sure your input satisfies the upper and lower bounds.') return False if sorted(state[:4]) in USED_STATES: print('You cannot reuse the same state') return False if sum(user_state[:4]) < 2: print('We have to deal with some edge cases...') return False return True class HashRoll: def __init__(self): self.reset_state() def hash_step(self, i): r1, r2 = self.state[2*i], self.state[2*i+1] return _ROL_(self.state[-2], r1) ^ _ROL_(self.state[-1], r2) def update_state(self, state=None): if not state: self.state = [0] * 6 self.state[:4] = [random.randint(0, N) for _ in range(4)] self.state[-2:] = [random.randint(0, 2**N) for _ in range(2)] else: self.state = state def reset_state(self): self.update_state() def digest(self, buffer): buffer = int.from_bytes(buffer, byteorder='big') m1 = buffer >> N m2 = buffer & (2**N - 1) self.h = b'' for i in range(2): self.h += int.to_bytes(self.hash_step(i) ^ (m1 if not i else m2), length=N//8, byteorder='big') return self.h print('Can you test my hash function for second preimage resistance? You get to select the state and I get to choose the message ... Good luck!') hashfunc = HashRoll() for _ in range(ROUNDS): print(f'ROUND {_+1}/{ROUNDS}!') server_msg = os.urandom(32) hashfunc.reset_state() server_hash = hashfunc.digest(server_msg) print(f'You know H({server_msg.hex()}) = {server_hash.hex()}') signal.signal(signal.SIGALRM, handler) signal.alarm(2) user_state = input('Send your hash function state (format: a,b,c,d,e,f) :: ').split(',') try: user_state = list(map(int, user_state)) if not validate_state(user_state): print("The state is not valid! Try again.") exit() hashfunc.update_state(user_state) if hashfunc.digest(server_msg) == server_hash: print(f'Moving on to the next round!') USED_STATES.append(sorted(user_state[:4])) else: print('Not today.') exit() except: print("The hash function's state must be all integers.") exit() finally: signal.alarm(0) print(f'Uhm... how did you do that? I thought I had cryptanalyzed it enough ... {FLAG}')