second iteration
This commit is contained in:
195
proverif/pq/pqxdh.pv
Normal file
195
proverif/pq/pqxdh.pv
Normal file
@@ -0,0 +1,195 @@
|
||||
(*
|
||||
PQXDH; proving authenticity, secrecy, forward secrecy, and quantum forward secrecy
|
||||
Author: jake ginesin
|
||||
|
||||
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 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)).
|
||||
|
||||
(* 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].
|
||||
|
||||
(* events *)
|
||||
event sendE1(bitstring, key).
|
||||
event recvE1(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) =
|
||||
|
||||
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 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, ct)) in
|
||||
event sendE1(m1, mak1);
|
||||
|
||||
out(c, (x1, x1_mac, gae1, ct));
|
||||
|
||||
phase 2;
|
||||
event compromiseSKA(SK_A);
|
||||
out(a, SK_A);
|
||||
|
||||
phase 3;
|
||||
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) =
|
||||
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 *)
|
||||
|
||||
(* first stage: derive bmaster, verfiy a's msgs, decrypt prekey message, reply *)
|
||||
|
||||
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 mbk1 = khash(cb1) in
|
||||
let (mbk1_auth: key, mbk1_enc: key) = hkdf2(mbk1) in
|
||||
if checkmac(mbk1_auth, concat1(x1, gae1, ct), 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.
|
||||
|
||||
query event(start()). (* reachable from all possible executions *)
|
||||
|
||||
|
||||
(* forward secrecy *)
|
||||
query sk1: skey, sk2: skey; (event(compromiseSKA(sk1)) && event(compromiseSKB(sk2)) && attacker(m1)) ==> false.
|
||||
|
||||
(* secrecy *)
|
||||
query attacker(m1).
|
||||
|
||||
(* forward pq secrecy *)
|
||||
query k1: key, k2: key, k3: key, k4: key; (event(breakDH(k1, k2, k3, k4)) && attacker(m1)) ==> false.
|
||||
|
||||
(* auth *)
|
||||
query m: bitstring, rk: key; event(recvE1(m, rk)) ==> event(sendE1(m, rk)).
|
||||
|
||||
(* reachability *)
|
||||
query m: bitstring, rk: key; event(recvE1(m, rk)). (* reachable from all executions *)
|
||||
query m: bitstring, rk: key; event(sendE1(m, rk)). (* 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);
|
||||
event start();
|
||||
( (PeerA(SK_A, PK_A, PK_B)) |
|
||||
(PeerB(SK_B, PK_B, PK_A)))
|
||||
Reference in New Issue
Block a user