(* Showing the compromise of a fan-out session signing key results in a loss of deniability, in isolation from the peer-to-peer layer *) set simplifyProcess = false. set preciseActions = true. free c: channel. free a: channel. (* channel for the attacker *) free p: channel [private]. (* For the distribution of public keys with integrity and authenticity - verification happens out of band. This is a standard assumption. *) (* Symmetric key encryption *) type key. fun senc(key, bitstring): bitstring. reduc forall m: bitstring, k: key; sdec(k, senc(k,m)) = m. (* Asymmetric key encryption *) type skey. type pkey. fun rb(pkey): bitstring. fun pk(skey): pkey. (* Digital signatures *) fun sign(skey, bitstring): bitstring. fun okay():bitstring. reduc forall m: bitstring, sk: skey; checksign(pk(sk), m, sign(sk, m)) = okay. (* MACs *) fun mac(key, bitstring): bitstring. reduc forall k: key, m: bitstring; checkmac(k, m, mac(k, m)) = okay. (* Diffie-Hellman *) (* DH -> Public^Private *) fun dh(pkey, skey): key. equation forall a: skey, b: skey; dh(pk(a), b) = dh(pk(b), a). (* symmetry of DH *) (* the concat functions *) fun hkdf1(key, key, key): key [data]. fun khash(key): key. fun hkdf2_dev1(key): key. fun hkdf2_dev2(key): key. letfun hkdf2(k: key) = (hkdf2_dev1(k), hkdf2_dev2(k)). (* the concats *) fun concat1(pkey, key): bitstring [data]. fun concat2(bitstring, bitstring): bitstring [data]. (* events *) event sendE1(bitstring, key, pkey). event recvE1(bitstring, key, pkey). event compromiseSKA(skey). event compromiseSKB(skey). event start(). free k: key [private]. free m1: bitstring [private]. let PeerA() = new SK_A: skey; let PK_A = pk(SK_A) in new rk: key; new fib1: skey; let sk_A = choice [fib1, SK_A] in let x1 = senc(k, (pk(sk_A), rk)) in let x1_mac = mac(k, x1) in out(c, (x1, x1_mac)); phase 1; let mx1 = senc(rk, m1) in let mx1_mac = mac(rk, mx1) in let mx1_sig = sign(sk_A, concat2(mx1, mx1_mac)) in out(c, (mx1, mx1_mac, mx1_sig)); phase 2; phase 3; out(a, PK_A); 0. let PeerB() = new SK_B: skey; let PK_B = pk(SK_B) in phase 1; in(c, (x1: bitstring, x1_mac: bitstring)); if checkmac(k, x1, x1_mac) = okay then let (PK_A: pkey, rk: key) = sdec(k, x1) in phase 2; in(c, (mx1: bitstring, mx1_mac: bitstring, mx1_sig: bitstring)); (* in(c, (mx1: bitstring, mx1_mac: bitstring)); *) if checksign(PK_A, concat2(mx1, mx1_mac), mx1_sig) = okay then if checkmac(rk, mx1, mx1_mac) = okay then let m1 = sdec(rk, mx1) in event start(); phase 3; 0. (* query event(start()). (* reachable from all possible executions *) *) process (* out(a, PK_A); out(a, PK_B); *) new fib1: skey; (* let (kM_A: skey) = choice [fib1, SK_A] in *) (* let kM_A = (SK_A) in *) ( (!PeerA()) | (!PeerB()))