(* Title: HOL/Metis_Examples/Message.thy Author: Lawrence C. Paulson, Cambridge University Computer Laboratory Author: Jasmin Blanchette, TU Muenchen
Metis example featuring message authentication.
*)
section \<open>Metis Example Featuring Message Authentication\<close>
theory Message imports Main begin
declare [[metis_new_skolem]]
lemma strange_Un_eq [simp]: "A \ (B \ A) = B \ A" by (metis Un_commute Un_left_absorb)
type_synonym key = nat
consts
all_symmetric :: bool \<comment> \<open>true if all keys are symmetric\<close>
invKey :: "key=>key"\<comment> \<open>inverse of a symmetric key\<close>
text\<open>Concrete syntax: messages appear as \<open>\<lbrace>A,B,NA\<rbrace>\<close>, etc...\<close> syntax "_MTuple" :: "['a, args] \ 'a * 'b" (\(\indent=2 notation=\mixfix message tuple\\\_,/ _\)\)
syntax_consts "_MTuple"\<rightleftharpoons> MPair translations "\x, y, z\" \ "\x, \y, z\\" "\x, y\" \ "CONST MPair x y"
definition HPair :: "[msg,msg] => msg" (\<open>(4Hash[_] /_)\<close> [0, 1000]) where \<comment> \<open>Message Y paired with a MAC computed with the help of X\<close> "Hash[X] Y == \ Hash\X,Y\, Y\"
definition keysFor :: "msg set => key set"where \<comment> \<open>Keys useful to decrypt elements of a message set\<close> "keysFor H == invKey ` {K. \X. Crypt K X \ H}"
subsubsection\<open>Inductive Definition of All Parts" of a Message\<close>
inductive_set
parts :: "msg set => msg set" for H :: "msg set" where
Inj [intro]: "X \ H ==> X \ parts H"
| Fst: "\X,Y\ \ parts H ==> X \ parts H"
| Snd: "\X,Y\ \ parts H ==> Y \ parts H"
| Body: "Crypt K X \ parts H ==> X \ parts H"
lemma parts_mono: "G \ H ==> parts(G) \ parts(H)" apply auto apply (erule parts.induct) apply (metis parts.Inj rev_subsetD) apply (metis parts.Fst) apply (metis parts.Snd) by (metis parts.Body)
text\<open>Equations hold because constructors are injective.\<close> lemma Friend_image_eq [simp]: "(Friend x \ Friend`A) = (x\A)" by (metis agent.inject image_iff)
lemma Key_image_eq [simp]: "(Key x \ Key`A) = (x \ A)" by (metis image_iff msg.inject(4))
lemma Nonce_Key_image_eq [simp]: "Nonce x \ Key`A" by (metis image_iff msg.distinct(23))
subsubsection\<open>Inverse of keys\<close>
lemma invKey_eq [simp]: "(invKey K = invKey K') = (K = K')" by (metis invKey)
lemma MPair_parts: "[| \X,Y\ \ parts H;
[| X \<in> parts H; Y \<in> parts H |] ==> P |] ==> P" by (blast dest: parts.Fst parts.Snd)
declare MPair_parts [elim!] parts.Body [dest!] text\<open>NB These two rules are UNSAFE in the formal sense, as they discard the
compound message. They work well on THIS FILE. \<open>MPair_parts\<close> is left as SAFE because it speeds up proofs.
The Crypt rule is normally kept UNSAFE to avoid breaking up certificates.\<close>
lemma parts_increasing: "H \ parts(H)" by blast
lemmas parts_insertI = subset_insertI [THEN parts_mono, THEN subsetD]
lemma parts_emptyE [elim!]: "X\ parts{} ==> P" by simp
text\<open>WARNING: loops if H = {Y}, therefore must not be repeated!\<close> lemma parts_singleton: "X\ parts H ==> \Y\H. X\ parts {Y}" apply (erule parts.induct) apply fast+ done
lemma parts_insert: "parts (insert X H) = parts {X} \ parts H" apply (subst insert_is_Un [of _ H]) apply (simp only: parts_Un) done
lemma parts_insert2: "parts (insert X (insert Y H)) = parts {X} \ parts {Y} \ parts H" by (metis Un_commute Un_empty_left Un_empty_right Un_insert_left Un_insert_right parts_Un)
lemma parts_UN_subset1: "(\x\A. parts(H x)) \ parts(\x\A. H x)" by (intro UN_least parts_mono UN_upper)
text\<open>This allows \<open>blast\<close> to simplify occurrences of \<^term>\<open>parts(G\<union>H)\<close> in the assumption.\<close> lemmas in_parts_UnE = parts_Un [THEN equalityD1, THEN subsetD, THEN UnE] declare in_parts_UnE [elim!]
lemma parts_insert_subset: "insert X (parts H) \ parts(insert X H)" by (blast intro: parts_mono [THEN [2] rev_subsetD])
subsubsection\<open>Idempotence and transitivity\<close>
lemma parts_partsD [dest!]: "X\ parts (parts H) ==> X\ parts H" by (erule parts.induct, blast+)
lemma parts_idem [simp]: "parts (parts H) = parts H" by blast
lemma parts_subset_iff [simp]: "(parts G \ parts H) = (G \ parts H)" apply (rule iffI) apply (metis Un_absorb1 Un_subset_iff parts_Un parts_increasing) apply (metis parts_idem parts_mono) done
lemma parts_trans: "[| X\ parts G; G \ parts H |] ==> X\ parts H" by (blast dest: parts_mono)
lemma parts_cut: "[|Y\ parts (insert X G); X\ parts H|] ==> Y\ parts(G \ H)" by (metis (no_types) Un_insert_left Un_insert_right insert_absorb le_supE
parts_Un parts_idem parts_increasing parts_trans)
subsubsection\<open>Rewrite rules for pulling out atomic messages\<close>
text\<open>Inductive definition of "analz" -- what can be broken down from a set of
messages, including keys. A form of downward closure. Pairs can
be taken apart; messages decrypted with known keys.\<close>
inductive_set
analz :: "msg set => msg set" for H :: "msg set" where
Inj [intro,simp] : "X \ H ==> X \ analz H"
| Fst: "\X,Y\ \ analz H ==> X \ analz H"
| Snd: "\X,Y\ \ analz H ==> Y \ analz H"
| Decrypt [dest]: "[|Crypt K X \ analz H; Key(invKey K) \ analz H|] ==> X \ analz H"
text\<open>Making it safe speeds up proofs\<close> lemma MPair_analz [elim!]: "[| \X,Y\ \ analz H;
[| X \<in> analz H; Y \<in> analz H |] ==> P
|] ==> P" by (blast dest: analz.Fst analz.Snd)
lemma analz_increasing: "H \ analz(H)" by blast
lemma analz_subset_parts: "analz H \ parts H" apply (rule subsetI) apply (erule analz.induct, blast+) done
text\<open>Converse fails: we can analz more from the union than from the
separate parts, as a key in one might decrypt a message in the other\<close> lemma analz_Un: "analz(G) \ analz(H) \ analz(G \ H)" by (intro Un_least analz_mono Un_upper1 Un_upper2)
lemma analz_insert: "insert X (analz H) \ analz(insert X H)" by (blast intro: analz_mono [THEN [2] rev_subsetD])
subsubsection\<open>Rewrite rules for pulling out atomic messages\<close>
text\<open>Can pull out enCrypted message if the Key is not known\<close> lemma analz_insert_Crypt: "Key (invKey K) \ analz H
==> analz (insert (Crypt K X) H) = insert (Crypt K X) (analz H)" apply (rule analz_insert_eq_I) apply (erule analz.induct, auto)
done
lemma lemma1: "Key (invKey K) \ analz H ==>
analz (insert (Crypt K X) H) \<subseteq>
insert (Crypt K X) (analz (insert X H))" apply (rule subsetI) apply (erule_tac x = x in analz.induct, auto) done
lemma lemma2: "Key (invKey K) \ analz H ==>
insert (Crypt K X) (analz (insert X H)) \<subseteq>
analz (insert (Crypt K X) H)" apply auto apply (erule_tac x = x in analz.induct, auto) apply (blast intro: analz_insertI analz.Decrypt) done
lemma analz_insert_Decrypt: "Key (invKey K) \ analz H ==>
analz (insert (Crypt K X) H) =
insert (Crypt K X) (analz (insert X H))" by (intro equalityI lemma1 lemma2)
text\<open>Case analysis: either the message is secure, or it is not! Effective,
but can cause subgoals to blow up! Usewith\<open>if_split\<close>; apparently \<open>split_tac\<close> does not cope with patterns such as \<^term>\<open>analz (insert
(Crypt K X) H)\<close>\<close> lemma analz_Crypt_if [simp]: "analz (insert (Crypt K X) H) =
(if (Key (invKey K) \<in> analz H) then insert (Crypt K X) (analz (insert X H))
else insert (Crypt K X) (analz H))" by (simp add: analz_insert_Crypt analz_insert_Decrypt)
text\<open>This rule supposes "for the sake of argument" that we have the key.\<close> lemma analz_insert_Crypt_subset: "analz (insert (Crypt K X) H) \
insert (Crypt K X) (analz (insert X H))" apply (rule subsetI) apply (erule analz.induct, auto) done
lemma analz_trans: "[| X\ analz G; G \ analz H |] ==> X\ analz H" by (drule analz_mono, blast)
declare analz_trans[intro]
lemma analz_cut: "[| Y\ analz (insert X H); X\ analz H |] ==> Y\ analz H" by (metis analz_idem analz_increasing analz_mono insert_absorb insert_mono insert_subset)
text\<open>This rewrite rule helps in the simplification of messages that involve
the forwarding of unknown components (X). Without it, removing occurrences
of X can be very complicated.\<close> lemma analz_insert_eq: "X\ analz H ==> analz (insert X H) = analz H" by (blast intro: analz_cut analz_insertI)
lemma analz_cong: "[| analz G = analz G'; analz H = analz H'
|] ==> analz (G \<union> H) = analz (G' \<union> H')" by (intro equalityI analz_subset_cong, simp_all)
lemma analz_insert_cong: "analz H = analz H' ==> analz(insert X H) = analz(insert X H')" by (force simp only: insert_def intro!: analz_cong)
text\<open>If there are no pairs or encryptions then analz does nothing\<close> lemma analz_trivial: "[| \X Y. \X,Y\ \ H; \X K. Crypt K X \ H |] ==> analz H = H" apply safe apply (erule analz.induct, blast+) done
text\<open>Inductive definition of "synth" -- what can be built up from a set of
messages. A form of upward closure. Pairs can be built, messages
encrypted with known keys. Agent names are public domain.
Numbers can be guessed, but Nonces cannot be.\<close>
inductive_set
synth :: "msg set => msg set" for H :: "msg set" where
Inj [intro]: "X \ H ==> X \ synth H"
| Agent [intro]: "Agent agt \ synth H"
| Number [intro]: "Number n \ synth H"
| Hash [intro]: "X \ synth H ==> Hash X \ synth H"
| MPair [intro]: "[|X \ synth H; Y \ synth H|] ==> \X,Y\ \ synth H"
| Crypt [intro]: "[|X \ synth H; Key(K) \ H|] ==> Crypt K X \ synth H"
text\<open>NO \<open>Agent_synth\<close>, as any Agent name can be synthesized.
The same holds for\<^term>\<open>Number\<close>\<close> inductive_cases Nonce_synth [elim!]: "Nonce n \ synth H" inductive_cases Key_synth [elim!]: "Key K \ synth H" inductive_cases Hash_synth [elim!]: "Hash X \ synth H" inductive_cases MPair_synth [elim!]: "\X,Y\ \ synth H" inductive_cases Crypt_synth [elim!]: "Crypt K X \ synth H"
lemma synth_increasing: "H \ synth(H)" by blast
subsubsection\<open>Unions\<close>
text\<open>Converse fails: we can synth more from the union than from the
separate parts, building a compound message using elements of each.\<close> lemma synth_Un: "synth(G) \ synth(H) \ synth(G \ H)" by (intro Un_least synth_mono Un_upper1 Un_upper2)
lemma synth_insert: "insert X (synth H) \ synth(insert X H)" by (metis insert_iff insert_subset subset_insertI synth.Inj synth_mono)
subsubsection\<open>Idempotence and transitivity\<close>
subsubsection\<open>For reasoning about the Fake rule in traces\<close>
lemma parts_insert_subset_Un: "X \ G ==> parts(insert X H) \ parts G \ parts H" proof - assume"X \ G" hence"\x\<^sub>1. G \ x\<^sub>1 \ X \ x\<^sub>1 " by auto hence"\x\<^sub>1. X \ G \ x\<^sub>1" by (metis Un_upper1) hence"insert X H \ G \ H" by (metis Un_upper2 insert_subset) hence"parts (insert X H) \ parts (G \ H)" by (metis parts_mono) thus"parts (insert X H) \ parts G \ parts H" by (metis parts_Un) qed
lemma Fake_parts_insert: "X \ synth (analz H) ==>
parts (insert X H) \<subseteq> synth (analz H) \<union> parts H" proof - assume A1: "X \ synth (analz H)" have F1: "\x\<^sub>1. analz x\<^sub>1 \ synth (analz x\<^sub>1) = analz (synth (analz x\<^sub>1))" by (metis analz_idem analz_synth) have F2: "\x\<^sub>1. parts x\<^sub>1 \ synth (analz x\<^sub>1) = parts (synth (analz x\<^sub>1))" by (metis parts_analz parts_synth) have F3: "X \ synth (analz H)" using A1 by metis have"\x\<^sub>2 x\<^sub>1::msg set. x\<^sub>1 \ sup x\<^sub>1 x\<^sub>2" by (metis inf_sup_ord(3)) hence F4: "\x\<^sub>1. analz x\<^sub>1 \ analz (synth x\<^sub>1)" by (metis analz_synth) have F5: "X \ synth (analz H)" using F3 by metis have"\x\<^sub>1. analz x\<^sub>1 \ synth (analz x\<^sub>1) \<longrightarrow> analz (synth (analz x\<^sub>1)) = synth (analz x\<^sub>1)" using F1 by (metis subset_Un_eq) hence F6: "\x\<^sub>1. analz (synth (analz x\<^sub>1)) = synth (analz x\<^sub>1)" by (metis synth_increasing) have"\x\<^sub>1. x\<^sub>1 \ analz (synth x\<^sub>1)" using F4 by (metis analz_subset_iff) hence"\x\<^sub>1. x\<^sub>1 \ analz (synth (analz x\<^sub>1))" by (metis analz_subset_iff) hence"\x\<^sub>1. x\<^sub>1 \ synth (analz x\<^sub>1)" using F6 by metis hence"H \ synth (analz H)" by metis hence"H \ synth (analz H) \ X \ synth (analz H)" using F5 by metis hence"insert X H \ synth (analz H)" by (metis insert_subset) hence"parts (insert X H) \ parts (synth (analz H))" by (metis parts_mono) hence"parts (insert X H) \ parts H \ synth (analz H)" using F2 by metis thus"parts (insert X H) \ synth (analz H) \ parts H" by (metis Un_commute) qed
lemma Fake_parts_insert_in_Un: "[|Z \ parts (insert X H); X \ synth (analz H)|]
==> Z \<in> synth (analz H) \<union> parts H" by (blast dest: Fake_parts_insert [THEN subsetD, dest])
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.