Add project files.

This commit is contained in:
micro
2026-06-20 09:31:59 -05:00
parent 9bb3f00d86
commit 4baa4ce8c0
346 changed files with 55751 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
# ProVerif model for SPQR
This folder contains a ProVerif model for the SPQR protocol.
+44
View File
@@ -0,0 +1,44 @@
(* Minimal generic crypto library *)
free c: channel.
event Reachable.
type principal.
type symkey.
fun aead_enc(symkey,bitstring,bitstring): bitstring.
fun aead_dec(symkey,bitstring,bitstring): bitstring
reduc forall k:symkey, m:bitstring, ad:bitstring;
aead_dec(k, aead_enc(k,m,ad), ad) = m.
type seed.
type enckey.
type deckey.
type ctsecret.
fun dk2seed(deckey): seed.
fun dk2enckey(deckey): enckey.
fun pkenc1(ctsecret, seed, symkey): bitstring.
fun pkenc2(ctsecret, enckey): bitstring.
fun pkdec(deckey, bitstring, bitstring): symkey
reduc forall dk:deckey, sk:symkey, r: ctsecret;
pkdec(dk, pkenc1(r, dk2seed(dk), sk), pkenc2(r, dk2enckey(dk))) = sk.
fun extractsecret(ctsecret, bitstring): symkey
reduc forall sk: symkey, s: seed, r: ctsecret;
extractsecret(r, pkenc1(r, s, sk)) = sk.
letfun kem_keygen() =
new dk: deckey;
(dk, dk2seed(dk), dk2enckey(dk)).
letfun kem_decap(dk: deckey, ct1: bitstring, ct2: bitstring) =
pkdec(dk, ct1, ct2).
type authenticator.
fun mac(authenticator, bitstring): bitstring.
fun auth_update(authenticator, symkey): authenticator.
(* hash function *)
fun h(bitstring): bitstring.
fun kdf(symkey, bitstring): symkey.
+377
View File
@@ -0,0 +1,377 @@
(* Protocol-specific crypto *)
free ct_label: bitstring.
free hdr_label: bitstring.
letfun mac_ct(auth: authenticator, ct1: bitstring, ct2: bitstring) =
mac(auth, (ct_label, ct1, ct2)).
letfun mac_header(auth: authenticator, ep: nat, ekseed: seed, ek_hash: bitstring) =
mac(auth, (hdr_label, ep, ekseed, ek_hash)).
free cka_label: bitstring.
(* Protocol Data structures *)
type opt_symkey.
fun SK_None(): opt_symkey [data].
fun SK(symkey): opt_symkey [data].
type opt_mac.
fun MAC_None(): opt_mac [data].
fun MAC(bitstring): opt_mac [data].
type opt_keypair.
fun KP_None(): opt_keypair [data].
fun KP(deckey, seed, enckey): opt_keypair [data].
(* Requestor/EK Generator States *)
type eksender.
fun NeedToSample(nat): eksender [data].
fun SentHeader(nat, deckey, seed, enckey): eksender [data].
fun ReceivedCt1(nat, deckey, seed, enckey, bitstring): eksender [data].
fun SentEk(nat, deckey, seed, enckey): eksender [data].
fun SentEkReceivedCt1(nat, deckey, seed, enckey, bitstring): eksender [data].
(* Responder/CT Generator States *)
type ctsender.
fun Waiting(nat): ctsender [data].
fun ReceivedHeader(nat, seed, bitstring): ctsender [data].
fun SentCt1(nat, ctsecret, seed, bitstring, bitstring, symkey): ctsender [data].
fun SentCt1ReceivedEk(nat, ctsecret, seed, enckey, bitstring, symkey): ctsender [data].
fun SentCt2(nat, symkey): ctsender [data].
reduc forall ep: nat; RequestorEpoch(NeedToSample(ep)) = ep;
forall ep: nat, dk: deckey, ekseed: seed, ek: enckey; RequestorEpoch(SentHeader(ep, dk, ekseed, ek)) = ep;
forall ep: nat, dk: deckey, ekseed: seed, ek: enckey, ct1: bitstring; RequestorEpoch(ReceivedCt1(ep, dk, ekseed, ek, ct1)) = ep;
forall ep: nat, dk: deckey, ekseed: seed, ek: enckey; RequestorEpoch(SentEk(ep, dk, ekseed, ek)) = ep;
forall ep: nat, dk: deckey, ekseed: seed, ek: enckey, ct1: bitstring; RequestorEpoch(SentEkReceivedCt1(ep, dk, ekseed, ek, ct1)) = ep
.
(* Requestor/EK Generator Functions *)
letfun sendHeader(req: eksender, auth: authenticator) =
let NeedToSample(ep) = req in
let (dk: deckey, ekseed: seed, ek: enckey) = kem_keygen() in
let ek_hash = h((ekseed, ek)) in
let header_mac = mac_header(auth, ep, ekseed, ek_hash) in
(SentHeader(ep, dk, ekseed, ek), (ekseed, ek_hash, header_mac))
.
letfun sendEK(req: eksender, auth: authenticator) =
let SentHeader(ep, dk, ekseed, ek) = req in
(SentEk(ep, dk, ekseed, ek), ek)
else let ReceivedCt1(ep, dk, ekseed, ek, ct1) = req in
(SentEkReceivedCt1(ep, dk, ekseed, ek, ct1), ek)
.
letfun recvCT1(req: eksender, ct1: bitstring) =
let SentEk(ep, dk, ekseed, ek) = req in
SentEkReceivedCt1(ep, dk, ekseed, ek, ct1)
else let SentHeader(ep, dk, ekseed, ek) = req in
ReceivedCt1(ep, dk, ekseed, ek, ct1)
.
letfun recvCT2(req: eksender, auth: authenticator, ct2: bitstring, ct_mac: bitstring) =
let SentEkReceivedCt1(ep, dk, ekseed, ek, ct1) = req in
let ss = kem_decap(dk, ct1, ct2) in
let k = kdf(ss, (h((ekseed,ek)), ep, cka_label)) in
let new_auth = auth_update(auth, k) in
if mac_ct(new_auth, ct1, ct2) = ct_mac then
(Waiting(ep+1), (new_auth, ep, k))
.
reduc forall ep: nat; ResponderEpoch(Waiting(ep)) = ep;
forall ep: nat, ekseed: seed, ek_hash: bitstring; ResponderEpoch(ReceivedHeader(ep, ekseed, ek_hash)) = ep;
forall ep: nat, r: ctsecret, ekseed: seed, ek_hash: bitstring, ct1: bitstring, k: symkey; ResponderEpoch(SentCt1(ep, r, ekseed, ek_hash, ct1, k)) = ep;
forall ep: nat, r: ctsecret, ekseed: seed, ek: enckey, ct1: bitstring, k: symkey; ResponderEpoch(SentCt1ReceivedEk(ep, r, ekseed, ek, ct1, k)) = ep;
forall ep: nat, k: symkey; ResponderEpoch(SentCt2(ep, k)) = ep
.
letfun recvHeader(rsp: ctsender, auth: authenticator, ekseed: seed, ek_hash: bitstring, header_mac: bitstring) =
let Waiting(ep) = rsp in
if mac_header(auth, ep, ekseed, ek_hash) = header_mac then
ReceivedHeader(ep, ekseed, ek_hash)
.
letfun sendCT1(rsp: ctsender, auth: authenticator) =
let ReceivedHeader(ep, ekseed, ek_hash) = rsp in
new r: ctsecret;
new sk: symkey;
let ct1 = pkenc1(r, ekseed, sk) in
let k = kdf(sk, (ek_hash, ep, cka_label)) in
let new_auth = auth_update(auth, k) in
(SentCt1(ep, r, ekseed, ek_hash, ct1, k), (new_auth, ct1))
.
(* we can probably get rid of SentCt1ReceivedEk and go straight to SentCt2 here *)
letfun recvEK(rsp: ctsender, auth: authenticator, ek: enckey) =
let SentCt1(ep, r, ekseed, ek_hash, ct1, k) = rsp in
if ek_hash = h((ekseed, ek)) then
SentCt1ReceivedEk(ep, r, ekseed, ek, ct1, k)
.
letfun sendCT2(rsp: ctsender, auth: authenticator) =
let SentCt1ReceivedEk(ep, r, ekseed, ek, ct1, k) = rsp in
let ct2: bitstring = pkenc2(r, ek) in
let ct_mac = mac_ct(auth, ct1, ct2) in
(SentCt2(ep, k), (ct2, ct_mac))
.
letfun takeResponderKey(rsp: ctsender) =
let SentCt2(ep, k) = rsp in
(NeedToSample(ep+1), (ep,k))
.
(* Main processes *)
free A: principal.
free B: principal.
table AStates(principal, principal, eksender, authenticator).
table BStates(principal, principal, ctsender, authenticator).
event StartedA(principal, principal, nat, seed).
event CompletedA(principal, principal, nat, symkey).
event StartedB(principal, principal, nat, seed).
event CompletedB(principal, principal, nat, symkey).
letfun max_epoch() = 5.
let SendEk0() =
get AStates(a, b, req, auth) in
let (req': eksender, (ekseed: seed, ek_hash: bitstring, header_mac: bitstring)) = sendHeader(req, auth) in
let ep = RequestorEpoch(req') in
event StartedA(a, b, ep, ekseed);
out(c, (ekseed, ek_hash, header_mac));
insert AStates(a, b, req', auth).
let SendEk1a() =
get AStates(a, b, req, auth) in
in (c, ct1: bitstring);
let req' = recvCT1(req, ct1) in
insert AStates(a, b, req', auth)
.
let SendEk1b() =
get AStates(a, b, req, auth) in
let (req': eksender, ek: enckey) = sendEK(req, auth) in
out(c, ek);
insert AStates(a, b, req', auth)
.
let SendEk2() =
get AStates(a, b, req, auth) in
in (c, (ct2: bitstring, ct_mac: bitstring));
let (req': ctsender,
(new_auth: authenticator,
ep: nat,
k: symkey)) = recvCT2(req, auth, ct2, ct_mac) in
event CompletedA(a, b, ep, k);
if ep < max_epoch() then insert BStates(a, b, req', new_auth).
let SendEkProc() =
SendEk0() | SendEk1a() | SendEk1b() | SendEk2()
.
let SendCt0() =
get BStates(b, a, rsp, auth) in
let ep = ResponderEpoch(rsp) in
in(c, (ekseed: seed, ek_hash: bitstring, header_mac: bitstring));
event StartedB(b, a, ep, ekseed);
let rsp' = recvHeader(rsp, auth, ekseed, ek_hash, header_mac) in
insert BStates(b, a, rsp', auth)
.
let SendCt1() =
get BStates(b, a, rsp, auth) in
let (rsp': ctsender, (new_auth: authenticator, ct1: bitstring)) = sendCT1(rsp, auth) in
out (c, ct1);
insert BStates(b, a, rsp', new_auth)
.
let SendCt2() =
get BStates(b, a, rsp, auth) in
in(c, ek: enckey);
let rsp': ctsender = recvEK(rsp, auth, ek) in
insert BStates(b, a, rsp', auth)
.
let SendCt3() =
get BStates(b, a, rsp, auth) in
let (rsp': ctsender, (ct2: bitstring, ct_mac: bitstring)) = sendCT2(rsp, auth) in
out(c, (ct2, ct_mac));
let (rsp'': eksender, (ep: nat, k: symkey)) = takeResponderKey(rsp') in
event CompletedB(b, a, ep, k);
if ep < max_epoch() then insert AStates(b, a, rsp'', auth)
.
let SendCtProc() =
SendCt0() | SendCt1() | SendCt2() | SendCt3()
.
(* Compromise Scenarions *)
event CompromisedKeysA(principal, principal, nat).
let CompromiseKeysA(a: principal, b:principal, ep:nat) =
(get AStates(=a, =b, req, auth) in
let SentHeader(=ep, dk, ekseed, ek) = req in
event CompromisedKeysA(a,b,ep);
out(c,dk)
else let ReceivedCt1(=ep, dk, ekseed, ek, ct1) = req in
event CompromisedKeysA(a,b,ep);
out(c,dk)
else let SentEk(=ep, dk, ekseed, ek) = req in
event CompromisedKeysA(a,b,ep);
out(c,dk)
else let SentEkReceivedCt1(=ep, dk, ekseed, ek, ct1) = req in
event CompromisedKeysA(a,b,ep);
out(c,dk))
.
event CompromisedAuthA(principal, principal, nat).
let CompromiseAuthA(a: principal, b:principal, ep:nat) =
(get AStates(=a, =b, req, auth) in
if ep = RequestorEpoch(req) then (
event CompromisedAuthA(a,b,ep);
out(c,auth)))
.
event CompromisedKeysB(principal, principal, nat).
let CompromiseKeysB(a: principal, b:principal, ep:nat) =
(get BStates(=a, =b, rsp, auth) in
let SentCt1(=ep, r, ekseed, ek_hash, ct1, k) = rsp in
event CompromisedKeysB(a,b,ep);
out(c,(r,k))
else let SentCt1ReceivedEk(=ep, r, ekseed, ek, ct1, k) = rsp in
event CompromisedKeysB(a,b,ep);
out(c,(r,k))
else let SentCt2(=ep, k) = rsp in
event CompromisedKeysB(a,b,ep);
out(c,k))
.
event CompromisedAuthB(principal, principal, nat).
let CompromiseAuthB(a: principal, b: principal, ep: nat) =
(get BStates(=a, =b, rsp, auth) in
if ep = ResponderEpoch(rsp) then (
event CompromisedAuthB(a,b,ep);
out(c,auth)))
.
(* Security Queries *)
(* Reachability Queries *)
query ep:nat, ek:seed;
event(StartedA(A,B,4,ek));
event(StartedB(B,A,4,ek))
.
query ep:nat, sk:symkey;
event(CompletedA(A,B,4,sk));
event(CompletedB(B,A,4,sk))
.
query ep:nat, ek:seed;
event(StartedA(B,A,3,ek));
event(StartedB(A,B,3,ek))
.
query ep:nat, sk:symkey;
event(CompletedA(B,A,3,sk));
event(CompletedB(A,B,3,sk))
.
(* Confidentiality Queries *)
query i: time, j: time, ep:nat, sk:symkey, ep_:nat, x:principal, y:principal;
event(CompletedA(A,B,0,sk)) && attacker(sk);
event(CompletedB(B,A,0,sk)) && attacker(sk);
event(CompletedA(B,A,1,sk)) && attacker(sk);
event(CompletedB(A,B,1,sk)) && attacker(sk);
event(CompletedA(A,B,2,sk)) && attacker(sk);
event(CompletedB(B,A,2,sk)) && attacker(sk);
event(CompletedA(B,A,3,sk)) && attacker(sk);
event(CompletedB(A,B,3,sk)) && attacker(sk);
event(CompletedA(x,y,ep,sk)) && attacker(sk) ==>
event(CompromisedKeysB(y,x,ep));
event(CompletedA(x,y,ep,sk)) && attacker(sk) ==>
event(CompromisedKeysA(x,y,ep));
event(CompletedB(x,y,ep,sk)) && attacker(sk) ==>
event(CompromisedKeysB(x,y,ep));
event(CompletedB(x,y,ep,sk)) && attacker(sk) ==>
event(CompromisedKeysA(y,x,ep));
event(CompletedA(x,y,ep,sk)) && attacker(sk) ==>
(event(CompromisedKeysA(x,y,ep)) || event(CompromisedKeysB(y,x,ep)));
event(CompletedB(x,y,ep,sk)) && attacker(sk) ==>
(event(CompromisedKeysB(x,y,ep)) || event(CompromisedKeysA(y,x,ep)));
(* An epoch key can be known to the attacker if either the states in that
epoch were compromised, or the MAC key or some prior epoch was compromised.
Compromising later keys has no effect. This encodes Forward Secrecy. *)
(* Furthermore, since we compromise all authentication keys in phase 1,
this also encodes post-compromise security *)
event(CompletedA(x,y,ep,sk))@i && attacker(sk) ==>
(event(CompromisedKeysA(x,y,ep)) || event(CompromisedKeysB(y,x,ep)) ||
(ep_ <= ep && event(CompromisedAuthA(y,x,ep_))@j && j < i) ||
(ep_ <= ep && event(CompromisedAuthA(x,y,ep_))@j && j < i) ||
(ep_ <= ep && event(CompromisedAuthB(x,y,ep_))@j && j < i) ||
(ep_ <= ep && event(CompromisedAuthB(y,x,ep_))@j && j < i));
event(CompletedB(x,y,ep,sk))@i && attacker(sk) ==>
(event(CompromisedKeysB(x,y,ep)) || event(CompromisedKeysA(y,x,ep)) ||
(ep_ <= ep && event(CompromisedAuthA(x,y,ep_))@j && j < i
(* && event(CompletedA(A,B,ep-1,sk')) && attacker(sk') *)) ||
(ep_ <= ep && event(CompromisedAuthA(y,x,ep_))@j && j < i
(* && event(CompletedA(A,B,ep-1,sk')) && attacker(sk') *)) ||
(ep_ <= ep && event(CompromisedAuthB(x,y,ep_))@j && j < i)||
(ep_ <= ep && event(CompromisedAuthB(y,x,ep_))@j && j < i))
.
(* Authentication Queries *)
query x: principal, y: principal, ep, ep_:nat, ek:seed, sk:symkey;
event(CompletedB(y,x,ep,sk)) ==> event(StartedA(x,y,ep,ek));
event(CompletedB(y,x,ep,sk)) ==>
(event(StartedA(x,y,ep,ek)) ||
(ep_ <= ep && (event(CompromisedAuthA(x,y,ep_)) || event(CompromisedAuthA(y,x,ep_))
|| event(CompromisedAuthB(y,x,ep_)) || event(CompromisedAuthB(x,y,ep_)))));
event(CompletedA(x,y,ep,sk)) ==> event(StartedB(y,x,ep,ek));
event(CompletedA(x,y,ep,sk)) ==>
(event(StartedB(y,x,ep,ek)) ||
(ep_ <= ep && (event(CompromisedAuthA(x,y,ep_)) || event(CompromisedAuthA(y,x,ep_))
|| event(CompromisedAuthB(y,x,ep_)) || event(CompromisedAuthB(x,y,ep_)))))
.
process
new authAB: authenticator;
insert AStates(A, B, NeedToSample(0), authAB);
insert BStates(B, A, Waiting(0), authAB);
(!SendEkProc() | !SendCtProc() |
(* Compromise Scenarios: comment out different options below to experiment *)
(* Compromise Private Keys *)
CompromiseKeysA(A,B,0) | (* CompromiseKeysB(B,A,0) |
CompromiseKeysA(B,A,1) | CompromiseKeysB(A,B,1) |
CompromiseKeysA(A,B,2) | *) CompromiseKeysB(B,A,2) |
(* CompromiseKeysA(B,A,3) | CompromiseKeysB(A,B,3) |
CompromiseKeysA(B,A,4) | CompromiseKeysB(A,B,4) | *)
(* Compromise MAC Keys *)
(* CompromiseAuthA(A,B,0) | CompromiseAuthB(B,A,0) |
CompromiseAuthA(B,A,1) | CompromiseAuthB(A,B,1) |
CompromiseAuthA(A,B,2) | CompromiseAuthB(B,A,2) |
CompromiseAuthA(B,A,3) | CompromiseAuthB(A,B,3) |
CompromiseAuthA(B,A,4) |*) CompromiseAuthB(A,B,4) |
(* Post-Compromise Secrecy: Passively Compromise MAC Keys *after* all epochs are done *)
(phase 1; (out(c,authAB) |
(in (c,(x:principal, y:principal, ep:nat));
(CompromiseAuthA(x,y,ep) | CompromiseAuthB(x,y,ep))))))
+162
View File
@@ -0,0 +1,162 @@
type dir.
free a2b:dir.
free b2a:dir.
table SharedKeys(principal, principal, dir, nat, symkey). (* a,b,dir,epoch,k: if dir is a2b then a as initiator esablished k at epoch ep with b using SPQR *)
table RootKeys(principal, principal, dir, nat, symkey). (* a <-> b: dir, epoch, rk *)
table ChainKeys(principal, principal, dir, nat, nat, symkey). (* a <-> b: dir, epoch, ctr, ck *)
table MsgKeys(principal, principal, dir, nat, nat, symkey). (* a <-> b: dir, epoch, ctr, mk *)
letfun max_epoch() = 3.
letfun max_ctr() = 3.
free root_key_label: bitstring.
free send_chain_key_label: bitstring.
free recv_chain_key_label: bitstring.
event CompromisedSharedKey(principal, principal, dir, nat).
let CKA_Key0(a:principal, b:principal) =
(new k:symkey;
insert SharedKeys(a, b, a2b, 0, k);
insert SharedKeys(b, a, b2a, 0, k))
(* We should allow attacker to choose 2 different keys *)
| (in (c, k:symkey);
event CompromisedSharedKey(a, b, a2b, 0);
insert SharedKeys(a, b, a2b, 0, k);
insert SharedKeys(b, a, b2a, 0, k)).
let CKA_KeyN(a:principal, b:principal) =
get SharedKeys(=a, =b, =a2b, ep, oldk) in
if ep+1 <= max_epoch() then (
(new k:symkey;
insert SharedKeys(a, b, a2b, ep+1, k);
insert SharedKeys(b, a, b2a, ep+1, k))
(* We should allow attacker to choose 2 different keys *)
| (in (c, k:symkey);
event CompromisedSharedKey(a, b, a2b, ep+1);
insert SharedKeys(a, b, a2b, ep+1, k);
insert SharedKeys(b, a, b2a, ep+1, k))).
event RootKey(principal, principal, dir, nat, symkey).
letfun SR_InitState(a:principal, b:principal, d:dir) =
get SharedKeys(=a, =b, =d, 0, k) in
let rk = kdf(k, root_key_label) in
let cks = kdf(k, send_chain_key_label) in
let ckr = kdf(k, recv_chain_key_label) in
event RootKey(a, b, d, 0, rk);
insert RootKeys(a, b, d, 0, rk);
if d = a2b then (
insert ChainKeys(a, b, a2b, 0, 0, cks);
insert ChainKeys(a, b, b2a, 0, 0, ckr);
0)
else (
insert ChainKeys(a, b, a2b, 0, 0, ckr);
insert ChainKeys(a, b, b2a, 0, 0, cks);
0).
letfun SR_NextEpoch(a:principal, b:principal, ep_:nat) =
get RootKeys(=a, =b, d, ep, rk) in
get SharedKeys(=a, =b, =d, key_epoch, k) in
if ep + 1 = key_epoch && key_epoch <= max_epoch() then (
let nrk = kdf(rk, (k,root_key_label)) in
let cks = kdf(rk, (k,send_chain_key_label)) in
let ckr = kdf(rk, (k,recv_chain_key_label)) in
event RootKey(a, b, d, key_epoch, nrk);
insert RootKeys(a, b, d, key_epoch, nrk);
if d = a2b then (
insert ChainKeys(a, b, a2b, key_epoch, 0, cks);
insert ChainKeys(a, b, b2a, key_epoch, 0, ckr);
0)
else (
insert ChainKeys(a, b, a2b, key_epoch, 0, ckr);
insert ChainKeys(a, b, b2a, key_epoch, 0, cks);
0))
else 0.
free chain_key_ratchet_label: bitstring.
free msg_key_label: bitstring.
event MsgKey(principal, principal, dir, nat, nat, symkey).
letfun SR_NextCtr(a:principal, b:principal, d:dir, key_epoch:nat, ctr:nat) =
get ChainKeys(=a, =b, =d, =key_epoch, =ctr, ck) in
if ctr + 1 <= max_ctr() then (
let nck = kdf(ck, chain_key_ratchet_label) in
let mk = kdf(ck, msg_key_label) in
insert ChainKeys(a, b, d, key_epoch, ctr+1, nck);
event MsgKey(a, b, d, key_epoch, ctr, mk);
insert MsgKeys(a, b, d, key_epoch, ctr, mk);
0)
else 0.
let SR_Init(a:principal, b:principal, d:dir) =
let r = SR_InitState(a, b, d) in
0.
let SR_AddEpoch(a:principal, b:principal) =
get RootKeys(=a, =b, d, ep, rk) in
let r = SR_NextEpoch(a, b, ep) in
0.
let SR_NextKey(a:principal, b:principal) =
get ChainKeys(=a, =b, d, ep, ctr, ck) in
let s0 = SR_NextCtr(a, b, d, ep, ctr) in
0.
event CompromisedRootKey(principal, principal, dir, nat, symkey).
event CompromisedChainKey(principal, principal, dir, nat, nat, symkey).
let CompromiseState(a:principal) =
(get RootKeys(=a, b, d, ep, rk) in
event CompromisedRootKey(a,b,d,ep,rk);
out (c,rk))
| (get ChainKeys(=a, b, d, ep, ctr, ck) in
event CompromisedChainKey(a,b,d,ep,ctr,ck);
out (c,ck)).
free A:principal.
free B:principal.
(* Reachability Queries *)
query a:principal, b:principal, ep:nat, ctr:nat, k:symkey;
event(MsgKey(a,b,a2b,0,0,k));
event(MsgKey(a,b,b2a,0,0,k));
event(MsgKey(a,b,a2b,2,2,k));
event(MsgKey(a,b,b2a,2,2,k)).
(* Confidentiality Queries *)
query a:principal, b:principal, ep:nat, ctr:nat, k:symkey, kk:symkey, ep_:nat;
event(MsgKey(a,b,a2b,0,0,k)) && attacker(k);
event(MsgKey(a,b,b2a,0,0,k)) && attacker(k);
(* Confidentiality for first epoch *)
(* Forward secrecy: Compromising later keys makes no difference *)
event(MsgKey(a,b,a2b,0,0,k)) && attacker(k) ==>
(event(CompromisedSharedKey(a,b,a2b,0)) ||
event(CompromisedSharedKey(b,a,a2b,0)));
(* Confidentiality for first epoch *)
(* Forward secrecy: Compromising later keys makes no difference *)
(* Post-Compromise Security: Compromising earlier keys makes no difference *)
event(MsgKey(a,b,a2b,ep+1,0,k)) && attacker(k) ==>
(event(CompromisedSharedKey(a,b,a2b,ep+1)) ||
event(CompromisedSharedKey(b,a,a2b,ep+1))).
process
CKA_Key0(A,B) |
!CKA_KeyN(A,B) |
!SR_Init(A,B,a2b) |
!SR_Init(B,A,b2a) |
!SR_AddEpoch(A,B) |
!SR_AddEpoch(B,A) |
!SR_NextKey(A,B) |
!SR_NextKey(B,A) (* |
!CompromiseState(A) |
!CompromiseState(B) *)