import base64
import hashlib
import os
import random

def parse_pbox(payload):
    return list(map(int, payload[1:-1].split(',')))


def permutate(payload, pbox):
    return bytes([payload[x] for x in pbox])


class Server:
    def __init__(self, password):
        assert len(password) == 16
        self.password = password

    def preauth(self):
        pbox = list(range(20))
        salt = os.urandom(4)
        random.shuffle(pbox)
        return pbox, salt

    def auth(self, pbox, salt, hashed_password):
        permutated_password = permutate(self.password + salt, pbox)
        return hashlib.sha256(permutated_password).hexdigest() == hashed_password


class Client:
    def __init__(self, password):
        self.password = password

    def spy(self, pbox, salt):
        assert len(set(pbox)) == 20
        assert len(salt) == 4
        password = self.password
        permutated_password = permutate(password + salt, pbox)

        hashed_password = hashlib.sha256(permutated_password).hexdigest()
        print(f'[hash] {hashed_password}')


def main():
    password = base64.b64encode(os.urandom(12))
    flag = os.environ.get('FLAG', 'hkcert20{***REDACTED***}')

    s = Server(password)
    c = Client(password)

    for _ in range(10):
        command = input('[cmd] ')
        try:
            if command == 'spy':
                pbox = parse_pbox(input('[pbox] '))
                salt = base64.b64decode(input('[salt] '))
                c.spy(pbox, salt)
            elif command == 'auth':
                pbox, salt = s.preauth()
                print(f'[pbox] {pbox}')
                print(f'[salt] {base64.b64encode(salt).decode()}')
                hashed_password = input('[hash] ')
                if not s.auth(pbox, salt, hashed_password):
                    raise Exception('No!')
                print(f'[flag] {flag}')
        except:
            print('no way!')


if __name__ == '__main__':
    main()
