(* Needham Shroeder shared key protocol

The weakness of this protocol is that if an attacker has
a session key k[Kas[], Kbs[], Na[Kbs[],c0]]
for one c0, he can have all secrets of B, since B cannot
distinguish different sessions.

Notice that we have slightly changed the protocol such that
the analyzer terminates. The
	{ Nb }Kab -> { Nb-1 }Kab 
is replaced by
	{ Nb, 0 }Kab -> { Nb, 1 }Kab

Three predicates:
comp:M iff M is a term containing only names of session0
cs0:M iff the attacker can get M in session0
cs1:M iff the attacker can get M in session1 using compromised terms 
of session0.

Rules:
1) rules for comp:
2) comp:x1 & ... & comp:xn -> cs0:a[session0,x1, ..., xn] for every 
session name a
3) the usual rules of the protocol with cs0 and session0
4) cs0:M -> cs1:M
5) the usual rules of the protocol with cs1 and session1

 *)

pred cs0/1 elimVar, decompData.
pred cs1/1 elimVar, decompData.
pred comp/1 elimVar, decompData.

fun encrypt/2.

fun host/1.

(* constants 0 and 1 *)

data c0/0.
data c1/0.

data session0/0.
data session1/0.

not cs0:Kas[].
not cs0:Kbs[].
not cs1:Kas[].
not cs1:Kbs[].

query cs1:secretA[session1].
query cs1:secretB[session1].

reduc

(* Attacker *)

cs0:k & cs0:encrypt(m,k) -> cs0:m;
cs0:host(x);
cs0:x & cs0:y -> cs0:encrypt(x,y);

(* key compromise *)

comp:Kas[];
comp:Kbs[];
comp:x -> comp:Na[x,session0];
comp:x & comp:y -> comp:Nb[x,y,session0];
comp:x & comp:y & comp:z -> comp:k[x,y,z,session0]; 
comp:x -> comp:host(x);
comp:x & comp:y -> comp:encrypt(x,y);
comp:secretA[session0];
comp:secretB[session0];

comp:x -> cs0:Na[x, session0];
comp:x & comp:y -> cs0:Nb[x,y,session0];
comp:x & comp:y & comp:z -> cs0:k[x,y,z,session0]; 
cs0:secretA[session0];
cs0:secretB[session0];


(* A *)

cs0:h -> cs0:(host(Kas[]), h, Na[h,session0]);
cs0:encrypt((Na[h,session0], h, key, m), Kas[]) -> cs0:m;
cs0:encrypt((Na[h,session0], h, key, m), Kas[]) & cs0:encrypt((n, c0), key) -> cs0:encrypt((n, c1), key);

cs0:encrypt((Na[host(Kbs[]),session0], host(Kbs[]), key, m), Kas[]) -> cs0:encrypt(secretA[session0], key);


(* B *)

cs0:encrypt((key, h), Kbs[]) -> cs0:encrypt((Nb[key,h,session0], c0), key);

cs0:encrypt((key, host(Kas[])), Kbs[]) & cs0:encrypt((Nb[key,host(Kas[]),session0], c1), key) -> cs0:encrypt(secretB[session0], key);

(* S *)

cs0:(host(Ks1), host(Ks2), n) -> cs0:encrypt((n, host(Ks2), k[Ks1, Ks2, n, session0], encrypt((k[Ks1, Ks2, n, session0], host(Ks1)), Ks2)), Ks1);

(* Implication *)

cs0:x -> cs1:x;

(* Attacker *)

cs1:k & cs1:encrypt(m,k) -> cs1:m;
cs1:host(x);
cs1:x & cs1:y -> cs1:encrypt(x,y);

(* A *)

cs1:h -> cs1:(host(Kas[]), h, Na[h,session1]);
cs1:encrypt((Na[h,session1], h, key, m), Kas[]) -> cs1:m;
cs1:encrypt((Na[h,session1], h, key, m), Kas[]) & cs1:encrypt((n, c0), key) -> cs1:encrypt((n, c1), key);

cs1:encrypt((Na[host(Kbs[]),session1], host(Kbs[]), key, m), Kas[]) -> cs1:encrypt(secretA[session1], key);


(* B *)

cs1:encrypt((key, h), Kbs[]) -> cs1:encrypt((Nb[key,h,session1], c0), key);

cs1:encrypt((key, host(Kas[])), Kbs[]) & cs1:encrypt((Nb[key,host(Kas[]),session1], c1), key) -> cs1:encrypt(secretB[session1], key);

(* S *)

cs1:(host(Ks1), host(Ks2), n) -> cs1:encrypt((n, host(Ks2), k[Ks1, Ks2, n, session1], encrypt((k[Ks1, Ks2, n, session1], host(Ks1)), Ks2)), Ks1).

(* EXPECTPV
RESULT goal reachable: cs1:secretB[session1()]
RESULT goal unreachable: cs1:secretA[session1()]
0.016s (user 0.012s + system 0.004s), max rss 9260K
END *)
