(* Yahalom protocol, version of Paulson

A -> B : A, N_A
B -> S : B, N_B, { c1, A, N_A }_Kbs
S -> A : { B, K_ab, N_A, N_B }_Kas, { c2, A, K_ab }_Kbs
A -> B : { c2, A, K_ab }_Kbs, { N_B }_Kab

*)

set keyCompromise = strict.
set ignoreTypes = true.

free c: channel.

type key.
type host.
type nonce.
type tag.

fun nonce_to_bitstring(nonce): bitstring [data,typeConverter].

(* Shared key encryption *)

fun encrypt(bitstring,key): bitstring.
reduc forall x: bitstring, y: key; decrypt(encrypt(x,y),y) = x.

(* tags *)

const c1:tag [data].
const c2:tag [data].

(* Secrecy assumptions *)

not attacker(new Kas).
not attacker(new Kbs).

(* 2 honest host names A and B *)

free A, B: host.

(* Queries *)

query attacker(new secretB).

event endBkey(host, host, nonce, key).
event beginBkey(host, host, nonce, key).


query x: host, y: host, z: nonce, t: key; inj-event(endBkey(x,y,z,t)) ==> inj-event(beginBkey(x,y,z,t)).

let processInitiator(xA: host, kas: key) =
	(* Real start of the role *)
	new Na: nonce; 
	out(c, (xA, Na)); 
	in(c, (nb: nonce, m1: bitstring, m2: bitstring));
        let (b: host, kab: key, =Na, =nb) = decrypt(m1, kas) in
 	event beginBkey(b, xA, nb, kab); 
        out(c, (m2, encrypt(nonce_to_bitstring(nb), kab))).
                         
(* Role of the responder with identity xB and key kbs shared with S *)
                         
let processResponder(xB: host, kbs: key) =
	new secretB: bitstring;
	in(c, (a: host, na: nonce)); 
	new Nb: nonce; 
	out(c, (xB, Nb, encrypt((c1,a,na), kbs)));
	in(c, (m3: bitstring, m4: bitstring));
        let (=c2, =a, kab: key) = decrypt(m3, kbs) in
        if nonce_to_bitstring(Nb) = decrypt(m4, kab) then
	(* OK *)
        if a = A then
	event endBkey(xB, a, Nb, kab);
	out(c, encrypt(secretB, kab)).

(* Server *)

let processS(a:host, b:host, kas:key, kbs:key) = 
	in(c, (=b, nb: nonce, m5: bitstring));
	let kbs2 = kbs in
 	let (=c1, =a, na: nonce) = decrypt(m5,kbs2) in
	let kas2 = kas in
        new kab: key;
	out(c, (encrypt((b, kab, na, nb), kas2), encrypt((c2, a, kab), kbs2))).


(* Start process *)

process
	new Kas: key; new Kbs: key;
	(
          (* Launch an unbounded number of sessions of the initiator *)
          (!processInitiator(A, Kas)) | 
          (* Launch an unbounded number of sessions of the responder *)
          (!processResponder(B, Kbs)) |
          (* Launch an unbounded number of sessions of the server *)
          (!processS(A, B, Kas, Kbs))
        )


(* EXPECTPV
RESULT not attacker_p1(secretB[!comp = @session1,!1 = v_2]) cannot be proved.
RESULT inj-event(endBkey(@session1,x,y,z,t)) ==> inj-event(beginBkey(v_2,x,y,z,t)) cannot be proved.
RESULT (even event(endBkey(@session1,x,y,z,t)) ==> event(beginBkey(v_2,x,y,z,t)) cannot be proved.)
0.028s (user 0.028s + system 0.000s), max rss 9880K
END *)
