second iteration

This commit is contained in:
2025-09-15 00:04:30 -04:00
parent 53303ba86e
commit 618ce7c797
8 changed files with 1701 additions and 1 deletions

View File

@@ -0,0 +1,302 @@
(*
Sender Keys protocol with PQXDH; proving secrecy, authentication, PFS, quantum 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): key.
equation forall a: skey, b: skey; dh(pk(a), b) = dh(pk(b), a). (* symmetry of DH *)
(* KEM encapsulation *)
type kempriv.
type kempub.
fun kempk(kempriv):kempub.
fun penc(kempub, bitstring):bitstring.
(* fun pdec(kempriv,bitstring):bitstring. *)
reduc forall sk: kempriv, m:bitstring; pdec(sk, penc(kempk(sk), m)) = m.
letfun kempriv2pub(k:kempriv) = kempk(k).
letfun pqkem_enc(pk:kempub) =
new ss:bitstring;
(penc(pk,ss),ss).
letfun pqkem_dec(sk:kempriv,ct:bitstring) =
pdec(sk,ct).
fun qb(kempub): bitstring [data].
(* the concats *)
fun concat1(bitstring, pkey, bitstring): bitstring [data].
fun concat2(key, key, key, key, bitstring): bitstring [data].
fun concat3(key, key): key [data].
fun concat4(bitstring, pkey): bitstring [data].
fun khash(key): key.
fun hkdf1(bitstring): key [data].
fun hkdf2_dev1(key): key [data].
fun hkdf2_dev2(key): key [data].
letfun hkdf2(k: key) =
(hkdf2_dev1(k), hkdf2_dev2(k)).
(* event declarations *)
event sendOE1(pkey, key, pkey).
event recvOE1(pkey, key, pkey).
event sendOE2(pkey, key, pkey).
event recvOE2(pkey, key, pkey).
event sendME1(bitstring, key).
event recvME1(bitstring, key).
event sendME2(bitstring, key).
event recvME2(bitstring, key).
event compromiseSKA(skey).
event compromiseSKB(skey).
event breakDH(key, key, key, key).
event start().
let PeerA(SK_A: skey, PK_A: pkey, PK_B: pkey, FSK_A: skey, FPK_A: 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, gpqbo: kempub, gpqbsig: bitstring));
if checksign(PK_B, rb(gbs), gbssig) = okay then
if checksign(PK_B, qb(gpqbo), gpqbsig) = okay then
let (ct: bitstring, ss: bitstring) = pqkem_enc(gpqbo) in
let amaster = hkdf1(concat2(dh(gbs, SK_A), dh(PK_B, ae1), dh(gbs, ae1), dh(gbo, ae1), ss)) in
let (ra1: key, ca1: key) = hkdf2(amaster) in (* derive the root and chain key *)
let ak1 = khash(ca1) in
let (ak1_auth: key, ak1_enc: key) = hkdf2(ak1) in
new mra0: key; (* mra0 := fan out layer ratchet *)
let x1 = senc(ak1_enc, (FPK_A, mra0)) in
let x1_mac = mac(ak1_auth, concat1(x1, gae1, ct)) in
event sendOE1(FPK_A, mra0, gae1);
out(c, (x1, x1_mac, gae1, ct));
(* =================== PHASE 3: SENDER KEYS SESSION B -> A =================== *)
in(c, (x2: bitstring, x2_mac: bitstring, gtb2: pkey));
let (ca2: key, ra2: key) = hkdf2(concat3(khash(ra1), dh(gtb2, ae1))) in
let ak2 = khash(ca2) in
let (ak2_auth: key, ak2_enc: key) = hkdf2(ak2) in
if checkmac(ak2_auth, concat4(x2, gtb2), x2_mac) = okay then
let (FPK_B: pkey, mrb0: key) = sdec(ak2_enc, x2) in
event recvOE2(FPK_B, mrb0, gae2);
(* =================== PHASE 4: SENDER KEYS MSG A -> B =================== *)
let mra1 = khash(mra0) in
let (mak1_auth: key, mak1_enc: key) = hkdf2(mra1) in
let mx1 = senc(mak1_enc, m1) in
let mx1_sig = sign(FSK_A, mx1) in
event sendME1(m1, mra1);
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: key, mbk1_enc: key) = hkdf2(mrb1) in
if checksign(FPK_B, mx2, mx2_sig) = okay then
let m2 = sdec(mbk1_enc, mx2) in
event recvME2(m2, mrb1);
(* =================== PHASE 6: Compromise =================== *)
phase 5;
event compromiseSKA(SK_A);
out(a, SK_A);
phase 6;
event breakDH(dh(gbs, SK_A), dh(PK_B, ae1), dh(gbs, ae1), dh(gbo, ae1));
out(a, (dh(gbs, SK_A), dh(PK_B, ae1), dh(gbs, ae1), dh(gbo, ae1)));
0.
let PeerB(SK_B: skey, PK_B: pkey, PK_A: pkey, FSK_B: skey, FPK_B: pkey) =
new bo: skey;
new bs: skey;
new pqbo: kempriv;
let gbs = pk(bs) in
let gbo = pk(bo) in
let gpqbo = kempk(pqbo) in
let gbssig = sign(SK_B, rb(gbs)) in
let gpqbsig = sign(SK_B, qb(gpqbo)) in
out(c, (gbssig, gbs, gbo, gpqbo, gpqbsig));
phase 1; (* peer B commits first *)
(* =================== PHASE 2: DERIVE P2P MASTER + SENDER KEYS SESSION A -> B =================== *)
in(c, (x1: bitstring, x1_mac: bitstring, gae1: pkey, ct: bitstring));
let ss = pqkem_dec(pqbo, ct) in
let bmaster = hkdf1(concat2(dh(PK_A, bs), dh(gae1, SK_B), dh(gae1, bs), dh(gae1, bo), ss)) in
let (rb1: key, cb1: key) = hkdf2(bmaster) in (* derive the root and chain key *)
let bk1 = khash(cb1) in
let (bk1_auth: key, bk1_enc: key) = hkdf2(bk1) in
if checkmac(bk1_auth, concat1(x1, gae1, ct), x1_mac) = okay then
let (mra0: key, FPK_A: pkey) = sdec(bk1_enc, x1) in
event recvOE1(FPK_A, mra0, gae1);
(* =================== PHASE 3: SENDER KEYS SESH B -> A =================== *)
new tb2: skey;
let gtb2 = pk(tb2) in
let (rb2: key, cb2: key) = hkdf2(concat3(khash(rb1), dh(gae1, tb2))) in
let bk2 = khash(cb2) in
let (bk2_auth: key, bk2_enc: key) = hkdf2(bk2) in
new mrb0: key; (* mrb0 := sender keys ratchet *)
let x2 = senc(bk2_enc, (FPK_B, mrb0)) in
let x2_mac = mac(bk2_auth, concat4(x2, gtb2)) in
event sendOE2(FPK_B, mrb0, gae1);
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: key, mak1_enc: key) = hkdf2(mra1) in
if checksign(FPK_A, mx1, mx1_sig) = okay then
let m1 = sdec(mak1_enc, mx1) in
event recvME1(m1, mra1);
(* =================== PHASE 5: SENDER KEYS MSG B -> A =================== *)
let mrb1 = khash(mrb0) in
let (mbk1_auth: key, mbk1_enc: key) = hkdf2(mrb1) in
let mx2 = senc(mbk1_enc, m2) in
let mx2_sig = sign(FSK_B, mx2) in
event sendME2(m2, mrb1);
out(c, (mx2, mx2_sig));
(* =================== PHASE 6: Compromise =================== *)
phase 5;
event compromiseSKB(SK_B);
out(a, SK_B);
0.
query event(start()).
(* forward secrecy *)
query sk1: skey, sk2: skey; (event(compromiseSKA(sk1)) && event(compromiseSKB(sk2)) && attacker(m1)) ==> false.
(* secrecy *)
query attacker(m1).
query attacker(m2).
(* forward pq secrecy *)
query k1: key, k2: key, k3: key, k4: key; (event(breakDH(k1, k2, k3, k4)) && attacker(m1)) ==> false.
(* auth *)
query k1: pkey, rk: key, k2: pkey; inj-event(recvOE1(k1, rk, k2)) ==> inj-event(sendOE1(k1, rk, k2)).
query k1: pkey, rk: key, k2: pkey; inj-event(recvOE2(k1, rk, k2)) ==> inj-event(sendOE2(k1, rk, k2)).
query m: bitstring, rk: key; inj-event(recvME1(m, rk)) ==> inj-event(sendME1(m, rk)).
query m: bitstring, rk: key; inj-event(recvME2(m, rk)) ==> inj-event(sendME2(m, rk)).
(* reachability *)
query k1: pkey, rk: key, k2: pkey; event(sendOE1(k1,rk,k2)).
query k1: pkey, rk: key, k2: pkey; event(recvOE1(k1,rk,k2)).
query k1: pkey, rk: key, k2: pkey; event(sendOE2(k1,rk,k2)).
query k1: pkey, rk: key, k2: pkey; event(recvOE2(k1,rk,k2)).
query m: bitstring, rk: key; event(sendME1(m, rk)).
query m: bitstring, rk: key; event(recvME1(m, rk)).
query m: bitstring, rk: key; event(sendME2(m, rk)).
query m: bitstring, rk: key; event(recvME2(m, rk)).
process
new SK_A: skey; let PK_A = pk(SK_A) in
new SK_B: skey; let PK_B = pk(SK_B) in
new FSK_A: skey; let FPK_A = pk(FSK_A) in
new FSK_B: skey; let FPK_B = pk(FSK_B) in
out(a, PK_A);
out(a, PK_B);
(*
out(a, FPK_A);
out(a, FPK_B);
*)
event start();
( (PeerA(SK_A, PK_A, PK_B, FSK_A, FPK_A)) |
(PeerB(SK_B, PK_B, PK_A, FSK_B, FPK_B)))