
(*header*)
set ignoreTypes=attacker.

type pkey.
type Pkey.
type host.
type ssid.

free c: channel.
free cp:channel [private].
free cp2:channel [private].

free A, B: host.
free secretv:bitstring [private].
query attacker(secretv).

(*functions*)
(* Chiffrement symetrique *)
fun senc(bitstring,bitstring):bitstring.
reduc forall x: bitstring, y: bitstring; sdec(senc(x,y),y) = x.

(* Chiffrement asymetrique *)
fun pk(pkey,host): Pkey.
reduc forall m:pkey, h:host; gethost(pk(m,h))=h.

fun encrypt(bitstring, Pkey): bitstring.
reduc forall x: bitstring, y: pkey, h:host; decrypt(encrypt(x,pk(y,h)),y) = x.

(* Hachage *)
fun hash(bitstring):bitstring.

fun partenaire(ssid,bitstring,bitstring,Pkey,bitstring):bitstring.

(*Process specifications*)

let processB(skA:pkey,skB: pkey) =  
    in (c, Y: host);
    if Y = A || Y = B then
    let skY = if Y = A then skA else skB in
   
    let pkY=pk(skY,Y) in
    in(c,(ra:bitstring,sida:ssid));
    new rb: bitstring;  
    out(c,(rb,sida,pkY));     
    
    in(c,m2: bitstring);
    let (SEEDKEY:bitstring)=decrypt(m2,skY) in
    let Ks = hash((ra,rb,SEEDKEY)) in 
    out(c,Ks); 0. 
   
let processTest(skA:pkey,skB: pkey) =  
    in (c, Y: host);
    if Y = A || Y = B then
    let skY = if Y = A then skA else skB in
   
    let pkY=pk(skY,Y) in
    in(c,(ra:bitstring,sida:ssid));
     new rb: bitstring;  
    out(c,(rb,sida,pkY));     
    
    in(c,m2: bitstring);
    let (SEEDKEY:bitstring)=decrypt(m2,skY) in
    let Ks = hash((ra,rb,SEEDKEY)) in 
    let pTest=partenaire(sida,ra,rb,pkY,m2) in 
    in(cp2,=pTest);
    out(cp,pTest);
    out(c,senc(secretv,Ks)).  

let processA() =
    new ra: bitstring;  
    new sida:ssid; 
    out(c,(ra,sida));
    
    in(c,(rb: bitstring,=sida,pkY:Pkey));                   
    new SEEDKEY:bitstring;
    let ma=encrypt(SEEDKEY,pkY)  in
    let Ks = hash((ra,rb,SEEDKEY)) in     	
    out(c,ma);

    let pA=partenaire(sida,ra,rb,pkY,ma) in  
    out(cp2,pA);in (cp,ptest:bitstring); 
    if pA<>ptest then out(c,Ks) else
    0. 	


process 
	new skA : pkey; let pkA = pk(skA,A) in
	new skB : pkey; let pkB = pk(skB,B) in
	out(c, pkA);
	out(c, pkB);	
	((!processA()) | (!processB(skA,skB)) |(processTest(skA,skB)) ) 
    
