from __future__ import annotations import hashlib import random def keystream(key: bytes, length: int) -> bytes: out = bytearray() ctr = 0 while len(out) < length: out.extend(hashlib.sha256(key + ctr.to_bytes(8, 'big')).digest()) ctr += 1 return bytes(out[:length]) def stream_xor(data: bytes, key: bytes) -> bytes: ks = keystream(key, len(data)) return bytes((a ^ b for a, b in zip(data, ks))) def make_perm(key: bytes) -> bytes: seed = int.from_bytes(hashlib.sha256(key).digest(), 'big') rng = random.Random(seed) perm = list(range(256)) rng.shuffle(perm) return bytes(perm) def invert_perm(perm: bytes) -> bytes: inv = bytearray(256) for i, p in enumerate(perm): inv[p] = i return bytes(inv) def perm_apply(data: bytes, key: bytes) -> bytes: perm = make_perm(key) return bytes((perm[b] for b in data)) def perm_invert(data: bytes, key: bytes) -> bytes: inv = invert_perm(make_perm(key)) return bytes((inv[b] for b in data)) def _rot_left(b: int, n: int) -> int: n &= 7 if not n: return b return (b << n | b >> 8 - n) & 255 def rot_apply(data: bytes, key: bytes) -> bytes: return bytes((_rot_left(b, key[i % len(key)]) for i, b in enumerate(data))) def rot_invert(data: bytes, key: bytes) -> bytes: return bytes((_rot_left(b, -key[i % len(key)] & 7) for i, b in enumerate(data)))