diff --git a/thys/Inductive_Confidentiality/DolevYao/Message.thy b/thys/Inductive_Confidentiality/DolevYao/Message.thy --- a/thys/Inductive_Confidentiality/DolevYao/Message.thy +++ b/thys/Inductive_Confidentiality/DolevYao/Message.thy @@ -1,926 +1,914 @@ (* Title: HOL/Auth/Message.thy Author: Lawrence C Paulson, Cambridge University Computer Laboratory Copyright 1996 University of Cambridge Datatypes of agents and messages; Inductive relations "parts", "analz" and "synth" *) section\Theory of Agents and Messages for Security Protocols against Dolev-Yao\ theory Message imports Main begin (*Needed occasionally with spy_analz_tac, e.g. in analz_insert_Key_newK*) lemma [simp] : "A \ (B \ A) = B \ A" by blast type_synonym key = nat consts all_symmetric :: bool \ \true if all keys are symmetric\ invKey :: "key=>key" \ \inverse of a symmetric key\ specification (invKey) invKey [simp]: "invKey (invKey K) = K" invKey_symmetric: "all_symmetric --> invKey = id" by (rule exI [of _ id], auto) text\The inverse of a symmetric key is itself; that of a public key is the private key and vice versa\ definition symKeys :: "key set" where "symKeys == {K. invKey K = K}" datatype \ \We allow any number of friendly agents\ agent = Server | Friend nat | Spy datatype msg = Agent agent \ \Agent names\ | Number nat \ \Ordinary integers, timestamps, ...\ | Nonce nat \ \Unguessable nonces\ | Key key \ \Crypto keys\ | Hash msg \ \Hashing\ | MPair msg msg \ \Compound messages\ | Crypt key msg \ \Encryption, public- or shared-key\ text\Concrete syntax: messages appear as \\A,B,NA\\, etc...\ syntax "_MTuple" :: "['a, args] => 'a * 'b" ("(2\_,/ _\)") translations "\x, y, z\" == "\x, \y, z\\" "\x, y\" == "CONST MPair x y" definition HPair :: "[msg,msg] => msg" ("(4Hash[_] /_)" [0, 1000]) where \ \Message Y paired with a MAC computed with the help of X\ "Hash[X] Y == \ Hash\X,Y\, Y\" definition keysFor :: "msg set => key set" where \ \Keys useful to decrypt elements of a message set\ "keysFor H == invKey ` {K. \X. Crypt K X \ H}" subsection\Inductive definition of all parts of a message\ 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" text\Monotonicity\ lemma parts_mono: "G \ H ==> parts(G) \ parts(H)" apply auto apply (erule parts.induct) apply (blast dest: parts.Fst parts.Snd parts.Body)+ done text\Equations hold because constructors are injective.\ lemma Friend_image_eq [simp]: "(Friend x \ Friend`A) = (x:A)" by auto lemma Key_image_eq [simp]: "(Key x \ Key`A) = (x\A)" by auto lemma Nonce_Key_image_eq [simp]: "(Nonce x \ Key`A)" by auto subsection\Inverse of keys\ lemma invKey_eq [simp]: "(invKey K = invKey K') = (K=K')" by (metis invKey) subsection\keysFor operator\ lemma keysFor_empty [simp]: "keysFor {} = {}" by (unfold keysFor_def, blast) lemma keysFor_Un [simp]: "keysFor (H \ H') = keysFor H \ keysFor H'" by (unfold keysFor_def, blast) lemma keysFor_UN [simp]: "keysFor (\i\A. H i) = (\i\A. keysFor (H i))" by (unfold keysFor_def, blast) text\Monotonicity\ lemma keysFor_mono: "G \ H ==> keysFor(G) \ keysFor(H)" by (unfold keysFor_def, blast) lemma keysFor_insert_Agent [simp]: "keysFor (insert (Agent A) H) = keysFor H" by (unfold keysFor_def, auto) lemma keysFor_insert_Nonce [simp]: "keysFor (insert (Nonce N) H) = keysFor H" by (unfold keysFor_def, auto) lemma keysFor_insert_Number [simp]: "keysFor (insert (Number N) H) = keysFor H" by (unfold keysFor_def, auto) lemma keysFor_insert_Key [simp]: "keysFor (insert (Key K) H) = keysFor H" by (unfold keysFor_def, auto) lemma keysFor_insert_Hash [simp]: "keysFor (insert (Hash X) H) = keysFor H" by (unfold keysFor_def, auto) lemma keysFor_insert_MPair [simp]: "keysFor (insert \X,Y\ H) = keysFor H" by (unfold keysFor_def, auto) lemma keysFor_insert_Crypt [simp]: "keysFor (insert (Crypt K X) H) = insert (invKey K) (keysFor H)" by (unfold keysFor_def, auto) lemma keysFor_image_Key [simp]: "keysFor (Key`E) = {}" by (unfold keysFor_def, auto) lemma Crypt_imp_invKey_keysFor: "Crypt K X \ H ==> invKey K \ keysFor H" by (unfold keysFor_def, blast) subsection\Inductive relation "parts"\ lemma MPair_parts: "[| \X,Y\ \ parts H; [| X \ parts H; Y \ parts H |] ==> P |] ==> P" by (blast dest: parts.Fst parts.Snd) declare MPair_parts [elim!] parts.Body [dest!] text\NB These two rules are UNSAFE in the formal sense, as they discard the compound message. They work well on THIS FILE. \MPair_parts\ is left as SAFE because it speeds up proofs. The Crypt rule is normally kept UNSAFE to avoid breaking up certificates.\ lemma parts_increasing: "H \ parts(H)" by blast lemmas parts_insertI = subset_insertI [THEN parts_mono, THEN subsetD] lemma parts_empty [simp]: "parts{} = {}" apply safe apply (erule parts.induct, blast+) done lemma parts_emptyE [elim!]: "X\ parts{} ==> P" by simp text\WARNING: loops if H = {Y}, therefore must not be repeated!\ lemma parts_singleton: "X\ parts H ==> \Y\H. X\ parts {Y}" by (erule parts.induct, fast+) subsubsection\Unions\ lemma parts_Un_subset1: "parts(G) \ parts(H) \ parts(G \ H)" by (intro Un_least parts_mono Un_upper1 Un_upper2) lemma parts_Un_subset2: "parts(G \ H) \ parts(G) \ parts(H)" apply (rule subsetI) apply (erule parts.induct, blast+) done lemma parts_Un [simp]: "parts(G \ H) = parts(G) \ parts(H)" by (intro equalityI parts_Un_subset1 parts_Un_subset2) lemma parts_insert: "parts (insert X H) = parts {X} \ parts H" by (metis insert_is_Un parts_Un) text\TWO inserts to avoid looping. This rewrite is better than nothing. Not suitable for Addsimps: its behaviour can be strange.\ lemma parts_insert2: "parts (insert X (insert Y H)) = parts {X} \ parts {Y} \ parts H" by (metis Un_commute Un_empty_right Un_insert_right insert_is_Un parts_Un) -lemma parts_UN_subset1: "(\x\A. parts(H x)) \ parts(\x\A. H x)" -by (intro UN_least parts_mono UN_upper) - -lemma parts_UN_subset2: "parts(\x\A. H x) \ (\x\A. parts(H x))" -apply (rule subsetI) -apply (erule parts.induct, blast+) -done - -lemma parts_UN [simp]: "parts(\x\A. H x) = (\x\A. parts(H x))" -by (intro equalityI parts_UN_subset1 parts_UN_subset2) - -text\Added to simplify arguments to parts, analz and synth. - NOTE: the UN versions are no longer used!\ +text\Added to simplify arguments to parts, analz and synth.\ text\This allows \blast\ to simplify occurrences of @{term "parts(G\H)"} in the assumption.\ 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\Idempotence and transitivity\ 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)" by (metis parts_idem parts_increasing parts_mono subset_trans) lemma parts_trans: "[| X\ parts G; G \ parts H |] ==> X\ parts H" by (metis parts_subset_iff subsetD) text\Cut\ lemma parts_cut: "[| Y\ parts (insert X G); X\ parts H |] ==> Y\ parts (G \ H)" by (blast intro: parts_trans) lemma parts_cut_eq [simp]: "X\ parts H ==> parts (insert X H) = parts H" by (metis insert_absorb parts_idem parts_insert) subsubsection\Rewrite rules for pulling out atomic messages\ lemmas parts_insert_eq_I = equalityI [OF subsetI parts_insert_subset] lemma parts_insert_Agent [simp]: "parts (insert (Agent agt) H) = insert (Agent agt) (parts H)" apply (rule parts_insert_eq_I) apply (erule parts.induct, auto) done lemma parts_insert_Nonce [simp]: "parts (insert (Nonce N) H) = insert (Nonce N) (parts H)" apply (rule parts_insert_eq_I) apply (erule parts.induct, auto) done lemma parts_insert_Number [simp]: "parts (insert (Number N) H) = insert (Number N) (parts H)" apply (rule parts_insert_eq_I) apply (erule parts.induct, auto) done lemma parts_insert_Key [simp]: "parts (insert (Key K) H) = insert (Key K) (parts H)" apply (rule parts_insert_eq_I) apply (erule parts.induct, auto) done lemma parts_insert_Hash [simp]: "parts (insert (Hash X) H) = insert (Hash X) (parts H)" apply (rule parts_insert_eq_I) apply (erule parts.induct, auto) done lemma parts_insert_Crypt [simp]: "parts (insert (Crypt K X) H) = insert (Crypt K X) (parts (insert X H))" apply (rule equalityI) apply (rule subsetI) apply (erule parts.induct, auto) apply (blast intro: parts.Body) done lemma parts_insert_MPair [simp]: "parts (insert \X,Y\ H) = insert \X,Y\ (parts (insert X (insert Y H)))" apply (rule equalityI) apply (rule subsetI) apply (erule parts.induct, auto) apply (blast intro: parts.Fst parts.Snd)+ done lemma parts_image_Key [simp]: "parts (Key`N) = Key`N" apply auto apply (erule parts.induct, auto) done text\In any message, there is an upper bound N on its greatest nonce.\ lemma msg_Nonce_supply: "\N. \n. N\n --> Nonce n \ parts {msg}" apply (induct msg) apply (simp_all (no_asm_simp) add: exI parts_insert2) txt\Nonce case\ apply (metis Suc_n_not_le_n) txt\MPair case: metis works out the necessary sum itself!\ apply (metis le_trans nat_le_linear) done subsection\Inductive relation "analz"\ text\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.\ 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\Monotonicity; Lemma 1 of Lowe's paper\ lemma analz_mono: "G\H ==> analz(G) \ analz(H)" apply auto apply (erule analz.induct) apply (auto dest: analz.Fst analz.Snd) done text\Making it safe speeds up proofs\ lemma MPair_analz [elim!]: "[| \X,Y\ \ analz H; [| X \ analz H; Y \ 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 lemmas analz_into_parts = analz_subset_parts [THEN subsetD] lemmas not_parts_not_analz = analz_subset_parts [THEN contra_subsetD] lemma parts_analz [simp]: "parts (analz H) = parts H" by (metis analz_increasing analz_subset_parts equalityI parts_mono parts_subset_iff) lemma analz_parts [simp]: "analz (parts H) = parts H" apply auto apply (erule analz.induct, auto) done lemmas analz_insertI = subset_insertI [THEN analz_mono, THEN [2] rev_subsetD] subsubsection\General equational properties\ lemma analz_empty [simp]: "analz{} = {}" apply safe apply (erule analz.induct, blast+) done text\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\ 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\Rewrite rules for pulling out atomic messages\ lemmas analz_insert_eq_I = equalityI [OF subsetI analz_insert] lemma analz_insert_Agent [simp]: "analz (insert (Agent agt) H) = insert (Agent agt) (analz H)" apply (rule analz_insert_eq_I) apply (erule analz.induct, auto) done lemma analz_insert_Nonce [simp]: "analz (insert (Nonce N) H) = insert (Nonce N) (analz H)" apply (rule analz_insert_eq_I) apply (erule analz.induct, auto) done lemma analz_insert_Number [simp]: "analz (insert (Number N) H) = insert (Number N) (analz H)" apply (rule analz_insert_eq_I) apply (erule analz.induct, auto) done lemma analz_insert_Hash [simp]: "analz (insert (Hash X) H) = insert (Hash X) (analz H)" apply (rule analz_insert_eq_I) apply (erule analz.induct, auto) done text\Can only pull out Keys if they are not needed to decrypt the rest\ lemma analz_insert_Key [simp]: "K \ keysFor (analz H) ==> analz (insert (Key K) H) = insert (Key K) (analz H)" apply (unfold keysFor_def) apply (rule analz_insert_eq_I) apply (erule analz.induct, auto) done lemma analz_insert_MPair [simp]: "analz (insert \X,Y\ H) = insert \X,Y\ (analz (insert X (insert Y H)))" apply (rule equalityI) apply (rule subsetI) apply (erule analz.induct, auto) apply (erule analz.induct) apply (blast intro: analz.Fst analz.Snd)+ done text\Can pull out enCrypted message if the Key is not known\ 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) \ 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)) \ 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\Case analysis: either the message is secure, or it is not! Effective, but can cause subgoals to blow up! Use with \if_split\; apparently \split_tac\ does not cope with patterns such as @{term"analz (insert (Crypt K X) H)"}\ lemma analz_Crypt_if [simp]: "analz (insert (Crypt K X) H) = (if (Key (invKey K) \ 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\This rule supposes "for the sake of argument" that we have the key.\ 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_image_Key [simp]: "analz (Key`N) = Key`N" apply auto apply (erule analz.induct, auto) done subsubsection\Idempotence and transitivity\ lemma analz_analzD [dest!]: "X\ analz (analz H) ==> X\ analz H" by (erule analz.induct, blast+) lemma analz_idem [simp]: "analz (analz H) = analz H" by blast lemma analz_subset_iff [simp]: "(analz G \ analz H) = (G \ analz H)" by (metis analz_idem analz_increasing analz_mono subset_trans) lemma analz_trans: "[| X\ analz G; G \ analz H |] ==> X\ analz H" by (drule analz_mono, blast) text\Cut; Lemma 2 of Lowe\ lemma analz_cut: "[| Y\ analz (insert X H); X\ analz H |] ==> Y\ analz H" by (erule analz_trans, blast) (*Cut can be proved easily by induction on "Y: analz (insert X H) ==> X: analz H --> Y: analz H" *) text\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.\ lemma analz_insert_eq: "X\ analz H ==> analz (insert X H) = analz H" by (metis analz_cut analz_insert_eq_I insert_absorb) text\A congruence rule for "analz"\ lemma analz_subset_cong: "[| analz G \ analz G'; analz H \ analz H' |] ==> analz (G \ H) \ analz (G' \ H')" by (metis Un_mono analz_Un analz_subset_iff subset_trans) lemma analz_cong: "[| analz G = analz G'; analz H = analz H' |] ==> analz (G \ H) = analz (G' \ 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\If there are no pairs or encryptions then analz does nothing\ 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 subsection\Inductive relation "synth"\ text\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.\ 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\Monotonicity\ lemma synth_mono: "G\H ==> synth(G) \ synth(H)" by (auto, erule synth.induct, auto) text\NO \Agent_synth\, as any Agent name can be synthesized. The same holds for @{term Number}\ inductive_simps synth_simps [iff]: "Nonce n \ synth H" "Key K \ synth H" "Hash X \ synth H" "\X,Y\ \ synth H" "Crypt K X \ synth H" lemma synth_increasing: "H \ synth(H)" by blast subsubsection\Unions\ text\Converse fails: we can synth more from the union than from the separate parts, building a compound message using elements of each.\ 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 (blast intro: synth_mono [THEN [2] rev_subsetD]) subsubsection\Idempotence and transitivity\ lemma synth_synthD [dest!]: "X\ synth (synth H) ==> X\ synth H" by (erule synth.induct, auto) lemma synth_idem: "synth (synth H) = synth H" by blast lemma synth_subset_iff [simp]: "(synth G \ synth H) = (G \ synth H)" by (metis subset_trans synth_idem synth_increasing synth_mono) lemma synth_trans: "[| X\ synth G; G \ synth H |] ==> X\ synth H" by (drule synth_mono, blast) text\Cut; Lemma 2 of Lowe\ lemma synth_cut: "[| Y\ synth (insert X H); X\ synth H |] ==> Y\ synth H" by (erule synth_trans, blast) lemma Agent_synth [simp]: "Agent A \ synth H" by blast lemma Number_synth [simp]: "Number n \ synth H" by blast lemma Nonce_synth_eq [simp]: "(Nonce N \ synth H) = (Nonce N \ H)" by blast lemma Key_synth_eq [simp]: "(Key K \ synth H) = (Key K \ H)" by blast lemma Crypt_synth_eq [simp]: "Key K \ H ==> (Crypt K X \ synth H) = (Crypt K X \ H)" by blast lemma keysFor_synth [simp]: "keysFor (synth H) = keysFor H \ invKey`{K. Key K \ H}" by (unfold keysFor_def, blast) subsubsection\Combinations of parts, analz and synth\ lemma parts_synth [simp]: "parts (synth H) = parts H \ synth H" apply (rule equalityI) apply (rule subsetI) apply (erule parts.induct) apply (blast intro: synth_increasing [THEN parts_mono, THEN subsetD] parts.Fst parts.Snd parts.Body)+ done lemma analz_analz_Un [simp]: "analz (analz G \ H) = analz (G \ H)" apply (intro equalityI analz_subset_cong)+ apply simp_all done lemma analz_synth_Un [simp]: "analz (synth G \ H) = analz (G \ H) \ synth G" apply (rule equalityI) apply (rule subsetI) apply (erule analz.induct) prefer 5 apply (blast intro: analz_mono [THEN [2] rev_subsetD]) apply (blast intro: analz.Fst analz.Snd analz.Decrypt)+ done lemma analz_synth [simp]: "analz (synth H) = analz H \ synth H" by (metis Un_empty_right analz_synth_Un) subsubsection\For reasoning about the Fake rule in traces\ lemma parts_insert_subset_Un: "X\ G ==> parts(insert X H) \ parts G \ parts H" by (metis UnCI Un_upper2 insert_subset parts_Un parts_mono) text\More specifically for Fake. See also \Fake_parts_sing\ below\ lemma Fake_parts_insert: "X \ synth (analz H) ==> parts (insert X H) \ synth (analz H) \ parts H" by (metis Un_commute analz_increasing insert_subset parts_analz parts_mono parts_synth synth_mono synth_subset_iff) lemma Fake_parts_insert_in_Un: "[|Z \ parts (insert X H); X: synth (analz H)|] ==> Z \ synth (analz H) \ parts H" by (metis Fake_parts_insert subsetD) text\@{term H} is sometimes @{term"Key ` KK \ spies evs"}, so can't put @{term "G=H"}.\ lemma Fake_analz_insert: "X\ synth (analz G) ==> analz (insert X H) \ synth (analz G) \ analz (G \ H)" apply (rule subsetI) apply (subgoal_tac "x \ analz (synth (analz G) \ H)", force) apply (blast intro: analz_mono [THEN [2] rev_subsetD] analz_mono [THEN synth_mono, THEN [2] rev_subsetD]) done lemma analz_conj_parts [simp]: "(X \ analz H \ X \ parts H) = (X \ analz H)" by (blast intro: analz_subset_parts [THEN subsetD]) lemma analz_disj_parts [simp]: "(X \ analz H | X \ parts H) = (X \ parts H)" by (blast intro: analz_subset_parts [THEN subsetD]) text\Without this equation, other rules for synth and analz would yield redundant cases\ lemma MPair_synth_analz [iff]: "(\X,Y\ \ synth (analz H)) = (X \ synth (analz H) \ Y \ synth (analz H))" by blast lemma Crypt_synth_analz: "[| Key K \ analz H; Key (invKey K) \ analz H |] ==> (Crypt K X \ synth (analz H)) = (X \ synth (analz H))" by blast lemma Hash_synth_analz [simp]: "X \ synth (analz H) ==> (Hash\X,Y\ \ synth (analz H)) = (Hash\X,Y\ \ analz H)" by blast subsection\HPair: a combination of Hash and MPair\ subsubsection\Freeness\ lemma Agent_neq_HPair: "Agent A ~= Hash[X] Y" by (unfold HPair_def, simp) lemma Nonce_neq_HPair: "Nonce N ~= Hash[X] Y" by (unfold HPair_def, simp) lemma Number_neq_HPair: "Number N ~= Hash[X] Y" by (unfold HPair_def, simp) lemma Key_neq_HPair: "Key K ~= Hash[X] Y" by (unfold HPair_def, simp) lemma Hash_neq_HPair: "Hash Z ~= Hash[X] Y" by (unfold HPair_def, simp) lemma Crypt_neq_HPair: "Crypt K X' ~= Hash[X] Y" by (unfold HPair_def, simp) lemmas HPair_neqs = Agent_neq_HPair Nonce_neq_HPair Number_neq_HPair Key_neq_HPair Hash_neq_HPair Crypt_neq_HPair declare HPair_neqs [iff] declare HPair_neqs [symmetric, iff] lemma HPair_eq [iff]: "(Hash[X'] Y' = Hash[X] Y) = (X' = X \ Y'=Y)" by (simp add: HPair_def) lemma MPair_eq_HPair [iff]: "(\X',Y'\ = Hash[X] Y) = (X' = Hash\X,Y\ \ Y'=Y)" by (simp add: HPair_def) lemma HPair_eq_MPair [iff]: "(Hash[X] Y = \X',Y'\) = (X' = Hash\X,Y\ \ Y'=Y)" by (auto simp add: HPair_def) subsubsection\Specialized laws, proved in terms of those for Hash and MPair\ lemma keysFor_insert_HPair [simp]: "keysFor (insert (Hash[X] Y) H) = keysFor H" by (simp add: HPair_def) lemma parts_insert_HPair [simp]: "parts (insert (Hash[X] Y) H) = insert (Hash[X] Y) (insert (Hash\X,Y\) (parts (insert Y H)))" by (simp add: HPair_def) lemma analz_insert_HPair [simp]: "analz (insert (Hash[X] Y) H) = insert (Hash[X] Y) (insert (Hash\X,Y\) (analz (insert Y H)))" by (simp add: HPair_def) lemma HPair_synth_analz [simp]: "X \ synth (analz H) ==> (Hash[X] Y \ synth (analz H)) = (Hash \X, Y\ \ analz H \ Y \ synth (analz H))" by (auto simp add: HPair_def) text\We do NOT want Crypt... messages broken up in protocols!!\ declare parts.Body [rule del] text\Rewrites to push in Key and Crypt messages, so that other messages can be pulled out using the \analz_insert\ rules\ lemmas pushKeys = insert_commute [of "Key K" "Agent C"] insert_commute [of "Key K" "Nonce N"] insert_commute [of "Key K" "Number N"] insert_commute [of "Key K" "Hash X"] insert_commute [of "Key K" "MPair X Y"] insert_commute [of "Key K" "Crypt X K'"] for K C N X Y K' lemmas pushCrypts = insert_commute [of "Crypt X K" "Agent C"] insert_commute [of "Crypt X K" "Agent C"] insert_commute [of "Crypt X K" "Nonce N"] insert_commute [of "Crypt X K" "Number N"] insert_commute [of "Crypt X K" "Hash X'"] insert_commute [of "Crypt X K" "MPair X' Y"] for X K C N X' Y text\Cannot be added with \[simp]\ -- messages should not always be re-ordered.\ lemmas pushes = pushKeys pushCrypts subsection\The set of key-free messages\ (*Note that even the encryption of a key-free message remains key-free. This concept is valuable because of the theorem analz_keyfree_into_Un, proved below. *) inductive_set keyfree :: "msg set" where Agent: "Agent A \ keyfree" | Number: "Number N \ keyfree" | Nonce: "Nonce N \ keyfree" | Hash: "Hash X \ keyfree" | MPair: "[|X \ keyfree; Y \ keyfree|] ==> \X,Y\ \ keyfree" | Crypt: "[|X \ keyfree|] ==> Crypt K X \ keyfree" declare keyfree.intros [intro] inductive_cases keyfree_KeyE: "Key K \ keyfree" inductive_cases keyfree_MPairE: "\X,Y\ \ keyfree" inductive_cases keyfree_CryptE: "Crypt K X \ keyfree" lemma parts_keyfree: "parts (keyfree) \ keyfree" by (clarify, erule parts.induct, auto elim!: keyfree_KeyE keyfree_MPairE keyfree_CryptE) (*The key-free part of a set of messages can be removed from the scope of the analz operator.*) lemma analz_keyfree_into_Un: "\X \ analz (G \ H); G \ keyfree\ \ X \ parts G \ analz H" apply (erule analz.induct, auto) apply (blast dest:parts.Body) apply (blast dest: parts.Body) apply (metis Un_absorb2 keyfree_KeyE parts_Un parts_keyfree UnI2) done subsection\Tactics useful for many protocol proofs\ ML \ (*Analysis of Fake cases. Also works for messages that forward unknown parts, but this application is no longer necessary if analz_insert_eq is used. DEPENDS UPON "X" REFERRING TO THE FRADULENT MESSAGE *) fun impOfSubs th = th RSN (2, @{thm rev_subsetD}) (*Apply rules to break down assumptions of the form Y \ parts(insert X H) and Y \ analz(insert X H) *) fun Fake_insert_tac ctxt = dresolve_tac ctxt [impOfSubs @{thm Fake_analz_insert}, impOfSubs @{thm Fake_parts_insert}] THEN' eresolve_tac ctxt [asm_rl, @{thm synth.Inj}]; fun Fake_insert_simp_tac ctxt i = REPEAT (Fake_insert_tac ctxt i) THEN asm_full_simp_tac ctxt i; fun atomic_spy_analz_tac ctxt = SELECT_GOAL (Fake_insert_simp_tac ctxt 1 THEN IF_UNSOLVED (Blast.depth_tac (ctxt addIs [@{thm analz_insertI}, impOfSubs @{thm analz_subset_parts}]) 4 1)); fun spy_analz_tac ctxt i = DETERM (SELECT_GOAL (EVERY [ (*push in occurrences of X...*) (REPEAT o CHANGED) (Rule_Insts.res_inst_tac ctxt [((("x", 1), Position.none), "X")] [] (insert_commute RS ssubst) 1), (*...allowing further simplifications*) simp_tac ctxt 1, REPEAT (FIRSTGOAL (resolve_tac ctxt [allI,impI,notI,conjI,iffI])), DEPTH_SOLVE (atomic_spy_analz_tac ctxt 1)]) i); \ text\By default only \o_apply\ is built-in. But in the presence of eta-expansion this means that some terms displayed as @{term "f o g"} will be rewritten, and others will not!\ declare o_def [simp] lemma Crypt_notin_image_Key [simp]: "Crypt K X \ Key ` A" by auto lemma Hash_notin_image_Key [simp] :"Hash X \ Key ` A" by auto lemma synth_analz_mono: "G\H ==> synth (analz(G)) \ synth (analz(H))" by (iprover intro: synth_mono analz_mono) lemma Fake_analz_eq [simp]: "X \ synth(analz H) ==> synth (analz (insert X H)) = synth (analz H)" by (metis Fake_analz_insert Un_absorb Un_absorb1 Un_commute subset_insertI synth_analz_mono synth_increasing synth_subset_iff) text\Two generalizations of \analz_insert_eq\\ lemma gen_analz_insert_eq [rule_format]: "X \ analz H ==> \G. H \ G --> analz (insert X G) = analz G" by (blast intro: analz_cut analz_insertI analz_mono [THEN [2] rev_subsetD]) lemma synth_analz_insert_eq [rule_format]: "X \ synth (analz H) ==> \G. H \ G --> (Key K \ analz (insert X G)) = (Key K \ analz G)" apply (erule synth.induct) apply (simp_all add: gen_analz_insert_eq subset_trans [OF _ subset_insertI]) done lemma Fake_parts_sing: "X \ synth (analz H) ==> parts{X} \ synth (analz H) \ parts H" by (metis Fake_parts_insert empty_subsetI insert_mono parts_mono subset_trans) lemmas Fake_parts_sing_imp_Un = Fake_parts_sing [THEN [2] rev_subsetD] method_setup spy_analz = \ Scan.succeed (SIMPLE_METHOD' o spy_analz_tac)\ "for proving the Fake case when analz is involved" method_setup atomic_spy_analz = \ Scan.succeed (SIMPLE_METHOD' o atomic_spy_analz_tac)\ "for debugging spy_analz" method_setup Fake_insert_simp = \ Scan.succeed (SIMPLE_METHOD' o Fake_insert_simp_tac)\ "for debugging spy_analz" end diff --git a/thys/Inductive_Confidentiality/GeneralAttacker/MessageGA.thy b/thys/Inductive_Confidentiality/GeneralAttacker/MessageGA.thy --- a/thys/Inductive_Confidentiality/GeneralAttacker/MessageGA.thy +++ b/thys/Inductive_Confidentiality/GeneralAttacker/MessageGA.thy @@ -1,919 +1,907 @@ section\Theory of Agents and Messages for Security Protocols against the General Attacker\ theory MessageGA imports Main begin (*Needed occasionally with spy_analz_tac, e.g. in analz_insert_Key_newK*) lemma [simp] : "A \ (B \ A) = B \ A" by blast type_synonym key = nat consts all_symmetric :: bool \ \true if all keys are symmetric\ invKey :: "key=>key" \ \inverse of a symmetric key\ specification (invKey) invKey [simp]: "invKey (invKey K) = K" invKey_symmetric: "all_symmetric \ invKey = id" by (rule exI [of _ id], auto) text\The inverse of a symmetric key is itself; that of a public key is the private key and vice versa\ definition symKeys :: "key set" where "symKeys == {K. invKey K = K}" datatype \ \We only allow for any number of friendly agents\ agent = Friend nat datatype msg = Agent agent \ \Agent names\ | Number nat \ \Ordinary integers, timestamps, ...\ | Nonce nat \ \Unguessable nonces\ | Key key \ \Crypto keys\ | Hash msg \ \Hashing\ | MPair msg msg \ \Compound messages\ | Crypt key msg \ \Encryption, public- or shared-key\ text\Concrete syntax: messages appear as \\A,B,NA\\, etc...\ syntax "_MTuple" :: "['a, args] => 'a * 'b" ("(2\_,/ _\)") translations "\x, y, z\" == "\x, \y, z\\" "\x, y\" == "CONST MPair x y" definition HPair :: "[msg,msg] => msg" ("(4Hash[_] /_)" [0, 1000]) where \ \Message Y paired with a MAC computed with the help of X\ "Hash[X] Y == \ Hash\X,Y\, Y\" definition keysFor :: "msg set => key set" where \ \Keys useful to decrypt elements of a message set\ "keysFor H == invKey ` {K. \X. Crypt K X \ H}" subsection\Inductive definition of all parts of a message\ 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" text\Monotonicity\ lemma parts_mono: "G \ H \ parts(G) \ parts(H)" apply auto apply (erule parts.induct) apply (blast dest: parts.Fst parts.Snd parts.Body)+ done text\Equations hold because constructors are injective.\ lemma Friend_image_eq [simp]: "(Friend x \ Friend`A) = (x:A)" by auto lemma Key_image_eq [simp]: "(Key x \ Key`A) = (x\A)" by auto lemma Nonce_Key_image_eq [simp]: "(Nonce x \ Key`A)" by auto subsection\Inverse of keys\ lemma invKey_eq [simp]: "(invKey K = invKey K') = (K=K')" by (metis invKey) subsection\keysFor operator\ lemma keysFor_empty [simp]: "keysFor {} = {}" by (unfold keysFor_def, blast) lemma keysFor_Un [simp]: "keysFor (H \ H') = keysFor H \ keysFor H'" by (unfold keysFor_def, blast) lemma keysFor_UN [simp]: "keysFor (\i\A. H i) = (\i\A. keysFor (H i))" by (unfold keysFor_def, blast) text\Monotonicity\ lemma keysFor_mono: "G \ H \ keysFor(G) \ keysFor(H)" by (unfold keysFor_def, blast) lemma keysFor_insert_Agent [simp]: "keysFor (insert (Agent A) H) = keysFor H" by (unfold keysFor_def, auto) lemma keysFor_insert_Nonce [simp]: "keysFor (insert (Nonce N) H) = keysFor H" by (unfold keysFor_def, auto) lemma keysFor_insert_Number [simp]: "keysFor (insert (Number N) H) = keysFor H" by (unfold keysFor_def, auto) lemma keysFor_insert_Key [simp]: "keysFor (insert (Key K) H) = keysFor H" by (unfold keysFor_def, auto) lemma keysFor_insert_Hash [simp]: "keysFor (insert (Hash X) H) = keysFor H" by (unfold keysFor_def, auto) lemma keysFor_insert_MPair [simp]: "keysFor (insert \X,Y\ H) = keysFor H" by (unfold keysFor_def, auto) lemma keysFor_insert_Crypt [simp]: "keysFor (insert (Crypt K X) H) = insert (invKey K) (keysFor H)" by (unfold keysFor_def, auto) lemma keysFor_image_Key [simp]: "keysFor (Key`E) = {}" by (unfold keysFor_def, auto) lemma Crypt_imp_invKey_keysFor: "Crypt K X \ H \ invKey K \ keysFor H" by (unfold keysFor_def, blast) subsection\Inductive relation "parts"\ lemma MPair_parts: "[| \X,Y\ \ parts H; [| X \ parts H; Y \ parts H |] ==> P |] ==> P" by (blast dest: parts.Fst parts.Snd) declare MPair_parts [elim!] parts.Body [dest!] text\NB These two rules are UNSAFE in the formal sense, as they discard the compound message. They work well on THIS FILE. \MPair_parts\ is left as SAFE because it speeds up proofs. The Crypt rule is normally kept UNSAFE to avoid breaking up certificates.\ lemma parts_increasing: "H \ parts(H)" by blast lemmas parts_insertI = subset_insertI [THEN parts_mono, THEN subsetD] lemma parts_empty [simp]: "parts{} = {}" apply safe apply (erule parts.induct, blast+) done lemma parts_emptyE [elim!]: "X\ parts{} \ P" by simp text\WARNING: loops if H = {Y}, therefore must not be repeated!\ lemma parts_singleton: "X\ parts H \ \Y\H. X\ parts {Y}" by (erule parts.induct, fast+) subsubsection\Unions\ lemma parts_Un_subset1: "parts(G) \ parts(H) \ parts(G \ H)" by (intro Un_least parts_mono Un_upper1 Un_upper2) lemma parts_Un_subset2: "parts(G \ H) \ parts(G) \ parts(H)" apply (rule subsetI) apply (erule parts.induct, blast+) done lemma parts_Un [simp]: "parts(G \ H) = parts(G) \ parts(H)" by (intro equalityI parts_Un_subset1 parts_Un_subset2) lemma parts_insert: "parts (insert X H) = parts {X} \ parts H" by (metis insert_is_Un parts_Un) text\TWO inserts to avoid looping. This rewrite is better than nothing. Not suitable for Addsimps: its behaviour can be strange.\ lemma parts_insert2: "parts (insert X (insert Y H)) = parts {X} \ parts {Y} \ parts H" by (metis Un_commute Un_empty_right Un_insert_right insert_is_Un parts_Un) -lemma parts_UN_subset1: "(\x\A. parts(H x)) \ parts(\x\A. H x)" -by (intro UN_least parts_mono UN_upper) - -lemma parts_UN_subset2: "parts(\x\A. H x) \ (\x\A. parts(H x))" -apply (rule subsetI) -apply (erule parts.induct, blast+) -done - -lemma parts_UN [simp]: "parts(\x\A. H x) = (\x\A. parts(H x))" -by (intro equalityI parts_UN_subset1 parts_UN_subset2) - -text\Added to simplify arguments to parts, analz and synth. - NOTE: the UN versions are no longer used!\ +text\Added to simplify arguments to parts, analz and synth.\ text\This allows \blast\ to simplify occurrences of @{term "parts(G\H)"} in the assumption.\ 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\Idempotence and transitivity\ 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)" by (metis parts_idem parts_increasing parts_mono subset_trans) lemma parts_trans: "[| X \ parts G; G \ parts H |] ==> X\ parts H" by (drule parts_mono, blast) text\Cut\ lemma parts_cut: "[| Y\ parts (insert X G); X \ parts H |] ==> Y\ parts (G \ H)" by (blast intro: parts_trans) lemma parts_cut_eq [simp]: "X \ parts H \ parts (insert X H) = parts H" by (force dest!: parts_cut intro: parts_insertI) subsubsection\Rewrite rules for pulling out atomic messages\ lemmas parts_insert_eq_I = equalityI [OF subsetI parts_insert_subset] lemma parts_insert_Agent [simp]: "parts (insert (Agent agt) H) = insert (Agent agt) (parts H)" apply (rule parts_insert_eq_I) apply (erule parts.induct, auto) done lemma parts_insert_Nonce [simp]: "parts (insert (Nonce N) H) = insert (Nonce N) (parts H)" apply (rule parts_insert_eq_I) apply (erule parts.induct, auto) done lemma parts_insert_Number [simp]: "parts (insert (Number N) H) = insert (Number N) (parts H)" apply (rule parts_insert_eq_I) apply (erule parts.induct, auto) done lemma parts_insert_Key [simp]: "parts (insert (Key K) H) = insert (Key K) (parts H)" apply (rule parts_insert_eq_I) apply (erule parts.induct, auto) done lemma parts_insert_Hash [simp]: "parts (insert (Hash X) H) = insert (Hash X) (parts H)" apply (rule parts_insert_eq_I) apply (erule parts.induct, auto) done lemma parts_insert_Crypt [simp]: "parts (insert (Crypt K X) H) = insert (Crypt K X) (parts (insert X H))" apply (rule equalityI) apply (rule subsetI) apply (erule parts.induct, auto) apply (blast intro: parts.Body) done lemma parts_insert_MPair [simp]: "parts (insert \X,Y\ H) = insert \X,Y\ (parts (insert X (insert Y H)))" apply (rule equalityI) apply (rule subsetI) apply (erule parts.induct, auto) apply (blast intro: parts.Fst parts.Snd)+ done lemma parts_image_Key [simp]: "parts (Key`N) = Key`N" apply auto apply (erule parts.induct, auto) done text\In any message, there is an upper bound N on its greatest nonce.\ lemma msg_Nonce_supply: "\N. \n. N\n \ Nonce n \ parts {msg}" apply (induct msg) apply (simp_all (no_asm_simp) add: exI parts_insert2) txt\Nonce case\ apply (metis Suc_n_not_le_n) txt\MPair case: metis works out the necessary sum itself!\ apply (metis le_trans nat_le_linear) done subsection\Inductive relation "analz"\ text\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.\ 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\Monotonicity; Lemma 1 of Lowe's paper\ lemma analz_mono: "G\H \ analz(G) \ analz(H)" apply auto apply (erule analz.induct) apply (auto dest: analz.Fst analz.Snd) done text\Making it safe speeds up proofs\ lemma MPair_analz [elim!]: "[| \X,Y\ \ analz H; [| X \ analz H; Y \ 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 lemmas analz_into_parts = analz_subset_parts [THEN subsetD] lemmas not_parts_not_analz = analz_subset_parts [THEN contra_subsetD] lemma parts_analz [simp]: "parts (analz H) = parts H" by (metis analz_increasing analz_subset_parts equalityI parts_mono parts_subset_iff) lemma analz_parts [simp]: "analz (parts H) = parts H" apply auto apply (erule analz.induct, auto) done lemmas analz_insertI = subset_insertI [THEN analz_mono, THEN [2] rev_subsetD] subsubsection\General equational properties\ lemma analz_empty [simp]: "analz{} = {}" apply safe apply (erule analz.induct, blast+) done text\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\ 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\Rewrite rules for pulling out atomic messages\ lemmas analz_insert_eq_I = equalityI [OF subsetI analz_insert] lemma analz_insert_Agent [simp]: "analz (insert (Agent agt) H) = insert (Agent agt) (analz H)" apply (rule analz_insert_eq_I) apply (erule analz.induct, auto) done lemma analz_insert_Nonce [simp]: "analz (insert (Nonce N) H) = insert (Nonce N) (analz H)" apply (rule analz_insert_eq_I) apply (erule analz.induct, auto) done lemma analz_insert_Number [simp]: "analz (insert (Number N) H) = insert (Number N) (analz H)" apply (rule analz_insert_eq_I) apply (erule analz.induct, auto) done lemma analz_insert_Hash [simp]: "analz (insert (Hash X) H) = insert (Hash X) (analz H)" apply (rule analz_insert_eq_I) apply (erule analz.induct, auto) done text\Can only pull out Keys if they are not needed to decrypt the rest\ lemma analz_insert_Key [simp]: "K \ keysFor (analz H) \ analz (insert (Key K) H) = insert (Key K) (analz H)" apply (unfold keysFor_def) apply (rule analz_insert_eq_I) apply (erule analz.induct, auto) done lemma analz_insert_MPair [simp]: "analz (insert \X,Y\ H) = insert \X,Y\ (analz (insert X (insert Y H)))" apply (rule equalityI) apply (rule subsetI) apply (erule analz.induct, auto) apply (erule analz.induct) apply (blast intro: analz.Fst analz.Snd)+ done text\Can pull out enCrypted message if the Key is not known\ 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) \ 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)) \ 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\Case analysis: either the message is secure, or it is not! Effective, but can cause subgoals to blow up! Use with \if_split\; apparently \split_tac\ does not cope with patterns such as @{term"analz (insert (Crypt K X) H)"}\ lemma analz_Crypt_if [simp]: "analz (insert (Crypt K X) H) = (if (Key (invKey K) \ 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\This rule supposes "for the sake of argument" that we have the key.\ 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_image_Key [simp]: "analz (Key`N) = Key`N" apply auto apply (erule analz.induct, auto) done subsubsection\Idempotence and transitivity\ lemma analz_analzD [dest!]: "X\ analz (analz H) \ X \ analz H" by (erule analz.induct, blast+) lemma analz_idem [simp]: "analz (analz H) = analz H" by blast lemma analz_subset_iff [simp]: "(analz G \ analz H) = (G \ analz H)" by (metis analz_idem analz_increasing analz_mono subset_trans) lemma analz_trans: "[| X\ analz G; G \ analz H |] ==> X\ analz H" by (drule analz_mono, blast) text\Cut; Lemma 2 of Lowe\ lemma analz_cut: "[| Y\ analz (insert X H); X\ analz H |] ==> Y\ analz H" by (erule analz_trans, blast) (*Cut can be proved easily by induction on "Y: analz (insert X H) \ X: analz H \ Y: analz H" *) text\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.\ lemma analz_insert_eq: "X \ analz H \ analz (insert X H) = analz H" by (blast intro: analz_cut analz_insertI) text\A congruence rule for "analz"\ lemma analz_subset_cong: "[| analz G \ analz G'; analz H \ analz H' |] ==> analz (G \ H) \ analz (G' \ H')" apply simp apply (iprover intro: conjI subset_trans analz_mono Un_upper1 Un_upper2) done lemma analz_cong: "[| analz G = analz G'; analz H = analz H' |] ==> analz (G \ H) = analz (G' \ 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\If there are no pairs or encryptions then analz does nothing\ 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 subsection\Inductive relation "synth"\ text\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.\ 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\Monotonicity\ lemma synth_mono: "G\H \ synth(G) \ synth(H)" by (auto, erule synth.induct, auto) text\NO \Agent_synth\, as any Agent name can be synthesized. The same holds for @{term Number}\ inductive_simps synth_simps [iff]: "Nonce n \ synth H" "Key K \ synth H" "Hash X \ synth H" "\X,Y\ \ synth H" "Crypt K X \ synth H" lemma synth_increasing: "H \ synth(H)" by blast subsubsection\Unions\ text\Converse fails: we can synth more from the union than from the separate parts, building a compound message using elements of each.\ 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 (blast intro: synth_mono [THEN [2] rev_subsetD]) subsubsection\Idempotence and transitivity\ lemma synth_synthD [dest!]: "X \ synth (synth H) \ X\ synth H" by (erule synth.induct, auto) lemma synth_idem: "synth (synth H) = synth H" by blast lemma synth_subset_iff [simp]: "(synth G \ synth H) = (G \ synth H)" by (metis subset_trans synth_idem synth_increasing synth_mono) lemma synth_trans: "[| X\ synth G; G \ synth H |] ==> X\ synth H" by (drule synth_mono, blast) text\Cut; Lemma 2 of Lowe\ lemma synth_cut: "[| Y\ synth (insert X H); X\ synth H |] ==> Y\ synth H" by (erule synth_trans, blast) lemma Agent_synth [simp]: "Agent A \ synth H" by blast lemma Number_synth [simp]: "Number n \ synth H" by blast lemma Nonce_synth_eq [simp]: "(Nonce N \ synth H) = (Nonce N \ H)" by blast lemma Key_synth_eq [simp]: "(Key K \ synth H) = (Key K \ H)" by blast lemma Crypt_synth_eq [simp]: "Key K \ H \ (Crypt K X \ synth H) = (Crypt K X \ H)" by blast lemma keysFor_synth [simp]: "keysFor (synth H) = keysFor H \ invKey`{K. Key K \ H}" by (unfold keysFor_def, blast) subsubsection\Combinations of parts, analz and synth\ lemma parts_synth [simp]: "parts (synth H) = parts H \ synth H" apply (rule equalityI) apply (rule subsetI) apply (erule parts.induct) apply (blast intro: synth_increasing [THEN parts_mono, THEN subsetD] parts.Fst parts.Snd parts.Body)+ done lemma analz_analz_Un [simp]: "analz (analz G \ H) = analz (G \ H)" apply (intro equalityI analz_subset_cong)+ apply simp_all done lemma analz_synth_Un [simp]: "analz (synth G \ H) = analz (G \ H) \ synth G" apply (rule equalityI) apply (rule subsetI) apply (erule analz.induct) prefer 5 apply (blast intro: analz_mono [THEN [2] rev_subsetD]) apply (blast intro: analz.Fst analz.Snd analz.Decrypt)+ done lemma analz_synth [simp]: "analz (synth H) = analz H \ synth H" by (metis Un_empty_right analz_synth_Un) subsubsection\For reasoning about the Fake rule in traces\ lemma parts_insert_subset_Un: "X \ G \ parts(insert X H) \ parts G \ parts H" by (metis UnCI Un_upper2 insert_subset parts_Un parts_mono) text\More specifically for Fake. See also \Fake_parts_sing\ below\ lemma Fake_parts_insert: "X \ synth (analz H) \ parts (insert X H) \ synth (analz H) \ parts H" by (metis Un_commute analz_increasing insert_subset parts_analz parts_mono parts_synth synth_mono synth_subset_iff) lemma Fake_parts_insert_in_Un: "[|Z \ parts (insert X H); X: synth (analz H)|] ==> Z \ synth (analz H) \ parts H" by (metis Fake_parts_insert subsetD) text\@{term H} is sometimes @{term"Key ` KK \ spies evs"}, so can't put @{term "G=H"}.\ lemma Fake_analz_insert: "X\ synth (analz G) \ analz (insert X H) \ synth (analz G) \ analz (G \ H)" apply (rule subsetI) apply (subgoal_tac "x \ analz (synth (analz G) \ H)", force) apply (blast intro: analz_mono [THEN [2] rev_subsetD] analz_mono [THEN synth_mono, THEN [2] rev_subsetD]) done lemma analz_conj_parts [simp]: "(X \ analz H \ X \ parts H) = (X \ analz H)" by (blast intro: analz_subset_parts [THEN subsetD]) lemma analz_disj_parts [simp]: "(X \ analz H | X \ parts H) = (X \ parts H)" by (blast intro: analz_subset_parts [THEN subsetD]) text\Without this equation, other rules for synth and analz would yield redundant cases\ lemma MPair_synth_analz [iff]: "(\X,Y\ \ synth (analz H)) = (X \ synth (analz H) \ Y \ synth (analz H))" by blast lemma Crypt_synth_analz: "[| Key K \ analz H; Key (invKey K) \ analz H |] ==> (Crypt K X \ synth (analz H)) = (X \ synth (analz H))" by blast lemma Hash_synth_analz [simp]: "X \ synth (analz H) \ (Hash\X,Y\ \ synth (analz H)) = (Hash\X,Y\ \ analz H)" by blast subsection\HPair: a combination of Hash and MPair\ subsubsection\Freeness\ lemma Agent_neq_HPair: "Agent A ~= Hash[X] Y" by (unfold HPair_def, simp) lemma Nonce_neq_HPair: "Nonce N ~= Hash[X] Y" by (unfold HPair_def, simp) lemma Number_neq_HPair: "Number N ~= Hash[X] Y" by (unfold HPair_def, simp) lemma Key_neq_HPair: "Key K ~= Hash[X] Y" by (unfold HPair_def, simp) lemma Hash_neq_HPair: "Hash Z ~= Hash[X] Y" by (unfold HPair_def, simp) lemma Crypt_neq_HPair: "Crypt K X' ~= Hash[X] Y" by (unfold HPair_def, simp) lemmas HPair_neqs = Agent_neq_HPair Nonce_neq_HPair Number_neq_HPair Key_neq_HPair Hash_neq_HPair Crypt_neq_HPair declare HPair_neqs [iff] declare HPair_neqs [symmetric, iff] lemma HPair_eq [iff]: "(Hash[X'] Y' = Hash[X] Y) = (X' = X \ Y'=Y)" by (simp add: HPair_def) lemma MPair_eq_HPair [iff]: "(\X',Y'\ = Hash[X] Y) = (X' = Hash\X,Y\ \ Y'=Y)" by (simp add: HPair_def) lemma HPair_eq_MPair [iff]: "(Hash[X] Y = \X',Y'\) = (X' = Hash\X,Y\ \ Y'=Y)" by (auto simp add: HPair_def) subsubsection\Specialized laws, proved in terms of those for Hash and MPair\ lemma keysFor_insert_HPair [simp]: "keysFor (insert (Hash[X] Y) H) = keysFor H" by (simp add: HPair_def) lemma parts_insert_HPair [simp]: "parts (insert (Hash[X] Y) H) = insert (Hash[X] Y) (insert (Hash\X,Y\) (parts (insert Y H)))" by (simp add: HPair_def) lemma analz_insert_HPair [simp]: "analz (insert (Hash[X] Y) H) = insert (Hash[X] Y) (insert (Hash\X,Y\) (analz (insert Y H)))" by (simp add: HPair_def) lemma HPair_synth_analz [simp]: "X \ synth (analz H) \ (Hash[X] Y \ synth (analz H)) = (Hash \X, Y\ \ analz H \ Y \ synth (analz H))" by (auto simp add: HPair_def) text\We do NOT want Crypt... messages broken up in protocols!!\ declare parts.Body [rule del] text\Rewrites to push in Key and Crypt messages, so that other messages can be pulled out using the \analz_insert\ rules\ lemmas pushKeys = insert_commute [of "Key K" "Agent C"] insert_commute [of "Key K" "Nonce N"] insert_commute [of "Key K" "Number N"] insert_commute [of "Key K" "Hash X"] insert_commute [of "Key K" "MPair X Y"] insert_commute [of "Key K" "Crypt X K'"] for K C N X Y K' lemmas pushCrypts = insert_commute [of "Crypt X K" "Agent C"] insert_commute [of "Crypt X K" "Agent C"] insert_commute [of "Crypt X K" "Nonce N"] insert_commute [of "Crypt X K" "Number N"] insert_commute [of "Crypt X K" "Hash X'"] insert_commute [of "Crypt X K" "MPair X' Y"] for X K C N X' Y text\Cannot be added with \[simp]\ -- messages should not always be re-ordered.\ lemmas pushes = pushKeys pushCrypts subsection\The set of key-free messages\ (*Note that even the encryption of a key-free message remains key-free. This concept is valuable because of the theorem analz_keyfree_into_Un, proved below. *) inductive_set keyfree :: "msg set" where Agent: "Agent A \ keyfree" | Number: "Number N \ keyfree" | Nonce: "Nonce N \ keyfree" | Hash: "Hash X \ keyfree" | MPair: "[|X \ keyfree; Y \ keyfree|] ==> \X,Y\ \ keyfree" | Crypt: "[|X \ keyfree|] ==> Crypt K X \ keyfree" declare keyfree.intros [intro] inductive_cases keyfree_KeyE: "Key K \ keyfree" inductive_cases keyfree_MPairE: "\X,Y\ \ keyfree" inductive_cases keyfree_CryptE: "Crypt K X \ keyfree" lemma parts_keyfree: "parts (keyfree) \ keyfree" by (clarify, erule parts.induct, auto elim!: keyfree_KeyE keyfree_MPairE keyfree_CryptE) (*The key-free part of a set of messages can be removed from the scope of the analz operator.*) lemma analz_keyfree_into_Un: "\X \ analz (G \ H); G \ keyfree\ \ X \ parts G \ analz H" apply (erule analz.induct, auto) apply (blast dest:parts.Body) apply (blast dest: parts.Body) apply (metis Un_absorb2 keyfree_KeyE parts_Un parts_keyfree UnI2) done subsection\Tactics useful for many protocol proofs\ ML \ (*Analysis of Fake cases. Also works for messages that forward unknown parts, but this application is no longer necessary if analz_insert_eq is used. DEPENDS UPON "X" REFERRING TO THE FRADULENT MESSAGE *) fun impOfSubs th = th RSN (2, @{thm rev_subsetD}) (*Apply rules to break down assumptions of the form Y \ parts(insert X H) and Y \ analz(insert X H) *) fun Fake_insert_tac ctxt = dresolve_tac ctxt [impOfSubs @{thm Fake_analz_insert}, impOfSubs @{thm Fake_parts_insert}] THEN' eresolve_tac ctxt [asm_rl, @{thm synth.Inj}]; fun Fake_insert_simp_tac ctxt i = REPEAT (Fake_insert_tac ctxt i) THEN asm_full_simp_tac ctxt i; fun atomic_spy_analz_tac ctxt = SELECT_GOAL (Fake_insert_simp_tac ctxt 1 THEN IF_UNSOLVED (Blast.depth_tac (ctxt addIs [@{thm analz_insertI}, impOfSubs @{thm analz_subset_parts}]) 4 1)); fun spy_analz_tac ctxt i = DETERM (SELECT_GOAL (EVERY [ (*push in occurrences of X...*) (REPEAT o CHANGED) (Rule_Insts.res_inst_tac ctxt [((("x", 1), Position.none), "X")] [] (insert_commute RS ssubst) 1), (*...allowing further simplifications*) simp_tac ctxt 1, REPEAT (FIRSTGOAL (resolve_tac ctxt [allI,impI,notI,conjI,iffI])), DEPTH_SOLVE (atomic_spy_analz_tac ctxt 1)]) i); \ text\By default only \o_apply\ is built-in. But in the presence of eta-expansion this means that some terms displayed as @{term "f o g"} will be rewritten, and others will not!\ declare o_def [simp] lemma Crypt_notin_image_Key [simp]: "Crypt K X \ Key ` A" by auto lemma Hash_notin_image_Key [simp] :"Hash X \ Key ` A" by auto lemma synth_analz_mono: "G\H \ synth (analz(G)) \ synth (analz(H))" by (iprover intro: synth_mono analz_mono) lemma Fake_analz_eq [simp]: "X \ synth(analz H) \ synth (analz (insert X H)) = synth (analz H)" by (metis Fake_analz_insert Un_absorb Un_absorb1 Un_commute subset_insertI synth_analz_mono synth_increasing synth_subset_iff) text\Two generalizations of \analz_insert_eq\\ lemma gen_analz_insert_eq [rule_format]: "X \ analz H \ \G. H \ G \ analz (insert X G) = analz G" by (blast intro: analz_cut analz_insertI analz_mono [THEN [2] rev_subsetD]) lemma synth_analz_insert_eq [rule_format]: "X \ synth (analz H) \ \ G. H \ G \ (Key K \ analz (insert X G)) = (Key K \ analz G)" apply (erule synth.induct) apply (simp_all add: gen_analz_insert_eq subset_trans [OF _ subset_insertI]) done lemma Fake_parts_sing: "X \ synth (analz H) \ parts{X} \ synth (analz H) \ parts H" by (metis Fake_parts_insert empty_subsetI insert_mono parts_mono subset_trans) lemmas Fake_parts_sing_imp_Un = Fake_parts_sing [THEN [2] rev_subsetD] method_setup spy_analz = \ Scan.succeed (SIMPLE_METHOD' o spy_analz_tac)\ "for proving the Fake case when analz is involved" method_setup atomic_spy_analz = \ Scan.succeed (SIMPLE_METHOD' o atomic_spy_analz_tac)\ "for debugging spy_analz" method_setup Fake_insert_simp = \ Scan.succeed (SIMPLE_METHOD' o Fake_insert_simp_tac)\ "for debugging spy_analz" end diff --git a/thys/Inductive_Confidentiality/GeneralAttacker/PublicGA.thy b/thys/Inductive_Confidentiality/GeneralAttacker/PublicGA.thy --- a/thys/Inductive_Confidentiality/GeneralAttacker/PublicGA.thy +++ b/thys/Inductive_Confidentiality/GeneralAttacker/PublicGA.thy @@ -1,412 +1,410 @@ section\Theory of Cryptographic Keys for Security Protocols against the General Attacker\ theory PublicGA imports EventGA begin lemma invKey_K: "K \ symKeys \ invKey K = K" by (simp add: symKeys_def) subsection\Asymmetric Keys\ datatype keymode = Signature | Encryption consts publicKey :: "[keymode,agent] => key" abbreviation pubEK :: "agent => key" where "pubEK == publicKey Encryption" abbreviation pubSK :: "agent => key" where "pubSK == publicKey Signature" abbreviation privateKey :: "[keymode, agent] => key" where "privateKey b A == invKey (publicKey b A)" abbreviation (*BEWARE!! priEK, priSK DON'T WORK with inj, range, image, etc.*) priEK :: "agent => key" where "priEK A == privateKey Encryption A" abbreviation priSK :: "agent => key" where "priSK A == privateKey Signature A" text\These abbreviations give backward compatibility. They represent the simple situation where the signature and encryption keys are the same.\ abbreviation pubK :: "agent => key" where "pubK A == pubEK A" abbreviation priK :: "agent => key" where "priK A == invKey (pubEK A)" text\By freeness of agents, no two agents have the same key. Since @{term "True\False"}, no agent has identical signing and encryption keys\ specification (publicKey) injective_publicKey: "publicKey b A = publicKey c A' \ b=c \ A=A'" apply (rule exI [of _ "%b A. 2 * case_agent (\n. n + 2) A + case_keymode 0 1 b"]) apply (auto simp add: inj_on_def split: agent.split keymode.split) apply presburger apply presburger done axiomatization where (*No private key equals any public key (essential to ensure that private keys are private!) *) privateKey_neq_publicKey [iff]: "privateKey b A \ publicKey c A'" lemmas publicKey_neq_privateKey = privateKey_neq_publicKey [THEN not_sym] declare publicKey_neq_privateKey [iff] subsection\Basic properties of @{term pubK} and @{term priK}\ lemma publicKey_inject [iff]: "(publicKey b A = publicKey c A') = (b=c \ A=A')" by (blast dest!: injective_publicKey) lemma not_symKeys_pubK [iff]: "publicKey b A \ symKeys" by (simp add: symKeys_def) lemma not_symKeys_priK [iff]: "privateKey b A \ symKeys" by (simp add: symKeys_def) lemma symKey_neq_priEK: "K \ symKeys \ K \ priEK A" by auto lemma symKeys_neq_imp_neq: "(K \ symKeys) \ (K' \ symKeys) \ K \ K'" by blast lemma symKeys_invKey_iff [iff]: "(invKey K \ symKeys) = (K \ symKeys)" by (unfold symKeys_def, auto) lemma analz_symKeys_Decrypt: "[| Crypt K X \ analz H; K \ symKeys; Key K \ analz H |] ==> X \ analz H" by (auto simp add: symKeys_def) subsection\"Image" equations that hold for injective functions\ lemma invKey_image_eq [simp]: "(invKey x \ invKey`A) = (x \ A)" by auto (*holds because invKey is injective*) lemma publicKey_image_eq [simp]: "(publicKey b x \ publicKey c ` AA) = (b=c \ x \ AA)" by auto lemma privateKey_notin_image_publicKey [simp]: "privateKey b x \ publicKey c ` AA" by auto lemma privateKey_image_eq [simp]: "(privateKey b A \ invKey ` publicKey c ` AS) = (b=c \ A\AS)" by auto lemma publicKey_notin_image_privateKey [simp]: "publicKey b A \ invKey ` publicKey c ` AS" by auto subsection\Symmetric Keys\ text\For some protocols, it is convenient to equip agents with symmetric as well as asymmetric keys. The theory \Shared\ assumes that all keys are symmetric.\ consts shrK :: "agent => key" \ \long-term shared keys\ specification (shrK) inj_shrK: "inj shrK" \ \No two agents have the same long-term key\ apply (rule exI [of _ "case_agent (\n. n + 2)"]) apply (simp add: inj_on_def split: agent.split) done axiomatization where sym_shrK [iff]: "shrK X \ symKeys" \ \All shared keys are symmetric\ text\Injectiveness: Agents' long-term keys are distinct.\ lemmas shrK_injective = inj_shrK [THEN inj_eq] declare shrK_injective [iff] lemma invKey_shrK [simp]: "invKey (shrK A) = shrK A" by (simp add: invKey_K) lemma analz_shrK_Decrypt: "[| Crypt (shrK A) X \ analz H; Key(shrK A) \ analz H |] ==> X \ analz H" by auto lemma analz_Decrypt': "[| Crypt K X \ analz H; K \ symKeys; Key K \ analz H |] ==> X \ analz H" by (auto simp add: invKey_K) lemma priK_neq_shrK [iff]: "shrK A \ privateKey b C" by (simp add: symKeys_neq_imp_neq) lemmas shrK_neq_priK = priK_neq_shrK [THEN not_sym] declare shrK_neq_priK [simp] lemma pubK_neq_shrK [iff]: "shrK A \ publicKey b C" by (simp add: symKeys_neq_imp_neq) lemmas shrK_neq_pubK = pubK_neq_shrK [THEN not_sym] declare shrK_neq_pubK [simp] lemma priEK_noteq_shrK [simp]: "priEK A \ shrK B" by auto lemma publicKey_notin_image_shrK [simp]: "publicKey b x \ shrK ` AA" by auto lemma privateKey_notin_image_shrK [simp]: "privateKey b x \ shrK ` AA" by auto lemma shrK_notin_image_publicKey [simp]: "shrK x \ publicKey b ` AA" by auto lemma shrK_notin_image_privateKey [simp]: "shrK x \ invKey ` publicKey b ` AA" by auto lemma shrK_image_eq [simp]: "(shrK x \ shrK ` AA) = (x \ AA)" by auto text\For some reason, moving this up can make some proofs loop!\ declare invKey_K [simp] subsection\Initial States of Agents\ overloading initState \ initState begin primrec initState where initState_Friend: "initState (Friend i) = {Key (priEK (Friend i)), Key (priSK (Friend i)), Key (shrK (Friend i))} \ (Key ` range pubEK) \ (Key ` range pubSK)" end lemma used_parts_subset_parts [rule_format]: "\X \ used evs. parts {X} \ used evs" apply (induct evs) prefer 2 - apply (simp add: used_Cons) - apply (rule ballI) - apply (case_tac a, auto) -apply (auto dest!: parts_cut) + apply (simp add: used_Cons split: event.split) + apply (metis Un_iff empty_subsetI insert_subset le_supI1 le_supI2 parts_subset_iff) txt\Base case\ -apply (simp add: used_Nil) +apply (auto dest!: parts_cut simp add: used_Nil) done lemma MPair_used_D: "\X,Y\ \ used H \ X \ used H \ Y \ used H" by (drule used_parts_subset_parts, simp, blast) text\There was a similar theorem in Event.thy, so perhaps this one can be moved up if proved directly by induction.\ lemma MPair_used [elim!]: "[| \X,Y\ \ used H; [| X \ used H; Y \ used H |] ==> P |] ==> P" by (blast dest: MPair_used_D) text\Rewrites should not refer to @{term "initState(Friend i)"} because that expression is not in normal form.\ lemma keysFor_parts_initState [simp]: "keysFor (parts (initState C)) = {}" apply (unfold keysFor_def) apply (induct_tac "C") apply (auto intro: range_eqI) done lemma Crypt_notin_initState: "Crypt K X \ parts (initState B)" by (induct B, auto) lemma Crypt_notin_used_empty [simp]: "Crypt K X \ used []" by (simp add: Crypt_notin_initState used_Nil) (*** Basic properties of shrK ***) (*Agents see their own shared keys!*) lemma shrK_in_initState [iff]: "Key (shrK A) \ initState A" by (induct_tac "A", auto) lemma shrK_in_knows [iff]: "Key (shrK A) \ knows A evs" by (simp add: initState_subset_knows [THEN subsetD]) lemma shrK_in_used [iff]: "Key (shrK A) \ used evs" by (rule initState_into_used, blast) (** Fresh keys never clash with long-term shared keys **) (*Used in parts_induct_tac and analz_Fake_tac to distinguish session keys from long-term shared keys*) lemma Key_not_used [simp]: "Key K \ used evs \ K \ range shrK" by blast lemma shrK_neq: "Key K \ used evs \ shrK B \ K" by blast lemmas neq_shrK = shrK_neq [THEN not_sym] declare neq_shrK [simp] subsection\Function @{term "knows Spy"}\ lemma not_SignatureE [elim!]: "b \ Signature \ b = Encryption" by (cases b, auto) text\Agents see their own private keys!\ lemma priK_in_initState [iff]: "Key (privateKey b A) \ initState A" by (cases A, auto) text\Agents see all public keys!\ lemma publicKey_in_initState [iff]: "Key (publicKey b A) \ initState B" by (cases B, auto) text\All public keys are visible\ lemma spies_pubK [iff]: "Key (publicKey b A) \ knows B evs" apply (induct_tac "evs") apply (auto simp add: imageI knows_Cons split: event.split) done lemmas analz_spies_pubK = spies_pubK [THEN analz.Inj] declare analz_spies_pubK [iff] (*Note: there never is at this stage a lemma about what an agent cannot know*) lemma publicKey_into_used [iff] :"Key (publicKey b A) \ used evs" apply (rule initState_into_used) apply (rule publicKey_in_initState [THEN parts.Inj]) done lemma privateKey_into_used [iff]: "Key (privateKey b A) \ used evs" apply(rule initState_into_used) apply(rule priK_in_initState [THEN parts.Inj]) done lemma Crypt_analz_bad: "[| Crypt (shrK A) X \ analz (knows A evs) |] ==> X \ analz (knows A evs)" by force subsection\Fresh Nonces\ lemma Nonce_notin_initState [iff]: "Nonce N \ parts (initState B)" by (induct_tac "B", auto) lemma Nonce_notin_used_empty [simp]: "Nonce N \ used []" by (simp add: used_Nil) subsection\Supply fresh nonces for possibility theorems\ text\In any trace, there is an upper bound N on the greatest nonce in use\ lemma Nonce_supply_lemma: "\N. \n. N\n \ Nonce n \ used evs" apply (induct_tac "evs") apply (rule_tac x = 0 in exI) apply (simp_all (no_asm_simp) add: used_Cons split: event.split) apply safe apply (rule msg_Nonce_supply [THEN exE], blast elim!: add_leE)+ done lemma Nonce_supply1: "\N. Nonce N \ used evs" by (rule Nonce_supply_lemma [THEN exE], blast) lemma Nonce_supply: "Nonce (SOME N. Nonce N \ used evs) \ used evs" apply (rule Nonce_supply_lemma [THEN exE]) apply (rule someI, fast) done subsection\Specialized Rewriting for Theorems About @{term analz} and Image\ lemma insert_Key_singleton: "insert (Key K) H = Key ` {K} \ H" by blast lemma insert_Key_image: "insert (Key K) (Key`KK \ C) = Key ` (insert K KK) \ C" by blast lemma Crypt_imp_keysFor :"[|Crypt K X \ H; K \ symKeys|] ==> K \ keysFor H" by (drule Crypt_imp_invKey_keysFor, simp) text\Lemma for the trivial direction of the if-and-only-if of the Session Key Compromise Theorem\ lemma analz_image_freshK_lemma: "(Key K \ analz (Key`nE \ H)) \ (K \ nE | Key K \ analz H) \ (Key K \ analz (Key`nE \ H)) = (K \ nE | Key K \ analz H)" by (blast intro: analz_mono [THEN [2] rev_subsetD]) lemmas analz_image_freshK_simps = simp_thms mem_simps \ \these two allow its use with @{text "only:"}\ disj_comms image_insert [THEN sym] image_Un [THEN sym] empty_subsetI insert_subset analz_insert_eq Un_upper2 [THEN analz_mono, THEN subsetD] insert_Key_singleton Key_not_used insert_Key_image Un_assoc [THEN sym] ML \ structure Public = struct val analz_image_freshK_ss = simpset_of (@{context} delsimps [image_insert, image_Un] delsimps [@{thm imp_disjL}] (*reduces blow-up*) addsimps @{thms analz_image_freshK_simps}) (*Tactic for possibility theorems*) fun possibility_tac ctxt = REPEAT (*omit used_Says so that Nonces start from different traces!*) (ALLGOALS (simp_tac (ctxt delsimps [@{thm used_Says}])) THEN REPEAT_FIRST (eq_assume_tac ORELSE' resolve_tac ctxt [refl, conjI, @{thm Nonce_supply}])) (*For harder protocols (such as Recur) where we have to set up some nonces and keys initially*) fun basic_possibility_tac ctxt = REPEAT (ALLGOALS (asm_simp_tac (ctxt setSolver safe_solver)) THEN REPEAT_FIRST (resolve_tac ctxt [refl, conjI])) end \ method_setup analz_freshK = \ Scan.succeed (fn ctxt => (SIMPLE_METHOD (EVERY [REPEAT_FIRST (resolve_tac ctxt [allI, ballI, impI]), REPEAT_FIRST (resolve_tac ctxt @{thms analz_image_freshK_lemma}), ALLGOALS (asm_simp_tac (put_simpset Public.analz_image_freshK_ss ctxt))])))\ "for proving the Session Key Compromise theorem" subsection\Specialized Methods for Possibility Theorems\ method_setup possibility = \ Scan.succeed (SIMPLE_METHOD o Public.possibility_tac)\ "for proving possibility theorems" method_setup basic_possibility = \ Scan.succeed (SIMPLE_METHOD o Public.basic_possibility_tac)\ "for proving possibility theorems" end diff --git a/thys/IsaNet/infrastructure/Message.thy b/thys/IsaNet/infrastructure/Message.thy --- a/thys/IsaNet/infrastructure/Message.thy +++ b/thys/IsaNet/infrastructure/Message.thy @@ -1,1203 +1,1191 @@ (******************************************************************************* Title: HOL/Auth/Message Author: Lawrence C Paulson, Cambridge University Computer Laboratory Copyright 1996 University of Cambridge Datatypes of agents and messages; Inductive relations "parts", "analz" and "synth" ******************************************************************************** Edited: Tobias Klenze, ETH Zurich Christoph Sprenger, ETH Zurich Integrated and adapted for security protocol refinement and to add a constructor for finite sets. *******************************************************************************) section \Theory of ASes and Messages for Security Protocols\ theory Message imports Keys "HOL-Library.Sublist" "HOL.Finite_Set" "HOL-Library.FSet" begin datatype msgterm = \ \ \Empty message. Used for instance to denote non-existent interface\ | AS as \ \Autonomous System identifier, i.e. agents. Note that AS is an alias of nat\ | Num nat \ \Ordinary integers, timestamps, ...\ | Key key \ \Crypto keys\ | Nonce nonce \ \Unguessable nonces\ | L "msgterm list" \ \Lists\ | FS "msgterm fset" \ \Finite Sets. Used to represent XOR values.\ | MPair msgterm msgterm \ \Compound messages\ | Hash msgterm \ \Hashing\ | Crypt key msgterm \ \Encryption, public- or shared-key\ text \Syntax sugar\ syntax "_MTuple" :: "['a, args] \ 'a * 'b" ("(2\_,/ _\)") syntax (xsymbols) "_MTuple" :: "['a, args] \ 'a * 'b" ("(2\_,/ _\)") translations "\x, y, z\" \ "\x, \y, z\\" "\x, y\" \ "CONST MPair x y" syntax "_MHF" :: "['a, 'b , 'c, 'd, 'e] \ 'a * 'b * 'c * 'd * 'e" ("(5HF\_,/ _,/ _,/ _,/ _\)") abbreviation Mac :: "[msgterm,msgterm] \ msgterm" ("(4Mac[_] /_)" [0, 1000]) where \ \Message Y paired with a MAC computed with the help of X\ "Mac[X] Y \ Hash \X,Y\" abbreviation macKey where "macKey a \ Key (macK a)" definition keysFor :: "msgterm set \ key set" where \ \Keys useful to decrypt elements of a message set\ "keysFor H \ invKey ` {K. \X. Crypt K X \ H}" subsubsection \Inductive Definition of "All Parts" of a Message\ inductive_set parts :: "msgterm set \ msgterm set" for H :: "msgterm set" where Inj [intro]: "X \ H \ X \ parts H" | Fst: "\X,_\ \ parts H \ X \ parts H" | Snd: "\_,Y\ \ parts H \ Y \ parts H" | Lst: "\ L xs \ parts H; X \ set xs \ \ X \ parts H" | FSt: "\ FS xs \ parts H; X |\| xs \ \ X \ parts H" (*| Hd: "L (X # xs) \ parts H \ X \ parts H" | Tl: "L (X # xs) \ parts H \ L xs \ parts H" *) | Body: "Crypt K X \ parts H \ X \ parts H" text \Monotonicity\ lemma parts_mono: "G \ H \ parts G \ parts H" apply auto apply (erule parts.induct) apply (blast dest: parts.Fst parts.Snd parts.Lst parts.FSt parts.Body)+ done text \Equations hold because constructors are injective.\ lemma Other_image_eq [simp]: "(AS x \ AS`A) = (x:A)" by auto lemma Key_image_eq [simp]: "(Key x \ Key`A) = (x\A)" by auto lemma AS_Key_image_eq [simp]: "(AS x \ Key`A)" by auto lemma Num_Key_image_eq [simp]: "(Num x \ Key`A)" by auto subsection \keysFor operator\ lemma keysFor_empty [simp]: "keysFor {} = {}" by (unfold keysFor_def, blast) lemma keysFor_Un [simp]: "keysFor (H \ H') = keysFor H \ keysFor H'" by (unfold keysFor_def, blast) lemma keysFor_UN [simp]: "keysFor (\i\A. H i) = (\i\A. keysFor (H i))" by (unfold keysFor_def, blast) text \Monotonicity\ lemma keysFor_mono: "G \ H \ keysFor G \ keysFor H" by (unfold keysFor_def, blast) lemma keysFor_insert_AS [simp]: "keysFor (insert (AS A) H) = keysFor H" by (unfold keysFor_def, auto) lemma keysFor_insert_Num [simp]: "keysFor (insert (Num N) H) = keysFor H" by (unfold keysFor_def, auto) lemma keysFor_insert_Key [simp]: "keysFor (insert (Key K) H) = keysFor H" by (unfold keysFor_def, auto) lemma keysFor_insert_Nonce [simp]: "keysFor (insert (Nonce n) H) = keysFor H" by (unfold keysFor_def, auto) lemma keysFor_insert_L [simp]: "keysFor (insert (L X) H) = keysFor H" by (unfold keysFor_def, auto) lemma keysFor_insert_FS [simp]: "keysFor (insert (FS X) H) = keysFor H" by (unfold keysFor_def, auto) lemma keysFor_insert_Hash [simp]: "keysFor (insert (Hash X) H) = keysFor H" by (unfold keysFor_def, auto) lemma keysFor_insert_MPair [simp]: "keysFor (insert \X,Y\ H) = keysFor H" by (unfold keysFor_def, auto) lemma keysFor_insert_Crypt [simp]: "keysFor (insert (Crypt K X) H) = insert (invKey K) (keysFor H)" by (unfold keysFor_def, auto) lemma keysFor_image_Key [simp]: "keysFor (Key`E) = {}" by (unfold keysFor_def, auto) lemma Crypt_imp_invKey_keysFor: "Crypt K X \ H \ invKey K \ keysFor H" by (unfold keysFor_def, blast) subsection \Inductive relation "parts"\ lemma MPair_parts: "\ \X,Y\ \ parts H; \ X \ parts H; Y \ parts H \ \ P \ \ P" by (blast dest: parts.Fst parts.Snd) lemma L_parts: "\ L l \ parts H; \ set l \ parts H \ \ P \ \ P" by (blast dest: parts.Lst) lemma FS_parts: "\ FS l \ parts H; \ fset l \ parts H \ \ P \ \ P" by (simp add: fmember_iff_member_fset parts.FSt subsetI) thm fmember_iff_member_fset parts.FSt subsetI declare fmember_iff_member_fset[simp] declare MPair_parts [elim!] L_parts [elim!] FS_parts [elim] parts.Body [dest!] text \NB These two rules are UNSAFE in the formal sense, as they discard the compound message. They work well on THIS FILE. @{text MPair_parts} is left as SAFE because it speeds up proofs. The Crypt rule is normally kept UNSAFE to avoid breaking up certificates.\ lemma parts_increasing: "H \ parts H" by blast lemmas parts_insertI = subset_insertI [THEN parts_mono, THEN subsetD] lemma parts_empty [simp]: "parts{} = {}" apply safe apply (erule parts.induct, blast+) done lemma parts_emptyE [elim!]: "X\ parts{} \ P" by simp text \WARNING: loops if H = {Y}, therefore must not be repeated!\ lemma parts_singleton: "X \ parts H \ \Y \ H. X \ parts {Y}" apply (erule parts.induct, fast) using parts.FSt by blast+ lemma parts_singleton_set: "x \ parts {s . P s} \ \Y. P Y \ x \ parts {Y}" by(auto dest: parts_singleton) lemma parts_singleton_set_rev: "\x \ parts {Y}; P Y\ \ x \ parts {s . P s}" by (induction rule: parts.induct) (blast dest: parts.Fst parts.Snd parts.Lst parts.FSt parts.Body)+ lemma parts_Hash: "\\t . t \ H \ \t' . t = Hash t'\ \ parts H = H" by (auto, erule parts.induct, fast+) subsubsection \Unions\ lemma parts_Un_subset1: "parts G \ parts H \ parts(G \ H)" by (intro Un_least parts_mono Un_upper1 Un_upper2) lemma parts_Un_subset2: "parts(G \ H) \ parts G \ parts H" apply (rule subsetI) apply (erule parts.induct, blast+) using parts.FSt by auto lemma parts_Un [simp]: "parts(G \ H) = parts G \ parts H" by (intro equalityI parts_Un_subset1 parts_Un_subset2) lemma parts_insert: "parts (insert X H) = parts {X} \ parts H" apply (subst insert_is_Un [of _ H]) apply (simp only: parts_Un) done text \TWO inserts to avoid looping. This rewrite is better than nothing. Not suitable for Addsimps: its behaviour can be strange.\ lemma parts_insert2: "parts (insert X (insert Y H)) = parts {X} \ parts {Y} \ parts H" apply (simp add: Un_assoc) apply (simp add: parts_insert [symmetric]) done (*needed?!*) lemma parts_two: "\x \ parts {e1, e2}; x \ parts {e1}\\ x \ parts {e2}" by (simp add: parts_insert2) -lemma parts_UN_subset1: "(\x\A. parts(H x)) \ parts(\x\A. H x)" -by (intro UN_least parts_mono UN_upper) -lemma parts_UN_subset2: "parts(\x\A. H x) \ (\x\A. parts(H x))" -apply (rule subsetI) - apply (erule parts.induct) - using parts.FSt by auto - -lemma parts_UN [simp]: "parts(\x\A. H x) = (\x\A. parts(H x))" -by (intro equalityI parts_UN_subset1 parts_UN_subset2) - - -text \Added to simplify arguments to parts, analz and synth. - NOTE: the UN versions are no longer used!\ +text \Added to simplify arguments to parts, analz and synth.\ text \This allows @{text blast} to simplify occurrences of @{term "parts(G\H)"} in the assumption.\ 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 \Idempotence\ lemma parts_partsD [dest!]: "X\ parts (parts H) \ X\ parts H" apply (erule parts.induct, blast+) using parts.FSt by auto 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 (iprover intro: subset_trans parts_increasing) apply (frule parts_mono, simp) done subsubsection \Transitivity\ lemma parts_trans: "\ X\ parts G; G \ parts H \ \ X\ parts H" by (drule parts_mono, blast) subsubsection \Unions, revisited\ text \You can take the union of parts h for all h in H\ lemma parts_split: "parts H = \ { parts {h} | h . h \ H}" apply auto apply (erule parts.induct) apply (blast dest: parts.Fst parts.Snd parts.Lst parts.FSt parts.Body)+ using parts_trans apply blast done text \Cut\ lemma parts_cut: "\ Y\ parts (insert X G); X \ parts H \ \ Y \ parts (G \ H)" by (blast intro: parts_trans) lemma parts_cut_eq [simp]: "X \ parts H \ parts (insert X H) = parts H" by (force dest!: parts_cut intro: parts_insertI) subsubsection \Rewrite rules for pulling out atomic messages\ lemmas parts_insert_eq_I = equalityI [OF subsetI parts_insert_subset] lemma parts_insert_AS [simp]: "parts (insert (AS agt) H) = insert (AS agt) (parts H)" apply (rule parts_insert_eq_I) by (erule parts.induct, auto elim!: FS_parts) lemma parts_insert_Epsilon [simp]: "parts (insert \ H) = insert \ (parts H)" apply (rule parts_insert_eq_I) by (erule parts.induct, auto) lemma parts_insert_Num [simp]: "parts (insert (Num N) H) = insert (Num N) (parts H)" apply (rule parts_insert_eq_I) by (erule parts.induct, auto) lemma parts_insert_Key [simp]: "parts (insert (Key K) H) = insert (Key K) (parts H)" apply (rule parts_insert_eq_I) by (erule parts.induct, auto) lemma parts_insert_Nonce [simp]: "parts (insert (Nonce n) H) = insert (Nonce n) (parts H)" apply (rule parts_insert_eq_I) by (erule parts.induct, auto) lemma parts_insert_Hash [simp]: "parts (insert (Hash X) H) = insert (Hash X) (parts H)" apply (rule parts_insert_eq_I) by (erule parts.induct, auto) lemma parts_insert_Crypt [simp]: "parts (insert (Crypt K X) H) = insert (Crypt K X) (parts (insert X H))" apply (rule equalityI) apply (rule subsetI) apply (erule parts.induct, auto) by (blast intro: parts.Body) lemma parts_insert_MPair [simp]: "parts (insert \X,Y\ H) = insert \X,Y\ (parts (insert X (insert Y H)))" apply (rule equalityI) apply (rule subsetI) apply (erule parts.induct, auto) by (blast intro: parts.Fst parts.Snd)+ lemma parts_insert_L [simp]: "parts (insert (L xs) H) = insert (L xs) (parts ((set xs) \ H))" apply (rule equalityI) apply (rule subsetI) apply (erule parts.induct, auto) by (blast intro: parts.Lst)+ lemma parts_insert_FS [simp]: "parts (insert (FS xs) H) = insert (FS xs) (parts ((fset xs) \ H))" apply (rule equalityI) apply (rule subsetI) apply (erule parts.induct, auto) by (auto intro: parts.FSt)+ lemma parts_image_Key [simp]: "parts (Key`N) = Key`N" apply auto apply (erule parts.induct, auto) done text \Parts of lists and finite sets.\ lemma parts_list_set (*[simp]*): "parts (L`ls) = (L`ls) \ (\l \ ls. parts (set l)) " apply (rule equalityI, rule subsetI) apply (erule parts.induct, auto) by (meson L_parts image_subset_iff parts_increasing parts_trans) lemma parts_insert_list_set (*[simp]*): "parts ((L`ls) \ H) = (L`ls) \ (\l \ ls. parts ((set l))) \ parts H" apply (rule equalityI, rule subsetI) by (erule parts.induct, auto simp add: parts_list_set) (*needed?!*) lemma parts_fset_set (*[simp]*): "parts (FS`ls) = (FS`ls) \ (\l \ ls. parts (fset l)) " apply (rule equalityI, rule subsetI) apply (erule parts.induct, auto) by (meson FS_parts image_subset_iff parts_increasing parts_trans) subsubsection \suffix of parts\ lemma suffix_in_parts: "suffix (x#xs) ys \ x \ parts {L ys}" by (auto simp add: suffix_def) lemma parts_L_set: "\x \ parts {L ys}; ys \ St\ \ x \ parts (L`St)" by (metis (no_types, lifting) image_insert insert_iff mk_disjoint_insert parts.Inj parts_cut_eq parts_insert parts_insert2) lemma suffix_in_parts_set: "\suffix (x#xs) ys; ys \ St\ \ x \ parts (L`St)" using parts_L_set suffix_in_parts by blast subsection \Inductive relation "analz"\ text \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.\ inductive_set analz :: "msgterm set \ msgterm set" for H :: "msgterm 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" | Lst: "(L y) \ analz H \ x \ set (y) \ x \ analz H " | FSt: "\ FS xs \ analz H; X |\| xs \ \ X \ analz H" | Decrypt [dest]: "\ Crypt K X \ analz H; Key (invKey K) \ analz H \ \ X \ analz H" text \Monotonicity; Lemma 1 of Lowe's paper\ lemma analz_mono: "G \ H \ analz(G) \ analz(H)" apply auto apply (erule analz.induct) apply (auto dest: analz.Fst analz.Snd analz.Lst analz.FSt ) done lemmas analz_monotonic = analz_mono [THEN [2] rev_subsetD] text \Making it safe speeds up proofs\ lemma MPair_analz [elim!]: "\ \X,Y\ \ analz H; \ X \ analz H; Y \ analz H \ \ P \ \ P" by (blast dest: analz.Fst analz.Snd) lemma L_analz [elim!]: "\ L l \ analz H; \ set l \ analz H \ \ P \ \ P" by (blast dest: analz.Lst analz.FSt) lemma FS_analz [elim!]: "\ FS l \ analz H; \ fset l \ analz H \ \ P \ \ P" by (simp add: fmember_iff_member_fset analz.FSt subsetI) thm fmember_iff_member_fset parts.FSt subsetI lemma analz_increasing: "H \ analz(H)" by blast lemma analz_subset_parts: "analz H \ parts H" apply (rule subsetI) apply (erule analz.induct, blast+) apply auto done text \If there is no cryptography, then analz and parts is equivalent.\ lemma no_crypt_analz_is_parts: "\ (\ K X . Crypt K X \ parts A) \ analz A = parts A" apply (rule equalityI, simp add: analz_subset_parts) apply (rule subsetI) by (erule parts.induct, blast+, auto) lemmas analz_into_parts = analz_subset_parts [THEN subsetD] lemmas not_parts_not_analz = analz_subset_parts [THEN contra_subsetD] lemma parts_analz [simp]: "parts (analz H) = parts H" apply (rule equalityI) apply (rule analz_subset_parts [THEN parts_mono, THEN subset_trans], simp) apply (blast intro: analz_increasing [THEN parts_mono, THEN subsetD]) done lemma analz_parts [simp]: "analz (parts H) = parts H" apply auto apply (erule analz.induct, auto) done lemmas analz_insertI = subset_insertI [THEN analz_mono, THEN [2] rev_subsetD] subsubsection \General equational properties\ lemma analz_empty [simp]: "analz {} = {}" apply safe apply (erule analz.induct, blast+) done text \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\ 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 \Rewrite rules for pulling out atomic messages\ lemmas analz_insert_eq_I = equalityI [OF subsetI analz_insert] lemma analz_insert_AS [simp]: "analz (insert (AS agt) H) = insert (AS agt) (analz H)" apply (rule analz_insert_eq_I) by (erule analz.induct, auto) lemma analz_insert_Num [simp]: "analz (insert (Num N) H) = insert (Num N) (analz H)" apply (rule analz_insert_eq_I) by (erule analz.induct, auto) text \Can only pull out Keys if they are not needed to decrypt the rest\ lemma analz_insert_Key [simp]: "K \ keysFor (analz H) \ analz (insert (Key K) H) = insert (Key K) (analz H)" apply (unfold keysFor_def) apply (rule analz_insert_eq_I) by (erule analz.induct, auto) lemma analz_insert_LEmpty [simp]: "analz (insert (L []) H) = insert (L []) (analz H)" apply (rule analz_insert_eq_I) by (erule analz.induct, auto) lemma analz_insert_L [simp]: "analz (insert (L l) H) = insert (L l) (analz (set l \ H))" apply (rule equalityI) apply (rule subsetI) apply (erule analz.induct, auto) apply (erule analz.induct, auto) using analz.Inj by blast lemma analz_insert_FS [simp]: "analz (insert (FS l) H) = insert (FS l) (analz (fset l \ H))" apply (rule equalityI) apply (rule subsetI) apply (erule analz.induct, auto) apply (erule analz.induct, auto) using analz.Inj by blast lemma "L[] \ analz {L[L[]]}" using analz.Inj by simp lemma analz_insert_Hash [simp]: "analz (insert (Hash X) H) = insert (Hash X) (analz H)" apply (rule analz_insert_eq_I) by (erule analz.induct, auto) lemma analz_insert_MPair [simp]: "analz (insert \X,Y\ H) = insert \X,Y\ (analz (insert X (insert Y H)))" apply (rule equalityI) apply (rule subsetI) apply (erule analz.induct, auto) apply (erule analz.induct, auto) using Fst Snd analz.Inj insertI1 by (metis)+ text \Can pull out enCrypted message if the Key is not known\ 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) by (erule analz.induct, auto) lemma analz_insert_Decrypt1: "Key (invKey K) \ analz H \ analz (insert (Crypt K X) H) \ insert (Crypt K X) (analz (insert X H))" apply (rule subsetI) by (erule_tac x = x in analz.induct, auto) lemma analz_insert_Decrypt2: "Key (invKey K) \ analz H \ insert (Crypt K X) (analz (insert X H)) \ analz (insert (Crypt K X) H)" apply auto apply (erule_tac x = x in analz.induct, auto) by (blast intro: analz_insertI analz.Decrypt) 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 analz_insert_Decrypt1 analz_insert_Decrypt2) text \Case analysis: either the message is secure, or it is not! Effective, but can cause subgoals to blow up! Use with @{text "split_if"}; apparently @{text "split_tac"} does not cope with patterns such as @{term"analz (insert (Crypt K X) H)"}\ lemma analz_Crypt_if [simp]: "analz (insert (Crypt K X) H) = (if (Key (invKey K) \ 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 \This rule supposes "for the sake of argument" that we have the key.\ lemma analz_insert_Crypt_subset: "analz (insert (Crypt K X) H) \ insert (Crypt K X) (analz (insert X H))" apply (rule subsetI) by (erule analz.induct, auto) lemma analz_image_Key [simp]: "analz (Key`N) = Key`N" apply auto apply (erule analz.induct, auto) done subsubsection \Idempotence and transitivity\ lemma analz_analzD [dest!]: "X\ analz (analz H) \ X\ analz H" by (erule analz.induct, auto) lemma analz_idem [simp]: "analz (analz H) = analz H" by blast lemma analz_subset_iff [simp]: "(analz G \ analz H) = (G \ analz H)" apply (rule iffI) apply (iprover intro: subset_trans analz_increasing) apply (frule analz_mono, simp) done lemma analz_trans: "\ X\ analz G; G \ analz H \ \ X\ analz H" by (drule analz_mono, blast) text \Cut; Lemma 2 of Lowe\ lemma analz_cut: "\ Y\ analz (insert X H); X\ analz H \ \ Y\ analz H" by (erule analz_trans, blast) (*Cut can be proved easily by induction on "Y: analz (insert X H) \ X: analz H --> Y: analz H" *) text \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.\ lemma analz_insert_eq: "X\ analz H \ analz (insert X H) = analz H" by (blast intro: analz_cut analz_insertI) text \A congruence rule for "analz"\ lemma analz_subset_cong: "\ analz G \ analz G'; analz H \ analz H' \ \ analz (G \ H) \ analz (G' \ H')" apply simp apply (iprover intro: conjI subset_trans analz_mono Un_upper1 Un_upper2) done lemma analz_cong: "\ analz G = analz G'; analz H = analz H' \ \ analz (G \ H) = analz (G' \ 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 \If there are no pairs, lists or encryptions then analz does nothing\ (*needed?*) lemma analz_trivial: "\ \X Y. \X,Y\ \ H; \xs. L xs \ H; \xs. FS xs \ H; \X K. Crypt K X \ H \ \ analz H = H" apply safe by (erule analz.induct, auto) text \These two are obsolete (with a single Spy) but cost little to prove...\ lemma analz_UN_analz_lemma: "X\ analz (\i\A. analz (H i)) \ X\ analz (\i\A. H i)" apply (erule analz.induct) by (auto intro: analz_mono [THEN [2] rev_subsetD]) lemma analz_UN_analz [simp]: "analz (\i\A. analz (H i)) = analz (\i\A. H i)" by (blast intro: analz_UN_analz_lemma analz_mono [THEN [2] rev_subsetD]) subsubsection \Lemmas assuming absense of keys\ text \If there are no keys in analz H, you can take the union of analz h for all h in H\ lemma analz_split: "\(\ K . Key K \ analz H) \ analz H = \ { analz {h} | h . h \ H}" apply auto subgoal apply (erule analz.induct) apply (auto dest: analz.Fst analz.Snd analz.Lst analz.FSt) done apply (erule analz.induct) apply (auto dest: analz.Fst analz.Snd analz.Lst analz.FSt) done lemma analz_Un_eq: assumes "\(\ K . Key K \ analz H)" and "\(\ K . Key K \ analz G)" shows "analz (H \ G) = analz H \ analz G" apply (intro equalityI, rule subsetI) apply (erule analz.induct) using assms by auto lemma analz_Un_eq_Crypt: assumes "\(\ K . Key K \ analz G)" and "\(\ K X . Crypt K X \ analz G)" shows "analz (H \ G) = analz H \ analz G" apply (intro equalityI, rule subsetI) apply (erule analz.induct) using assms by auto lemma analz_list_set (*[simp]*): "\(\ K . Key K \ analz (L`ls)) \ analz (L`ls) = (L`ls) \ (\l \ ls. analz (set l)) " apply (rule equalityI, rule subsetI) apply (erule analz.induct, auto) using L_analz image_subset_iff analz_increasing analz_trans by metis lemma analz_fset_set (*[simp]*): "\(\ K . Key K \ analz (FS`ls)) \ analz (FS`ls) = (FS`ls) \ (\l \ ls. analz (fset l)) " apply (rule equalityI, rule subsetI) apply (erule analz.induct, auto) using FS_analz image_subset_iff analz_increasing analz_trans by metis subsection \Inductive relation "synth"\ text \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. AS names are public domain. Nums can be guessed, but Nonces cannot be.\ inductive_set synth :: "msgterm set \ msgterm set" for H :: "msgterm set" where Inj [intro]: "X \ H \ X \ synth H" | \ [simp,intro!]: "\ \ synth H" | AS [simp,intro!]: "AS agt \ synth H" | Num [simp,intro!]: "Num n \ synth H" | Lst [intro]: "\ \x . x \ set xs \ x \ synth H \ \ L xs \ synth H" - | FSt [intro]: "\ \x . x \ fset xs \ x \ synth H; - \x ys . x \ fset xs \ x \ FS ys \ + | FSt [intro]: "\ \x . x \ fset xs \ x \ synth H; + \x ys . x \ fset xs \ x \ FS ys \ \ FS xs \ 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" (*removed fcard xs \ Suc 0 from FSt premise*) text \Monotonicity\ lemma synth_mono: "G \ H \ synth(G) \ synth(H)" apply (auto, erule synth.induct, auto) by blast text \NO @{text AS_synth}, as any AS name can be synthesized. The same holds for @{term Num}\ inductive_cases Key_synth [elim!]: "Key K \ synth H" inductive_cases Nonce_synth [elim!]: "Nonce n \ synth H" inductive_cases Hash_synth [elim!]: "Hash X \ synth H" inductive_cases MPair_synth [elim!]: "\X,Y\ \ synth H" inductive_cases L_synth [elim!]: "L X \ synth H" inductive_cases FS_synth [elim!]: "FS X \ synth H" inductive_cases Crypt_synth [elim!]: "Crypt K X \ synth H" lemma synth_increasing: "H \ synth(H)" by blast lemma synth_analz_self: "x \ H \ x \ synth (analz H)" by blast subsubsection \Unions\ text \Converse fails: we can synth more from the union than from the separate parts, building a compound message using elements of each.\ 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 (blast intro: synth_mono [THEN [2] rev_subsetD]) subsubsection \Idempotence and transitivity\ lemma synth_synthD [dest!]: "X\ synth (synth H) \ X \ synth H" apply (erule synth.induct, blast) apply auto by blast lemma synth_idem: "synth (synth H) = synth H" by blast lemma synth_subset_iff [simp]: "(synth G \ synth H) = (G \ synth H)" apply (rule iffI) apply (iprover intro: subset_trans synth_increasing) apply (frule synth_mono, simp add: synth_idem) done lemma synth_trans: "\ X\ synth G; G \ synth H \ \ X\ synth H" by (drule synth_mono, blast) text \Cut; Lemma 2 of Lowe\ lemma synth_cut: "\ Y\ synth (insert X H); X\ synth H \ \ Y\ synth H" by (erule synth_trans, blast) lemma Nonce_synth_eq [simp]: "(Nonce N \ synth H) = (Nonce N \ H)" by blast lemma Key_synth_eq [simp]: "(Key K \ synth H) = (Key K \ H)" by blast lemma Crypt_synth_eq [simp]: "Key K \ H \ (Crypt K X \ synth H) = (Crypt K X \ H)" by blast lemma keysFor_synth [simp]: "keysFor (synth H) = keysFor H \ invKey`{K. Key K \ H}" by (unfold keysFor_def, blast) lemma L_cons_synth [simp]: "(set xs \ H) \ (L xs \ synth H)" by auto lemma FS_cons_synth [simp]: "\fset xs \ H; \x ys. x \ fset xs \ x \ FS ys; fcard xs \ Suc 0 \ \ (FS xs \ synth H)" by auto subsubsection \Combinations of parts, analz and synth\ lemma parts_synth [simp]: "parts (synth H) = parts H \ synth H" proof (safe del: UnCI) fix X assume "X \ parts (synth H)" thus "X \ parts H \ synth H" by (induct rule: parts.induct) (auto intro: parts.Fst parts.Snd parts.Lst parts.FSt parts.Body) next fix X assume "X \ parts H" thus "X \ parts (synth H)" by (induction rule: parts.induct) (auto intro: parts.Fst parts.Snd parts.Lst parts.FSt parts.Body) next fix X assume "X \ synth H" thus "X \ parts (synth H)" apply (induction rule: synth.induct) apply(auto intro: parts.Fst parts.Snd parts.Lst parts.FSt parts.Body) by blast qed lemma analz_analz_Un [simp]: "analz (analz G \ H) = analz (G \ H)" apply (intro equalityI analz_subset_cong)+ apply simp_all done lemma analz_synth_Un [simp]: "analz (synth G \ H) = analz (G \ H) \ synth G" proof (safe del: UnCI) fix X assume "X \ analz (synth G \ H)" thus "X \ analz (G \ H) \ synth G" by (induction rule: analz.induct) (auto intro: analz.Fst analz.Snd analz.Lst analz.FSt analz.Decrypt) qed (auto elim: analz_mono [THEN [2] rev_subsetD]) lemma analz_synth [simp]: "analz (synth H) = analz H \ synth H" apply (cut_tac H = "{}" in analz_synth_Un) apply (simp (no_asm_use)) done lemma analz_Un_analz [simp]: "analz (G \ analz H) = analz (G \ H)" by (subst Un_commute, auto)+ lemma analz_synth_Un2 [simp]: "analz (G \ synth H) = analz (G \ H) \ synth H" by (subst Un_commute, auto)+ subsubsection \For reasoning about the Fake rule in traces\ lemma parts_insert_subset_Un: "X\ G \ parts(insert X H) \ parts G \ parts H" by (rule subset_trans [OF parts_mono parts_Un_subset2], blast) text \More specifically for Fake. Very occasionally we could do with a version of the form @{term"parts{X} \ synth (analz H) \ parts H"}\ lemma Fake_parts_insert: "X \ synth (analz H) \ parts (insert X H) \ synth (analz H) \ parts H" apply (drule parts_insert_subset_Un) apply (simp (no_asm_use)) apply blast done lemma Fake_parts_insert_in_Un: "\Z \ parts (insert X H); X \ synth (analz H)\ \ Z \ synth (analz H) \ parts H" by (blast dest: Fake_parts_insert [THEN subsetD, dest]) text \@{term H} is sometimes @{term"Key ` KK \ spies evs"}, so can't put @{term "G=H"}.\ lemma Fake_analz_insert: "X\ synth (analz G) \ analz (insert X H) \ synth (analz G) \ analz (G \ H)" apply (rule subsetI) apply (subgoal_tac "x \ analz (synth (analz G) \ H) ") prefer 2 apply (blast intro: analz_mono [THEN [2] rev_subsetD] analz_mono [THEN synth_mono, THEN [2] rev_subsetD]) apply (simp (no_asm_use)) apply blast done lemma analz_conj_parts [simp]: "(X \ analz H & X \ parts H) = (X \ analz H)" by (blast intro: analz_subset_parts [THEN subsetD]) lemma analz_disj_parts [simp]: "(X \ analz H | X \ parts H) = (X \ parts H)" by (blast intro: analz_subset_parts [THEN subsetD]) text \Without this equation, other rules for synth and analz would yield redundant cases\ lemma MPair_synth_analz [iff]: "(\X,Y\ \ synth (analz H)) = (X \ synth (analz H) & Y \ synth (analz H))" by blast lemma L_cons_synth_analz [iff]: "(L xs \ synth (analz H)) = (set xs \ synth (analz H))" by blast lemma L_cons_synth_parts [iff]: "(L xs \ synth (parts H)) = (set xs \ synth (parts H))" by blast lemma FS_cons_synth_analz [iff]: - "\\x ys . x \ fset xs \ x \ FS ys; fcard xs \ Suc 0 \ \ + "\\x ys . x \ fset xs \ x \ FS ys; fcard xs \ Suc 0 \ \ (FS xs \ synth (analz H)) = (fset xs \ synth (analz H))" by blast lemma FS_cons_synth_parts [iff]: - "\\x ys . x \ fset xs \ x \ FS ys; fcard xs \ Suc 0 \ \ + "\\x ys . x \ fset xs \ x \ FS ys; fcard xs \ Suc 0 \ \ (FS xs \ synth (parts H)) = (fset xs \ synth (parts H))" by blast lemma Crypt_synth_analz: "\ Key K \ analz H; Key (invKey K) \ analz H \ \ (Crypt K X \ synth (analz H)) = (X \ synth (analz H))" by blast lemma Hash_synth_analz [simp]: "X \ synth (analz H) \ (Hash\X,Y\ \ synth (analz H)) = (Hash\X,Y\ \ analz H)" by blast subsection \HPair: a combination of Hash and MPair\ text \We do NOT want Crypt... messages broken up in protocols!!\ declare parts.Body [rule del] text \Rewrites to push in Key and Crypt messages, so that other messages can be pulled out using the @{text analz_insert} rules\ (*needed?*) lemmas pushKeys = insert_commute [of "Key K" "AS C" for K C] insert_commute [of "Key K" "Nonce N" for K N] insert_commute [of "Key K" "Num N" for K N] insert_commute [of "Key K" "Hash X" for K X] insert_commute [of "Key K" "MPair X Y" for K X Y] insert_commute [of "Key K" "Crypt X K'" for K K' X] (*needed?*) lemmas pushCrypts = insert_commute [of "Crypt X K" "AS C" for X K C] insert_commute [of "Crypt X K" "AS C" for X K C] insert_commute [of "Crypt X K" "Nonce N" for X K N] insert_commute [of "Crypt X K" "Num N" for X K N] insert_commute [of "Crypt X K" "Hash X'" for X K X'] insert_commute [of "Crypt X K" "MPair X' Y" for X K X' Y] text \Cannot be added with @{text "[simp]"} -- messages should not always be re-ordered.\ lemmas pushes = pushKeys pushCrypts text \By default only @{text o_apply} is built-in. But in the presence of eta-expansion this means that some terms displayed as @{term "f o g"} will be rewritten, and others will not!\ declare o_def [simp] lemma Crypt_notin_image_Key [simp]: "Crypt K X \ Key ` A" by auto lemma Hash_notin_image_Key [simp] :"Hash X \ Key ` A" by auto lemma synth_analz_mono: "G\H \ synth (analz(G)) \ synth (analz(H))" by (iprover intro: synth_mono analz_mono) lemma synth_parts_mono: "G\H \ synth (parts G) \ synth (parts H)" by (iprover intro: synth_mono parts_mono) lemma Fake_analz_eq [simp]: "X \ synth(analz H) \ synth (analz (insert X H)) = synth (analz H)" apply (drule Fake_analz_insert[of _ _ "H"]) apply (simp add: synth_increasing[THEN Un_absorb2]) apply (drule synth_mono) apply (simp add: synth_idem) apply (rule equalityI) apply (simp add: ) apply (rule synth_analz_mono, blast) done text \Two generalizations of @{text analz_insert_eq}\ lemma gen_analz_insert_eq [rule_format]: "X \ analz H \ ALL G. H \ G --> analz (insert X G) = analz G" by (blast intro: analz_cut analz_insertI analz_mono [THEN [2] rev_subsetD]) lemma Fake_parts_sing: "X \ synth (analz H) \ parts{X} \ synth (analz H) \ parts H" apply (rule subset_trans) apply (erule_tac [2] Fake_parts_insert) apply (rule parts_mono, blast) done lemmas Fake_parts_sing_imp_Un = Fake_parts_sing [THEN [2] rev_subsetD] text \For some reason, moving this up can make some proofs loop!\ declare invKey_K [simp] lemma synth_analz_insert: assumes "analz H \ synth (analz H')" shows "analz (insert X H) \ synth (analz (insert X H'))" proof fix x assume "x \ analz (insert X H)" then have "x \ analz (insert X (synth (analz H')))" using assms by (meson analz_increasing analz_monotonic insert_mono) then show "x \ synth (analz (insert X H'))" - by (metis (no_types) Un_iff analz_idem analz_insert analz_monotonic analz_synth synth.Inj + by (metis (no_types) Un_iff analz_idem analz_insert analz_monotonic analz_synth synth.Inj synth_insert synth_mono) qed lemma synth_parts_insert: assumes "parts H \ synth (parts H')" shows "parts (insert X H) \ synth (parts (insert X H'))" proof fix x assume "x \ parts (insert X H)" then have "x \ parts (insert X (synth (parts H')))" using assms parts_increasing by (metis UnE UnI1 analz_monotonic analz_parts parts_insert parts_insertI) then show "x \ synth (parts (insert X H'))" using Un_iff parts_idem parts_insert parts_synth synth.Inj by (metis Un_subset_iff synth_increasing synth_trans) qed lemma parts_insert_subset_impl: "\x \ parts (insert a G); x \ parts G \ x \ synth (parts H); a \ synth (parts H)\ \ x \ synth (parts H)" using Fake_parts_sing in_parts_UnE insert_is_Un parts_idem parts_synth subsetCE sup.absorb2 synth_idem synth_increasing by (metis (no_types, lifting) analz_parts) lemma synth_parts_subset_elem: "\A \ synth (parts B); x \ parts A\ \ x \ synth (parts B)" by (meson parts_emptyE parts_insert_subset_impl parts_singleton subset_iff) lemma synth_parts_subset: "A \ synth (parts B) \ parts A \ synth (parts B)" by (auto simp add: synth_parts_subset_elem) lemma parts_synth_parts[simp]: "parts (synth (parts H)) = synth (parts H)" by auto lemma synth_parts_trans: assumes "A \ synth (parts B)" and "B \ synth (parts C)" shows "A \ synth (parts C)" using assms by (metis order_trans parts_synth_parts synth_idem synth_parts_mono) lemma synth_parts_trans_elem: assumes "x \ A" and "A \ synth (parts B)" and "B \ synth (parts C)" shows "x \ synth (parts C)" using synth_parts_trans assms by auto lemma synth_un_parts_split: assumes "x \ synth (parts A \ parts B)" and "\x . x \ A \ x \ synth (parts C)" and "\x . x \ B \ x \ synth (parts C)" shows "x \ synth (parts C)" proof - have "parts A \ synth (parts C)" "parts B \ synth (parts C)" using assms(2) assms(3) synth_parts_subset by blast+ then have "x \ synth (synth (parts C) \ synth (parts C))" using assms(1) using synth_trans by auto then show ?thesis by auto qed subsubsection \Normalization of Messages\ -text\Prevent FS from being contained directly in other FS. +text\Prevent FS from being contained directly in other FS. For instance, a term @{term "FS {| FS {| Num 0 |}, Num 0 |}"} is not normalized, whereas @{term "FS {| Hash (FS {| Num 0 |}), Num 0 |}"} is normalized.\ inductive normalized :: "msgterm \ bool" where \ [simp,intro!]: "normalized \" | AS [simp,intro!]: "normalized (AS agt)" | Num [simp,intro!]: "normalized (Num n)" | Key [simp,intro!]: "normalized (Key n)" | Nonce [simp,intro!]: "normalized (Nonce n)" | Lst [intro]: "\ \x . x \ set xs \ normalized x \ \ normalized (L xs)" - | FSt [intro]: "\ \x . x \ fset xs \ normalized x; - \x ys . x \ fset xs \ x \ FS ys \ + | FSt [intro]: "\ \x . x \ fset xs \ normalized x; + \x ys . x \ fset xs \ x \ FS ys \ \ normalized (FS xs)" | Hash [intro]: "normalized X \ normalized (Hash X)" | MPair [intro]: "\ normalized X; normalized Y \ \ normalized \X,Y\" | Crypt [intro]: "\ normalized X \ \ normalized (Crypt K X)" thm normalized.simps find_theorems normalized text\Examples\ lemma "normalized (FS {| Hash (FS {| Num 0 |}), Num 0 |})" by fastforce lemma "\ normalized (FS {| FS {| Num 0 |}, Num 0 |})" by (auto elim: normalized.cases) subsubsection\Closure of @{text "normalized"} under @{text "parts"}, @{text "analz"} and @{text "synth"}\ text\All synthesized terms are normalized (since @{text "synth"} prevents directly nested FSets).\ lemma normalized_synth[elim!]: "\t \ synth H; \t. t \ H \ normalized t\ \ normalized t" by(induction t, auto 3 4) lemma normalized_parts[elim!]: "\t \ parts H; \t. t \ H \ normalized t\ \ normalized t" by(induction t rule: parts.induct) (auto elim: normalized.cases) lemma normalized_analz[elim!]: "\t \ analz H; \t. t \ H \ normalized t\ \ normalized t" by(induction t rule: analz.induct) (auto elim: normalized.cases) subsubsection\Properties of @{text "normalized"}\ lemma normalized_FS[elim]: "\normalized (FS xs); x |\| xs\ \ normalized x" by(auto simp add: normalized.simps[of "FS xs"]) lemma normalized_FS_FS[elim]: "\normalized (FS xs); x |\| xs; x = FS ys\ \ False" by(auto simp add: normalized.simps[of "FS xs"]) lemma normalized_subset: "\normalized (FS xs); ys |\| xs\ \ normalized (FS ys)" by (auto intro!: normalized.FSt) lemma normalized_insert[elim!]: "normalized (FS (finsert x xs)) \ normalized (FS xs)" - by(auto elim!: normalized_subset) + by(auto elim!: normalized_subset) -lemma normalized_union: +lemma normalized_union: assumes "normalized (FS xs)" "normalized (FS ys)" "zs |\| xs |\| ys" shows "normalized (FS zs)" using assms by(auto intro!: normalized.FSt) -lemma normalized_minus[elim]: - assumes "normalized (FS (ys |-| xs))" "normalized (FS xs)" +lemma normalized_minus[elim]: + assumes "normalized (FS (ys |-| xs))" "normalized (FS xs)" shows "normalized (FS ys)" using normalized_union assms by blast subsubsection\Lemmas that do not use @{text "normalized"}, but are helpful in proving its properties\ lemma FS_mono: "\zs_s = finsert (f (FS zs_s)) zs_b; \ x. size (f x) > size x\ \ False" - by (metis (no_types) add.right_neutral add_Suc_right finite_fset finsert.rep_eq less_add_Suc1 + by (metis (no_types) add.right_neutral add_Suc_right finite_fset finsert.rep_eq less_add_Suc1 msgterm.size(17) not_less_eq size_fset_simps sum.insert_remove) lemma FS_contr: "\zs = f (FS {|zs|}); \ x. size (f x) > size x\ \ False" using FS_mono by blast end diff --git a/thys/Key_Agreement_Strong_Adversaries/Message_derivation.thy b/thys/Key_Agreement_Strong_Adversaries/Message_derivation.thy --- a/thys/Key_Agreement_Strong_Adversaries/Message_derivation.thy +++ b/thys/Key_Agreement_Strong_Adversaries/Message_derivation.thy @@ -1,708 +1,700 @@ (******************************************************************************* Project: Refining Authenticated Key Agreement with Strong Adversaries Module: Message_derivation.thy (Isabelle/HOL 2016-1) ID: $Id: Message_derivation.thy 132885 2016-12-23 18:41:32Z csprenge $ Author: Joseph Lallemand, INRIA Nancy Christoph Sprenger, ETH Zurich - + A theory of message derivations (analz, synth, parts). Based on Larry Paulson's theory HOL/Auth/Message.thy, but extended with - composed keys - including ephemeral asymmetric keys - Diffie-Hellman exponentiation and associated equational theory Copyright (c) 2015-2016 Joseph Lallemand and Christoph Sprenger Licence: LGPL *******************************************************************************) -section \Message theory\ +section \Message theory\ theory Message_derivation imports Messages begin text \This theory is adapted from Larry Paulson's original Message theory.\ (****************************************************************************************) subsection \Message composition\ (****************************************************************************************) text \Dolev-Yao message synthesis.\ inductive_set - synth :: "msg set \ msg set" + synth :: "msg set \ msg set" for H :: "msg set" where Ax [intro]: "X \ H \ X \ synth H" | Agent [simp, intro]: "Agent A \ synth H" | Number [simp, intro]: "Number n \ synth H" | NonceA [simp, intro]: "NonceA n \ synth H" | EpubKA [simp, intro]: "epubKA n \ synth H" | EpriKA [simp, intro]: "epriKA n \ synth H" | Hash [intro]: "X \ synth H \ Hash X \ synth H" | Pair [intro]: "X \ synth H \ Y \ synth H \ (Pair X Y) \ synth H" | Enc [intro]: "X \ synth H \ Y \ synth H \ (Enc X Y) \ synth H" | Aenc [intro]: "X \ synth H \ Y \ synth H \ (Aenc X Y) \ synth H" | Sign [intro]: "X \ synth H \ Y \ synth H \ Sign X Y \ synth H" | Exp [intro]: "X \ synth H \ Y \ synth H \ (Exp X Y) \ synth H" text \Lemmas about Dolev-Yao message synthesis.\ lemma synth_mono [mono_set]: "G \ H \ synth G \ synth H" - by (auto, erule synth.induct, auto) + by (auto, erule synth.induct, auto) lemmas synth_monotone = synth_mono [THEN [2] rev_subsetD] \ \\[elim!]\ slows down certain proofs, e.g., \\ synth H \ B \ {} \ \ P\\ inductive_cases NonceF_synth: "NonceF n \ synth H" inductive_cases LtK_synth: "LtK K \ synth H" inductive_cases EpubKF_synth: "epubKF K \ synth H" inductive_cases EpriKF_synth: "epriKF K \ synth H" inductive_cases Hash_synth: "Hash X \ synth H" inductive_cases Pair_synth: "Pair X Y \ synth H" inductive_cases Enc_synth: "Enc X K \ synth H" inductive_cases Aenc_synth: "Aenc X K \ synth H" inductive_cases Sign_synth: "Sign X K \ synth H" inductive_cases Tag_synth: "Tag t \ synth H" lemma EpriK_synth [elim]: "epriK K \ synth H \ epriK K \ H \ (\ N. epriK K = epriKA N)" by (cases K, auto elim: EpriKF_synth) lemma EpubK_synth [elim]: "epubK K \ synth H \ epubK K \ H \ (\ N. epubK K = epubKA N)" by (cases K, auto elim: EpubKF_synth) -lemmas synth_inversion [elim] = - NonceF_synth LtK_synth EpubKF_synth EpriKF_synth Hash_synth Pair_synth +lemmas synth_inversion [elim] = + NonceF_synth LtK_synth EpubKF_synth EpriKF_synth Hash_synth Pair_synth Enc_synth Aenc_synth Sign_synth Tag_synth lemma synth_increasing: "H \ synth H" by blast lemma synth_Int1: "x \ synth (A \ B) \ x \ synth A " by (erule synth.induct) (auto) lemma synth_Int2: "x \ synth (A \ B) \ x \ synth B" by (erule synth.induct) (auto) lemma synth_Int: "x \ synth (A \ B) \ x \ synth A \ synth B" by (blast intro: synth_Int1 synth_Int2) 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 (blast intro: synth_mono [THEN [2] rev_subsetD]) lemma synth_synthD [dest!]: "X \ synth (synth H) \ X \ synth H" by (erule synth.induct, blast+) lemma synth_idem [simp]: "synth (synth H) = synth H" by blast lemma synth_subset_iff: "synth G \ synth H \ G \ synth H" by (blast dest: synth_mono) lemma synth_trans: "\ X \ synth G; G \ synth H \ \ X \ synth H" by (drule synth_mono, blast) lemma synth_cut: "\ Y \ synth (insert X H); X \ synth H \ \ Y \ synth H" by (erule synth_trans, blast) lemma Nonce_synth_eq [simp]: "(NonceF N \ synth H) = (NonceF N \ H)" by blast lemma LtK_synth_eq [simp]: "(LtK K \ synth H) = (LtK K \ H)" by blast lemma EpubKF_synth_eq [simp]: "(epubKF K \ synth H) = (epubKF K \ H)" by blast lemma EpriKF_synth_eq [simp]: "(epriKF K \ synth H) = (epriKF K \ H)" by blast lemma Enc_synth_eq1 [simp]: "K \ synth H \ (Enc X K \ synth H) = (Enc X K \ H)" by blast lemma Enc_synth_eq2 [simp]: "X \ synth H \ (Enc X K \ synth H) = (Enc X K \ H)" by blast lemma Aenc_synth_eq1 [simp]: "K \ synth H \ (Aenc X K \ synth H) = (Aenc X K \ H)" by blast lemma Aenc_synth_eq2 [simp]: "X \ synth H \ (Aenc X K \ synth H) = (Aenc X K \ H)" by blast lemma Sign_synth_eq1 [simp]: "K \ synth H \ (Sign X K \ synth H) = (Sign X K \ H)" by blast lemma Sign_synth_eq2 [simp]: "X \ synth H \ (Sign X K \ synth H) = (Sign X K \ H)" by blast (****************************************************************************************) subsection \Message decomposition\ (****************************************************************************************) text \Dolev-Yao message decomposition using known keys.\ inductive_set analz :: "msg set \ msg set" for H :: "msg set" where Ax [intro]: "X \ H \ X \ analz H" | Fst: "Pair X Y \ analz H \ X \ analz H" | Snd: "Pair X Y \ analz H \ Y \ analz H" - | Dec [dest]: + | Dec [dest]: "\ Enc X Y \ analz H; Y \ synth (analz H) \ \ X \ analz H" - | Adec_lt [dest]: + | Adec_lt [dest]: "\ Aenc X (LtK (publK Y)) \ analz H; priK Y \ analz H \ \ X \ analz H" - | Adec_eph [dest]: + | Adec_eph [dest]: "\ Aenc X (EphK (epublK Y)) \ analz H; epriK Y \ synth (analz H) \ \ X \ analz H" - | Sign_getmsg [dest]: + | Sign_getmsg [dest]: "Sign X (priK Y) \ analz H \ pubK Y \ analz H \ X \ analz H" text \Lemmas about Dolev-Yao message decomposition.\ lemma analz_mono: "G \ H \ analz(G) \ analz(H)" by (safe, erule analz.induct) (auto dest: Fst Snd synth_Int2) lemmas analz_monotone = analz_mono [THEN [2] rev_subsetD] lemma Pair_analz [elim!]: "\ Pair X Y \ analz H; \ X \ analz H; Y \ analz H \ \ P \ \ P" by (blast dest: analz.Fst analz.Snd) lemma analz_empty [simp]: "analz {} = {}" by (safe, erule analz.induct) (blast+) lemma analz_increasing: "H \ analz(H)" by auto lemma analz_analzD [dest!]: "X \ analz (analz H) \ X \ analz H" by (induction X rule: analz.induct) (auto dest: synth_monotone) lemma analz_idem [simp]: "analz (analz H) = analz H" by auto lemma analz_Un: "analz G \ analz H \ analz (G \ H)" by (intro Un_least analz_mono Un_upper1 Un_upper2) lemma analz_insertI: "X \ analz H \ X \ analz (insert Y H)" by (blast intro: analz_monotone) lemma analz_insert: "insert X (analz H) \ analz (insert X H)" by (blast intro: analz_monotone) lemmas analz_insert_eq_I = equalityI [OF subsetI analz_insert] lemma analz_subset_iff [simp]: "analz G \ analz H \ G \ analz H" by (blast dest: analz_mono) lemma analz_trans: "X \ analz G \ G \ analz H \ X \ analz H" by (drule analz_mono) blast lemma analz_cut: "Y \ analz (insert X H) \ X \ analz H \ Y \ analz H" by (erule analz_trans) blast lemma analz_insert_eq: "X \ analz H \ analz (insert X H) = analz H" by (blast intro: analz_cut analz_insertI) lemma analz_subset_cong: "analz G \ analz G' \ - analz H \ analz H' \ + analz H \ analz H' \ analz (G \ H) \ analz (G' \ H')" apply simp -apply (iprover intro: conjI subset_trans analz_mono Un_upper1 Un_upper2) +apply (iprover intro: conjI subset_trans analz_mono Un_upper1 Un_upper2) done lemma analz_cong: "analz G = analz G' \ analz H = analz H' \ analz (G \ H) = analz (G' \ H')" -by (intro equalityI analz_subset_cong, simp_all) +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) lemma analz_trivial: "\X Y. Pair X Y \ H \ \X Y. Enc X Y \ H \ \X Y. Aenc X Y \ H \ \X Y. Sign X Y \ H \ analz H = H" apply safe apply (erule analz.induct, blast+) done lemma analz_analz_Un [simp]: "analz (analz G \ H) = analz (G \ H)" apply (intro equalityI analz_subset_cong)+ apply simp_all done lemma analz_Un_analz [simp]: "analz (G \ analz H) = analz (G \ H)" by (subst Un_commute, auto)+ -text \Lemmas about analz and insert.\ +text \Lemmas about analz and insert.\ lemma analz_insert_Agent [simp]: "analz (insert (Agent A) H) = insert (Agent A) (analz H)" -apply (rule analz_insert_eq_I) +apply (rule analz_insert_eq_I) apply (erule analz.induct) thm analz.induct apply fastforce apply fastforce apply fastforce defer 1 apply fastforce defer 1 apply fastforce apply (rename_tac x X Y) apply (subgoal_tac "Y \ synth (analz H)", auto) apply (thin_tac "Enc X Y \ Z" for Z)+ apply (drule synth_Int2, auto) apply (erule synth.induct, auto) apply (rename_tac X Y) apply (subgoal_tac "epriK Y \ synth (analz H)", auto) apply (thin_tac "Aenc X (epubK Y) \ Z" for Z)+ apply (erule synth.induct, auto) done (****************************************************************************************) subsection \Lemmas about combined composition/decomposition\ (****************************************************************************************) lemma synth_analz_incr: "H \ synth (analz H)" by auto -lemmas synth_analz_increasing = synth_analz_incr [THEN [2] rev_subsetD] +lemmas synth_analz_increasing = synth_analz_incr [THEN [2] rev_subsetD] lemma synth_analz_mono: "G \ H \ synth (analz G) \ synth (analz H)" by (blast intro!: analz_mono synth_mono) lemmas synth_analz_monotone = synth_analz_mono [THEN [2] rev_subsetD] -lemma lem1: - "Y \ synth (analz (synth G \ H) \ (analz (G \ H) \ synth G)) +lemma lem1: + "Y \ synth (analz (synth G \ H) \ (analz (G \ H) \ synth G)) \ Y \ synth (analz (G \ H))" apply (rule subsetD, auto simp add: synth_subset_iff intro: analz_increasing synth_monotone) done lemma lem2: "{a. a \ analz (G \ H) \ a \ synth G} = analz (G \ H) \ synth G" by auto lemma analz_synth_Un: "analz (synth G \ H) = analz (G \ H) \ synth G" proof (intro equalityI subsetI) fix x - assume "x \ analz (synth G \ H)" + assume "x \ analz (synth G \ H)" thus "x \ analz (G \ H) \ synth G" by (induction x rule: analz.induct) - (auto simp add: lem2 intro: analz_monotone Fst Snd Dec Adec_eph Adec_lt Sign_getmsg + (auto simp add: lem2 intro: analz_monotone Fst Snd Dec Adec_eph Adec_lt Sign_getmsg dest: lem1) -next +next fix x - assume "x \ analz (G \ H) \ synth G" - thus "x \ analz (synth G \ H)" - by (blast intro: analz_monotone) + assume "x \ analz (G \ H) \ synth G" + thus "x \ analz (synth G \ H)" + by (blast intro: analz_monotone) qed lemma analz_synth: "analz (synth H) = analz H \ synth H" by (rule analz_synth_Un [where H="{}", simplified]) lemma analz_synth_Un2 [simp]: "analz (G \ synth H) = analz (G \ H) \ synth H" by (subst Un_commute, auto simp add: analz_synth_Un)+ lemma synth_analz_synth [simp]: "synth (analz (synth H)) = synth (analz H)" by (auto del:subsetI) (auto simp add: synth_subset_iff analz_synth) lemma analz_synth_analz [simp]: "analz (synth (analz H)) = synth (analz H)" by (auto simp add: analz_synth) lemma synth_analz_idem [simp]: "synth (analz (synth (analz H))) = synth (analz H)" by (simp only: analz_synth_analz) simp -lemma insert_subset_synth_analz [simp]: +lemma insert_subset_synth_analz [simp]: "X \ synth (analz H) \ insert X H \ synth (analz H)" by auto -lemma synth_analz_insert [simp]: +lemma synth_analz_insert [simp]: assumes "X \ synth (analz H)" shows "synth (analz (insert X H)) = synth (analz H)" using assms proof (intro equalityI subsetI) fix Z assume "Z \ synth (analz (insert X H))" - hence "Z \ synth (analz (synth (analz H)))" using assms + hence "Z \ synth (analz (synth (analz H)))" using assms by - (erule synth_analz_monotone, rule insert_subset_synth_analz) thus "Z \ synth (analz H)" using assms by simp qed (auto intro: synth_analz_monotone) (****************************************************************************************) subsection \Accessible message parts\ (****************************************************************************************) text \Accessible message parts: all subterms that are in principle extractable by the Dolev-Yao attacker, i.e., provided he knows all keys. Note that keys in key positions and messages under hashes are not message parts in this sense.\ inductive_set parts :: "msg set => msg set" for H :: "msg set" where Inj [intro]: "X \ H \ X \ parts H" | Fst [intro]: "Pair X Y \ parts H \ X \ parts H" | Snd [intro]: "Pair X Y \ parts H \ Y \ parts H" | Dec [intro]: "Enc X Y \ parts H \ X \ parts H" | Adec [intro]: "Aenc X Y \ parts H \ X \ parts H" | Sign_getmsg [intro]: "Sign X Y \ parts H \ X \ parts H" text \Lemmas about accessible message parts.\ lemma parts_mono [mono_set]: "G \ H \ parts G \ parts H" by (auto, erule parts.induct, auto) lemmas parts_monotone = parts_mono [THEN [2] rev_subsetD] lemma Pair_parts [elim]: "\ Pair X Y \ parts H; \ X \ parts H; Y \ parts H \ \ P \ \ P" -by blast +by blast lemma parts_increasing: "H \ parts H" by blast lemmas parts_insertI = subset_insertI [THEN parts_mono, THEN subsetD] lemma parts_empty [simp]: "parts {} = {}" by (safe, erule parts.induct, auto) lemma parts_atomic [simp]: "atomic x \ parts {x} = {x}" by (auto, erule parts.induct, auto) - -lemma parts_InsecTag [simp]: "parts {Tag t} = {Tag t}" + +lemma parts_InsecTag [simp]: "parts {Tag t} = {Tag t}" by (safe, erule parts.induct) (auto) lemma parts_emptyE [elim!]: "X \ parts {} \ P" by simp lemma parts_Tags [simp]: "parts Tags = Tags" -by (rule, rule, erule parts.induct, auto) +by (rule, rule, erule parts.induct, auto) lemma parts_singleton: "X \ parts H \ \ Y\H. X \ parts {Y}" by (erule parts.induct, blast+) lemma parts_Agents [simp]: "parts (Agent` G) = Agent` G" by (auto elim: parts.induct) lemma parts_Un [simp]: "parts (G \ H) = parts G \ parts H" -proof +proof show "parts (G \ H) \ parts G \ parts H" by (rule, erule parts.induct) (auto) -next - show "parts G \ parts H \ parts (G \ H)" +next + show "parts G \ parts H \ parts (G \ H)" by (intro Un_least parts_mono Un_upper1 Un_upper2) -qed +qed -lemma parts_insert_subset_Un: - assumes "X \ G" +lemma parts_insert_subset_Un: + assumes "X \ G" shows "parts (insert X H) \ parts G \ parts H" proof - - from assms have "parts (insert X H) \ parts (G \ H)" by (blast intro!: parts_mono) + from assms have "parts (insert X H) \ parts (G \ H)" by (blast intro!: parts_mono) thus ?thesis by simp -qed +qed lemma parts_insert: "parts (insert X H) = parts {X} \ parts H" by (blast intro!: parts_insert_subset_Un intro: parts_monotone) lemma parts_insert2: "parts (insert X (insert Y H)) = parts {X} \ parts {Y} \ parts H" apply (simp add: Un_assoc) apply (simp add: parts_insert [symmetric]) done -lemma parts_UN [simp]: "parts (\x\A. H x) = (\x\A. parts(H x))" (is "?X = ?Y") -proof - show "?X \ ?Y" by (rule subsetI, erule parts.induct) (blast+) -next - show "?Y \ ?X" by (intro UN_least parts_mono UN_upper) -qed - - -lemmas in_parts_UnE [elim!] = parts_Un [THEN equalityD1, THEN subsetD, THEN UnE] +lemmas in_parts_UnE [elim!] = parts_Un [THEN equalityD1, THEN subsetD, THEN UnE] lemma parts_insert_subset: "insert X (parts H) \ parts (insert X H)" by (blast intro: parts_mono [THEN [2] rev_subsetD]) 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)" by (blast dest: parts_mono) lemma parts_trans: "X \ parts G \ G \ parts H \ X \ parts H" by (drule parts_mono, blast) lemma parts_cut: - "Y \ parts (insert X G) \ X \ parts H \ Y \ parts (G \ H)" + "Y \ parts (insert X G) \ X \ parts H \ Y \ parts (G \ H)" by (blast intro: parts_trans) lemma parts_cut_eq [simp]: "X \ parts H \ parts (insert X H) = parts H" by (force dest!: parts_cut intro: parts_insertI) lemmas parts_insert_eq_I = equalityI [OF subsetI parts_insert_subset] lemma parts_insert_Agent [simp]: "parts (insert (Agent agt) H) = insert (Agent agt) (parts H)" by (rule parts_insert_eq_I, erule parts.induct, auto) lemma parts_insert_Nonce [simp]: "parts (insert (Nonce N) H) = insert (Nonce N) (parts H)" by (rule parts_insert_eq_I, erule parts.induct, auto) lemma parts_insert_Number [simp]: "parts (insert (Number N) H) = insert (Number N) (parts H)" by (rule parts_insert_eq_I, erule parts.induct, auto) lemma parts_insert_LtK [simp]: "parts (insert (LtK K) H) = insert (LtK K) (parts H)" by (rule parts_insert_eq_I, erule parts.induct, auto) lemma parts_insert_Hash [simp]: "parts (insert (Hash X) H) = insert (Hash X) (parts H)" by (rule parts_insert_eq_I, erule parts.induct, auto) lemma parts_insert_Enc [simp]: "parts (insert (Enc X Y) H) = insert (Enc X Y) (parts {X} \ parts H)" apply (rule equalityI) apply (rule subsetI) apply (erule parts.induct, auto) done lemma parts_insert_Aenc [simp]: "parts (insert (Aenc X Y) H) = insert (Aenc X Y) (parts {X} \ parts H)" apply (rule equalityI) apply (rule subsetI) apply (erule parts.induct, auto) done lemma parts_insert_Sign [simp]: "parts (insert (Sign X Y) H) = insert (Sign X Y) (parts {X} \ parts H)" apply (rule equalityI) apply (rule subsetI) apply (erule parts.induct, auto) done lemma parts_insert_Pair [simp]: "parts (insert (Pair X Y) H) = insert (Pair X Y) (parts {X} \ parts {Y} \ parts H)" apply (rule equalityI) apply (rule subsetI) apply (erule parts.induct, auto) done subsubsection \Lemmas about combinations with composition and decomposition\ (****************************************************************************************) lemma analz_subset_parts: "analz H \ parts H" apply (rule subsetI) apply (erule analz.induct, blast+) done lemmas analz_into_parts [simp] = analz_subset_parts [THEN subsetD] lemmas not_parts_not_analz = analz_subset_parts [THEN contra_subsetD] lemma parts_analz [simp]: "parts (analz H) = parts H" apply (rule equalityI) apply (rule analz_subset_parts [THEN parts_mono, THEN subset_trans], simp) apply (blast intro: analz_increasing [THEN parts_mono, THEN subsetD]) done lemma analz_parts [simp]: "analz (parts H) = parts H" apply auto apply (erule analz.induct, auto) done lemma parts_synth [simp]: "parts (synth H) = parts H \ synth H" apply (rule equalityI) apply (rule subsetI) apply (erule parts.induct) apply (blast intro: synth_increasing [THEN parts_mono, THEN subsetD] )+ done lemma Fake_parts_insert: "X \ synth (analz H) \ parts (insert X H) \ synth (analz H) \ parts H" apply (drule parts_insert_subset_Un) apply (simp (no_asm_use)) apply blast done lemma Fake_parts_insert_in_Un: "Z \ parts (insert X H) \ X \ synth (analz H) \ Z \ synth (analz H) \ parts H" by (blast dest: Fake_parts_insert [THEN subsetD, dest]) lemma analz_conj_parts [simp]: "X \ analz H \ X \ parts H \ X \ analz H" by (blast intro: analz_subset_parts [THEN subsetD]) lemma analz_disj_parts [simp]: "X \ analz H \ X \ parts H \ X \ parts H" by (blast intro: analz_subset_parts [THEN subsetD]) (****************************************************************************************) subsection \More lemmas about combinations of closures\ (****************************************************************************************) text \Combinations of @{term synth} and @{term analz}.\ lemma Pair_synth_analz [simp]: "Pair X Y \ synth (analz H) \ X \ synth (analz H) \ Y \ synth (analz H)" by blast lemma Enc_synth_analz: "Y \ synth (analz H) \ (Enc X Y \ synth (analz H)) \ (X \ synth (analz H))" by blast lemma Hash_synth_analz [simp]: "X \ synth (analz H) \ (Hash (Pair X Y) \ synth (analz H)) \ (Hash (Pair X Y) \ analz H)" by blast lemma gen_analz_insert_eq: "\ X \ analz G; G \ H \ \ analz (insert X H) = analz H" by (blast intro: analz_cut analz_insertI analz_monotone) lemma synth_analz_insert_eq: "\ X \ synth (analz G); G \ H \ \ synth (analz (insert X H)) = synth (analz H)" by (blast intro!: synth_analz_insert synth_analz_monotone) lemma Fake_parts_sing: "X \ synth (analz H) \ parts {X} \ synth (analz H) \ parts H" apply (rule subset_trans) apply (erule_tac [2] Fake_parts_insert) apply (rule parts_mono, blast) done lemmas Fake_parts_sing_imp_Un = Fake_parts_sing [THEN [2] rev_subsetD] -lemma analz_hash_nonce [simp]: +lemma analz_hash_nonce [simp]: "analz {M. \N. M = Hash (Nonce N)} = {M. \N. M = Hash (Nonce N)}" by (auto, rule analz.induct, auto) -lemma synth_analz_hash_nonce [simp]: +lemma synth_analz_hash_nonce [simp]: "NonceF N \ synth (analz {M. \N. M = Hash (Nonce N)})" by auto lemma synth_analz_idem_mono: "S \ synth (analz S') \ synth (analz S) \ synth (analz S')" by (frule synth_analz_mono, auto) lemmas synth_analz_idem_monoI = synth_analz_idem_mono [THEN [2] rev_subsetD] lemma analz_synth_subset: "analz X \ synth (analz X') \ analz Y \ synth (analz Y') \ analz (X \ Y) \ synth (analz (X' \ Y'))" proof - assume "analz X \ synth (analz X')" then have HX:"analz X \ analz (synth (analz X'))" by blast assume "analz Y \ synth (analz Y')" then have HY:"analz Y \ analz (synth (analz Y'))" by blast - from analz_subset_cong [OF HX HY] + from analz_subset_cong [OF HX HY] have "analz (X \ Y) \ analz (synth (analz X') \ synth (analz Y'))" by blast also have "... \ analz (synth (analz X' \ analz Y'))" by (intro analz_mono synth_Un) also have "... \ analz (synth (analz (X' \ Y')))" by (intro synth_mono analz_mono analz_Un) also have "... \ synth (analz (X' \ Y'))" by auto finally show "analz (X \ Y) \ synth (analz (X' \ Y'))" by auto qed lemma analz_synth_subset_Un1 : "analz X \ synth (analz X') \ analz (X \ Y) \ synth (analz (X' \ Y))" using analz_synth_subset by blast lemma analz_synth_subset_Un2 : "analz X \ synth (analz X') \ analz (Y \ X) \ synth (analz (Y \ X'))" using analz_synth_subset by blast lemma analz_synth_insert: "analz X \ synth (analz X') \ analz (insert Y X) \ synth (analz (insert Y X'))" by (metis analz_synth_subset_Un2 insert_def) lemma Fake_analz_insert_Un: - assumes "Y \ analz (insert X H)" and "X \ synth (analz G)" + assumes "Y \ analz (insert X H)" and "X \ synth (analz G)" shows "Y \ synth (analz G) \ analz (G \ H)" proof - from assms have "Y \ analz (synth (analz G) \ H)" - by (blast intro: analz_mono [THEN [2] rev_subsetD] + by (blast intro: analz_mono [THEN [2] rev_subsetD] analz_mono [THEN synth_mono, THEN [2] rev_subsetD]) - thus ?thesis by (simp add: sup.commute) + thus ?thesis by (simp add: sup.commute) qed end diff --git a/thys/Security_Protocol_Refinement/Refinement/Message.thy b/thys/Security_Protocol_Refinement/Refinement/Message.thy --- a/thys/Security_Protocol_Refinement/Refinement/Message.thy +++ b/thys/Security_Protocol_Refinement/Refinement/Message.thy @@ -1,878 +1,866 @@ (******************************************************************************* Title: HOL/Auth/Message Author: Lawrence C Paulson, Cambridge University Computer Laboratory Copyright 1996 University of Cambridge Datatypes of agents and messages; Inductive relations "parts", "analz" and "synth" ******************************************************************************** Module: Refinement/Message.thy (Isabelle/HOL 2016-1) ID: $Id: Message.thy 133856 2017-03-20 18:05:54Z csprenge $ Edited: Christoph Sprenger , ETH Zurich Integrated and adapted for security protocol refinement *******************************************************************************) section \Theory of Agents and Messages for Security Protocols\ theory Message imports Keys begin (*Needed occasionally with spy_analz_tac, e.g. in analz_insert_Key_newK*) lemma Un_idem_collapse [simp]: "A \ (B \ A) = B \ A" by blast datatype msg = Agent agent \ \Agent names\ | Number nat \ \Ordinary integers, timestamps, ...\ | Nonce nonce \ \Unguessable nonces\ | Key key \ \Crypto keys\ | Hash msg \ \Hashing\ | MPair msg msg \ \Compound messages\ | Crypt key msg \ \Encryption, public- or shared-key\ text\Concrete syntax: messages appear as \\A,B,NA\\, etc...\ syntax "_MTuple" :: "['a, args] => 'a * 'b" ("(2\_,/ _\)") translations "\x, y, z\" == "\x, \y, z\\" "\x, y\" == "CONST MPair x y" definition HPair :: "[msg,msg] \ msg" ("(4Hash[_] /_)" [0, 1000]) where \ \Message Y paired with a MAC computed with the help of X\ "Hash[X] Y \ \Hash\X,Y\, Y\" definition keysFor :: "msg set \ key set" where \ \Keys useful to decrypt elements of a message set\ "keysFor H \ invKey ` {K. \X. Crypt K X \ H}" subsubsection\Inductive Definition of All Parts" of a Message\ 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" text\Monotonicity\ lemma parts_mono: "G \ H ==> parts(G) \ parts(H)" apply auto apply (erule parts.induct) apply (blast dest: parts.Fst parts.Snd parts.Body)+ done text\Equations hold because constructors are injective.\ lemma Other_image_eq [simp]: "(Agent x \ Agent`A) = (x:A)" by auto lemma Key_image_eq [simp]: "(Key x \ Key`A) = (x\A)" by auto lemma Nonce_Key_image_eq [simp]: "(Nonce x \ Key`A)" by auto subsection\keysFor operator\ lemma keysFor_empty [simp]: "keysFor {} = {}" by (unfold keysFor_def, blast) lemma keysFor_Un [simp]: "keysFor (H \ H') = keysFor H \ keysFor H'" by (unfold keysFor_def, blast) lemma keysFor_UN [simp]: "keysFor (\i\A. H i) = (\i\A. keysFor (H i))" by (unfold keysFor_def, blast) text\Monotonicity\ lemma keysFor_mono: "G \ H ==> keysFor(G) \ keysFor(H)" by (unfold keysFor_def, blast) lemma keysFor_insert_Agent [simp]: "keysFor (insert (Agent A) H) = keysFor H" by (unfold keysFor_def, auto) lemma keysFor_insert_Nonce [simp]: "keysFor (insert (Nonce N) H) = keysFor H" by (unfold keysFor_def, auto) lemma keysFor_insert_Number [simp]: "keysFor (insert (Number N) H) = keysFor H" by (unfold keysFor_def, auto) lemma keysFor_insert_Key [simp]: "keysFor (insert (Key K) H) = keysFor H" by (unfold keysFor_def, auto) lemma keysFor_insert_Hash [simp]: "keysFor (insert (Hash X) H) = keysFor H" by (unfold keysFor_def, auto) lemma keysFor_insert_MPair [simp]: "keysFor (insert \X,Y\ H) = keysFor H" by (unfold keysFor_def, auto) lemma keysFor_insert_Crypt [simp]: "keysFor (insert (Crypt K X) H) = insert (invKey K) (keysFor H)" by (unfold keysFor_def, auto) lemma keysFor_image_Key [simp]: "keysFor (Key`E) = {}" by (unfold keysFor_def, auto) lemma Crypt_imp_invKey_keysFor: "Crypt K X \ H ==> invKey K \ keysFor H" by (unfold keysFor_def, blast) subsection\Inductive relation "parts"\ lemma MPair_parts: "[| \X,Y\ \ parts H; [| X \ parts H; Y \ parts H |] ==> P |] ==> P" by (blast dest: parts.Fst parts.Snd) declare MPair_parts [elim!] parts.Body [dest!] text\NB These two rules are UNSAFE in the formal sense, as they discard the compound message. They work well on THIS FILE. \MPair_parts\ is left as SAFE because it speeds up proofs. The Crypt rule is normally kept UNSAFE to avoid breaking up certificates.\ lemma parts_increasing: "H \ parts(H)" by blast lemmas parts_insertI = subset_insertI [THEN parts_mono, THEN subsetD] lemma parts_empty [simp]: "parts{} = {}" apply safe apply (erule parts.induct, blast+) done lemma parts_emptyE [elim!]: "X\ parts{} ==> P" by simp text\WARNING: loops if H = {Y}, therefore must not be repeated!\ lemma parts_singleton: "X\ parts H ==> \Y\H. X\ parts {Y}" by (erule parts.induct, fast+) subsubsection\Unions\ lemma parts_Un_subset1: "parts(G) \ parts(H) \ parts(G \ H)" by (intro Un_least parts_mono Un_upper1 Un_upper2) lemma parts_Un_subset2: "parts(G \ H) \ parts(G) \ parts(H)" apply (rule subsetI) apply (erule parts.induct, blast+) done lemma parts_Un [simp]: "parts(G \ H) = parts(G) \ parts(H)" by (intro equalityI parts_Un_subset1 parts_Un_subset2) lemma parts_insert: "parts (insert X H) = parts {X} \ parts H" apply (subst insert_is_Un [of _ H]) apply (simp only: parts_Un) done text\TWO inserts to avoid looping. This rewrite is better than nothing. Not suitable for Addsimps: its behaviour can be strange.\ lemma parts_insert2: "parts (insert X (insert Y H)) = parts {X} \ parts {Y} \ parts H" apply (simp add: Un_assoc) apply (simp add: parts_insert [symmetric]) done -lemma parts_UN_subset1: "(\x\A. parts(H x)) \ parts(\x\A. H x)" -by (intro UN_least parts_mono UN_upper) - -lemma parts_UN_subset2: "parts(\x\A. H x) \ (\x\A. parts(H x))" -apply (rule subsetI) -apply (erule parts.induct, blast+) -done - -lemma parts_UN [simp]: "parts(\x\A. H x) = (\x\A. parts(H x))" -by (intro equalityI parts_UN_subset1 parts_UN_subset2) - -text\Added to simplify arguments to parts, analz and synth. - NOTE: the UN versions are no longer used!\ +text\Added to simplify arguments to parts, analz and synth.\ text\This allows \blast\ to simplify occurrences of @{term "parts(G\H)"} in the assumption.\ 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\Idempotence and transitivity\ 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 (iprover intro: subset_trans parts_increasing) apply (frule parts_mono, simp) done lemma parts_trans: "[| X\ parts G; G \ parts H |] ==> X\ parts H" by (drule parts_mono, blast) text\Cut\ lemma parts_cut: "[| Y\ parts (insert X G); X\ parts H |] ==> Y\ parts (G \ H)" by (blast intro: parts_trans) lemma parts_cut_eq [simp]: "X\ parts H ==> parts (insert X H) = parts H" by (force dest!: parts_cut intro: parts_insertI) subsubsection\Rewrite rules for pulling out atomic messages\ lemmas parts_insert_eq_I = equalityI [OF subsetI parts_insert_subset] lemma parts_insert_Agent [simp]: "parts (insert (Agent agt) H) = insert (Agent agt) (parts H)" apply (rule parts_insert_eq_I) apply (erule parts.induct, auto) done lemma parts_insert_Nonce [simp]: "parts (insert (Nonce N) H) = insert (Nonce N) (parts H)" apply (rule parts_insert_eq_I) apply (erule parts.induct, auto) done lemma parts_insert_Number [simp]: "parts (insert (Number N) H) = insert (Number N) (parts H)" apply (rule parts_insert_eq_I) apply (erule parts.induct, auto) done lemma parts_insert_Key [simp]: "parts (insert (Key K) H) = insert (Key K) (parts H)" apply (rule parts_insert_eq_I) apply (erule parts.induct, auto) done lemma parts_insert_Hash [simp]: "parts (insert (Hash X) H) = insert (Hash X) (parts H)" apply (rule parts_insert_eq_I) apply (erule parts.induct, auto) done lemma parts_insert_Crypt [simp]: "parts (insert (Crypt K X) H) = insert (Crypt K X) (parts (insert X H))" apply (rule equalityI) apply (rule subsetI) apply (erule parts.induct, auto) apply (blast intro: parts.Body) done lemma parts_insert_MPair [simp]: "parts (insert \X,Y\ H) = insert \X,Y\ (parts (insert X (insert Y H)))" apply (rule equalityI) apply (rule subsetI) apply (erule parts.induct, auto) apply (blast intro: parts.Fst parts.Snd)+ done lemma parts_image_Key [simp]: "parts (Key`N) = Key`N" apply auto apply (erule parts.induct, auto) done text\In any message, there is an upper bound N on its greatest nonce.\ (* lemma msg_Nonce_supply: "\N. \n. N\n --> Nonce n \ parts {msg}" apply (induct msg) apply (simp_all (no_asm_simp) add: exI parts_insert2) txt{*MPair case: blast works out the necessary sum itself!*} prefer 2 apply auto apply (blast elim!: add_leE) txt{*Nonce case*} apply (rule_tac x = "N + Suc nat" in exI, auto) done *) subsection\Inductive relation "analz"\ text\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.\ 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\Monotonicity; Lemma 1 of Lowe's paper\ lemma analz_mono: "G\H ==> analz(G) \ analz(H)" apply auto apply (erule analz.induct) apply (auto dest: analz.Fst analz.Snd) done lemmas analz_monotonic = analz_mono [THEN [2] rev_subsetD] text\Making it safe speeds up proofs\ lemma MPair_analz [elim!]: "[| \X,Y\ \ analz H; [| X \ analz H; Y \ 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 lemmas analz_into_parts = analz_subset_parts [THEN subsetD] lemmas not_parts_not_analz = analz_subset_parts [THEN contra_subsetD] lemma parts_analz [simp]: "parts (analz H) = parts H" apply (rule equalityI) apply (rule analz_subset_parts [THEN parts_mono, THEN subset_trans], simp) apply (blast intro: analz_increasing [THEN parts_mono, THEN subsetD]) done lemma analz_parts [simp]: "analz (parts H) = parts H" apply auto apply (erule analz.induct, auto) done lemmas analz_insertI = subset_insertI [THEN analz_mono, THEN [2] rev_subsetD] subsubsection\General equational properties\ lemma analz_empty [simp]: "analz{} = {}" apply safe apply (erule analz.induct, blast+) done text\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\ 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\Rewrite rules for pulling out atomic messages\ lemmas analz_insert_eq_I = equalityI [OF subsetI analz_insert] lemma analz_insert_Agent [simp]: "analz (insert (Agent agt) H) = insert (Agent agt) (analz H)" apply (rule analz_insert_eq_I) apply (erule analz.induct, auto) done lemma analz_insert_Nonce [simp]: "analz (insert (Nonce N) H) = insert (Nonce N) (analz H)" apply (rule analz_insert_eq_I) apply (erule analz.induct, auto) done lemma analz_insert_Number [simp]: "analz (insert (Number N) H) = insert (Number N) (analz H)" apply (rule analz_insert_eq_I) apply (erule analz.induct, auto) done lemma analz_insert_Hash [simp]: "analz (insert (Hash X) H) = insert (Hash X) (analz H)" apply (rule analz_insert_eq_I) apply (erule analz.induct, auto) done text\Can only pull out Keys if they are not needed to decrypt the rest\ lemma analz_insert_Key [simp]: "K \ keysFor (analz H) ==> analz (insert (Key K) H) = insert (Key K) (analz H)" apply (unfold keysFor_def) apply (rule analz_insert_eq_I) apply (erule analz.induct, auto) done lemma analz_insert_MPair [simp]: "analz (insert \X,Y\ H) = insert \X,Y\ (analz (insert X (insert Y H)))" apply (rule equalityI) apply (rule subsetI) apply (erule analz.induct, auto) apply (erule analz.induct) apply (blast intro: analz.Fst analz.Snd)+ done text\Can pull out enCrypted message if the Key is not known\ 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) \ 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)) \ 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\Case analysis: either the message is secure, or it is not! Effective, but can cause subgoals to blow up! Use with \split_if\; apparently \split_tac\ does not cope with patterns such as @{term"analz (insert (Crypt K X) H)"}\ lemma analz_Crypt_if [simp]: "analz (insert (Crypt K X) H) = (if (Key (invKey K) \ 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\This rule supposes "for the sake of argument" that we have the key.\ 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_image_Key [simp]: "analz (Key`N) = Key`N" apply auto apply (erule analz.induct, auto) done subsubsection\Idempotence and transitivity\ lemma analz_analzD [dest!]: "X\ analz (analz H) ==> X\ analz H" by (erule analz.induct, blast+) lemma analz_idem [simp]: "analz (analz H) = analz H" by blast lemma analz_subset_iff [simp]: "(analz G \ analz H) = (G \ analz H)" apply (rule iffI) apply (iprover intro: subset_trans analz_increasing) apply (frule analz_mono, simp) done lemma analz_trans: "[| X\ analz G; G \ analz H |] ==> X\ analz H" by (drule analz_mono, blast) text\Cut; Lemma 2 of Lowe\ lemma analz_cut: "[| Y\ analz (insert X H); X\ analz H |] ==> Y\ analz H" by (erule analz_trans, blast) (*Cut can be proved easily by induction on "Y: analz (insert X H) ==> X: analz H --> Y: analz H" *) text\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.\ lemma analz_insert_eq: "X\ analz H ==> analz (insert X H) = analz H" by (blast intro: analz_cut analz_insertI) text\A congruence rule for "analz"\ lemma analz_subset_cong: "[| analz G \ analz G'; analz H \ analz H' |] ==> analz (G \ H) \ analz (G' \ H')" apply simp apply (iprover intro: conjI subset_trans analz_mono Un_upper1 Un_upper2) done lemma analz_cong: "[| analz G = analz G'; analz H = analz H' |] ==> analz (G \ H) = analz (G' \ 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\If there are no pairs or encryptions then analz does nothing\ 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 subsection\Inductive relation "synth"\ text\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.\ 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\Monotonicity\ lemma synth_mono: "G\H ==> synth(G) \ synth(H)" by (auto, erule synth.induct, auto) text\NO \Agent_synth\, as any Agent name can be synthesized. The same holds for @{term Number}\ 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\Unions\ text\Converse fails: we can synth more from the union than from the separate parts, building a compound message using elements of each.\ 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 (blast intro: synth_mono [THEN [2] rev_subsetD]) subsubsection\Idempotence and transitivity\ lemma synth_synthD [dest!]: "X\ synth (synth H) ==> X\ synth H" by (erule synth.induct, blast+) lemma synth_idem: "synth (synth H) = synth H" by blast lemma synth_subset_iff [simp]: "(synth G \ synth H) = (G \ synth H)" apply (rule iffI) apply (iprover intro: subset_trans synth_increasing) apply (frule synth_mono, simp add: synth_idem) done lemma synth_trans: "[| X\ synth G; G \ synth H |] ==> X\ synth H" by (drule synth_mono, blast) text\Cut; Lemma 2 of Lowe\ lemma synth_cut: "[| Y\ synth (insert X H); X\ synth H |] ==> Y\ synth H" by (erule synth_trans, blast) lemma Agent_synth [simp]: "Agent A \ synth H" by blast lemma Number_synth [simp]: "Number n \ synth H" by blast lemma Nonce_synth_eq [simp]: "(Nonce N \ synth H) = (Nonce N \ H)" by blast lemma Key_synth_eq [simp]: "(Key K \ synth H) = (Key K \ H)" by blast lemma Crypt_synth_eq [simp]: "Key K \ H ==> (Crypt K X \ synth H) = (Crypt K X \ H)" by blast lemma keysFor_synth [simp]: "keysFor (synth H) = keysFor H \ invKey`{K. Key K \ H}" by (unfold keysFor_def, blast) subsubsection\Combinations of parts, analz and synth\ lemma parts_synth [simp]: "parts (synth H) = parts H \ synth H" apply (rule equalityI) apply (rule subsetI) apply (erule parts.induct) apply (blast intro: synth_increasing [THEN parts_mono, THEN subsetD] parts.Fst parts.Snd parts.Body)+ done lemma analz_analz_Un [simp]: "analz (analz G \ H) = analz (G \ H)" apply (intro equalityI analz_subset_cong)+ apply simp_all done lemma analz_synth_Un [simp]: "analz (synth G \ H) = analz (G \ H) \ synth G" apply (rule equalityI) apply (rule subsetI) apply (erule analz.induct) prefer 5 apply (blast intro: analz_mono [THEN [2] rev_subsetD]) apply (blast intro: analz.Fst analz.Snd analz.Decrypt)+ done lemma analz_synth [simp]: "analz (synth H) = analz H \ synth H" apply (cut_tac H = "{}" in analz_synth_Un) apply (simp (no_asm_use)) done text \chsp: added\ lemma analz_Un_analz [simp]: "analz (G \ analz H) = analz (G \ H)" by (subst Un_commute, auto)+ lemma analz_synth_Un2 [simp]: "analz (G \ synth H) = analz (G \ H) \ synth H" by (subst Un_commute, auto)+ subsubsection\For reasoning about the Fake rule in traces\ lemma parts_insert_subset_Un: "X\ G ==> parts(insert X H) \ parts G \ parts H" by (rule subset_trans [OF parts_mono parts_Un_subset2], blast) text\More specifically for Fake. Very occasionally we could do with a version of the form @{term"parts{X} \ synth (analz H) \ parts H"}\ lemma Fake_parts_insert: "X \ synth (analz H) ==> parts (insert X H) \ synth (analz H) \ parts H" apply (drule parts_insert_subset_Un) apply (simp (no_asm_use)) apply blast done lemma Fake_parts_insert_in_Un: "[|Z \ parts (insert X H); X \ synth (analz H)|] ==> Z \ synth (analz H) \ parts H" by (blast dest: Fake_parts_insert [THEN subsetD, dest]) text\@{term H} is sometimes @{term"Key ` KK \ spies evs"}, so can't put @{term "G=H"}.\ lemma Fake_analz_insert: "X\ synth (analz G) ==> analz (insert X H) \ synth (analz G) \ analz (G \ H)" apply (rule subsetI) apply (subgoal_tac "x \ analz (synth (analz G) \ H) ") prefer 2 apply (blast intro: analz_mono [THEN [2] rev_subsetD] analz_mono [THEN synth_mono, THEN [2] rev_subsetD]) apply (simp (no_asm_use)) apply blast done lemma analz_conj_parts [simp]: "(X \ analz H & X \ parts H) = (X \ analz H)" by (blast intro: analz_subset_parts [THEN subsetD]) lemma analz_disj_parts [simp]: "(X \ analz H | X \ parts H) = (X \ parts H)" by (blast intro: analz_subset_parts [THEN subsetD]) text\Without this equation, other rules for synth and analz would yield redundant cases\ lemma MPair_synth_analz [iff]: "(\X,Y\ \ synth (analz H)) = (X \ synth (analz H) & Y \ synth (analz H))" by blast lemma Crypt_synth_analz: "[| Key K \ analz H; Key (invKey K) \ analz H |] ==> (Crypt K X \ synth (analz H)) = (X \ synth (analz H))" by blast lemma Hash_synth_analz [simp]: "X \ synth (analz H) ==> (Hash\X,Y\ \ synth (analz H)) = (Hash\X,Y\ \ analz H)" by blast subsection\HPair: a combination of Hash and MPair\ subsubsection\Freeness\ lemma Agent_neq_HPair: "Agent A ~= Hash[X] Y" by (unfold HPair_def, simp) lemma Nonce_neq_HPair: "Nonce N ~= Hash[X] Y" by (unfold HPair_def, simp) lemma Number_neq_HPair: "Number N ~= Hash[X] Y" by (unfold HPair_def, simp) lemma Key_neq_HPair: "Key K ~= Hash[X] Y" by (unfold HPair_def, simp) lemma Hash_neq_HPair: "Hash Z ~= Hash[X] Y" by (unfold HPair_def, simp) lemma Crypt_neq_HPair: "Crypt K X' ~= Hash[X] Y" by (unfold HPair_def, simp) lemmas HPair_neqs = Agent_neq_HPair Nonce_neq_HPair Number_neq_HPair Key_neq_HPair Hash_neq_HPair Crypt_neq_HPair declare HPair_neqs [iff] declare HPair_neqs [symmetric, iff] lemma HPair_eq [iff]: "(Hash[X'] Y' = Hash[X] Y) = (X' = X & Y'=Y)" by (simp add: HPair_def) lemma MPair_eq_HPair [iff]: "(\X',Y'\ = Hash[X] Y) = (X' = Hash\X,Y\ & Y'=Y)" by (simp add: HPair_def) lemma HPair_eq_MPair [iff]: "(Hash[X] Y = \X',Y'\) = (X' = Hash\X,Y\ & Y'=Y)" by (auto simp add: HPair_def) subsubsection\Specialized laws, proved in terms of those for Hash and MPair\ lemma keysFor_insert_HPair [simp]: "keysFor (insert (Hash[X] Y) H) = keysFor H" by (simp add: HPair_def) lemma parts_insert_HPair [simp]: "parts (insert (Hash[X] Y) H) = insert (Hash[X] Y) (insert (Hash\X,Y\) (parts (insert Y H)))" by (simp add: HPair_def) lemma analz_insert_HPair [simp]: "analz (insert (Hash[X] Y) H) = insert (Hash[X] Y) (insert (Hash\X,Y\) (analz (insert Y H)))" by (simp add: HPair_def) lemma HPair_synth_analz [simp]: "X \ synth (analz H) ==> (Hash[X] Y \ synth (analz H)) = (Hash\X, Y\ \ analz H & Y \ synth (analz H))" by (simp add: HPair_def) text\We do NOT want Crypt... messages broken up in protocols!!\ declare parts.Body [rule del] text\Rewrites to push in Key and Crypt messages, so that other messages can be pulled out using the \analz_insert\ rules\ lemmas pushKeys = insert_commute [of "Key K" "Agent C" for K C] insert_commute [of "Key K" "Nonce N" for K N] insert_commute [of "Key K" "Number N" for K N] insert_commute [of "Key K" "Hash X" for K X] insert_commute [of "Key K" "MPair X Y" for K X Y] insert_commute [of "Key K" "Crypt X K'" for K K' X] lemmas pushCrypts = insert_commute [of "Crypt X K" "Agent C" for X K C] insert_commute [of "Crypt X K" "Agent C" for X K C] insert_commute [of "Crypt X K" "Nonce N" for X K N] insert_commute [of "Crypt X K" "Number N" for X K N] insert_commute [of "Crypt X K" "Hash X'" for X K X'] insert_commute [of "Crypt X K" "MPair X' Y" for X K X' Y] text\Cannot be added with \[simp]\ -- messages should not always be re-ordered.\ lemmas pushes = pushKeys pushCrypts text\By default only \o_apply\ is built-in. But in the presence of eta-expansion this means that some terms displayed as @{term "f o g"} will be rewritten, and others will not!\ declare o_def [simp] lemma Crypt_notin_image_Key [simp]: "Crypt K X \ Key ` A" by auto lemma Hash_notin_image_Key [simp] :"Hash X \ Key ` A" by auto lemma synth_analz_mono: "G\H ==> synth (analz(G)) \ synth (analz(H))" by (iprover intro: synth_mono analz_mono) lemma Fake_analz_eq [simp]: "X \ synth(analz H) ==> synth (analz (insert X H)) = synth (analz H)" apply (drule Fake_analz_insert[of _ _ "H"]) apply (simp add: synth_increasing[THEN Un_absorb2]) apply (drule synth_mono) apply (simp add: synth_idem) apply (rule equalityI) apply simp apply (rule synth_analz_mono, blast) done text\Two generalizations of \analz_insert_eq\\ lemma gen_analz_insert_eq [rule_format]: "X \ analz H ==> ALL G. H \ G --> analz (insert X G) = analz G" by (blast intro: analz_cut analz_insertI analz_mono [THEN [2] rev_subsetD]) lemma synth_analz_insert_eq [rule_format]: "X \ synth (analz H) ==> ALL G. H \ G --> (Key K \ analz (insert X G)) = (Key K \ analz G)" apply (erule synth.induct) apply (simp_all add: gen_analz_insert_eq subset_trans [OF _ subset_insertI]) done lemma Fake_parts_sing: "X \ synth (analz H) ==> parts{X} \ synth (analz H) \ parts H" apply (rule subset_trans) apply (erule_tac [2] Fake_parts_insert) apply (rule parts_mono, blast) done lemmas Fake_parts_sing_imp_Un = Fake_parts_sing [THEN [2] rev_subsetD] text\For some reason, moving this up can make some proofs loop!\ declare invKey_K [simp] end