(*

WooLam shared-key auth protocol (1992, computer)
Version of Gordon, Jeffrey, CSFW 2001

A -> B : A
B -> A : N (fresh)
A -> B : { m3, N }_kAS
B -> S : { m4, A,{ m3, N }_kAS }_kBS
S -> B : { m5, N }_kBS
B: verify { m5, N }_kBS = the message from S

Session identifier (A, N)
Authentication in one direction only.
{ m3, N }_kAS is not authenticated because it is just forwarded
by B to the server.
*)

param NA, NB, NS, NK.

type nonce [large,fixed].
type host [bounded].
type key [fixed].
type enc_seed [fixed].
type tag [bounded].


fun concat1(tag, nonce):bitstring [data].
fun concat2(tag, host, bitstring):bitstring [data].

equation forall x:tag, y:nonce, x2:tag, y2:host, z2:bitstring;
	concat1(x,y) <> concat2(x2,y2,z2).

(* Shared-key encryption (IND-CPA + INT-CTXT Stream cipher) *)

proba Penc.
proba Pencctxt.

expand IND_CPA_INT_CTXT_sym_enc_all_args(key, bitstring, bitstring, enc_seed, enc, enc_r, enc_r', dec, injbot, Z, Penc, Pencctxt).

ifdef(`CryptoVerif',`
(* The function Z returns for each bitstring, a bitstring
   of the same length, consisting only of zeroes. *)
fun Zconcat2(bitstring):bitstring.
const Zconcat1:bitstring.
equation forall y:tag, z:nonce; 
	Z(concat1(y,z)) = Zconcat1.
equation forall y:tag, z:host, u:bitstring; 
	Z(concat2(y,z,u)) = Zconcat2(Z(u)).
equation forall x:bitstring, k:key, r:enc_seed;
	Z(enc_r(x,k,r)) = Z(x).
',`
const Zbitstring:bitstring.
equation forall x:bitstring; Z(x) = Zbitstring.
')

(* Queries *)

channel c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14,
	start, finish.

const A: host.
const B: host.
fun acceptA(host):bitstring.
fun acceptB(host):bitstring.


const tag3: tag.
const tag4: tag.
const tag5: tag.

event fullA(host, bitstring).
event fullB(host, bitstring).

query y:bitstring;
	inj-event(fullB(A,y)) ==> inj-event(fullA(B,y)).

let processA(Kas: key) =
	in(c1, hostB2:host); (* Choose the B host *)
	out(c2, A);
	in(c3, n:nonce);
	let e1 = enc(concat1(tag3, n), Kas) in
	event fullA(hostB2, (A, n));
	out(c4, (e1, acceptA(hostB2))).

let processB(Kbs: key) =
	in(c5, hostA2:host);
	new N:nonce;
	out(c6, N);
	in(c7, m:bitstring);
	let e2 = enc(concat2(tag4, hostA2, m), Kbs) in
	out(c8, e2);
	in(c9, m2:bitstring);
	if injbot(concat1(tag5, N)) = dec(m2, Kbs) then
	(* OK *)
	event fullB(hostA2, (hostA2, N));
	out(c14, acceptB(hostA2)).

table keys(host, key).

let processK(Kas:key, Kbs:key) =
   in(c10, (Khost: host, Kkey: key));
   if Khost = A then
      insert keys(A,Kas)
   else if Khost = B then
      insert keys(B,Kbs)
   else
      insert keys(Khost,Kkey).

let processS =
	in(c11, (hostB0:host, m:bitstring));
	get keys(=hostB0, kbs) in
	let injbot(concat2(=tag4, hostA1, m2)) = dec(m, kbs) in
	get keys(=hostA1, kas) in
	let injbot(concat1(=tag3, n)) = dec(m2, kas) in
	let e3 = enc(concat1(tag5, n), kbs) in
	out(c12, e3).


process 
	in(start, ());
	new Kas: key;
	new Kbs: key;
	out(c13, ());
    	((! iA <= NA processA(Kas)) |
	 (! iB <= NB processB(Kbs)) |
	 (! iS <= NS processS) |
	 (! iK <= NK processK(Kas,Kbs)))

(* EXPECTED
RESULT Could not prove inj-event(fullB(A, y)) ==> inj-event(fullA(B, y)).
0.184s (user 0.180s + system 0.004s), max rss 22416K
END *)

(* EXPECTPV
RESULT inj-event(fullB(A,y)) ==> inj-event(fullA(B,y)) is false.
RESULT (even event(fullB(A,y)) ==> event(fullA(B,y)) is false.)
0.036s (user 0.032s + system 0.004s), max rss 10760K
END *)
