hash h
hash h1
hash h2
hash h3

abstract ok : message
abstract error : message

abstract TSinit : message
abstract TSorderOk : message
abstract TSorder : message * message -> message
abstract TSnext : message -> message

name k : message

name key1 : index -> message
name key2 : index -> message
name key3 : index -> message
name pin : index -> message
name idinit : index -> message

mutable kT(i:index) : message = <idinit(i),TSinit>
mutable kR(ii:index) : message = idinit(ii)
mutable TS : message = TSinit

channel cT
channel cR

(* i = tag's identity, j = tag's session for identity i *)
process tag(i:index,j:index) =
in(cR, x1);
if fst(x1) = h(snd(x1),k) && TSorder(snd(kT(i)),snd(x1)) = TSorderOk then
(out(cT, h1(fst(kT(i)),key1(i)));
in(cR, x3);
if x3 = h2(<fst(kT(i)),pin(i)>,key2(i)) then
(kT(i) := <h3(<<fst(kT(i)),pin(i)>,snd(x1)>,key3(i)), snd(x1)>;
out(cT, ok))
else
out(cT, error))
else
out(cT, error)

(* jj = generic reader's session *)
process reader(jj:index) =
TS := TSnext(TS);
out(cR, <h(TS,k),TS>);
in(cT, x2);
try find ii such that x2 = h1(kR(ii), key1(ii)) in
let m = h2(<kR(ii),pin(ii)>,key2(ii)) in
kR(ii) := h3(<<kR(ii),pin(ii)>,TS>,key3(ii));
out(cR, m)
else
out(cR, error)

system ((!_jj R: reader(jj)) | (!_i !_j T: tag(i,j))).
Typed-check process:

null

Added action dependencies lemmas:


System after processing:

null

System Empty registered with actions (init).
[warning>Loaded "Prelude.sp".
<]global axiom namelength_k {'P:system} @system:(set:'P; equiv:None) :
[len k = namelength_message]
global axiom namelength_key1 {'P:system} @system:(set:'P; equiv:None) :
[forall (i:index), len (key1 i) = namelength_message]
global axiom namelength_key2 {'P:system} @system:(set:'P; equiv:None) :
[forall (i:index), len (key2 i) = namelength_message]
global axiom namelength_key3 {'P:system} @system:(set:'P; equiv:None) :
[forall (i:index), len (key3 i) = namelength_message]
global axiom namelength_pin {'P:system} @system:(set:'P; equiv:None) :
[forall (i:index), len (pin i) = namelength_message]
global axiom namelength_idinit {'P:system} @system:(set:'P; equiv:None) :
[forall (i:index), len (idinit i) = namelength_message]
process tag (i,j:index) =
in(cR,x1);
if fst x1 = h (snd x1, k) && TSorder (snd (kT i@τ), snd x1) = TSorderOk then
out(cT,h1 (fst (kT i@τ), key1 i));
in(cR,x3);
if x3 = h2 (<fst (kT i@τ),pin i>, key2 i) then
kT(i) := <h3 (<<fst (kT i@τ),pin i>,snd x1>, key3 i),snd x1>;
out(cT,ok);
null
else
out(cT,error); null
else
out(cT,error); null
process reader (jj:index) =
TS := TSnext (TS@τ);
out(cR,<h (TS@τ, k),TS@τ>);
in(cT,x2);
find (ii) such that x2 = h1 (kR ii@τ, key1 ii) in
let m : message = h2 (<kR ii@τ,pin ii>, key2 ii) in
kR(ii) := h3 (<<kR ii@τ,pin ii>,TS@τ>, key3 ii);
out(cR,m);
null
else
out(cR,error); null
Typed-check process:

( !_jj( R: reader jj) ) | !_i( !_j( T: tag i j))

Added action dependencies lemmas:

axiom mutex_T3_T2 {'P:system[like default]} @system:(set:'P; equiv:None) :
forall (i,j:index), not happens(T3(i, j)) || not happens(T2(i, j))
axiom mutex_T3_T1 {'P:system[like default]} @system:(set:'P; equiv:None) :
forall (i,j:index), not happens(T3(i, j)) || not happens(T1(i, j))
axiom mutex_T3_T {'P:system[like default]} @system:(set:'P; equiv:None) :
forall (i,j:index), not happens(T3(i, j)) || not happens(T(i, j))
axiom mutex_T2_T3 {'P:system[like default]} @system:(set:'P; equiv:None) :
forall (i,j:index), not happens(T2(i, j)) || not happens(T3(i, j))
axiom mutex_T2_T1 {'P:system[like default]} @system:(set:'P; equiv:None) :
forall (i,j:index), not happens(T2(i, j)) || not happens(T1(i, j))
axiom mutex_T1_T3 {'P:system[like default]} @system:(set:'P; equiv:None) :
forall (i,j:index), not happens(T1(i, j)) || not happens(T3(i, j))
axiom mutex_T1_T2 {'P:system[like default]} @system:(set:'P; equiv:None) :
forall (i,j:index), not happens(T1(i, j)) || not happens(T2(i, j))
axiom mutex_T_T3 {'P:system[like default]} @system:(set:'P; equiv:None) :
forall (i,j:index), not happens(T(i, j)) || not happens(T3(i, j))
axiom depends_T_T2 {'P:system[like default]} @system:(set:'P; equiv:None) :
forall (i,j:index), happens(T2(i, j)) => T(i, j) < T2(i, j)
axiom depends_T_T1 {'P:system[like default]} @system:(set:'P; equiv:None) :
forall (i,j:index), happens(T1(i, j)) => T(i, j) < T1(i, j)
axiom mutex_R2_R1 {'P:system[like default]} @system:(set:'P; equiv:None) :
forall (jj,ii:index), not happens(R2(jj)) || not happens(R1(jj, ii))
axiom mutex_R1_R2 {'P:system[like default]} @system:(set:'P; equiv:None) :
forall (jj,ii:index), not happens(R1(jj, ii)) || not happens(R2(jj))
axiom depends_R_R2 {'P:system[like default]} @system:(set:'P; equiv:None) :
forall (jj:index), happens(R2(jj)) => R(jj) < R2(jj)
axiom depends_R_R1 {'P:system[like default]} @system:(set:'P; equiv:None) :
forall (jj,ii:index), happens(R1(jj, ii)) => R(jj) < R1(jj, ii)
axiom depends_init_T3 {'P:system[like default]} @system:(set:'P; equiv:None)
: forall (i,j:index), happens(T3(i, j)) => init < T3(i, j)
axiom depends_init_T2 {'P:system[like default]} @system:(set:'P; equiv:None)
: forall (i,j:index), happens(T2(i, j)) => init < T2(i, j)
axiom depends_init_T1 {'P:system[like default]} @system:(set:'P; equiv:None)
: forall (i,j:index), happens(T1(i, j)) => init < T1(i, j)
axiom depends_init_T {'P:system[like default]} @system:(set:'P; equiv:None) :
forall (i,j:index), happens(T(i, j)) => init < T(i, j)
axiom depends_init_R2 {'P:system[like default]} @system:(set:'P; equiv:None)
: forall (jj:index), happens(R2(jj)) => init < R2(jj)
axiom depends_init_R1 {'P:system[like default]} @system:(set:'P; equiv:None)
: forall (jj,ii:index), happens(R1(jj, ii)) => init < R1(jj, ii)
axiom depends_init_R {'P:system[like default]} @system:(set:'P; equiv:None) :
forall (jj:index), happens(R(jj)) => init < R(jj)

System after processing:

( !_jj(
TS := TSnext (TS@τ);
R: out(cR,<h (TS@τ, k),TS@τ>);
in(cT,x2);
find (ii) such that x2 = h1 (kR ii@τ, key1 ii) in
let m : message = h2 (<kR ii@τ,pin ii>, key2 ii) in
kR(ii) := h3 (<<kR ii@τ,pin ii>,TS@τ>, key3 ii);
R1: out(cR,m jj ii@τ);
null
else
R2: out(cR,error); null) ) |
!_i(
!_j(
in(cR,x1);
if fst x1 = h (snd x1, k) &&
TSorder (snd (kT i@τ), snd x1) = TSorderOk then
T: out(cT,h1 (fst (kT i@τ), key1 i));
in(cR,x3);
if x3 = h2 (<fst (kT i@τ),pin i>, key2 i) then
kT(i) :=
<h3 (<<fst (kT i@τ),pin i>,snd (input@T(i, j))>, key3 i),
snd (input@T(i, j))>;
T1: out(cT,ok);
null
else
T2: out(cT,error); null
else
T3: out(cT,error); null))

System Empty registered with actions (init).
System default registered with actions (init,R,R1,R2,T,T1,T2,T3).

SLK06

T. van Deursen and S. Radomirović, ‘Attacks on RFID Protocols’, Cryptology ePrint Archive, vol. 2008, no. 310, pp. 1–56, Aug. 2009.

The protocol assumes that the reader and tag share the secrets k, ID, and PIN. While ID and PIN are unique to each tag, k is equal for all tags the reader is allowed to authenticate. The tag further stores the timestamp TSlast of the last successful mutual authentication initialized to 0 at the factory.

R -> T : <h(k,TS),TS> T -> R : h(ID) if TS > TSlast ID := h(ID,PIN,TS) TSlast := TS R -> T : h(ID,PIN) ID’ := h(ID,PIN,TS)

COMMENTS - In this model we use 3 different keyed hash functions, instead of a single (not keyed) hash function as in the specification.

SECURITY PROPERTIES - authentication (reader and tag) ******************************************************************************



(* SECURITY PROPERTIES *)

lemma auth_R1 (jj,ii:index):
happens(R1(jj,ii)) =>
cond@R1(jj,ii) =>
exists (j:index),
T(ii,j) < R1(jj,ii) && output@T(ii,j) = input@R1(jj,ii).
Goal auth_R1 :
happens(R1(jj, ii)) =>
cond@R1(jj, ii) =>
exists (j:index),
T(ii, j) < R1(jj, ii) && output@T(ii, j) = input@R1(jj, ii)

Proof.
[goal> Focused goal (1/1):
System: (set:default; equiv:None)
Variables: ii,jj:index
----------------------------------------
happens(R1(jj, ii)) =>
cond@R1(jj, ii) =>
exists (j:index), T(ii, j) < R1(jj, ii) && output@T(ii, j) = input@R1(jj, ii)


intro Hap @/cond Hcond.
[> Line 93: (intro) [goal> Focused goal (1/1):
System: (set:default; equiv:None)
Variables: ii,jj:index[const]
Hap: happens(R1(jj, ii))
Hcond: input@R1(jj, ii) = h1 (kR ii@pred (R1(jj, ii)), key1 ii)
----------------------------------------
exists (j:index), T(ii, j) < R1(jj, ii) && output@T(ii, j) = input@R1(jj, ii)


euf Hcond.
[> Line 94: (euf) Indirect bad occurrences of key key1(ii), and messages authenticated by it
in other actions:
fst (kT i@T(i, j)) auth. by key1(i)
(collision with kR ii@pred (R1(jj, ii)) auth. by key1(ii))
in action T(i, j)
in term (happens(T(i, j)), h1 (fst (kT i@T(i, j)), key1 i))

Total: 1 occurrence
0 of them are subsumed by another
1 occurrence remaining

[goal> Focused goal (1/1):
System: (set:default; equiv:None)
Variables: ii,jj:index[const]
Hap: happens(R1(jj, ii))
Hcond: input@R1(jj, ii) = h1 (kR ii@pred (R1(jj, ii)), key1 ii)
----------------------------------------
(exists (j:index),
T(ii, j) < R1(jj, ii) && kR ii@pred (R1(jj, ii)) = fst (kT ii@T(ii, j)))
=>
exists (j:index), T(ii, j) < R1(jj, ii) && output@T(ii, j) = input@R1(jj, ii)


intro [j _].
[> Line 95: (intro) [goal> Focused goal (1/1):
System: (set:default; equiv:None)
Variables: ii,j,jj:index[const]
Hap: happens(R1(jj, ii))
Hcond: input@R1(jj, ii) = h1 (kR ii@pred (R1(jj, ii)), key1 ii)
_: T(ii, j) < R1(jj, ii) && kR ii@pred (R1(jj, ii)) = fst (kT ii@T(ii, j))
----------------------------------------
exists (j:index), T(ii, j) < R1(jj, ii) && output@T(ii, j) = input@R1(jj, ii)


by exists j.
[> Line 96: by (exists) [goal> lemma auth_R1 is proved


Qed.
lemma auth_R1 @system:(set:default; equiv:None) :
forall (jj,ii:index),
happens(R1(jj, ii)) =>
cond@R1(jj, ii) =>
exists (j:index),
T(ii, j) < R1(jj, ii) && output@T(ii, j) = input@R1(jj, ii)
Exiting proof mode.



lemma auth_T1 (i,j:index):
happens(T1(i,j)) =>
cond@T1(i,j) =>
exists (jj:index),
R1(jj,i) < T1(i,j) && output@R1(jj,i) = input@T1(i,j).
Goal auth_T1 :
happens(T1(i, j)) =>
cond@T1(i, j) =>
exists (jj:index),
R1(jj, i) < T1(i, j) && output@R1(jj, i) = input@T1(i, j)

Proof.
[goal> Focused goal (1/1):
System: (set:default; equiv:None)
Variables: i,j:index
----------------------------------------
happens(T1(i, j)) =>
cond@T1(i, j) =>
exists (jj:index), R1(jj, i) < T1(i, j) && output@R1(jj, i) = input@T1(i, j)


intro Hap @/cond Hcond.
[> Line 105: (intro) [goal> Focused goal (1/1):
System: (set:default; equiv:None)
Variables: i,j:index[const]
Hap: happens(T1(i, j))
Hcond: input@T1(i, j) = h2 (<fst (kT i@pred (T1(i, j))),pin i>, key2 i)
----------------------------------------
exists (jj:index), R1(jj, i) < T1(i, j) && output@R1(jj, i) = input@T1(i, j)


euf Hcond.
[> Line 106: (euf) Indirect bad occurrences of key key2(i), and messages authenticated by it
in other actions:
<kR ii@pred (R1(jj, ii)),pin ii> auth. by key2(ii)
(collision with <fst (kT i@pred (T1(i, j))),pin i> auth. by key2(i))
in action R1(jj, ii)
in term (happens(R1(jj, ii)), m jj ii@R1(jj, ii))

Total: 1 occurrence
0 of them are subsumed by another
1 occurrence remaining

[goal> Focused goal (1/1):
System: (set:default; equiv:None)
Variables: i,j:index[const]
Hap: happens(T1(i, j))
Hcond: input@T1(i, j) = h2 (<fst (kT i@pred (T1(i, j))),pin i>, key2 i)
----------------------------------------
(exists (jj:index),
R1(jj, i) < T1(i, j) &&
<fst (kT i@pred (T1(i, j))),pin i> = <kR i@pred (R1(jj, i)),pin i>)
=>
exists (jj:index), R1(jj, i) < T1(i, j) && output@R1(jj, i) = input@T1(i, j)


intro [jj _].
[> Line 107: (intro) [goal> Focused goal (1/1):
System: (set:default; equiv:None)
Variables: i,j,jj:index[const]
Hap: happens(T1(i, j))
Hcond: input@T1(i, j) = h2 (<fst (kT i@pred (T1(i, j))),pin i>, key2 i)
_: R1(jj, i) < T1(i, j) &&
<fst (kT i@pred (T1(i, j))),pin i> = <kR i@pred (R1(jj, i)),pin i>
----------------------------------------
exists (jj:index), R1(jj, i) < T1(i, j) && output@R1(jj, i) = input@T1(i, j)


by exists jj.
[> Line 108: by (exists) [goal> lemma auth_T1 is proved


Qed.
lemma auth_T1 @system:(set:default; equiv:None) :
forall (i,j:index),
happens(T1(i, j)) =>
cond@T1(i, j) =>
exists (jj:index),
R1(jj, i) < T1(i, j) && output@R1(jj, i) = input@T1(i, j)
Exiting proof mode.

Press the left and right arrows to do and undo an instruction.

Alternatively, you can double-click on an instruction.

This zone shows a Squirrel file. You can double-click on a comment to collapse it for better readabilility.

This zone shows the output given by Squirrel.

This zone shows the output of the previous instruction, to help identifying the change caused by the instruction.

Previously: