Theory ZhouGollmann
theory ZhouGollmann imports Public begin
abbreviation
TTP :: agent where "TTP == Server"
abbreviation f_sub :: nat where "f_sub == 5"
abbreviation f_nro :: nat where "f_nro == 2"
abbreviation f_nrr :: nat where "f_nrr == 3"
abbreviation f_con :: nat where "f_con == 4"
definition broken :: "agent set" where
"broken == bad - {Spy}"
declare broken_def [simp]
inductive_set zg :: "event list set"
where
Nil: "[] ∈ zg"
| Fake: "⟦evsf ∈ zg; X ∈ synth (analz (spies evsf))⟧
⟹ Says Spy B X # evsf ∈ zg"
| Reception: "⟦evsr ∈ zg; Says A B X ∈ set evsr⟧ ⟹ Gets B X # evsr ∈ zg"
| ZG1: "⟦evs1 ∈ zg; Nonce L ∉ used evs1; C = Crypt K (Number m);
K ∈ symKeys;
NRO = Crypt (priK A) ⦃Number f_nro, Agent B, Nonce L, C⦄⟧
⟹ Says A B ⦃Number f_nro, Agent B, Nonce L, C, NRO⦄ # evs1 ∈ zg"
| ZG2: "⟦evs2 ∈ zg;
Gets B ⦃Number f_nro, Agent B, Nonce L, C, NRO⦄ ∈ set evs2;
NRO = Crypt (priK A) ⦃Number f_nro, Agent B, Nonce L, C⦄;
NRR = Crypt (priK B) ⦃Number f_nrr, Agent A, Nonce L, C⦄⟧
⟹ Says B A ⦃Number f_nrr, Agent A, Nonce L, NRR⦄ # evs2 ∈ zg"
| ZG3: "⟦evs3 ∈ zg; C = Crypt K M; K ∈ symKeys;
Says A B ⦃Number f_nro, Agent B, Nonce L, C, NRO⦄ ∈ set evs3;
Gets A ⦃Number f_nrr, Agent A, Nonce L, NRR⦄ ∈ set evs3;
NRR = Crypt (priK B) ⦃Number f_nrr, Agent A, Nonce L, C⦄;
sub_K = Crypt (priK A) ⦃Number f_sub, Agent B, Nonce L, Key K⦄⟧
⟹ Says A TTP ⦃Number f_sub, Agent B, Nonce L, Key K, sub_K⦄
# evs3 ∈ zg"
| ZG4: "⟦evs4 ∈ zg; K ∈ symKeys;
Gets TTP ⦃Number f_sub, Agent B, Nonce L, Key K, sub_K⦄
∈ set evs4;
sub_K = Crypt (priK A) ⦃Number f_sub, Agent B, Nonce L, Key K⦄;
con_K = Crypt (priK TTP) ⦃Number f_con, Agent A, Agent B,
Nonce L, Key K⦄⟧
⟹ Says TTP Spy con_K
#
Notes TTP ⦃Number f_con, Agent A, Agent B, Nonce L, Key K, con_K⦄
# evs4 ∈ zg"
declare Says_imp_knows_Spy [THEN analz.Inj, dest]
declare Fake_parts_insert_in_Un [dest]
declare analz_into_parts [dest]
declare symKey_neq_priEK [simp]
declare symKey_neq_priEK [THEN not_sym, simp]
text‹A "possibility property": there are traces that reach the end›
lemma "⟦A ≠ B; TTP ≠ A; TTP ≠ B; K ∈ symKeys⟧ ⟹
∃L. ∃evs ∈ zg.
Notes TTP ⦃Number f_con, Agent A, Agent B, Nonce L, Key K,
Crypt (priK TTP) ⦃Number f_con, Agent A, Agent B, Nonce L, Key K⦄⦄
∈ set evs"
apply (intro exI bexI)
apply (rule_tac [2] zg.Nil
[THEN zg.ZG1, THEN zg.Reception [of _ A B],
THEN zg.ZG2, THEN zg.Reception [of _ B A],
THEN zg.ZG3, THEN zg.Reception [of _ A TTP],
THEN zg.ZG4])
apply (basic_possibility, auto)
done
subsection ‹Basic Lemmas›
lemma Gets_imp_Says:
"⟦Gets B X ∈ set evs; evs ∈ zg⟧ ⟹ ∃A. Says A B X ∈ set evs"
apply (erule rev_mp)
apply (erule zg.induct, auto)
done
lemma Gets_imp_knows_Spy:
"⟦Gets B X ∈ set evs; evs ∈ zg⟧ ⟹ X ∈ spies evs"
by (blast dest!: Gets_imp_Says Says_imp_knows_Spy)
text‹Lets us replace proofs about \<^term>‹used evs› by simpler proofs
about \<^term>‹parts (spies evs)›.›
lemma Crypt_used_imp_spies:
"⟦Crypt K X ∈ used evs; evs ∈ zg⟧
⟹ Crypt K X ∈ parts (spies evs)"
apply (erule rev_mp)
apply (erule zg.induct)
apply (simp_all add: parts_insert_knows_A)
done
lemma Notes_TTP_imp_Gets:
"⟦Notes TTP ⦃Number f_con, Agent A, Agent B, Nonce L, Key K, con_K⦄
∈ set evs;
sub_K = Crypt (priK A) ⦃Number f_sub, Agent B, Nonce L, Key K⦄;
evs ∈ zg⟧
⟹ Gets TTP ⦃Number f_sub, Agent B, Nonce L, Key K, sub_K⦄ ∈ set evs"
apply (erule rev_mp)
apply (erule zg.induct, auto)
done
text‹For reasoning about C, which is encrypted in message ZG2›
lemma ZG2_msg_in_parts_spies:
"⟦Gets B ⦃F, B', L, C, X⦄ ∈ set evs; evs ∈ zg⟧
⟹ C ∈ parts (spies evs)"
by (blast dest: Gets_imp_Says)
lemma Spy_see_priK [simp]:
"evs ∈ zg ⟹ (Key (priK A) ∈ parts (spies evs)) = (A ∈ bad)"
apply (erule zg.induct)
apply (frule_tac [5] ZG2_msg_in_parts_spies, auto)
done
text‹So that blast can use it too›
declare Spy_see_priK [THEN [2] rev_iffD1, dest!]
lemma Spy_analz_priK [simp]:
"evs ∈ zg ⟹ (Key (priK A) ∈ analz (spies evs)) = (A ∈ bad)"
by auto
subsection‹About NRO: Validity for \<^term>‹B››
text‹Below we prove that if \<^term>‹NRO› exists then \<^term>‹A› definitely
sent it, provided \<^term>‹A› is not broken.›
text‹Strong conclusion for a good agent›
lemma NRO_validity_good:
"⟦NRO = Crypt (priK A) ⦃Number f_nro, Agent B, Nonce L, C⦄;
NRO ∈ parts (spies evs);
A ∉ bad; evs ∈ zg⟧
⟹ Says A B ⦃Number f_nro, Agent B, Nonce L, C, NRO⦄ ∈ set evs"
apply clarify
apply (erule rev_mp)
apply (erule zg.induct)
apply (frule_tac [5] ZG2_msg_in_parts_spies, auto)
done
lemma NRO_sender:
"⟦Says A' B ⦃n, b, l, C, Crypt (priK A) X⦄ ∈ set evs; evs ∈ zg⟧
⟹ A' ∈ {A,Spy}"
apply (erule rev_mp)
apply (erule zg.induct, simp_all)
done
text‹Holds also for \<^term>‹A = Spy›!›
theorem NRO_validity:
"⟦Gets B ⦃Number f_nro, Agent B, Nonce L, C, NRO⦄ ∈ set evs;
NRO = Crypt (priK A) ⦃Number f_nro, Agent B, Nonce L, C⦄;
A ∉ broken; evs ∈ zg⟧
⟹ Says A B ⦃Number f_nro, Agent B, Nonce L, C, NRO⦄ ∈ set evs"
apply (drule Gets_imp_Says, assumption)
apply clarify
apply (frule NRO_sender, auto)
txt‹We are left with the case where the sender is \<^term>‹Spy› and not
equal to \<^term>‹A›, because \<^term>‹A ∉ bad›.
Thus theorem ‹NRO_validity_good› applies.›
apply (blast dest: NRO_validity_good [OF refl])
done
subsection‹About NRR: Validity for \<^term>‹A››
text‹Below we prove that if \<^term>‹NRR› exists then \<^term>‹B› definitely
sent it, provided \<^term>‹B› is not broken.›
text‹Strong conclusion for a good agent›
lemma NRR_validity_good:
"⟦NRR = Crypt (priK B) ⦃Number f_nrr, Agent A, Nonce L, C⦄;
NRR ∈ parts (spies evs);
B ∉ bad; evs ∈ zg⟧
⟹ Says B A ⦃Number f_nrr, Agent A, Nonce L, NRR⦄ ∈ set evs"
apply clarify
apply (erule rev_mp)
apply (erule zg.induct)
apply (frule_tac [5] ZG2_msg_in_parts_spies, auto)
done
lemma NRR_sender:
"⟦Says B' A ⦃n, a, l, Crypt (priK B) X⦄ ∈ set evs; evs ∈ zg⟧
⟹ B' ∈ {B,Spy}"
apply (erule rev_mp)
apply (erule zg.induct, simp_all)
done
text‹Holds also for \<^term>‹B = Spy›!›
theorem NRR_validity:
"⟦Says B' A ⦃Number f_nrr, Agent A, Nonce L, NRR⦄ ∈ set evs;
NRR = Crypt (priK B) ⦃Number f_nrr, Agent A, Nonce L, C⦄;
B ∉ broken; evs ∈ zg⟧
⟹ Says B A ⦃Number f_nrr, Agent A, Nonce L, NRR⦄ ∈ set evs"
apply clarify
apply (frule NRR_sender, auto)
txt‹We are left with the case where \<^term>‹B' = Spy› and \<^term>‹B' ≠ B›,
i.e. \<^term>‹B ∉ bad›, when we can apply ‹NRR_validity_good›.›
apply (blast dest: NRR_validity_good [OF refl])
done
subsection‹Proofs About \<^term>‹sub_K››
text‹Below we prove that if \<^term>‹sub_K› exists then \<^term>‹A› definitely
sent it, provided \<^term>‹A› is not broken.›
text‹Strong conclusion for a good agent›
lemma sub_K_validity_good:
"⟦sub_K = Crypt (priK A) ⦃Number f_sub, Agent B, Nonce L, Key K⦄;
sub_K ∈ parts (spies evs);
A ∉ bad; evs ∈ zg⟧
⟹ Says A TTP ⦃Number f_sub, Agent B, Nonce L, Key K, sub_K⦄ ∈ set evs"
apply clarify
apply (erule rev_mp)
apply (erule zg.induct)
apply (frule_tac [5] ZG2_msg_in_parts_spies, simp_all)
txt‹Fake›
apply (blast dest!: Fake_parts_sing_imp_Un)
done
lemma sub_K_sender:
"⟦Says A' TTP ⦃n, b, l, k, Crypt (priK A) X⦄ ∈ set evs; evs ∈ zg⟧
⟹ A' ∈ {A,Spy}"
apply (erule rev_mp)
apply (erule zg.induct, simp_all)
done
text‹Holds also for \<^term>‹A = Spy›!›
theorem sub_K_validity:
"⟦Gets TTP ⦃Number f_sub, Agent B, Nonce L, Key K, sub_K⦄ ∈ set evs;
sub_K = Crypt (priK A) ⦃Number f_sub, Agent B, Nonce L, Key K⦄;
A ∉ broken; evs ∈ zg⟧
⟹ Says A TTP ⦃Number f_sub, Agent B, Nonce L, Key K, sub_K⦄ ∈ set evs"
apply (drule Gets_imp_Says, assumption)
apply clarify
apply (frule sub_K_sender, auto)
txt‹We are left with the case where the sender is \<^term>‹Spy› and not
equal to \<^term>‹A›, because \<^term>‹A ∉ bad›.
Thus theorem ‹sub_K_validity_good› applies.›
apply (blast dest: sub_K_validity_good [OF refl])
done
subsection‹Proofs About \<^term>‹con_K››
text‹Below we prove that if \<^term>‹con_K› exists, then \<^term>‹TTP› has it,
and therefore \<^term>‹A› and \<^term>‹B›) can get it too. Moreover, we know
that \<^term>‹A› sent \<^term>‹sub_K››
lemma con_K_validity:
"⟦con_K ∈ used evs;
con_K = Crypt (priK TTP)
⦃Number f_con, Agent A, Agent B, Nonce L, Key K⦄;
evs ∈ zg⟧
⟹ Notes TTP ⦃Number f_con, Agent A, Agent B, Nonce L, Key K, con_K⦄
∈ set evs"
apply clarify
apply (erule rev_mp)
apply (erule zg.induct)
apply (frule_tac [5] ZG2_msg_in_parts_spies, simp_all)
txt‹Fake›
apply (blast dest!: Fake_parts_sing_imp_Un)
txt‹ZG2›
apply (blast dest: parts_cut)
done
text‹If \<^term>‹TTP› holds \<^term>‹con_K› then \<^term>‹A› sent
\<^term>‹sub_K›. We assume that \<^term>‹A› is not broken. Importantly, nothing
needs to be assumed about the form of \<^term>‹con_K›!›
lemma Notes_TTP_imp_Says_A:
"⟦Notes TTP ⦃Number f_con, Agent A, Agent B, Nonce L, Key K, con_K⦄
∈ set evs;
sub_K = Crypt (priK A) ⦃Number f_sub, Agent B, Nonce L, Key K⦄;
A ∉ broken; evs ∈ zg⟧
⟹ Says A TTP ⦃Number f_sub, Agent B, Nonce L, Key K, sub_K⦄ ∈ set evs"
apply clarify
apply (erule rev_mp)
apply (erule zg.induct)
apply (frule_tac [5] ZG2_msg_in_parts_spies, simp_all)
txt‹ZG4›
apply clarify
apply (rule sub_K_validity, auto)
done
text‹If \<^term>‹con_K› exists, then \<^term>‹A› sent \<^term>‹sub_K›. We again
assume that \<^term>‹A› is not broken.›
theorem B_sub_K_validity:
"⟦con_K ∈ used evs;
con_K = Crypt (priK TTP) ⦃Number f_con, Agent A, Agent B,
Nonce L, Key K⦄;
sub_K = Crypt (priK A) ⦃Number f_sub, Agent B, Nonce L, Key K⦄;
A ∉ broken; evs ∈ zg⟧
⟹ Says A TTP ⦃Number f_sub, Agent B, Nonce L, Key K, sub_K⦄ ∈ set evs"
by (blast dest: con_K_validity Notes_TTP_imp_Says_A)
subsection‹Proving fairness›
text‹Cannot prove that, if \<^term>‹B› has NRO, then \<^term>‹A› has her NRR.
It would appear that \<^term>‹B› has a small advantage, though it is
useless to win disputes: \<^term>‹B› needs to present \<^term>‹con_K› as well.›
text‹Strange: unicity of the label protects \<^term>‹A›?›
lemma A_unicity:
"⟦NRO = Crypt (priK A) ⦃Number f_nro, Agent B, Nonce L, Crypt K M⦄;
NRO ∈ parts (spies evs);
Says A B ⦃Number f_nro, Agent B, Nonce L, Crypt K M', NRO'⦄
∈ set evs;
A ∉ bad; evs ∈ zg⟧
⟹ M'=M"
apply clarify
apply (erule rev_mp)
apply (erule rev_mp)
apply (erule zg.induct)
apply (frule_tac [5] ZG2_msg_in_parts_spies, auto)
txt‹ZG1: freshness›
apply (blast dest: parts.Body)
done
text‹Fairness lemma: if \<^term>‹sub_K› exists, then \<^term>‹A› holds
NRR. Relies on unicity of labels.›
lemma sub_K_implies_NRR:
"⟦NRO = Crypt (priK A) ⦃Number f_nro, Agent B, Nonce L, Crypt K M⦄;
NRR = Crypt (priK B) ⦃Number f_nrr, Agent A, Nonce L, Crypt K M⦄;
sub_K ∈ parts (spies evs);
NRO ∈ parts (spies evs);
sub_K = Crypt (priK A) ⦃Number f_sub, Agent B, Nonce L, Key K⦄;
A ∉ bad; evs ∈ zg⟧
⟹ Gets A ⦃Number f_nrr, Agent A, Nonce L, NRR⦄ ∈ set evs"
apply clarify
apply hypsubst_thin
apply (erule rev_mp)
apply (erule rev_mp)
apply (erule zg.induct)
apply (frule_tac [5] ZG2_msg_in_parts_spies, simp_all)
txt‹Fake›
apply blast
txt‹ZG1: freshness›
apply (blast dest: parts.Body)
txt‹ZG3›
apply (blast dest: A_unicity [OF refl])
done
lemma Crypt_used_imp_L_used:
"⟦Crypt (priK TTP) ⦃F, A, B, L, K⦄ ∈ used evs; evs ∈ zg⟧
⟹ L ∈ used evs"
apply (erule rev_mp)
apply (erule zg.induct, auto)
txt‹Fake›
apply (blast dest!: Fake_parts_sing_imp_Un)
txt‹ZG2: freshness›
apply (blast dest: parts.Body)
done
text‹Fairness for \<^term>‹A›: if \<^term>‹con_K› and \<^term>‹NRO› exist,
then \<^term>‹A› holds NRR. \<^term>‹A› must be uncompromised, but there is no
assumption about \<^term>‹B›.›
theorem A_fairness_NRO:
"⟦con_K ∈ used evs;
NRO ∈ parts (spies evs);
con_K = Crypt (priK TTP)
⦃Number f_con, Agent A, Agent B, Nonce L, Key K⦄;
NRO = Crypt (priK A) ⦃Number f_nro, Agent B, Nonce L, Crypt K M⦄;
NRR = Crypt (priK B) ⦃Number f_nrr, Agent A, Nonce L, Crypt K M⦄;
A ∉ bad; evs ∈ zg⟧
⟹ Gets A ⦃Number f_nrr, Agent A, Nonce L, NRR⦄ ∈ set evs"
apply clarify
apply (erule rev_mp)
apply (erule rev_mp)
apply (erule zg.induct)
apply (frule_tac [5] ZG2_msg_in_parts_spies, simp_all)
txt‹Fake›
apply (simp add: parts_insert_knows_A)
apply (blast dest: Fake_parts_sing_imp_Un)
txt‹ZG1›
apply (blast dest: Crypt_used_imp_L_used)
txt‹ZG2›
apply (blast dest: parts_cut)
txt‹ZG4›
apply (blast intro: sub_K_implies_NRR [OF refl]
dest: Gets_imp_knows_Spy [THEN parts.Inj])
done
text‹Fairness for \<^term>‹B›: NRR exists at all, then \<^term>‹B› holds NRO.
\<^term>‹B› must be uncompromised, but there is no assumption about \<^term>‹A›.›
theorem B_fairness_NRR:
"⟦NRR ∈ used evs;
NRR = Crypt (priK B) ⦃Number f_nrr, Agent A, Nonce L, C⦄;
NRO = Crypt (priK A) ⦃Number f_nro, Agent B, Nonce L, C⦄;
B ∉ bad; evs ∈ zg⟧
⟹ Gets B ⦃Number f_nro, Agent B, Nonce L, C, NRO⦄ ∈ set evs"
apply clarify
apply (erule rev_mp)
apply (erule zg.induct)
apply (frule_tac [5] ZG2_msg_in_parts_spies, simp_all)
txt‹Fake›
apply (blast dest!: Fake_parts_sing_imp_Un)
txt‹ZG2›
apply (blast dest: parts_cut)
done
text‹If \<^term>‹con_K› exists at all, then \<^term>‹B› can get it, by ‹con_K_validity›. Cannot conclude that also NRO is available to \<^term>‹B›,
because if \<^term>‹A› were unfair, \<^term>‹A› could build message 3 without
building message 1, which contains NRO.›
end