1 (* Title: HOL/Auth/Message
2 Author: Lawrence C Paulson, Cambridge University Computer Laboratory
3 Copyright 1996 University of Cambridge
5 Datatypes of agents and messages;
6 Inductive relations "parts", "analz" and "synth"
9 header{*Theory of Agents and Messages for Security Protocols*}
11 theory Message imports Main uses "../../antiquote_setup.ML" begin
13 (*Needed occasionally with spy_analz_tac, e.g. in analz_insert_Key_newK*)
14 lemma [simp] : "A \<union> (B \<union> A) = B \<union> A"
18 section{* Agents and Messages *}
21 All protocol specifications refer to a syntactic theory of messages.
23 @{text agent} introduces the constant @{text Server} (a trusted central
24 machine, needed for some protocols), an infinite population of
25 friendly agents, and the~@{text Spy}:
28 datatype agent = Server | Friend nat | Spy
31 Keys are just natural numbers. Function @{text invKey} maps a public key to
32 the matching private key, and vice versa:
36 consts invKey :: "key \<Rightarrow> key"
38 consts all_symmetric :: bool --{*true if all keys are symmetric*}
40 specification (invKey)
41 invKey [simp]: "invKey (invKey K) = K"
42 invKey_symmetric: "all_symmetric --> invKey = id"
43 by (rule exI [of _ id], auto)
46 text{*The inverse of a symmetric key is itself; that of a public key
47 is the private key and vice versa*}
49 definition symKeys :: "key set" where
50 "symKeys == {K. invKey K = K}"
55 @{text msg} introduces the message forms, which include agent names, nonces,
56 keys, compound messages, and encryptions.
68 The notation $\comp{X\sb 1,\ldots X\sb{n-1},X\sb n}$
70 $\isa{MPair}\,X\sb 1\,\ldots\allowbreak(\isa{MPair}\,X\sb{n-1}\,X\sb n)$.
72 Since datatype constructors are injective, we have the theorem
73 @{thm [display,indent=0] msg.inject(5) [THEN iffD1, of K X K' X']}
74 A ciphertext can be decrypted using only one key and
75 can yield only one plaintext. In the real world, decryption with the
76 wrong key succeeds but yields garbage. Our model of encryption is
77 realistic if encryption adds some redundancy to the plaintext, such as a
78 checksum, so that garbage can be detected.
82 text{*Concrete syntax: messages appear as {|A,B,NA|}, etc...*}
84 "_MTuple" :: "['a, args] => 'a * 'b" ("(2{|_,/ _|})")
87 "_MTuple" :: "['a, args] => 'a * 'b" ("(2\<lbrace>_,/ _\<rbrace>)")
90 "{|x, y, z|}" == "{|x, {|y, z|}|}"
91 "{|x, y|}" == "CONST MPair x y"
94 definition keysFor :: "msg set => key set" where
95 --{*Keys useful to decrypt elements of a message set*}
96 "keysFor H == invKey ` {K. \<exists>X. Crypt K X \<in> H}"
99 subsubsection{*Inductive Definition of All Parts" of a Message*}
102 parts :: "msg set => msg set"
105 Inj [intro]: "X \<in> H ==> X \<in> parts H"
106 | Fst: "{|X,Y|} \<in> parts H ==> X \<in> parts H"
107 | Snd: "{|X,Y|} \<in> parts H ==> Y \<in> parts H"
108 | Body: "Crypt K X \<in> parts H ==> X \<in> parts H"
112 lemma parts_mono: "G \<subseteq> H ==> parts(G) \<subseteq> parts(H)"
114 apply (erule parts.induct)
115 apply (blast dest: parts.Fst parts.Snd parts.Body)+
119 text{*Equations hold because constructors are injective.*}
120 lemma Friend_image_eq [simp]: "(Friend x \<in> Friend`A) = (x:A)"
123 lemma Key_image_eq [simp]: "(Key x \<in> Key`A) = (x\<in>A)"
126 lemma Nonce_Key_image_eq [simp]: "(Nonce x \<notin> Key`A)"
130 subsubsection{*Inverse of keys *}
132 lemma invKey_eq [simp]: "(invKey K = invKey K') = (K=K')"
134 apply (drule_tac f = invKey in arg_cong, simp)
138 subsection{*keysFor operator*}
140 lemma keysFor_empty [simp]: "keysFor {} = {}"
141 by (unfold keysFor_def, blast)
143 lemma keysFor_Un [simp]: "keysFor (H \<union> H') = keysFor H \<union> keysFor H'"
144 by (unfold keysFor_def, blast)
146 lemma keysFor_UN [simp]: "keysFor (\<Union>i\<in>A. H i) = (\<Union>i\<in>A. keysFor (H i))"
147 by (unfold keysFor_def, blast)
150 lemma keysFor_mono: "G \<subseteq> H ==> keysFor(G) \<subseteq> keysFor(H)"
151 by (unfold keysFor_def, blast)
153 lemma keysFor_insert_Agent [simp]: "keysFor (insert (Agent A) H) = keysFor H"
154 by (unfold keysFor_def, auto)
156 lemma keysFor_insert_Nonce [simp]: "keysFor (insert (Nonce N) H) = keysFor H"
157 by (unfold keysFor_def, auto)
159 lemma keysFor_insert_Key [simp]: "keysFor (insert (Key K) H) = keysFor H"
160 by (unfold keysFor_def, auto)
162 lemma keysFor_insert_MPair [simp]: "keysFor (insert {|X,Y|} H) = keysFor H"
163 by (unfold keysFor_def, auto)
165 lemma keysFor_insert_Crypt [simp]:
166 "keysFor (insert (Crypt K X) H) = insert (invKey K) (keysFor H)"
167 by (unfold keysFor_def, auto)
169 lemma keysFor_image_Key [simp]: "keysFor (Key`E) = {}"
170 by (unfold keysFor_def, auto)
172 lemma Crypt_imp_invKey_keysFor: "Crypt K X \<in> H ==> invKey K \<in> keysFor H"
173 by (unfold keysFor_def, blast)
176 subsection{*Inductive relation "parts"*}
179 "[| {|X,Y|} \<in> parts H;
180 [| X \<in> parts H; Y \<in> parts H |] ==> P |] ==> P"
181 by (blast dest: parts.Fst parts.Snd)
183 declare MPair_parts [elim!] parts.Body [dest!]
184 text{*NB These two rules are UNSAFE in the formal sense, as they discard the
185 compound message. They work well on THIS FILE.
186 @{text MPair_parts} is left as SAFE because it speeds up proofs.
187 The Crypt rule is normally kept UNSAFE to avoid breaking up certificates.*}
189 lemma parts_increasing: "H \<subseteq> parts(H)"
192 lemmas parts_insertI = subset_insertI [THEN parts_mono, THEN subsetD, standard]
194 lemma parts_empty [simp]: "parts{} = {}"
196 apply (erule parts.induct, blast+)
199 lemma parts_emptyE [elim!]: "X\<in> parts{} ==> P"
202 text{*WARNING: loops if H = {Y}, therefore must not be repeated!*}
203 lemma parts_singleton: "X\<in> parts H ==> \<exists>Y\<in>H. X\<in> parts {Y}"
204 by (erule parts.induct, fast+)
207 subsubsection{*Unions *}
209 lemma parts_Un_subset1: "parts(G) \<union> parts(H) \<subseteq> parts(G \<union> H)"
210 by (intro Un_least parts_mono Un_upper1 Un_upper2)
212 lemma parts_Un_subset2: "parts(G \<union> H) \<subseteq> parts(G) \<union> parts(H)"
214 apply (erule parts.induct, blast+)
217 lemma parts_Un [simp]: "parts(G \<union> H) = parts(G) \<union> parts(H)"
218 by (intro equalityI parts_Un_subset1 parts_Un_subset2)
220 lemma parts_insert: "parts (insert X H) = parts {X} \<union> parts H"
221 apply (subst insert_is_Un [of _ H])
222 apply (simp only: parts_Un)
225 text{*TWO inserts to avoid looping. This rewrite is better than nothing.
226 Not suitable for Addsimps: its behaviour can be strange.*}
228 "parts (insert X (insert Y H)) = parts {X} \<union> parts {Y} \<union> parts H"
229 apply (simp add: Un_assoc)
230 apply (simp add: parts_insert [symmetric])
233 lemma parts_UN_subset1: "(\<Union>x\<in>A. parts(H x)) \<subseteq> parts(\<Union>x\<in>A. H x)"
234 by (intro UN_least parts_mono UN_upper)
236 lemma parts_UN_subset2: "parts(\<Union>x\<in>A. H x) \<subseteq> (\<Union>x\<in>A. parts(H x))"
238 apply (erule parts.induct, blast+)
241 lemma parts_UN [simp]: "parts(\<Union>x\<in>A. H x) = (\<Union>x\<in>A. parts(H x))"
242 by (intro equalityI parts_UN_subset1 parts_UN_subset2)
244 text{*Added to simplify arguments to parts, analz and synth.
245 NOTE: the UN versions are no longer used!*}
248 text{*This allows @{text blast} to simplify occurrences of
249 @{term "parts(G\<union>H)"} in the assumption.*}
250 lemmas in_parts_UnE = parts_Un [THEN equalityD1, THEN subsetD, THEN UnE]
251 declare in_parts_UnE [elim!]
254 lemma parts_insert_subset: "insert X (parts H) \<subseteq> parts(insert X H)"
255 by (blast intro: parts_mono [THEN [2] rev_subsetD])
257 subsubsection{*Idempotence and transitivity *}
259 lemma parts_partsD [dest!]: "X\<in> parts (parts H) ==> X\<in> parts H"
260 by (erule parts.induct, blast+)
262 lemma parts_idem [simp]: "parts (parts H) = parts H"
265 lemma parts_subset_iff [simp]: "(parts G \<subseteq> parts H) = (G \<subseteq> parts H)"
267 apply (iprover intro: subset_trans parts_increasing)
268 apply (frule parts_mono, simp)
271 lemma parts_trans: "[| X\<in> parts G; G \<subseteq> parts H |] ==> X\<in> parts H"
272 by (drule parts_mono, blast)
276 "[| Y\<in> parts (insert X G); X\<in> parts H |] ==> Y\<in> parts (G \<union> H)"
277 by (blast intro: parts_trans)
280 lemma parts_cut_eq [simp]: "X\<in> parts H ==> parts (insert X H) = parts H"
281 by (force dest!: parts_cut intro: parts_insertI)
284 subsubsection{*Rewrite rules for pulling out atomic messages *}
286 lemmas parts_insert_eq_I = equalityI [OF subsetI parts_insert_subset]
289 lemma parts_insert_Agent [simp]:
290 "parts (insert (Agent agt) H) = insert (Agent agt) (parts H)"
291 apply (rule parts_insert_eq_I)
292 apply (erule parts.induct, auto)
295 lemma parts_insert_Nonce [simp]:
296 "parts (insert (Nonce N) H) = insert (Nonce N) (parts H)"
297 apply (rule parts_insert_eq_I)
298 apply (erule parts.induct, auto)
301 lemma parts_insert_Key [simp]:
302 "parts (insert (Key K) H) = insert (Key K) (parts H)"
303 apply (rule parts_insert_eq_I)
304 apply (erule parts.induct, auto)
307 lemma parts_insert_Crypt [simp]:
308 "parts (insert (Crypt K X) H) = insert (Crypt K X) (parts (insert X H))"
309 apply (rule equalityI)
311 apply (erule parts.induct, auto)
312 apply (blast intro: parts.Body)
315 lemma parts_insert_MPair [simp]:
316 "parts (insert {|X,Y|} H) =
317 insert {|X,Y|} (parts (insert X (insert Y H)))"
318 apply (rule equalityI)
320 apply (erule parts.induct, auto)
321 apply (blast intro: parts.Fst parts.Snd)+
324 lemma parts_image_Key [simp]: "parts (Key`N) = Key`N"
326 apply (erule parts.induct, auto)
330 text{*In any message, there is an upper bound N on its greatest nonce.*}
331 lemma msg_Nonce_supply: "\<exists>N. \<forall>n. N\<le>n --> Nonce n \<notin> parts {msg}"
332 apply (induct_tac "msg")
333 apply (simp_all (no_asm_simp) add: exI parts_insert2)
334 txt{*MPair case: blast works out the necessary sum itself!*}
335 prefer 2 apply auto apply (blast elim!: add_leE)
337 apply (rule_tac x = "N + Suc nat" in exI, auto)
341 section{* Modelling the Adversary *}
344 The spy is part of the system and must be built into the model. He is
345 a malicious user who does not have to follow the protocol. He
346 watches the network and uses any keys he knows to decrypt messages.
347 Thus he accumulates additional keys and nonces. These he can use to
348 compose new messages, which he may send to anybody.
350 Two functions enable us to formalize this behaviour: @{text analz} and
351 @{text synth}. Each function maps a sets of messages to another set of
352 messages. The set @{text "analz H"} formalizes what the adversary can learn
353 from the set of messages~$H$. The closure properties of this set are
358 analz :: "msg set \<Rightarrow> msg set"
361 Inj [intro,simp] : "X \<in> H \<Longrightarrow> X \<in> analz H"
362 | Fst: "\<lbrace>X,Y\<rbrace> \<in> analz H \<Longrightarrow> X \<in> analz H"
363 | Snd: "\<lbrace>X,Y\<rbrace> \<in> analz H \<Longrightarrow> Y \<in> analz H"
365 "\<lbrakk>Crypt K X \<in> analz H; Key(invKey K) \<in> analz H\<rbrakk>
366 \<Longrightarrow> X \<in> analz H"
368 text{*Monotonicity; Lemma 1 of Lowe's paper*}
369 lemma analz_mono: "G\<subseteq>H ==> analz(G) \<subseteq> analz(H)"
371 apply (erule analz.induct)
372 apply (auto dest: analz.Fst analz.Snd)
375 text{*Making it safe speeds up proofs*}
376 lemma MPair_analz [elim!]:
377 "[| {|X,Y|} \<in> analz H;
378 [| X \<in> analz H; Y \<in> analz H |] ==> P
380 by (blast dest: analz.Fst analz.Snd)
382 lemma analz_increasing: "H \<subseteq> analz(H)"
385 lemma analz_subset_parts: "analz H \<subseteq> parts H"
387 apply (erule analz.induct, blast+)
390 lemmas analz_into_parts = analz_subset_parts [THEN subsetD, standard]
392 lemmas not_parts_not_analz = analz_subset_parts [THEN contra_subsetD, standard]
395 lemma parts_analz [simp]: "parts (analz H) = parts H"
396 apply (rule equalityI)
397 apply (rule analz_subset_parts [THEN parts_mono, THEN subset_trans], simp)
398 apply (blast intro: analz_increasing [THEN parts_mono, THEN subsetD])
401 lemma analz_parts [simp]: "analz (parts H) = parts H"
403 apply (erule analz.induct, auto)
406 lemmas analz_insertI = subset_insertI [THEN analz_mono, THEN [2] rev_subsetD, standard]
408 subsubsection{*General equational properties *}
410 lemma analz_empty [simp]: "analz{} = {}"
412 apply (erule analz.induct, blast+)
415 text{*Converse fails: we can analz more from the union than from the
416 separate parts, as a key in one might decrypt a message in the other*}
417 lemma analz_Un: "analz(G) \<union> analz(H) \<subseteq> analz(G \<union> H)"
418 by (intro Un_least analz_mono Un_upper1 Un_upper2)
420 lemma analz_insert: "insert X (analz H) \<subseteq> analz(insert X H)"
421 by (blast intro: analz_mono [THEN [2] rev_subsetD])
423 subsubsection{*Rewrite rules for pulling out atomic messages *}
425 lemmas analz_insert_eq_I = equalityI [OF subsetI analz_insert]
427 lemma analz_insert_Agent [simp]:
428 "analz (insert (Agent agt) H) = insert (Agent agt) (analz H)"
429 apply (rule analz_insert_eq_I)
430 apply (erule analz.induct, auto)
433 lemma analz_insert_Nonce [simp]:
434 "analz (insert (Nonce N) H) = insert (Nonce N) (analz H)"
435 apply (rule analz_insert_eq_I)
436 apply (erule analz.induct, auto)
439 text{*Can only pull out Keys if they are not needed to decrypt the rest*}
440 lemma analz_insert_Key [simp]:
441 "K \<notin> keysFor (analz H) ==>
442 analz (insert (Key K) H) = insert (Key K) (analz H)"
443 apply (unfold keysFor_def)
444 apply (rule analz_insert_eq_I)
445 apply (erule analz.induct, auto)
448 lemma analz_insert_MPair [simp]:
449 "analz (insert {|X,Y|} H) =
450 insert {|X,Y|} (analz (insert X (insert Y H)))"
451 apply (rule equalityI)
453 apply (erule analz.induct, auto)
454 apply (erule analz.induct)
455 apply (blast intro: analz.Fst analz.Snd)+
458 text{*Can pull out enCrypted message if the Key is not known*}
459 lemma analz_insert_Crypt:
460 "Key (invKey K) \<notin> analz H
461 ==> analz (insert (Crypt K X) H) = insert (Crypt K X) (analz H)"
462 apply (rule analz_insert_eq_I)
463 apply (erule analz.induct, auto)
467 lemma lemma1: "Key (invKey K) \<in> analz H ==>
468 analz (insert (Crypt K X) H) \<subseteq>
469 insert (Crypt K X) (analz (insert X H))"
471 apply (erule_tac x = x in analz.induct, auto)
474 lemma lemma2: "Key (invKey K) \<in> analz H ==>
475 insert (Crypt K X) (analz (insert X H)) \<subseteq>
476 analz (insert (Crypt K X) H)"
478 apply (erule_tac x = x in analz.induct, auto)
479 apply (blast intro: analz_insertI analz.Decrypt)
482 lemma analz_insert_Decrypt:
483 "Key (invKey K) \<in> analz H ==>
484 analz (insert (Crypt K X) H) =
485 insert (Crypt K X) (analz (insert X H))"
486 by (intro equalityI lemma1 lemma2)
488 text{*Case analysis: either the message is secure, or it is not! Effective,
489 but can cause subgoals to blow up! Use with @{text "split_if"}; apparently
490 @{text "split_tac"} does not cope with patterns such as @{term"analz (insert
492 lemma analz_Crypt_if [simp]:
493 "analz (insert (Crypt K X) H) =
494 (if (Key (invKey K) \<in> analz H)
495 then insert (Crypt K X) (analz (insert X H))
496 else insert (Crypt K X) (analz H))"
497 by (simp add: analz_insert_Crypt analz_insert_Decrypt)
500 text{*This rule supposes "for the sake of argument" that we have the key.*}
501 lemma analz_insert_Crypt_subset:
502 "analz (insert (Crypt K X) H) \<subseteq>
503 insert (Crypt K X) (analz (insert X H))"
505 apply (erule analz.induct, auto)
509 lemma analz_image_Key [simp]: "analz (Key`N) = Key`N"
511 apply (erule analz.induct, auto)
515 subsubsection{*Idempotence and transitivity *}
517 lemma analz_analzD [dest!]: "X\<in> analz (analz H) ==> X\<in> analz H"
518 by (erule analz.induct, blast+)
520 lemma analz_idem [simp]: "analz (analz H) = analz H"
523 lemma analz_subset_iff [simp]: "(analz G \<subseteq> analz H) = (G \<subseteq> analz H)"
525 apply (iprover intro: subset_trans analz_increasing)
526 apply (frule analz_mono, simp)
529 lemma analz_trans: "[| X\<in> analz G; G \<subseteq> analz H |] ==> X\<in> analz H"
530 by (drule analz_mono, blast)
532 text{*Cut; Lemma 2 of Lowe*}
533 lemma analz_cut: "[| Y\<in> analz (insert X H); X\<in> analz H |] ==> Y\<in> analz H"
534 by (erule analz_trans, blast)
536 (*Cut can be proved easily by induction on
537 "Y: analz (insert X H) ==> X: analz H --> Y: analz H"
540 text{*This rewrite rule helps in the simplification of messages that involve
541 the forwarding of unknown components (X). Without it, removing occurrences
542 of X can be very complicated. *}
543 lemma analz_insert_eq: "X\<in> analz H ==> analz (insert X H) = analz H"
544 by (blast intro: analz_cut analz_insertI)
547 text{*A congruence rule for "analz" *}
549 lemma analz_subset_cong:
550 "[| analz G \<subseteq> analz G'; analz H \<subseteq> analz H' |]
551 ==> analz (G \<union> H) \<subseteq> analz (G' \<union> H')"
553 apply (iprover intro: conjI subset_trans analz_mono Un_upper1 Un_upper2)
557 "[| analz G = analz G'; analz H = analz H' |]
558 ==> analz (G \<union> H) = analz (G' \<union> H')"
559 by (intro equalityI analz_subset_cong, simp_all)
561 lemma analz_insert_cong:
562 "analz H = analz H' ==> analz(insert X H) = analz(insert X H')"
563 by (force simp only: insert_def intro!: analz_cong)
565 text{*If there are no pairs or encryptions then analz does nothing*}
567 "[| \<forall>X Y. {|X,Y|} \<notin> H; \<forall>X K. Crypt K X \<notin> H |] ==> analz H = H"
569 apply (erule analz.induct, blast+)
572 text{*These two are obsolete (with a single Spy) but cost little to prove...*}
573 lemma analz_UN_analz_lemma:
574 "X\<in> analz (\<Union>i\<in>A. analz (H i)) ==> X\<in> analz (\<Union>i\<in>A. H i)"
575 apply (erule analz.induct)
576 apply (blast intro: analz_mono [THEN [2] rev_subsetD])+
579 lemma analz_UN_analz [simp]: "analz (\<Union>i\<in>A. analz (H i)) = analz (\<Union>i\<in>A. H i)"
580 by (blast intro: analz_UN_analz_lemma analz_mono [THEN [2] rev_subsetD])
583 Note the @{text Decrypt} rule: the spy can decrypt a
584 message encrypted with key~$K$ if he has the matching key,~$K^{-1}$.
585 Properties proved by rule induction include the following:
586 @{named_thms [display,indent=0] analz_mono [no_vars] (analz_mono) analz_idem [no_vars] (analz_idem)}
588 The set of fake messages that an intruder could invent
589 starting from~@{text H} is @{text "synth(analz H)"}, where @{text "synth H"}
590 formalizes what the adversary can build from the set of messages~$H$.
594 synth :: "msg set \<Rightarrow> msg set"
597 Inj [intro]: "X \<in> H \<Longrightarrow> X \<in> synth H"
598 | Agent [intro]: "Agent agt \<in> synth H"
600 "\<lbrakk>X \<in> synth H; Y \<in> synth H\<rbrakk> \<Longrightarrow> \<lbrace>X,Y\<rbrace> \<in> synth H"
602 "\<lbrakk>X \<in> synth H; Key K \<in> H\<rbrakk> \<Longrightarrow> Crypt K X \<in> synth H"
604 lemma synth_mono: "G\<subseteq>H ==> synth(G) \<subseteq> synth(H)"
605 by (auto, erule synth.induct, auto)
607 inductive_cases Key_synth [elim!]: "Key K \<in> synth H"
608 inductive_cases MPair_synth [elim!]: "{|X,Y|} \<in> synth H"
609 inductive_cases Crypt_synth [elim!]: "Crypt K X \<in> synth H"
611 lemma analz_synth_Un [simp]: "analz (synth G \<union> H) = analz (G \<union> H) \<union> synth G"
612 apply (rule equalityI)
614 apply (erule analz.induct)
615 prefer 5 apply (blast intro: analz_mono [THEN [2] rev_subsetD])
616 apply (blast intro: analz.Fst analz.Snd analz.Decrypt)+
619 lemma analz_synth [simp]: "analz (synth H) = analz H \<union> synth H"
620 apply (cut_tac H = "{}" in analz_synth_Un)
621 apply (simp (no_asm_use))
625 The set includes all agent names. Nonces and keys are assumed to be
626 unguessable, so none are included beyond those already in~$H$. Two
627 elements of @{term "synth H"} can be combined, and an element can be encrypted
628 using a key present in~$H$.
630 Like @{text analz}, this set operator is monotone and idempotent. It also
631 satisfies an interesting equation involving @{text analz}:
632 @{named_thms [display,indent=0] analz_synth [no_vars] (analz_synth)}
633 Rule inversion plays a major role in reasoning about @{text synth}, through
634 declarations such as this one:
637 inductive_cases Nonce_synth [elim!]: "Nonce n \<in> synth H"
641 The resulting elimination rule replaces every assumption of the form
642 @{term "Nonce n \<in> synth H"} by @{term "Nonce n \<in> H"},
643 expressing that a nonce cannot be guessed.
645 A third operator, @{text parts}, is useful for stating correctness
647 @{term "parts H"} consists of the components of elements of~$H$. This set
648 includes~@{text H} and is closed under the projections from a compound
649 message to its immediate parts.
650 Its definition resembles that of @{text analz} except in the rule
651 corresponding to the constructor @{text Crypt}:
652 @{thm [display,indent=5] parts.Body [no_vars]}
653 The body of an encrypted message is always regarded as part of it. We can
654 use @{text parts} to express general well-formedness properties of a protocol,
655 for example, that an uncompromised agent's private key will never be
656 included as a component of any message.
659 lemma synth_increasing: "H \<subseteq> synth(H)"
662 subsubsection{*Unions *}
664 text{*Converse fails: we can synth more from the union than from the
665 separate parts, building a compound message using elements of each.*}
666 lemma synth_Un: "synth(G) \<union> synth(H) \<subseteq> synth(G \<union> H)"
667 by (intro Un_least synth_mono Un_upper1 Un_upper2)
669 lemma synth_insert: "insert X (synth H) \<subseteq> synth(insert X H)"
670 by (blast intro: synth_mono [THEN [2] rev_subsetD])
672 subsubsection{*Idempotence and transitivity *}
674 lemma synth_synthD [dest!]: "X\<in> synth (synth H) ==> X\<in> synth H"
675 by (erule synth.induct, blast+)
677 lemma synth_idem: "synth (synth H) = synth H"
680 lemma synth_subset_iff [simp]: "(synth G \<subseteq> synth H) = (G \<subseteq> synth H)"
682 apply (iprover intro: subset_trans synth_increasing)
683 apply (frule synth_mono, simp add: synth_idem)
686 lemma synth_trans: "[| X\<in> synth G; G \<subseteq> synth H |] ==> X\<in> synth H"
687 by (drule synth_mono, blast)
689 text{*Cut; Lemma 2 of Lowe*}
690 lemma synth_cut: "[| Y\<in> synth (insert X H); X\<in> synth H |] ==> Y\<in> synth H"
691 by (erule synth_trans, blast)
693 lemma Agent_synth [simp]: "Agent A \<in> synth H"
696 lemma Nonce_synth_eq [simp]: "(Nonce N \<in> synth H) = (Nonce N \<in> H)"
699 lemma Key_synth_eq [simp]: "(Key K \<in> synth H) = (Key K \<in> H)"
702 lemma Crypt_synth_eq [simp]:
703 "Key K \<notin> H ==> (Crypt K X \<in> synth H) = (Crypt K X \<in> H)"
707 lemma keysFor_synth [simp]:
708 "keysFor (synth H) = keysFor H \<union> invKey`{K. Key K \<in> H}"
709 by (unfold keysFor_def, blast)
712 subsubsection{*Combinations of parts, analz and synth *}
714 lemma parts_synth [simp]: "parts (synth H) = parts H \<union> synth H"
715 apply (rule equalityI)
717 apply (erule parts.induct)
718 apply (blast intro: synth_increasing [THEN parts_mono, THEN subsetD]
719 parts.Fst parts.Snd parts.Body)+
722 lemma analz_analz_Un [simp]: "analz (analz G \<union> H) = analz (G \<union> H)"
723 apply (intro equalityI analz_subset_cong)+
728 subsubsection{*For reasoning about the Fake rule in traces *}
730 lemma parts_insert_subset_Un: "X\<in> G ==> parts(insert X H) \<subseteq> parts G \<union> parts H"
731 by (rule subset_trans [OF parts_mono parts_Un_subset2], blast)
733 text{*More specifically for Fake. Very occasionally we could do with a version
734 of the form @{term"parts{X} \<subseteq> synth (analz H) \<union> parts H"} *}
735 lemma Fake_parts_insert:
736 "X \<in> synth (analz H) ==>
737 parts (insert X H) \<subseteq> synth (analz H) \<union> parts H"
738 apply (drule parts_insert_subset_Un)
739 apply (simp (no_asm_use))
743 lemma Fake_parts_insert_in_Un:
744 "[|Z \<in> parts (insert X H); X: synth (analz H)|]
745 ==> Z \<in> synth (analz H) \<union> parts H";
746 by (blast dest: Fake_parts_insert [THEN subsetD, dest])
748 text{*@{term H} is sometimes @{term"Key ` KK \<union> spies evs"}, so can't put
750 lemma Fake_analz_insert:
751 "X\<in> synth (analz G) ==>
752 analz (insert X H) \<subseteq> synth (analz G) \<union> analz (G \<union> H)"
754 apply (subgoal_tac "x \<in> analz (synth (analz G) \<union> H) ")
755 prefer 2 apply (blast intro: analz_mono [THEN [2] rev_subsetD] analz_mono [THEN synth_mono, THEN [2] rev_subsetD])
756 apply (simp (no_asm_use))
760 lemma analz_conj_parts [simp]:
761 "(X \<in> analz H & X \<in> parts H) = (X \<in> analz H)"
762 by (blast intro: analz_subset_parts [THEN subsetD])
764 lemma analz_disj_parts [simp]:
765 "(X \<in> analz H | X \<in> parts H) = (X \<in> parts H)"
766 by (blast intro: analz_subset_parts [THEN subsetD])
768 text{*Without this equation, other rules for synth and analz would yield
770 lemma MPair_synth_analz [iff]:
771 "({|X,Y|} \<in> synth (analz H)) =
772 (X \<in> synth (analz H) & Y \<in> synth (analz H))"
775 lemma Crypt_synth_analz:
776 "[| Key K \<in> analz H; Key (invKey K) \<in> analz H |]
777 ==> (Crypt K X \<in> synth (analz H)) = (X \<in> synth (analz H))"
781 text{*We do NOT want Crypt... messages broken up in protocols!!*}
782 declare parts.Body [rule del]
785 text{*Rewrites to push in Key and Crypt messages, so that other messages can
786 be pulled out using the @{text analz_insert} rules*}
788 lemmas pushKeys [standard] =
789 insert_commute [of "Key K" "Agent C"]
790 insert_commute [of "Key K" "Nonce N"]
791 insert_commute [of "Key K" "Number N"]
792 insert_commute [of "Key K" "Hash X"]
793 insert_commute [of "Key K" "MPair X Y"]
794 insert_commute [of "Key K" "Crypt X K'"]
796 lemmas pushCrypts [standard] =
797 insert_commute [of "Crypt X K" "Agent C"]
798 insert_commute [of "Crypt X K" "Agent C"]
799 insert_commute [of "Crypt X K" "Nonce N"]
800 insert_commute [of "Crypt X K" "Number N"]
801 insert_commute [of "Crypt X K" "Hash X'"]
802 insert_commute [of "Crypt X K" "MPair X' Y"]
804 text{*Cannot be added with @{text "[simp]"} -- messages should not always be
806 lemmas pushes = pushKeys pushCrypts
809 subsection{*Tactics useful for many protocol proofs*}
812 val invKey = thm "invKey"
813 val keysFor_def = thm "keysFor_def"
814 val symKeys_def = thm "symKeys_def"
815 val parts_mono = thm "parts_mono";
816 val analz_mono = thm "analz_mono";
817 val synth_mono = thm "synth_mono";
818 val analz_increasing = thm "analz_increasing";
820 val analz_insertI = thm "analz_insertI";
821 val analz_subset_parts = thm "analz_subset_parts";
822 val Fake_parts_insert = thm "Fake_parts_insert";
823 val Fake_analz_insert = thm "Fake_analz_insert";
824 val pushes = thms "pushes";
827 (*Prove base case (subgoal i) and simplify others. A typical base case
828 concerns Crypt K X \<notin> Key`shrK`bad and cannot be proved by rewriting
830 fun prove_simple_subgoals_tac (cs, ss) i =
831 force_tac (cs, ss addsimps [@{thm image_eq_UN}]) i THEN
832 ALLGOALS (asm_simp_tac ss)
834 (*Analysis of Fake cases. Also works for messages that forward unknown parts,
835 but this application is no longer necessary if analz_insert_eq is used.
836 Abstraction over i is ESSENTIAL: it delays the dereferencing of claset
837 DEPENDS UPON "X" REFERRING TO THE FRADULENT MESSAGE *)
839 (*Apply rules to break down assumptions of the form
840 Y \<in> parts(insert X H) and Y \<in> analz(insert X H)
842 fun impOfSubs th = th RSN (2, @{thm rev_subsetD})
844 val Fake_insert_tac =
845 dresolve_tac [impOfSubs Fake_analz_insert,
846 impOfSubs Fake_parts_insert] THEN'
847 eresolve_tac [asm_rl, thm"synth.Inj"];
849 fun Fake_insert_simp_tac ss i =
850 REPEAT (Fake_insert_tac i) THEN asm_full_simp_tac ss i;
852 fun atomic_spy_analz_tac (cs,ss) = SELECT_GOAL
853 (Fake_insert_simp_tac ss 1
855 IF_UNSOLVED (Blast.depth_tac
856 (cs addIs [analz_insertI,
857 impOfSubs analz_subset_parts]) 4 1))
859 fun spy_analz_tac (cs,ss) i =
863 [ (*push in occurrences of X...*)
865 (res_inst_tac (Simplifier.the_context ss)
866 [(("x", 1), "X")] (insert_commute RS ssubst) 1),
867 (*...allowing further simplifications*)
869 REPEAT (FIRSTGOAL (resolve_tac [allI,impI,notI,conjI,iffI])),
870 DEPTH_SOLVE (atomic_spy_analz_tac (cs,ss) 1)]) i)
873 text{*By default only @{text o_apply} is built-in. But in the presence of
874 eta-expansion this means that some terms displayed as @{term "f o g"} will be
875 rewritten, and others will not!*}
879 lemma Crypt_notin_image_Key [simp]: "Crypt K X \<notin> Key ` A"
882 lemma synth_analz_mono: "G\<subseteq>H ==> synth (analz(G)) \<subseteq> synth (analz(H))"
883 by (iprover intro: synth_mono analz_mono)
885 lemma Fake_analz_eq [simp]:
886 "X \<in> synth(analz H) ==> synth (analz (insert X H)) = synth (analz H)"
887 apply (drule Fake_analz_insert[of _ _ "H"])
888 apply (simp add: synth_increasing[THEN Un_absorb2])
889 apply (drule synth_mono)
890 apply (simp add: synth_idem)
891 apply (rule equalityI)
893 apply (rule synth_analz_mono, blast)
896 text{*Two generalizations of @{text analz_insert_eq}*}
897 lemma gen_analz_insert_eq [rule_format]:
898 "X \<in> analz H ==> ALL G. H \<subseteq> G --> analz (insert X G) = analz G";
899 by (blast intro: analz_cut analz_insertI analz_mono [THEN [2] rev_subsetD])
901 lemma synth_analz_insert_eq [rule_format]:
902 "X \<in> synth (analz H)
903 ==> ALL G. H \<subseteq> G --> (Key K \<in> analz (insert X G)) = (Key K \<in> analz G)";
904 apply (erule synth.induct)
905 apply (simp_all add: gen_analz_insert_eq subset_trans [OF _ subset_insertI])
908 lemma Fake_parts_sing:
909 "X \<in> synth (analz H) ==> parts{X} \<subseteq> synth (analz H) \<union> parts H";
910 apply (rule subset_trans)
911 apply (erule_tac [2] Fake_parts_insert)
912 apply (rule parts_mono, blast)
915 lemmas Fake_parts_sing_imp_Un = Fake_parts_sing [THEN [2] rev_subsetD]
917 method_setup spy_analz = {*
918 Scan.succeed (SIMPLE_METHOD' o spy_analz_tac o clasimpset_of) *}
919 "for proving the Fake case when analz is involved"
921 method_setup atomic_spy_analz = {*
922 Scan.succeed (SIMPLE_METHOD' o atomic_spy_analz_tac o clasimpset_of) *}
923 "for debugging spy_analz"
925 method_setup Fake_insert_simp = {*
926 Scan.succeed (SIMPLE_METHOD' o Fake_insert_simp_tac o simpset_of) *}
927 "for debugging spy_analz"