This commit is contained in:
2025-08-27 02:13:43 -04:00
commit 333cb4a69d
31 changed files with 4934 additions and 0 deletions

View File

@@ -0,0 +1,150 @@
(*
3DH INITIATOR DENY
Author: [redacted]
model assumption #1: same key is used for signing and encryption (i.e. X25519)
*)
free m1: bitstring [private].
set selFun = Nounifset.
(*
set simpEqAll = false.
set redundancyElim = best.
set redundantHypElim = true.
set simplifyProcess = true.
set stopTerm = false.
*)
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(bitstring, pkey): bitstring [data].
(* events *)
event sendE1(bitstring, key, pkey).
event recvE1(bitstring, key, pkey).
event compromiseSKA(skey).
event compromiseSKB(skey).
event start().
let PeerA(SK_A: skey, PK_A: pkey, PK_B: pkey) =
phase 1;
new ao: skey;
let gao = pk(ao) in
(* generate amaster and enc msg (PHASE 1) *)
(* in(c, gbo: pkey); *)
in(c, (gbo: pkey, gbo_sig: bitstring));
if checksign(PK_B, rb(gbo), gbo_sig) = okay then (
let amaster = hkdf1(dh(PK_B, SK_A), dh(gbo, SK_A), dh(PK_B, ao)) in
let (ra1: key, ca1: key) = hkdf2(amaster) in (* derive the root and chain key *)
let mak1 = khash(ca1) in
let (mak1_auth: key, mak1_enc: key) = hkdf2(mak1) in
let x1 = senc(mak1_enc, m1) in
let x1_mac = mac(mak1_auth, concat1(x1, gao)) in
event sendE1(m1, mak1, gao);
phase 2;
out(c, (x1, x1_mac, gao))
).
let PeerB(SK_B: skey, PK_B: pkey, PK_A: pkey) =
new bo: skey;
let gbo = pk(bo) in
let gbo_sig = sign(SK_B, rb(gbo)) in
out(c, (gbo, gbo_sig));
phase 1;
(* first stage: derive bmaster, verfiy a's msgs, decrypt prekey message, reply *)
in(c, (x1: bitstring, x1_mac: bitstring, gao: pkey));
let bmaster = hkdf1(dh(PK_A, SK_B), dh(PK_A, bo), dh(gao, SK_B)) in
let (rb1: key, cb1: key) = hkdf2(bmaster) in (* derive the root and chain key *)
let mbk1 = khash(cb1) in
let (mbk1_auth: key, mbk1_enc: key) = hkdf2(mbk1) in
if checkmac(mbk1_auth, concat1(x1, gao), x1_mac) = okay then
(
let m1 = sdec(mbk1_enc, x1) in
event recvE1(m1, mbk1, gao);
phase 2;
event compromiseSKB(SK_B);
out(c, SK_B)
).
process
new SK_A: skey; let PK_A = pk(SK_A) in
new SK_B: skey; let PK_B = pk(SK_B) in
out(a, PK_A);
out(a, PK_B);
new fib1: skey;
new fib2: skey;
let k_A = choice [ SK_A, fib1 ] in
let k_B = choice [ SK_B, fib2 ] in
event start();
( (PeerA(k_A, pk(k_A), PK_B)) |
(PeerB(SK_B, PK_B, PK_A)) |
out(a, m1)) (* transcript publish *)

View File

@@ -0,0 +1,167 @@
(*
3DH MUTUAL DENIABILITY
Author: [redacted]
model assumption #1: same key is used for signing and encryption (i.e. X25519)
*)
free m1: bitstring [private].
set selFun = Nounifset.
set simplifyProcess = false.
(*
set simpEqAll = false.
set redundancyElim = best.
set redundantHypElim = true.
set simplifyProcess = true.
set stopTerm = false.
*)
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(bitstring, pkey): bitstring [data].
(* events *)
event sendE1(bitstring, key, pkey).
event recvE1(bitstring, key, pkey).
event compromiseSKA(skey).
event compromiseSKB(skey).
event start().
let PeerA(SK_A: skey, PK_A: pkey, PK_B: pkey) =
phase 1;
new ao: skey;
let gao = pk(ao) in
(* generate amaster and enc msg (PHASE 1) *)
(* in(c, gbo: pkey); *)
in(c, (gbo: pkey, gbo_sig: bitstring));
if checksign(PK_B, rb(gbo), gbo_sig) = okay then (
let amaster = hkdf1(dh(PK_B, SK_A), dh(gbo, SK_A), dh(PK_B, ao)) in
let (ra1: key, ca1: key) = hkdf2(amaster) in (* derive the root and chain key *)
let mak1 = khash(ca1) in
let (mak1_auth: key, mak1_enc: key) = hkdf2(mak1) in
let x1 = senc(mak1_enc, m1) in
let x1_mac = mac(mak1_auth, concat1(x1, gao)) in
event sendE1(m1, mak1, gao);
phase 2;
out(c, (x1, x1_mac, gao))
).
let PeerB(SK_B: skey, PK_B: pkey, PK_A: pkey) =
new bo: skey;
let gbo = pk(bo) in
let gbo_sig = sign(SK_B, rb(gbo)) in
out(c, (gbo, gbo_sig));
phase 1;
(* first stage: derive bmaster, verfiy a's msgs, decrypt prekey message, reply *)
in(c, (x1: bitstring, x1_mac: bitstring, gao: pkey));
let bmaster = hkdf1(dh(PK_A, SK_B), dh(PK_A, bo), dh(gao, SK_B)) in
let (rb1: key, cb1: key) = hkdf2(bmaster) in (* derive the root and chain key *)
let mbk1 = khash(cb1) in
let (mbk1_auth: key, mbk1_enc: key) = hkdf2(mbk1) in
if checkmac(mbk1_auth, concat1(x1, gao), x1_mac) = okay then
(
let m1 = sdec(mbk1_enc, x1) in
event recvE1(m1, mbk1, gao);
phase 2;
event compromiseSKB(SK_B);
out(c, SK_B)
).
(*
query event(start()). (* reachable from all possible executions *)
(* auth *)
query m: bitstring, rk: key, k1: pkey; inj-event(recvE1(m, rk, k1)) ==> inj-event(sendE1(m, rk, k1)).
(* secrecy *)
query attacker(m1).
(* reachability *)
query m: bitstring, rk: key, k1: pkey; event(recvE1(m, rk, k1)). (* reachable from all executions *)
query m: bitstring, rk: key, k1: pkey; event(sendE1(m, rk, k1)). (* reachable from all executions *)
*)
process
new SK_A: skey; let PK_A = pk(SK_A) in
new SK_B: skey; let PK_B = pk(SK_B) in
out(a, PK_A);
out(a, PK_B);
new fib1: skey;
new fib2: skey;
let k_A = choice [ SK_A, fib1 ] in
let k_B = choice [ SK_B, fib2 ] in
event start();
( (PeerA(SK_B, PK_A, pk(k_B))) |
(PeerB(k_B, pk(k_B), PK_A)) |
out(a, m1))

View File

@@ -0,0 +1,135 @@
(*
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()))

View File

@@ -0,0 +1,232 @@
(*
Olm + Megolm initiator deniability
Author: [redacted]
*)
free m1: bitstring [private].
free m2: bitstring [private].
set attacker = passive.
set simpEqAll = false.
set selFun = Nounifset.
set redundancyElim = best.
set redundantHypElim = true.
set simplifyProcess = false.
set stopTerm = false.
(*
set redundancyElim = best.
set simpEqAll = false.
set redundantHypElim = true.
set simplifyProcess = true.
set stopTerm = false.
*)
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.
fun aenc(bitstring, pkey): bitstring.
reduc forall m: bitstring, sk: skey; adec(aenc(m,pk(sk)),sk) = m.
(* 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): bitstring.
equation forall a: skey, b: skey; dh(pk(a), b) = dh(pk(b), a). (* symmetry of DH *)
(* the concat functions *)
fun khash(key): key.
fun hkdf(bitstring): key [data].
fun concat0(key): bitstring [data, typeConverter].
fun concat1(bitstring, pkey, pkey): bitstring [data].
reduc forall m1: bitstring, k1: pkey, k2: pkey; split1(concat1(m1, k1, k2)) = (m1, k1, k2).
fun concat2(bitstring, pkey): bitstring [data].
reduc forall m1: bitstring, k1: pkey; split2(concat2(m1, k1)) = (m1, k1).
fun concat3(bitstring, bitstring): bitstring [data].
reduc forall m1: bitstring, m2: bitstring; split3(concat3(m1, m2)) = (m1, m2).
fun concat4(bitstring, bitstring, bitstring): bitstring [data].
reduc forall m1: bitstring, m2: bitstring, m3:bitstring; split4(concat4(m1, m2, m3)) = (m1, m2, m3).
equation forall k: key, a: skey, b: skey; hkdf(concat3(concat0(khash(k)), dh(pk(a), b))) = hkdf(concat3(concat0(khash(k)), dh(pk(b), a))).
(* the concats *)
(* events *)
event sendOE1(pkey, key, pkey, pkey).
event recvOE1(pkey, key, pkey, pkey).
event sendOE2(pkey, key, pkey, pkey).
event recvOE2(pkey, key, pkey, pkey).
event sendME1(bitstring, key, pkey).
event recvME1(bitstring, key, pkey).
event sendME2(bitstring, key, pkey).
event recvME2(bitstring, key, pkey).
event compromiseOSKA(skey).
event compromiseOSKB(skey).
event start().
free tag_oe1: bitstring [private].
free tag_oe2: bitstring [private].
free tag_me1: bitstring [private].
free tag_me2: bitstring [private].
free tag_b_eph: bitstring [private].
let PeerA(OSK_A: skey, OPK_A: pkey, OPK_B: pkey, OLM_KEYS_STR:bitstring, OLM_ROOT_STR: bitstring, MSK_A: skey, MPK_A: pkey) =
phase 1;
new ao: skey;
let gao = pk(ao) in
(* generate amaster and enc msg (PHASE 1) *)
(* in(c, gbo: pkey); *)
in(c, (gbo: pkey, gbo_sig: bitstring));
if checksign(OPK_B, rb(gbo), gbo_sig) = okay then (
(* =================== PHASE 2: DERIVE OLM MASTER + MEGOLM SESSION A -> B =================== *)
let amaster = hkdf(concat4(dh(OPK_B, OSK_A), dh(gbo, OSK_A), dh(OPK_B, ao))) in
let ra1 = hkdf(concat0(amaster)) in
let ca1 = hkdf(concat0(amaster)) in
new ta1: skey;
let gta1 = pk(ta1) in
let ak1 = khash(ca1) in
let ak1_auth = hkdf(concat0(ak1)) in
let ak1_enc = hkdf(concat0(ak1)) in
new mra0: key; (* mra0 := megolm ratchet *)
let x1 = senc(ak1_enc, (MPK_A, mra0)) in
let x1_mac = mac(ak1_auth, concat1(x1, gao, gta1)) in
event sendOE1(MPK_A, mra0, gao, gta1);
out(c, (x1, x1_mac, gao, gta1));
(* =================== PHASE 4: MEGOLM MSG A -> B =================== *)
let mra1 = khash(mra0) in
let mak1_auth = hkdf(concat0(mra1)) in
let mak1_enc = hkdf(concat0(mra1)) in
let mx1 = senc(mak1_enc, m1) in
let mx1_mac = mac(mak1_auth, mx1) in
let mx1_sig = sign(MSK_A, concat3(mx1, mx1_mac)) in
event sendME1(m1, mra1, MPK_A);
out(c, (mx1, mx1_mac, mx1_sig));
phase 3 (* =================== PHASE 6: PCS =================== *)
).
let PeerB(OSK_B: skey, OPK_B: pkey, OPK_A: pkey, OLM_KEYS_STR:bitstring, OLM_ROOT_STR: bitstring, MSK_B: skey, MPK_B: pkey) =
new bo: skey;
let gbo = pk(bo) in
let gbo_sig = sign(OSK_B, rb(gbo)) in
out(c, (gbo, gbo_sig));
phase 1;
(* =================== PHASE 2: DERIVE OLM MASTER + MEGOLM SESSION A -> B =================== *)
(* first stage: derive bmaster, verfiy a's msgs, decrypt prekey message, reply *)
in(c, (x1: bitstring, x1_mac: bitstring, gao: pkey, gta1: pkey));
let bmaster = hkdf(concat4(dh(OPK_A, OSK_B), dh(OPK_A, bo), dh(gao, OSK_B))) in
let rb1 = hkdf(concat0(bmaster)) in
let cb1 = hkdf(concat0(bmaster)) in
let bk1 = khash(cb1) in
let bk1_auth = hkdf(concat0(bk1)) in
let bk1_enc = hkdf(concat0(bk1)) in
if checkmac(bk1_auth, concat1(x1, gao, gta1), x1_mac) = okay then
(
let (MPK_A: pkey, mra0: key) = sdec(bk1_enc, x1) in
event recvOE1(MPK_A, mra0, gao, gta1);
(* =================== PHASE 4: MEGOLM MSG A -> B =================== *)
in(c, (mx1: bitstring, mx1_mac: bitstring, mx1_sig: bitstring));
let mra1 = khash(mra0) in
let mak1_auth = hkdf(concat0(mra1)) in
let mak1_enc = hkdf(concat0(mra1)) in
if checksign(MPK_A, concat3(mx1, mx1_mac), mx1_sig) = okay then (
if checkmac(mak1_auth, mx1, mx1_mac) = okay then (
let m1 = sdec(mak1_enc, mx1) in
event recvME1(m1, mra1, MPK_A);
(* =================== PHASE 6: PCS =================== *)
phase 3;
event compromiseOSKB(OSK_B);
out(c, OSK_B)
))).
process
new OLM_KEYS_STR:bitstring; out(a, OLM_KEYS_STR);
new OLM_ROOT_STR:bitstring; out(a, OLM_ROOT_STR);
new OSK_A: skey; let OPK_A = pk(OSK_A) in
new OSK_B: skey; let OPK_B = pk(OSK_B) in
new MSK_A: skey; let MPK_A = pk(MSK_A) in
new MSK_B: skey; let MPK_B = pk(MSK_B) in
out(a, OPK_A);
out(a, OPK_B);
(*
out(a, MPK_A);
out(a, MPK_B);
*)
new fib1: skey;
new fib2: skey;
new fib3: skey;
new fib4: skey;
let (kO_A: skey, kM_A: skey) = choice [(OSK_A, MSK_A), (fib1, fib2) ] in
let (kO_B: skey, kM_B: skey) = choice [(OSK_B, MSK_B), (fib1, fib2) ] in
( (!PeerA(kO_A, pk(kO_A), OPK_B, OLM_KEYS_STR, OLM_ROOT_STR, kM_A, pk(kM_A))) |
(!PeerB(OSK_B, OPK_B, OPK_A, OLM_KEYS_STR, OLM_ROOT_STR, MSK_B, MPK_B)))

View File

@@ -0,0 +1,232 @@
(*
Olm + Megolm responder deniability
Author: [redacted]
*)
free m1: bitstring [private].
free m2: bitstring [private].
set attacker = active.
set simpEqAll = false.
set selFun = Nounifset.
set redundancyElim = best.
set redundantHypElim = true.
set simplifyProcess = false.
set stopTerm = false.
(*
set redundancyElim = best.
set simpEqAll = false.
set redundantHypElim = true.
set simplifyProcess = true.
set stopTerm = false.
*)
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.
fun aenc(bitstring, pkey): bitstring.
reduc forall m: bitstring, sk: skey; adec(aenc(m,pk(sk)),sk) = m.
(* 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): bitstring.
equation forall a: skey, b: skey; dh(pk(a), b) = dh(pk(b), a). (* symmetry of DH *)
(* the concat functions *)
fun khash(key): key.
fun hkdf(bitstring): key [data].
fun concat0(key): bitstring [data, typeConverter].
fun concat1(bitstring, pkey, pkey): bitstring [data].
reduc forall m1: bitstring, k1: pkey, k2: pkey; split1(concat1(m1, k1, k2)) = (m1, k1, k2).
fun concat2(bitstring, pkey): bitstring [data].
reduc forall m1: bitstring, k1: pkey; split2(concat2(m1, k1)) = (m1, k1).
fun concat3(bitstring, bitstring): bitstring [data].
reduc forall m1: bitstring, m2: bitstring; split3(concat3(m1, m2)) = (m1, m2).
fun concat4(bitstring, bitstring, bitstring): bitstring [data].
reduc forall m1: bitstring, m2: bitstring, m3:bitstring; split4(concat4(m1, m2, m3)) = (m1, m2, m3).
equation forall k: key, a: skey, b: skey; hkdf(concat3(concat0(khash(k)), dh(pk(a), b))) = hkdf(concat3(concat0(khash(k)), dh(pk(b), a))).
(* the concats *)
(* events *)
event sendOE1(pkey, key, pkey, pkey).
event recvOE1(pkey, key, pkey, pkey).
event sendOE2(pkey, key, pkey, pkey).
event recvOE2(pkey, key, pkey, pkey).
event sendME1(bitstring, key, pkey).
event recvME1(bitstring, key, pkey).
event sendME2(bitstring, key, pkey).
event recvME2(bitstring, key, pkey).
event compromiseOSKA(skey).
event compromiseOSKB(skey).
event start().
free tag_oe1: bitstring [private].
free tag_oe2: bitstring [private].
free tag_me1: bitstring [private].
free tag_me2: bitstring [private].
free tag_b_eph: bitstring [private].
let PeerA(OSK_A: skey, OPK_A: pkey, OPK_B: pkey, OLM_KEYS_STR:bitstring, OLM_ROOT_STR: bitstring, MSK_A: skey, MPK_A: pkey) =
phase 1;
new ao: skey;
let gao = pk(ao) in
(* generate amaster and enc msg (PHASE 1) *)
(* in(c, gbo: pkey); *)
in(c, (gbo: pkey, gbo_sig: bitstring));
if checksign(OPK_B, rb(gbo), gbo_sig) = okay then (
(* =================== PHASE 2: DERIVE OLM MASTER + MEGOLM SESSION A -> B =================== *)
let amaster = hkdf(concat4(dh(OPK_B, OSK_A), dh(gbo, OSK_A), dh(OPK_B, ao))) in
let ra1 = hkdf(concat0(amaster)) in
let ca1 = hkdf(concat0(amaster)) in
new ta1: skey;
let gta1 = pk(ta1) in
let ak1 = khash(ca1) in
let ak1_auth = hkdf(concat0(ak1)) in
let ak1_enc = hkdf(concat0(ak1)) in
new mra0: key; (* mra0 := megolm ratchet *)
let x1 = senc(ak1_enc, (MPK_A, mra0)) in
let x1_mac = mac(ak1_auth, concat1(x1, gao, gta1)) in
event sendOE1(MPK_A, mra0, gao, gta1);
out(c, (x1, x1_mac, gao, gta1));
(* =================== PHASE 4: MEGOLM MSG A -> B =================== *)
let mra1 = khash(mra0) in
let mak1_auth = hkdf(concat0(mra1)) in
let mak1_enc = hkdf(concat0(mra1)) in
let mx1 = senc(mak1_enc, m1) in
let mx1_mac = mac(mak1_auth, mx1) in
let mx1_sig = sign(MSK_A, concat3(mx1, mx1_mac)) in
event sendME1(m1, mra1, MPK_A);
out(c, (mx1, mx1_mac, mx1_sig));
phase 3 (* =================== PHASE 6: PCS =================== *)
).
let PeerB(OSK_B: skey, OPK_B: pkey, OPK_A: pkey, OLM_KEYS_STR:bitstring, OLM_ROOT_STR: bitstring, MSK_B: skey, MPK_B: pkey) =
new bo: skey;
let gbo = pk(bo) in
let gbo_sig = sign(OSK_B, rb(gbo)) in
out(c, (gbo, gbo_sig));
phase 1;
(* =================== PHASE 2: DERIVE OLM MASTER + MEGOLM SESSION A -> B =================== *)
(* first stage: derive bmaster, verfiy a's msgs, decrypt prekey message, reply *)
in(c, (x1: bitstring, x1_mac: bitstring, gao: pkey, gta1: pkey));
let bmaster = hkdf(concat4(dh(OPK_A, OSK_B), dh(OPK_A, bo), dh(gao, OSK_B))) in
let rb1 = hkdf(concat0(bmaster)) in
let cb1 = hkdf(concat0(bmaster)) in
let bk1 = khash(cb1) in
let bk1_auth = hkdf(concat0(bk1)) in
let bk1_enc = hkdf(concat0(bk1)) in
if checkmac(bk1_auth, concat1(x1, gao, gta1), x1_mac) = okay then
(
let (MPK_A: pkey, mra0: key) = sdec(bk1_enc, x1) in
event recvOE1(MPK_A, mra0, gao, gta1);
(* =================== PHASE 4: MEGOLM MSG A -> B =================== *)
in(c, (mx1: bitstring, mx1_mac: bitstring, mx1_sig: bitstring));
let mra1 = khash(mra0) in
let mak1_auth = hkdf(concat0(mra1)) in
let mak1_enc = hkdf(concat0(mra1)) in
if checksign(MPK_A, concat3(mx1, mx1_mac), mx1_sig) = okay then (
if checkmac(mak1_auth, mx1, mx1_mac) = okay then (
let m1 = sdec(mak1_enc, mx1) in
event recvME1(m1, mra1, MPK_A);
(* =================== PHASE 6: PCS =================== *)
phase 3;
event compromiseOSKB(OSK_B);
out(c, OSK_B)
))).
process
new OLM_KEYS_STR:bitstring; out(a, OLM_KEYS_STR);
new OLM_ROOT_STR:bitstring; out(a, OLM_ROOT_STR);
new OSK_A: skey; let OPK_A = pk(OSK_A) in
new OSK_B: skey; let OPK_B = pk(OSK_B) in
new MSK_A: skey; let MPK_A = pk(MSK_A) in
new MSK_B: skey; let MPK_B = pk(MSK_B) in
out(a, OPK_A);
out(a, OPK_B);
(*
out(a, MPK_A);
out(a, MPK_B);
*)
new fib1: skey;
new fib2: skey;
new fib3: skey;
new fib4: skey;
let (kO_A: skey, kM_A: skey) = choice [(OSK_A, MSK_A), (fib1, fib2) ] in
let (kO_B: skey, kM_B: skey) = choice [(OSK_B, MSK_B), (fib1, fib2) ] in
( (!PeerA(OSK_A, OPK_A, OPK_B, OLM_KEYS_STR, OLM_ROOT_STR, MSK_A, MPK_A)) |
(!PeerB(kO_B, pk(kO_B), OPK_A, OLM_KEYS_STR, OLM_ROOT_STR, kM_A, pk(kM_A))))

View File

@@ -0,0 +1,203 @@
(*
Olm 3DH+Double Ratchet; initiator deniability
Author: [redacted]
model assumption #1: same key is used for signing and encryption (i.e. X25519)
*)
free m1: bitstring [private].
free m2: bitstring [private].
set attacker = passive.
set simpEqAll = false.
set selFun = Nounifset.
set redundancyElim = best.
set redundantHypElim = true.
set simplifyProcess = false.
set stopTerm = false.
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.
fun aenc(bitstring, pkey): bitstring.
reduc forall m: bitstring, sk: skey; adec(aenc(m,pk(sk)),sk) = m.
(* 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)).
fun hkdf3_dev1(key, bitstring): key.
fun hkdf3_dev2(key, bitstring): key.
letfun hkdf3(k: key, b: bitstring) =
(hkdf3_dev1(k, b), hkdf3_dev2(k, b)).
fun hkdf4_dev1(key, key): key.
fun hkdf4_dev2(key, key): key.
letfun hkdf4(k1: key, k2: key) =
(hkdf4_dev1(k1, k2), hkdf4_dev2(k1, k2)).
(* the concats *)
fun concat1(bitstring, pkey, pkey): bitstring [data].
fun concat2(bitstring, pkey): bitstring [data].
(* events *)
event sendE1(bitstring, key, pkey, pkey).
event recvE1(bitstring, key, pkey, pkey).
event sendE2(bitstring, key, pkey, pkey).
event recvE2(bitstring, key, pkey, pkey).
event compromiseSKA(skey).
event compromiseSKB(skey).
event start().
free tag_oe1: bitstring [private].
free tag_oe2: bitstring [private].
free tag_me1: bitstring [private].
free tag_me2: bitstring [private].
free tag_b_eph: bitstring [private].
let PeerA(SK_A: skey, PK_A: pkey, PK_B: pkey, OLM_KEYS_STR:bitstring, OLM_ROOT_STR: bitstring) =
phase 1;
new ao: skey;
let gao = pk(ao) in
(* generate amaster and enc msg (PHASE 1) *)
(* in(c, gbo: pkey); *)
in(c, (gbo: pkey, gbo_sig: bitstring));
if checksign(PK_B, rb(gbo), gbo_sig) = okay then (
let amaster = hkdf1(dh(PK_B, SK_A), dh(gbo, SK_A), dh(PK_B, ao)) in
let (ra1: key, ca1: key) = hkdf3(amaster, OLM_ROOT_STR) in (* derive the root and chain key *)
new ta1: skey;
let gta1 = pk(ta1) in
let mak1 = khash(ca1) in
let (mak1_auth: key, mak1_enc: key) = hkdf2(mak1) in
let x1 = senc(mak1_enc, m1) in
let x1_mac = mac(mak1_auth, concat1(x1, gao, gta1)) in
event sendE1(m1, mak1, gao, gta1);
out(c, (x1, x1_mac, gao, gta1));
(* second stage: now, decrypt the received message from bob *)
in(c, (x2: bitstring, x2_mac: bitstring, gtb2: pkey));
let (ra2: key, ca2: key) = hkdf4(ra1, dh(gtb2, ta1)) in
let mak2 = khash(ca2) in
let (mak2_auth: key, mak2_enc: key) = hkdf2(mak2) in
if checkmac(mak2_auth, concat2(x2, gtb2), x2_mac) = okay then
(
let m2 = sdec(mak2_enc, x2) in
event recvE2(m2, mak2, gta1, gtb2);
phase 2;
event compromiseSKA(SK_A);
out(c, SK_A)
)).
let PeerB(SK_B: skey, PK_B: pkey, PK_A: pkey, OLM_KEYS_STR:bitstring, OLM_ROOT_STR: bitstring) =
new bo: skey;
let gbo = pk(bo) in
let gbo_sig = sign(SK_B, rb(gbo)) in
out(c, (gbo, gbo_sig));
phase 1;
(* first stage: derive bmaster, verfiy a's msgs, decrypt prekey message, reply *)
in(c, (x1: bitstring, x1_mac: bitstring, gao: pkey, gta1: pkey));
let bmaster = hkdf1(dh(PK_A, SK_B), dh(PK_A, bo), dh(gao, SK_B)) in
let (rb1: key, cb1: key) = hkdf3(bmaster, OLM_ROOT_STR) in (* derive the root and chain key *)
let mbk1 = khash(cb1) in
let (mbk1_auth: key, mbk1_enc: key) = hkdf2(mbk1) in
if checkmac(mbk1_auth, concat1(x1, gao, gta1), x1_mac) = okay then
(
let m1 = sdec(mbk1_enc, x1) in
event recvE1(m1, mbk1, gao, gta1);
new tb2: skey;
let gtb2 = pk(tb2) in
let (rb2: key, cb2: key) = hkdf4(rb1, dh(gta1, tb2)) in
let mbk2 = khash(cb2) in
let (mbk2_auth: key, mbk2_enc: key) = hkdf2(mbk2) in
let x2 = senc(mbk2_enc, m2) in
let x2_mac = mac(mbk2_auth, concat2(x2, gtb2)) in
event sendE2(m2, mbk2, gta1, gtb2);
out(c, (x2, x2_mac, gtb2));
phase 2;
event compromiseSKB(SK_B);
out(c, SK_B)
).
process
new OLM_KEYS_STR:bitstring; out(a, OLM_KEYS_STR);
new OLM_ROOT_STR:bitstring; out(a, OLM_ROOT_STR);
new SK_A: skey; let PK_A = pk(SK_A) in
new SK_B: skey; let PK_B = pk(SK_B) in
out(a, PK_A);
out(a, PK_B);
new fib1: skey;
new fib2: skey;
let k_A = choice [ SK_A, fib1 ] in
let k_B = choice [ SK_B, fib2 ] in
event start();
( (PeerA(k_A, pk(k_A), PK_B, OLM_KEYS_STR, OLM_ROOT_STR)) |
(PeerB(SK_B, PK_B, PK_A, OLM_KEYS_STR, OLM_ROOT_STR)) |
out(a, (m1, m2))) (* transcript publish *)

View File

@@ -0,0 +1,204 @@
(*
Olm 3DH+Double Ratchet; responder deniability
Author: [redacted]
model assumption #1: same key is used for signing and encryption (i.e. X25519)
*)
free m1: bitstring [private].
free m2: bitstring [private].
set attacker = passive.
set simpEqAll = false.
set selFun = Nounifset.
set redundancyElim = best.
set redundantHypElim = true.
set simplifyProcess = false.
set stopTerm = false.
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.
fun aenc(bitstring, pkey): bitstring.
reduc forall m: bitstring, sk: skey; adec(aenc(m,pk(sk)),sk) = m.
(* 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)).
fun hkdf3_dev1(key, bitstring): key.
fun hkdf3_dev2(key, bitstring): key.
letfun hkdf3(k: key, b: bitstring) =
(hkdf3_dev1(k, b), hkdf3_dev2(k, b)).
fun hkdf4_dev1(key, key): key.
fun hkdf4_dev2(key, key): key.
letfun hkdf4(k1: key, k2: key) =
(hkdf4_dev1(k1, k2), hkdf4_dev2(k1, k2)).
(* the concats *)
fun concat1(bitstring, pkey, pkey): bitstring [data].
fun concat2(bitstring, pkey): bitstring [data].
(* events *)
event sendE1(bitstring, key, pkey, pkey).
event recvE1(bitstring, key, pkey, pkey).
event sendE2(bitstring, key, pkey, pkey).
event recvE2(bitstring, key, pkey, pkey).
event compromiseSKA(skey).
event compromiseSKB(skey).
event start().
free tag_oe1: bitstring [private].
free tag_oe2: bitstring [private].
free tag_me1: bitstring [private].
free tag_me2: bitstring [private].
free tag_b_eph: bitstring [private].
let PeerA(SK_A: skey, PK_A: pkey, PK_B: pkey, OLM_KEYS_STR:bitstring, OLM_ROOT_STR: bitstring) =
phase 1;
new ao: skey;
let gao = pk(ao) in
(* generate amaster and enc msg (PHASE 1) *)
(* in(c, gbo: pkey); *)
in(c, (gbo: pkey, gbo_sig: bitstring));
if checksign(PK_B, rb(gbo), gbo_sig) = okay then (
let amaster = hkdf1(dh(PK_B, SK_A), dh(gbo, SK_A), dh(PK_B, ao)) in
let (ra1: key, ca1: key) = hkdf3(amaster, OLM_ROOT_STR) in (* derive the root and chain key *)
new ta1: skey;
let gta1 = pk(ta1) in
let mak1 = khash(ca1) in
let (mak1_auth: key, mak1_enc: key) = hkdf2(mak1) in
let x1 = senc(mak1_enc, m1) in
let x1_mac = mac(mak1_auth, concat1(x1, gao, gta1)) in
event sendE1(m1, mak1, gao, gta1);
out(c, (x1, x1_mac, gao, gta1));
(* second stage: now, decrypt the received message from bob *)
in(c, (x2: bitstring, x2_mac: bitstring, gtb2: pkey));
let (ra2: key, ca2: key) = hkdf4(ra1, dh(gtb2, ta1)) in
let mak2 = khash(ca2) in
let (mak2_auth: key, mak2_enc: key) = hkdf2(mak2) in
if checkmac(mak2_auth, concat2(x2, gtb2), x2_mac) = okay then
(
let m2 = sdec(mak2_enc, x2) in
event recvE2(m2, mak2, gta1, gtb2);
phase 2;
event compromiseSKA(SK_A);
out(c, SK_A)
)).
let PeerB(SK_B: skey, PK_B: pkey, PK_A: pkey, OLM_KEYS_STR:bitstring, OLM_ROOT_STR: bitstring) =
new bo: skey;
let gbo = pk(bo) in
let gbo_sig = sign(SK_B, rb(gbo)) in
out(c, (gbo, gbo_sig));
phase 1;
(* first stage: derive bmaster, verfiy a's msgs, decrypt prekey message, reply *)
in(c, (x1: bitstring, x1_mac: bitstring, gao: pkey, gta1: pkey));
let bmaster = hkdf1(dh(PK_A, SK_B), dh(PK_A, bo), dh(gao, SK_B)) in
let (rb1: key, cb1: key) = hkdf3(bmaster, OLM_ROOT_STR) in (* derive the root and chain key *)
let mbk1 = khash(cb1) in
let (mbk1_auth: key, mbk1_enc: key) = hkdf2(mbk1) in
if checkmac(mbk1_auth, concat1(x1, gao, gta1), x1_mac) = okay then
(
let m1 = sdec(mbk1_enc, x1) in
event recvE1(m1, mbk1, gao, gta1);
new tb2: skey;
let gtb2 = pk(tb2) in
let (rb2: key, cb2: key) = hkdf4(rb1, dh(gta1, tb2)) in
let mbk2 = khash(cb2) in
let (mbk2_auth: key, mbk2_enc: key) = hkdf2(mbk2) in
let x2 = senc(mbk2_enc, m2) in
let x2_mac = mac(mbk2_auth, concat2(x2, gtb2)) in
event sendE2(m2, mbk2, gta1, gtb2);
out(c, (x2, x2_mac, gtb2));
phase 2;
event compromiseSKB(SK_B);
out(c, SK_B)
).
process
new OLM_KEYS_STR:bitstring; out(a, OLM_KEYS_STR);
new OLM_ROOT_STR:bitstring; out(a, OLM_ROOT_STR);
new SK_A: skey; let PK_A = pk(SK_A) in
new SK_B: skey; let PK_B = pk(SK_B) in
out(a, PK_A);
out(a, PK_B);
new fib1: skey;
new fib2: skey;
let k_A = choice [ SK_A, fib1 ] in
let k_B = choice [ SK_B, fib2 ] in
event start();
event start();
( (PeerA(SK_B, PK_A, PK_B, OLM_KEYS_STR, OLM_ROOT_STR)) |
(PeerB(k_B, pk(k_B), PK_A, OLM_KEYS_STR, OLM_ROOT_STR)) |
out(a, (m1, m2))) (* transcript publish *)

View File

@@ -0,0 +1,281 @@
(*
Sender Keys protocol; proving secrecy, authentication, PCS, and PFS
Author: [redacted]
*)
free m1: bitstring [private].
free m2: bitstring [private].
set selFun = Nounifset.
set redundancyElim = best.
set simpEqAll = false.
set redundantHypElim = true.
set simplifyProcess = true.
set stopTerm = false.
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.
fun aenc(bitstring, pkey): bitstring.
reduc forall m: bitstring, sk: skey; adec(aenc(m,pk(sk)),sk) = m.
(* 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): bitstring.
equation forall a: skey, b: skey; dh(pk(a), b) = dh(pk(b), a). (* symmetry of DH *)
(* the concat functions *)
fun khash(key): key.
fun hkdf(bitstring): key [data].
fun concat0(key): bitstring [data, typeConverter].
fun concat1(bitstring, pkey, pkey): bitstring [data].
reduc forall m1: bitstring, k1: pkey, k2: pkey; split1(concat1(m1, k1, k2)) = (m1, k1, k2).
fun concat2(bitstring, pkey): bitstring [data].
reduc forall m1: bitstring, k1: pkey; split2(concat2(m1, k1)) = (m1, k1).
fun concat3(bitstring, bitstring): bitstring [data].
reduc forall m1: bitstring, m2: bitstring; split3(concat3(m1, m2)) = (m1, m2).
fun concat4(bitstring, bitstring, bitstring): bitstring [data].
reduc forall m1: bitstring, m2: bitstring, m3:bitstring; split4(concat4(m1, m2, m3)) = (m1, m2, m3).
equation forall k: key, a: skey, b: skey; hkdf(concat3(concat0(khash(k)), dh(pk(a), b))) = hkdf(concat3(concat0(khash(k)), dh(pk(b), a))).
(* the concats *)
(* events *)
event sendOE1(pkey, key, pkey, pkey).
event recvOE1(pkey, key, pkey, pkey).
event sendOE2(pkey, key, pkey, pkey).
event recvOE2(pkey, key, pkey, pkey).
event sendME1(bitstring, key, pkey).
event recvME1(bitstring, key, pkey).
event sendME2(bitstring, key, pkey).
event recvME2(bitstring, key, pkey).
event compromiseOSKA(skey).
event compromiseOSKB(skey).
event start().
free tag_oe1: bitstring [private].
free tag_oe2: bitstring [private].
free tag_me1: bitstring [private].
free tag_me2: bitstring [private].
free tag_b_eph: bitstring [private].
let PeerA(OSK_A: skey, OPK_A: pkey, OPK_B: pkey, MSK_A: skey, MPK_A: pkey) =
phase 1;
new ao: skey;
let gao = pk(ao) in
(* generate amaster and enc msg (PHASE 1) *)
(* in(c, gbo: pkey); *)
in(c, (gbo: pkey, gbo_sig: bitstring));
if checksign(OPK_B, rb(gbo), gbo_sig) = okay then
(* =================== PHASE 2: DERIVE P2P MASTER + SENDER KEYS SESSION A -> B =================== *)
let amaster = hkdf(concat4(dh(OPK_B, OSK_A), dh(gbo, OSK_A), dh(OPK_B, ao))) in
let ra1 = hkdf(concat0(amaster)) in
let ca1 = hkdf(concat0(amaster)) in
new ta1: skey;
let gta1 = pk(ta1) in
let ak1 = khash(ca1) in
let ak1_auth = hkdf(concat0(ak1)) in
let ak1_enc = hkdf(concat0(ak1)) in
new mra0: key; (* mra0 := megolm ratchet *)
let x1 = senc(ak1_enc, (MPK_A, mra0)) in
let x1_mac = mac(ak1_auth, concat1(x1, gao, gta1)) in
event sendOE1(MPK_A, mra0, gao, gta1);
out(c, (x1, x1_mac, gao, gta1));
(* =================== PHASE 3: SENDER KEYS SESSION B -> A =================== *)
(* second stage: now, decrypt the received message from bob *)
in(c, (x2: bitstring, x2_mac: bitstring, gtb2: pkey));
let ca2 = hkdf(concat3(concat0(khash(ra1)), dh(gtb2, ta1))) in
let ak2 = khash(ca2) in
let ak2_auth = hkdf(concat0(ak2)) in
if checkmac(ak2_auth, concat2(x2, gtb2), x2_mac) = okay then (
let mak2_enc = hkdf(concat0(ak2)) in
let (MPK_B: pkey, mrb0: key) = sdec(mak2_enc, x2) in
event recvOE2(MPK_B, mrb0, gao, gta1);
(* =================== PHASE 4: SENDER KEYS MSG A -> B =================== *)
let mra1 = khash(mra0) in
let mak1_auth = hkdf(concat0(mra1)) in
let mak1_enc = hkdf(concat0(mra1)) in
let mx1 = senc(mak1_enc, m1) in
let mx1_sig = sign(MSK_A, mx1) in
event sendME1(m1, mra1, MPK_A);
out(c, (mx1, mx1_sig));
(* =================== PHASE 5: SENDER KEYS MSG B -> A =================== *)
in(c, (mx2: bitstring, mx2_sig: bitstring));
let mrb1 = khash(mrb0) in
let mbk1_auth = hkdf(concat0(mrb1)) in
let mbk1_enc = hkdf(concat0(mrb1)) in
if checksign(MPK_B, mx2, mx2_sig) = okay then
let m2 = sdec(mbk1_enc, mx2) in
event recvME2(m2, mrb1, MPK_B);
phase 3; (* =================== PHASE 6: PCS =================== *)
event compromiseOSKA(OSK_A);
out(c, OSK_A)
).
let PeerB(OSK_B: skey, OPK_B: pkey, OPK_A: pkey, MSK_B: skey, MPK_B: pkey) =
new bo: skey;
let gbo = pk(bo) in
let gbo_sig = sign(OSK_B, rb(gbo)) in
out(c, (gbo, gbo_sig));
phase 1;
(* =================== PHASE 2: DERIVE P2P MASTER + SENDER KEYS SESSION A -> B =================== *)
(* first stage: derive bmaster, verfiy a's msgs, decrypt prekey message, reply *)
in(c, (x1: bitstring, x1_mac: bitstring, gao: pkey, gta1: pkey));
let bmaster = hkdf(concat4(dh(OPK_A, OSK_B), dh(OPK_A, bo), dh(gao, OSK_B))) in
let rb1 = hkdf(concat0(bmaster)) in
let cb1 = hkdf(concat0(bmaster)) in
let bk1 = khash(cb1) in
let bk1_auth = hkdf(concat0(bk1)) in
let bk1_enc = hkdf(concat0(bk1)) in
if checkmac(bk1_auth, concat1(x1, gao, gta1), x1_mac) = okay then
(
let (MPK_A: pkey, mra0: key) = sdec(bk1_enc, x1) in
event recvOE1(MPK_A, mra0, gao, gta1);
(* =================== PHASE 3: SENDER KEYS SESH B -> A =================== *)
new tb2: skey;
let gtb2 = pk(tb2) in
new tb2: skey;
let gtb2 = pk(tb2) in
let rb2 = hkdf(concat3(concat0(khash(rb1)), dh(gta1, tb2))) in
let cb2 = hkdf(concat3(concat0(khash(rb1)), dh(gta1, tb2))) in
let bk2 = khash(cb2) in
let bk2_auth = hkdf(concat0(bk2)) in
let bk2_enc = hkdf(concat0(bk2)) in
new mrb0: key; (* mrb0 := sender keys ratchet *)
let x2 = senc(bk2_enc, (MPK_B, mrb0)) in
let x2_mac = mac(bk2_auth, concat2(x2, gtb2)) in
event sendOE2(MPK_B, mrb0, gao, gta1);
out(c, (x2, x2_mac, gtb2));
(* =================== PHASE 4: SENDER KEYS MSG A -> B =================== *)
in(c, (mx1: bitstring, mx1_sig: bitstring));
let mra1 = khash(mra0) in
let mak1_auth = hkdf(concat0(mra1)) in
let mak1_enc = hkdf(concat0(mra1)) in
if checksign(MPK_A, mx1, mx1_sig) = okay then (
let m1 = sdec(mak1_enc, mx1) in
event recvME1(m1, mra1, MPK_A);
phase 3;
event compromiseOSKB(OSK_B);
out(c, OSK_B);
(* =================== PHASE 5: SENDER KEYS MSG B -> A =================== *)
let mrb1 = khash(mrb0) in
let mbk1_auth = hkdf(concat0(mrb1)) in
let mbk1_enc = hkdf(concat0(mrb1)) in
let mx2 = senc(mbk1_enc, m2) in
let mx2_sig = sign(MSK_B, mx2) in
event sendME2(m2, mrb1, MPK_B);
out(c, (mx2, mx2_sig))
(* =================== PHASE 6: PCS =================== *)
)).
process
new OSK_A: skey; let OPK_A = pk(OSK_A) in
new OSK_B: skey; let OPK_B = pk(OSK_B) in
new MSK_A: skey; let MPK_A = pk(MSK_A) in
new MSK_B: skey; let MPK_B = pk(MSK_B) in
out(a, OPK_A);
out(a, OPK_B);
(*
out(a, MPK_A);
out(a, MPK_B);
*)
new fib1: skey;
new fib2: skey;
new fib3: skey;
new fib4: skey;
let (kO_A: skey, kM_A: skey) = choice [(OSK_A, MSK_A), (fib1, fib2) ] in
let (kO_B: skey, kM_B: skey) = choice [(OSK_B, MSK_B), (fib1, fib2) ] in
( (!PeerA(kO_A, pk(kO_A), OPK_B, kM_A, pk(kM_A))) |
(!PeerB(OSK_B, OPK_B, OPK_A, MSK_B, MPK_B)))

View File

@@ -0,0 +1,281 @@
(*
Sender Keys protocol; proving secrecy, authentication, PCS, and PFS
Author: [redacted]
*)
free m1: bitstring [private].
free m2: bitstring [private].
set selFun = Nounifset.
set redundancyElim = best.
set simpEqAll = false.
set redundantHypElim = true.
set simplifyProcess = true.
set stopTerm = false.
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.
fun aenc(bitstring, pkey): bitstring.
reduc forall m: bitstring, sk: skey; adec(aenc(m,pk(sk)),sk) = m.
(* 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): bitstring.
equation forall a: skey, b: skey; dh(pk(a), b) = dh(pk(b), a). (* symmetry of DH *)
(* the concat functions *)
fun khash(key): key.
fun hkdf(bitstring): key [data].
fun concat0(key): bitstring [data, typeConverter].
fun concat1(bitstring, pkey, pkey): bitstring [data].
reduc forall m1: bitstring, k1: pkey, k2: pkey; split1(concat1(m1, k1, k2)) = (m1, k1, k2).
fun concat2(bitstring, pkey): bitstring [data].
reduc forall m1: bitstring, k1: pkey; split2(concat2(m1, k1)) = (m1, k1).
fun concat3(bitstring, bitstring): bitstring [data].
reduc forall m1: bitstring, m2: bitstring; split3(concat3(m1, m2)) = (m1, m2).
fun concat4(bitstring, bitstring, bitstring): bitstring [data].
reduc forall m1: bitstring, m2: bitstring, m3:bitstring; split4(concat4(m1, m2, m3)) = (m1, m2, m3).
equation forall k: key, a: skey, b: skey; hkdf(concat3(concat0(khash(k)), dh(pk(a), b))) = hkdf(concat3(concat0(khash(k)), dh(pk(b), a))).
(* the concats *)
(* events *)
event sendOE1(pkey, key, pkey, pkey).
event recvOE1(pkey, key, pkey, pkey).
event sendOE2(pkey, key, pkey, pkey).
event recvOE2(pkey, key, pkey, pkey).
event sendME1(bitstring, key, pkey).
event recvME1(bitstring, key, pkey).
event sendME2(bitstring, key, pkey).
event recvME2(bitstring, key, pkey).
event compromiseOSKA(skey).
event compromiseOSKB(skey).
event start().
free tag_oe1: bitstring [private].
free tag_oe2: bitstring [private].
free tag_me1: bitstring [private].
free tag_me2: bitstring [private].
free tag_b_eph: bitstring [private].
let PeerA(OSK_A: skey, OPK_A: pkey, OPK_B: pkey, MSK_A: skey, MPK_A: pkey) =
phase 1;
new ao: skey;
let gao = pk(ao) in
(* generate amaster and enc msg (PHASE 1) *)
(* in(c, gbo: pkey); *)
in(c, (gbo: pkey, gbo_sig: bitstring));
if checksign(OPK_B, rb(gbo), gbo_sig) = okay then
(* =================== PHASE 2: DERIVE P2P MASTER + SENDER KEYS SESSION A -> B =================== *)
let amaster = hkdf(concat4(dh(OPK_B, OSK_A), dh(gbo, OSK_A), dh(OPK_B, ao))) in
let ra1 = hkdf(concat0(amaster)) in
let ca1 = hkdf(concat0(amaster)) in
new ta1: skey;
let gta1 = pk(ta1) in
let ak1 = khash(ca1) in
let ak1_auth = hkdf(concat0(ak1)) in
let ak1_enc = hkdf(concat0(ak1)) in
new mra0: key; (* mra0 := megolm ratchet *)
let x1 = senc(ak1_enc, (MPK_A, mra0)) in
let x1_mac = mac(ak1_auth, concat1(x1, gao, gta1)) in
event sendOE1(MPK_A, mra0, gao, gta1);
out(c, (x1, x1_mac, gao, gta1));
(* =================== PHASE 3: SENDER KEYS SESSION B -> A =================== *)
(* second stage: now, decrypt the received message from bob *)
in(c, (x2: bitstring, x2_mac: bitstring, gtb2: pkey));
let ca2 = hkdf(concat3(concat0(khash(ra1)), dh(gtb2, ta1))) in
let ak2 = khash(ca2) in
let ak2_auth = hkdf(concat0(ak2)) in
if checkmac(ak2_auth, concat2(x2, gtb2), x2_mac) = okay then (
let mak2_enc = hkdf(concat0(ak2)) in
let (MPK_B: pkey, mrb0: key) = sdec(mak2_enc, x2) in
event recvOE2(MPK_B, mrb0, gao, gta1);
(* =================== PHASE 4: SENDER KEYS MSG A -> B =================== *)
let mra1 = khash(mra0) in
let mak1_auth = hkdf(concat0(mra1)) in
let mak1_enc = hkdf(concat0(mra1)) in
let mx1 = senc(mak1_enc, m1) in
let mx1_sig = sign(MSK_A, mx1) in
event sendME1(m1, mra1, MPK_A);
out(c, (mx1, mx1_sig));
(* =================== PHASE 5: SENDER KEYS MSG B -> A =================== *)
in(c, (mx2: bitstring, mx2_sig: bitstring));
let mrb1 = khash(mrb0) in
let mbk1_auth = hkdf(concat0(mrb1)) in
let mbk1_enc = hkdf(concat0(mrb1)) in
if checksign(MPK_B, mx2, mx2_sig) = okay then
let m2 = sdec(mbk1_enc, mx2) in
event recvME2(m2, mrb1, MPK_B);
phase 3; (* =================== PHASE 6: PCS =================== *)
event compromiseOSKA(OSK_A);
out(c, OSK_A)
).
let PeerB(OSK_B: skey, OPK_B: pkey, OPK_A: pkey, MSK_B: skey, MPK_B: pkey) =
new bo: skey;
let gbo = pk(bo) in
let gbo_sig = sign(OSK_B, rb(gbo)) in
out(c, (gbo, gbo_sig));
phase 1;
(* =================== PHASE 2: DERIVE P2P MASTER + SENDER KEYS SESSION A -> B =================== *)
(* first stage: derive bmaster, verfiy a's msgs, decrypt prekey message, reply *)
in(c, (x1: bitstring, x1_mac: bitstring, gao: pkey, gta1: pkey));
let bmaster = hkdf(concat4(dh(OPK_A, OSK_B), dh(OPK_A, bo), dh(gao, OSK_B))) in
let rb1 = hkdf(concat0(bmaster)) in
let cb1 = hkdf(concat0(bmaster)) in
let bk1 = khash(cb1) in
let bk1_auth = hkdf(concat0(bk1)) in
let bk1_enc = hkdf(concat0(bk1)) in
if checkmac(bk1_auth, concat1(x1, gao, gta1), x1_mac) = okay then
(
let (MPK_A: pkey, mra0: key) = sdec(bk1_enc, x1) in
event recvOE1(MPK_A, mra0, gao, gta1);
(* =================== PHASE 3: SENDER KEYS SESH B -> A =================== *)
new tb2: skey;
let gtb2 = pk(tb2) in
new tb2: skey;
let gtb2 = pk(tb2) in
let rb2 = hkdf(concat3(concat0(khash(rb1)), dh(gta1, tb2))) in
let cb2 = hkdf(concat3(concat0(khash(rb1)), dh(gta1, tb2))) in
let bk2 = khash(cb2) in
let bk2_auth = hkdf(concat0(bk2)) in
let bk2_enc = hkdf(concat0(bk2)) in
new mrb0: key; (* mrb0 := sender keys ratchet *)
let x2 = senc(bk2_enc, (MPK_B, mrb0)) in
let x2_mac = mac(bk2_auth, concat2(x2, gtb2)) in
event sendOE2(MPK_B, mrb0, gao, gta1);
out(c, (x2, x2_mac, gtb2));
(* =================== PHASE 4: SENDER KEYS MSG A -> B =================== *)
in(c, (mx1: bitstring, mx1_sig: bitstring));
let mra1 = khash(mra0) in
let mak1_auth = hkdf(concat0(mra1)) in
let mak1_enc = hkdf(concat0(mra1)) in
if checksign(MPK_A, mx1, mx1_sig) = okay then (
let m1 = sdec(mak1_enc, mx1) in
event recvME1(m1, mra1, MPK_A);
phase 3;
event compromiseOSKB(OSK_B);
out(c, OSK_B);
(* =================== PHASE 5: SENDER KEYS MSG B -> A =================== *)
let mrb1 = khash(mrb0) in
let mbk1_auth = hkdf(concat0(mrb1)) in
let mbk1_enc = hkdf(concat0(mrb1)) in
let mx2 = senc(mbk1_enc, m2) in
let mx2_sig = sign(MSK_B, mx2) in
event sendME2(m2, mrb1, MPK_B);
out(c, (mx2, mx2_sig))
(* =================== PHASE 6: PCS =================== *)
)).
process
new OSK_A: skey; let OPK_A = pk(OSK_A) in
new OSK_B: skey; let OPK_B = pk(OSK_B) in
new MSK_A: skey; let MPK_A = pk(MSK_A) in
new MSK_B: skey; let MPK_B = pk(MSK_B) in
out(a, OPK_A);
out(a, OPK_B);
(*
out(a, MPK_A);
out(a, MPK_B);
*)
new fib1: skey;
new fib2: skey;
new fib3: skey;
new fib4: skey;
let (kO_A: skey, kM_A: skey) = choice [(OSK_A, MSK_A), (fib1, fib2) ] in
let (kO_B: skey, kM_B: skey) = choice [(OSK_B, MSK_B), (fib1, fib2) ] in
( (!PeerA(OSK_A, OPK_A, OPK_B, MSK_A, MPK_A)) |
(!PeerB(kO_B, pk(kO_B), OPK_A, kM_A, pk(kM_A))))

View File

@@ -0,0 +1,194 @@
(*
Signal X3DH+Double Ratchet; initiator deniability
Author: [redacted]
model assumption #1: same key is used for signing and encryption (i.e. X25519)
*)
free m1: bitstring [private].
free m2: bitstring [private].
set attacker = passive.
set simpEqAll = false.
set selFun = Nounifset.
set redundancyElim = best.
set redundantHypElim = true.
set simplifyProcess = false.
set stopTerm = false.
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.
fun aenc(bitstring, pkey): bitstring.
reduc forall m: bitstring, sk: skey; adec(aenc(m,pk(sk)),sk) = m.
(* 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(bitstring): key.
fun khash(key): key.
fun hkdf2_dev1(key): key.
fun hkdf2_dev2(key): key.
letfun hkdf2(k: key) =
(hkdf2_dev1(k), hkdf2_dev2(k)).
fun hkdf4_dev1(key, key): key.
fun hkdf4_dev2(key, key): key.
letfun hkdf4(k1: key, k2: key) =
(hkdf4_dev1(k1, k2), hkdf4_dev2(k1, k2)).
(* the concats *)
fun concat1(bitstring, pkey, pkey): bitstring [data].
fun concat2(bitstring, pkey): bitstring [data].
fun concat3(key, key, key, key): bitstring [data].
(* events *)
event sendE1(bitstring, key).
event recvE1(bitstring, key).
event sendE2(bitstring, key).
event recvE2(bitstring, key).
event compromiseSKA(skey).
event compromiseSKB(skey).
event start().
free tag_oe1: bitstring [private].
free tag_oe2: bitstring [private].
free tag_me1: bitstring [private].
free tag_me2: bitstring [private].
free tag_b_eph: bitstring [private].
let PeerA(SK_A: skey, PK_A: pkey, PK_B: pkey) =
phase 1;
new ao: skey;
new ae1: skey;
let gae1 = pk(ae1) in
(* generate amaster and enc msg (PHASE 1) *)
in(c, (gbssig: bitstring, gbs: pkey, gbo: pkey));
if checksign(PK_B, rb(gbs), gbssig) = okay then
let amaster = hkdf1(concat3(dh(gbs, SK_A), dh(PK_B, ae1), dh(gbs, ae1), dh(gbo, ae1))) in
let (ra1: key, ca1: key) = hkdf2(amaster) in (* derive the root and chain key *)
new ta1: skey;
let gta1 = pk(ta1) in
let mak1 = khash(ca1) in
let (mak1_auth: key, mak1_enc: key) = hkdf2(mak1) in
let x1 = senc(mak1_enc, m1) in
let x1_mac = mac(mak1_auth, concat1(x1, gta1, gae1)) in
event sendE1(m1, mak1);
out(c, (x1, x1_mac, gta1, gae1));
(* second stage: now, decrypt the received message from bob *)
in(c, (x2: bitstring, x2_mac: bitstring, gtb2: pkey));
let (ra2: key, ca2: key) = hkdf4(ra1, dh(gtb2, ta1)) in
let mak2 = khash(ca2) in
let (mak2_auth: key, mak2_enc: key) = hkdf2(mak2) in
if checkmac(mak2_auth, concat2(x2, gtb2), x2_mac) = okay then
let m2 = sdec(mak2_enc, x2) in
event recvE2(m2, mak2);
phase 2;
0.
let PeerB(SK_B: skey, PK_B: pkey, PK_A: pkey) =
new bo: skey;
new bs: skey;
let gbo = pk(bo) in
let gbs = pk(bs) in
let gbssig = sign(SK_B, rb(gbs)) in
out(c, (gbssig, gbs, gbo));
phase 1;
(* first stage: derive bmaster, verfiy a's msgs, decrypt prekey message, reply *)
in(c, (x1: bitstring, x1_mac: bitstring, gta1: pkey, gae1: pkey));
let bmaster = hkdf1(concat3(dh(PK_A, bs), dh(gae1, SK_B), dh(gae1, bs), dh(gae1, bo))) in
let (rb1: key, cb1: key) = hkdf2(bmaster) in (* derive the root and chain key *)
let mbk1 = khash(cb1) in
let (mbk1_auth: key, mbk1_enc: key) = hkdf2(mbk1) in
if checkmac(mbk1_auth, concat1(x1, gta1, gae1), x1_mac) = okay then
let m1 = sdec(mbk1_enc, x1) in
event recvE1(m1, mbk1);
new tb2: skey;
let gtb2 = pk(tb2) in
let (rb2: key, cb2: key) = hkdf4(rb1, dh(gta1, tb2)) in
let mbk2 = khash(cb2) in
let (mbk2_auth: key, mbk2_enc: key) = hkdf2(mbk2) in
let x2 = senc(mbk2_enc, m2) in
let x2_mac = mac(mbk2_auth, concat2(x2, gtb2)) in
event sendE2(m2, mbk2);
out(c, (x2, x2_mac, gtb2));
phase 2;
event compromiseSKB(SK_B);
out(c, SK_B);
0.
process
new SK_A: skey; let PK_A = pk(SK_A) in
new SK_B: skey; let PK_B = pk(SK_B) in
out(a, PK_A);
out(a, PK_B);
new fib1: skey;
new fib2: skey;
let k_A = choice [ SK_A, fib1 ] in
let k_B = choice [ SK_B, fib2 ] in
( (!PeerA(k_A, pk(k_A), PK_B)) |
(!PeerB(SK_B, PK_B, PK_A)))

View File

@@ -0,0 +1,193 @@
(*
Signal X3DH+Double Ratchet; initiator deniability
Author: [redacted]
model assumption #1: same key is used for signing and encryption (i.e. X25519)
*)
free m1: bitstring [private].
free m2: bitstring [private].
set attacker = passive.
set simpEqAll = false.
set selFun = Nounifset.
set redundancyElim = best.
set redundantHypElim = true.
set simplifyProcess = false.
set stopTerm = false.
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.
fun aenc(bitstring, pkey): bitstring.
reduc forall m: bitstring, sk: skey; adec(aenc(m,pk(sk)),sk) = m.
(* 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(bitstring): key.
fun khash(key): key.
fun hkdf2_dev1(key): key.
fun hkdf2_dev2(key): key.
letfun hkdf2(k: key) =
(hkdf2_dev1(k), hkdf2_dev2(k)).
fun hkdf4_dev1(key, key): key.
fun hkdf4_dev2(key, key): key.
letfun hkdf4(k1: key, k2: key) =
(hkdf4_dev1(k1, k2), hkdf4_dev2(k1, k2)).
(* the concats *)
fun concat1(bitstring, pkey, pkey): bitstring [data].
fun concat2(bitstring, pkey): bitstring [data].
fun concat3(key, key, key, key): bitstring [data].
(* events *)
event sendE1(bitstring, key).
event recvE1(bitstring, key).
event sendE2(bitstring, key).
event recvE2(bitstring, key).
event compromiseSKA(skey).
event compromiseSKB(skey).
event start().
free tag_oe1: bitstring [private].
free tag_oe2: bitstring [private].
free tag_me1: bitstring [private].
free tag_me2: bitstring [private].
free tag_b_eph: bitstring [private].
let PeerA(SK_A: skey, PK_A: pkey, PK_B: pkey) =
phase 1;
new ao: skey;
new ae1: skey;
let gae1 = pk(ae1) in
(* generate amaster and enc msg (PHASE 1) *)
in(c, (gbssig: bitstring, gbs: pkey, gbo: pkey));
if checksign(PK_B, rb(gbs), gbssig) = okay then
let amaster = hkdf1(concat3(dh(gbs, SK_A), dh(PK_B, ae1), dh(gbs, ae1), dh(gbo, ae1))) in
let (ra1: key, ca1: key) = hkdf2(amaster) in (* derive the root and chain key *)
new ta1: skey;
let gta1 = pk(ta1) in
let mak1 = khash(ca1) in
let (mak1_auth: key, mak1_enc: key) = hkdf2(mak1) in
let x1 = senc(mak1_enc, m1) in
let x1_mac = mac(mak1_auth, concat1(x1, gta1, gae1)) in
event sendE1(m1, mak1);
out(c, (x1, x1_mac, gta1, gae1));
(* second stage: now, decrypt the received message from bob *)
in(c, (x2: bitstring, x2_mac: bitstring, gtb2: pkey));
let (ra2: key, ca2: key) = hkdf4(ra1, dh(gtb2, ta1)) in
let mak2 = khash(ca2) in
let (mak2_auth: key, mak2_enc: key) = hkdf2(mak2) in
if checkmac(mak2_auth, concat2(x2, gtb2), x2_mac) = okay then
let m2 = sdec(mak2_enc, x2) in
event recvE2(m2, mak2);
phase 2;
0.
let PeerB(SK_B: skey, PK_B: pkey, PK_A: pkey) =
new bo: skey;
new bs: skey;
let gbo = pk(bo) in
let gbs = pk(bs) in
let gbssig = sign(SK_B, rb(gbs)) in
out(c, (gbssig, gbs, gbo));
phase 1;
(* first stage: derive bmaster, verfiy a's msgs, decrypt prekey message, reply *)
in(c, (x1: bitstring, x1_mac: bitstring, gta1: pkey, gae1: pkey));
let bmaster = hkdf1(concat3(dh(PK_A, bs), dh(gae1, SK_B), dh(gae1, bs), dh(gae1, bo))) in
let (rb1: key, cb1: key) = hkdf2(bmaster) in (* derive the root and chain key *)
let mbk1 = khash(cb1) in
let (mbk1_auth: key, mbk1_enc: key) = hkdf2(mbk1) in
if checkmac(mbk1_auth, concat1(x1, gta1, gae1), x1_mac) = okay then
let m1 = sdec(mbk1_enc, x1) in
event recvE1(m1, mbk1);
new tb2: skey;
let gtb2 = pk(tb2) in
let (rb2: key, cb2: key) = hkdf4(rb1, dh(gta1, tb2)) in
let mbk2 = khash(cb2) in
let (mbk2_auth: key, mbk2_enc: key) = hkdf2(mbk2) in
let x2 = senc(mbk2_enc, m2) in
let x2_mac = mac(mbk2_auth, concat2(x2, gtb2)) in
event sendE2(m2, mbk2);
out(c, (x2, x2_mac, gtb2));
phase 2;
event compromiseSKB(SK_B);
out(c, SK_B);
0.
process
new SK_A: skey; let PK_A = pk(SK_A) in
new SK_B: skey; let PK_B = pk(SK_B) in
out(a, PK_A);
out(a, PK_B);
new fib1: skey;
new fib2: skey;
let k_A = choice [ SK_A, fib1 ] in
let k_B = choice [ SK_B, fib2 ] in
( (PeerA(SK_A, PK_A, PK_B)) |
(PeerB(k_B, pk(k_B), PK_A)))

View File

@@ -0,0 +1,168 @@
(*
X3DH; initiator deniability
Author: [redacted]
model assumption #1: same key is used for signing and encryption (i.e. X25519)
*)
free m1: bitstring [private].
set selFun = Nounifset.
set attacker = passive.
(*
set simpEqAll = false.
set simpEqAll = false.
set redundancyElim = best.
set redundantHypElim = true.
set simplifyProcess = true.
set stopTerm = false.
*)
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 [data].
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(bitstring): key [data].
fun khash(key): key.
fun hkdf2_dev1(key): key [data].
fun hkdf2_dev2(key): key [data].
letfun hkdf2(k: key) =
(hkdf2_dev1(k), hkdf2_dev2(k)).
(* the concats *)
fun concat1(bitstring, pkey): bitstring [data].
fun concat2(key, key, key, key): bitstring [data].
(* events *)
event sendE1(bitstring, key).
event recvE1(bitstring, key).
event compromiseSKA(skey).
event compromiseSKB(skey).
event start().
equation forall a1: key, a2: key, a3: key, a4: key; hkdf1(concat2(a1,a2,a3,a4)) = hkdf1(concat2(a1,a2,a3,a4)).
(*
k1: bs
k2: SK_A
k3: SK_B
k4: ae1
k5: bo
let amaster = hkdf1(concat2(dh(gbs, SK_A), dh(PK_B, ae1), dh(gbs, ae1), dh(gbo, ae1))) in
let bmaster = hkdf1(concat2(dh(PK_A, bs), dh(gae1, SK_B), dh(gae1, bs), dh(gae1, bo))) in
equation forall k1: skey, k2: skey, k3: skey, k4: skey, k5: skey; hkdf1(concat2(dh(pk(k1), k2),dh(pk(k3), k4),dh(pk(k1), k4),dh(pk(k5), k4))) = hkdf1(concat2(dh(pk(k2), k1),dh(pk(k4), k3),dh(pk(k4), k1),dh(pk(k4), k5))) [convergent].
*)
let PeerA(SK_A: skey, PK_A: pkey, PK_B: pkey) =
new ae1: skey;
new ae2: skey;
let gae1 = pk(ae1) in
let gae2 = pk(ae2) in
(* generate amaster and enc msg (PHASE 1) *)
phase 1;
in(c, (gbssig: bitstring, gbs: pkey, gbo: pkey));
if checksign(PK_B, rb(gbs), gbssig) = okay then
let amaster = hkdf1(concat2(dh(gbs, SK_A), dh(PK_B, ae1), dh(gbs, ae1), dh(gbo, ae1))) in
let (ra1: key, ca1: key) = hkdf2(amaster) in (* derive the root and chain key *)
let mak1 = khash(ca1) in
let (mak1_auth: key, mak1_enc: key) = hkdf2(mak1) in
let x1 = senc(mak1_enc, m1) in
let x1_mac = mac(mak1_auth, concat1(x1, gae1)) in
event sendE1(m1, mak1);
out(c, (x1, x1_mac, gae1));
phase 2;
0.
let PeerB(SK_B: skey, PK_B: pkey, PK_A: pkey) =
new bo: skey;
new bs: skey;
let gbs = pk(bs) in
let gbo = pk(bo) in
let gbssig = sign(SK_B, rb(gbs)) in
out(c, (gbssig, gbs, gbo));
phase 1; (* peer B commits first *)
(* first stage: derive bmaster, verfiy a's msgs, decrypt prekey message, reply *)
in(c, (x1: bitstring, x1_mac: bitstring, gae1: pkey));
let bmaster = hkdf1(concat2(dh(PK_A, bs), dh(gae1, SK_B), dh(gae1, bs), dh(gae1, bo))) in
let (rb1: key, cb1: key) = hkdf2(bmaster) in (* derive the root and chain key *)
let mbk1 = khash(cb1) in
let (mbk1_auth: key, mbk1_enc: key) = hkdf2(mbk1) in
if checkmac(mbk1_auth, concat1(x1, gae1), x1_mac) = okay then
let m1 = sdec(mbk1_enc, x1) in
event recvE1(m1, mbk1);
phase 2;
event compromiseSKB(SK_B);
out(a, SK_B);
0.
process
new SK_A: skey; let PK_A = pk(SK_A) in
new SK_B: skey; let PK_B = pk(SK_B) in
out(a, PK_A);
out(a, PK_B);
new fib1: skey;
new fib2: skey;
let k_A = choice [ SK_A, fib1 ] in
let k_B = choice [ SK_B, fib2 ] in
event start();
( (PeerA(k_A, pk(k_A), PK_B)) |
(PeerB(SK_B, PK_B, PK_A)) |
out(a, m1)) (* transcript publish *)

View File

@@ -0,0 +1,168 @@
(*
X3DH; responder deniability
Author: [redacted]
model assumption #1: same key is used for signing and encryption (i.e. X25519)
*)
free m1: bitstring [private].
set selFun = Nounifset.
set attacker = passive.
set simplifyProcess = false.
(*
set simpEqAll = false.
set simpEqAll = false.
set redundancyElim = best.
set redundantHypElim = true.
set stopTerm = false.
*)
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 [data].
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(bitstring): key [data].
fun khash(key): key.
fun hkdf2_dev1(key): key [data].
fun hkdf2_dev2(key): key [data].
letfun hkdf2(k: key) =
(hkdf2_dev1(k), hkdf2_dev2(k)).
(* the concats *)
fun concat1(bitstring, pkey): bitstring [data].
fun concat2(key, key, key, key): bitstring [data].
(* events *)
event sendE1(bitstring, key).
event recvE1(bitstring, key).
event compromiseSKA(skey).
event compromiseSKB(skey).
event start().
equation forall a1: key, a2: key, a3: key, a4: key; hkdf1(concat2(a1,a2,a3,a4)) = hkdf1(concat2(a1,a2,a3,a4)).
(*
k1: bs
k2: SK_A
k3: SK_B
k4: ae1
k5: bo
let amaster = hkdf1(concat2(dh(gbs, SK_A), dh(PK_B, ae1), dh(gbs, ae1), dh(gbo, ae1))) in
let bmaster = hkdf1(concat2(dh(PK_A, bs), dh(gae1, SK_B), dh(gae1, bs), dh(gae1, bo))) in
equation forall k1: skey, k2: skey, k3: skey, k4: skey, k5: skey; hkdf1(concat2(dh(pk(k1), k2),dh(pk(k3), k4),dh(pk(k1), k4),dh(pk(k5), k4))) = hkdf1(concat2(dh(pk(k2), k1),dh(pk(k4), k3),dh(pk(k4), k1),dh(pk(k4), k5))) [convergent].
*)
let PeerA(SK_A: skey, PK_A: pkey, PK_B: pkey) =
new ae1: skey;
new ae2: skey;
let gae1 = pk(ae1) in
let gae2 = pk(ae2) in
(* generate amaster and enc msg (PHASE 1) *)
phase 1;
in(c, (gbssig: bitstring, gbs: pkey, gbo: pkey));
if checksign(PK_B, rb(gbs), gbssig) = okay then
let amaster = hkdf1(concat2(dh(gbs, SK_A), dh(PK_B, ae1), dh(gbs, ae1), dh(gbo, ae1))) in
let (ra1: key, ca1: key) = hkdf2(amaster) in (* derive the root and chain key *)
let mak1 = khash(ca1) in
let (mak1_auth: key, mak1_enc: key) = hkdf2(mak1) in
let x1 = senc(mak1_enc, m1) in
let x1_mac = mac(mak1_auth, concat1(x1, gae1)) in
event sendE1(m1, mak1);
out(c, (x1, x1_mac, gae1));
phase 2;
0.
let PeerB(SK_B: skey, PK_B: pkey, PK_A: pkey) =
new bo: skey;
new bs: skey;
let gbs = pk(bs) in
let gbo = pk(bo) in
let gbssig = sign(SK_B, rb(gbs)) in
out(c, (gbssig, gbs, gbo));
phase 1; (* peer B commits first *)
(* first stage: derive bmaster, verfiy a's msgs, decrypt prekey message, reply *)
in(c, (x1: bitstring, x1_mac: bitstring, gae1: pkey));
let bmaster = hkdf1(concat2(dh(PK_A, bs), dh(gae1, SK_B), dh(gae1, bs), dh(gae1, bo))) in
let (rb1: key, cb1: key) = hkdf2(bmaster) in (* derive the root and chain key *)
let mbk1 = khash(cb1) in
let (mbk1_auth: key, mbk1_enc: key) = hkdf2(mbk1) in
if checkmac(mbk1_auth, concat1(x1, gae1), x1_mac) = okay then
let m1 = sdec(mbk1_enc, x1) in
event recvE1(m1, mbk1);
phase 2;
event compromiseSKB(SK_B);
out(a, SK_B);
0.
process
new SK_A: skey; let PK_A = pk(SK_A) in
new SK_B: skey; let PK_B = pk(SK_B) in
out(a, PK_A);
out(a, PK_B);
new fib1: skey;
new fib2: skey;
let k_A = choice [ SK_A, fib1 ] in
let k_B = choice [ SK_B, fib2 ] in
event start();
( (PeerA(SK_B, PK_A, pk(k_B))) |
(PeerB(k_B, pk(k_B), PK_A)) |
out(a, m1))