Загрузка данных


#!/usr/bin/env python3
import urllib.request
import json
import base64
import struct
import sys

BASE = sys.argv[1] if len(sys.argv) > 1 else "http://localhost:5000"

R = 0xE1000000000000000000000000000000
MASK128 = (1 << 128) - 1

def gf128_mul(x, y):
    z = 0
    v = x & MASK128
    for i in range(128):
        if (y >> i) & 1:          # ИСПРАВЛЕНО: младший бит
            z ^= v
        msb = (v >> 127) & 1
        v = (v << 1) & MASK128
        if msb:
            v ^= R
    return z & MASK128

def gf128_inv(x):
    result = 1
    base = x
    exp = (1 << 128) - 2
    while exp:
        if exp & 1:
            result = gf128_mul(result, base)
        base = gf128_mul(base, base)
        exp >>= 1
    return result

def ghash(H_bytes, aad, ct):
    H = int.from_bytes(H_bytes, "big")
    len_block = struct.pack(">QQ", len(aad) * 8, len(ct) * 8)
    data = aad + ct + len_block
    Y = 0
    for i in range(0, len(data), 16):
        block = data[i:i+16]
        if len(block) < 16:
            block = block + b"\x00" * (16 - len(block))
        X = int.from_bytes(block, "big")
        Y = gf128_mul(Y ^ X, H)
    return Y.to_bytes(16, "big")

def post(path, payload):
    req = urllib.request.Request(
        BASE + path,
        data=json.dumps(payload).encode(),
        headers={"Content-Type": "application/json"},
        method="POST"
    )
    with urllib.request.urlopen(req, timeout=10) as resp:
        return json.loads(resp.read().decode())

def get(path):
    with urllib.request.urlopen(BASE + path, timeout=10) as resp:
        return json.loads(resp.read().decode())

def ghash_probe(aad, ct):
    r = post("/ghash_probe", {
        "who": "attacker",
        "aad_hex": aad.hex(),
        "ct_b64": base64.b64encode(ct).decode()
    })
    return base64.b64decode(r["ghash_b64"])

def main():
    # --- ТЕСТ МАТЕМАТИКИ ---
    print("=== ТЕСТ МАТЕМАТИКИ ===")
    print(f"gf128_mul(1,1) = {gf128_mul(1,1):032x} (должно быть 1)")
    print(f"gf128_mul(1,2) = {gf128_mul(1,2):032x} (должно быть 2)")
    print(f"gf128_mul(2,2) = {gf128_mul(2,2):032x} (должно быть 4)")
    xt = 0x123456789abcdef0123456789abcdef0
    print(f"x * inv(x) = {gf128_mul(xt, gf128_inv(xt)):032x} (должно быть 1)")
    print("=== КОНЕЦ ТЕСТА ===\n")

    # 1. FLAG_BLOB
    r = get("/flag")
    flag_blob = base64.b64decode(r["flag_blob"])
    FLAG_IV  = flag_blob[:12]
    FLAG_CT  = flag_blob[12:-16]
    FLAG_TAG = flag_blob[-16:]
    print(f"[+] FLAG_IV  = {FLAG_IV.hex()}")
    print(f"[+] FLAG_CT  = {FLAG_CT.hex()} ({len(FLAG_CT)} bytes)")
    print(f"[+] FLAG_TAG = {FLAG_TAG.hex()}")

    # 2. H^2 через разность двух запросов
    X1 = b"\x00" * 15 + b"\x01"
    X2 = b"\x00" * 15 + b"\x02"
    g1 = ghash_probe(X1, b"")
    g2 = ghash_probe(X2, b"")
    X1_int = int.from_bytes(X1, "big")
    X2_int = int.from_bytes(X2, "big")
    g1_int = int.from_bytes(g1, "big")
    g2_int = int.from_bytes(g2, "big")
    diff_X = X1_int ^ X2_int
    diff_g = g1_int ^ g2_int
    H2 = gf128_mul(diff_g, gf128_inv(diff_X))
    print(f"[+] H^2 = {H2:032x}")

    # 3. H через GHASH(H, "", Y)
    Y = b"\x00" * 15 + b"\x03"
    g3 = ghash_probe(b"", Y)
    Y_int = int.from_bytes(Y, "big")
    g3_int = int.from_bytes(g3, "big")
    L = 0x80
    H_times_L = g3_int ^ gf128_mul(Y_int, H2)
    H = gf128_mul(H_times_L, gf128_inv(L))
    H_bytes = H.to_bytes(16, "big")
    print(f"[+] H = {H_bytes.hex()}")

    # Проверка
    assert ghash(H_bytes, X1, b"") == g1, "H verification failed"
    print("[+] H verified!")

    # 4. E_K(FLAG_J0)
    FLAG_J0 = FLAG_IV + b"\x00\x00\x00\x01"
    r = post("/aes_ecb_tenant", {
        "who": "victim",
        "block_b64": base64.b64encode(FLAG_J0).decode()
    })
    E_K_J0 = base64.b64decode(r["cipher_b64"])
    print(f"[+] E_K(J0) = {E_K_J0.hex()}")

    # 5. known
    known = bytes(a ^ b for a, b in zip(FLAG_TAG, E_K_J0))
    print(f"[+] known = {known.hex()}")

    # 6. G0
    AAD_PREFIX = b"user-aad-prefix:"
    G0 = ghash(H_bytes, AAD_PREFIX + b"\x00" * 16, FLAG_CT)
    print(f"[+] G0 = {G0.hex()}")

    # 7. SECRET_VICTIM
    N = 2 + (len(FLAG_CT) + 15) // 16 + 1
    diff_int = int.from_bytes(bytes(a ^ b for a, b in zip(known, G0)), "big")
    H_inv = gf128_inv(H)
    H_inv_pow = 1
    for _ in range(N - 1):
        H_inv_pow = gf128_mul(H_inv_pow, H_inv)
    SECRET_VICTIM = gf128_mul(diff_int, H_inv_pow).to_bytes(16, "big")
    print(f"[+] SECRET_VICTIM = {SECRET_VICTIM.hex()}")

    # 8. /verify
    r = post("/verify", {
        "who": "victim",
        "blob": base64.b64encode(flag_blob).decode(),
        "aad_hex": SECRET_VICTIM.hex()
    })
    print(f"[+] /verify response: {r}")
    if "plaintext_b64" in r:
        flag = base64.b64decode(r["plaintext_b64"]).decode()
        print(f"\n[***] FLAG: {flag}")
        return flag
    return None

if __name__ == "__main__":
    main()