(* LO-Auth: Key Possession Proof (Theorem 6) * * Protocol (§6): * Server → Client: c, where (c, ss) ← XWing.Encaps(pk_IK_client[XWing]) * Client → Server: proof = MAC(key=ss, data="lo-auth-v1") * Server: accept iff proof = token, where token = MAC(key=ss, data="lo-auth-v1") * * Security claims: * 1. Correspondence: ServerAccepts ==> ClientResponds (Theorem 6) * 2. Injective correspondence: each acceptance maps to a distinct client * response (single-use, matching Tamarin's Auth_Single_Use) * * Reduces to: X-Wing IND-CCA2 + HMAC-SHA3-256 SUF-CMA. * * Decaps oracle (§8.3 compositional note): In the Tamarin model, an explicit * DecapsOracle rule models the adversary's ability to submit arbitrary * ciphertexts and observe MAC(Decaps(sk_IK, c), "lo-auth-v1"). In CryptoVerif, * this is subsumed by the IND-CCA2 KEM assumption, which already provides the * adversary with a raw decapsulation oracle returning ss directly — strictly * more powerful than the MAC-wrapped output. The Nc parameter counts all * client-side decapsulation queries (both legitimate responses and adversarial * oracle use); the IND-CCA2 advantage bound P_kem(time, 1, Ns, Nc) accounts * for all such queries. *) (* Session counts *) param Ns. (* Server challenge sessions *) param Nc. (* Client response sessions (includes §8.3 Decaps oracle queries) *) (* ---------- Type declarations ---------- *) type kem_keyseed [large, fixed]. type kem_pkey [bounded]. type kem_skey [bounded]. type kem_secret [large, fixed]. type kem_ciphertext [bounded]. type kem_encapoutput [bounded]. type macres [fixed]. type label [fixed]. (* ---------- X-Wing KEM (IND-CCA2) ---------- *) proba P_kem. proba P_kem_keycoll. proba P_kem_ctxtcoll. expand IND_CCA2_KEM( kem_keyseed, kem_pkey, kem_skey, kem_secret, kem_ciphertext, kem_encapoutput, kem_pkgen, kem_skgen, kem_encap, kem_pair, kem_decap, injbot_kem, P_kem, P_kem_keycoll, P_kem_ctxtcoll ). (* ---------- HMAC-SHA3-256 as SUF-CMA deterministic MAC ---------- *) proba P_mac. expand SUF_CMA_det_mac(kem_secret, label, macres, mac_auth, mac_check, P_mac). const lo_auth_label: label. (* ---------- Events ---------- *) event ServerAccepts(kem_pkey, kem_ciphertext). event ClientResponds(kem_pkey, kem_ciphertext). (* ---------- Security queries ---------- *) (* Theorem 6 (Key Possession): If the server accepts for a challenge * ciphertext ct, then the client responded to that same ct. *) query pk: kem_pkey, ct: kem_ciphertext; event(ServerAccepts(pk, ct)) ==> event(ClientResponds(pk, ct)). (* Single-use (Tamarin: Auth_Single_Use): Each server acceptance maps to * a distinct client response — no replay of a single client response can * satisfy two server sessions. *) query pk: kem_pkey, ct: kem_ciphertext; inj-event(ServerAccepts(pk, ct)) ==> inj-event(ClientResponds(pk, ct)). (* ---------- Channels ---------- *) channel c_start, c_srv_start, c_srv_out, c_srv_recv, c_cli_in, c_cli_out, c_pub. (* ---------- Server process ---------- *) let Server(pk_client: kem_pkey) = foreach i_s <= Ns do in(c_srv_start, ()); let kem_pair(ss: kem_secret, ct: kem_ciphertext) = kem_encap(pk_client) in let token: macres = mac_auth(lo_auth_label, ss) in out(c_srv_out, ct); in(c_srv_recv, p: macres); if p = token then ( event ServerAccepts(pk_client, ct) ). (* ---------- Client process ---------- *) let Client(sk_client: kem_skey, pk_client: kem_pkey) = foreach i_c <= Nc do in(c_cli_in, ct: kem_ciphertext); let injbot_kem(ss: kem_secret) = kem_decap(ct, sk_client) in let tag: macres = mac_auth(lo_auth_label, ss) in event ClientResponds(pk_client, ct); out(c_cli_out, tag). (* ---------- Main process ---------- *) process in(c_start, ()); new kem_seed: kem_keyseed; let pk_client = kem_pkgen(kem_seed) in let sk_client = kem_skgen(kem_seed) in out(c_pub, pk_client); (Server(pk_client) | Client(sk_client, pk_client)) (* EXPECTED All queries proved. END *)