src/HOL/UNITY/Simple/NSP_Bad.thy
changeset 63146 f1ecba0272f9
parent 61956 38b73f7940af
child 66453 cc19f7ca2ed6
equal deleted inserted replaced
63145:703edebd1d92 63146:f1ecba0272f9
     3     Copyright   1996  University of Cambridge
     3     Copyright   1996  University of Cambridge
     4 
     4 
     5 Original file is ../Auth/NS_Public_Bad
     5 Original file is ../Auth/NS_Public_Bad
     6 *)
     6 *)
     7 
     7 
     8 section{*Analyzing the Needham-Schroeder Public-Key Protocol in UNITY*}
     8 section\<open>Analyzing the Needham-Schroeder Public-Key Protocol in UNITY\<close>
     9 
     9 
    10 theory NSP_Bad imports "../../Auth/Public" "../UNITY_Main" begin
    10 theory NSP_Bad imports "../../Auth/Public" "../UNITY_Main" begin
    11 
    11 
    12 text{*This is the flawed version, vulnerable to Lowe's attack.
    12 text\<open>This is the flawed version, vulnerable to Lowe's attack.
    13 From page 260 of
    13 From page 260 of
    14   Burrows, Abadi and Needham.  A Logic of Authentication.
    14   Burrows, Abadi and Needham.  A Logic of Authentication.
    15   Proc. Royal Soc. 426 (1989).
    15   Proc. Royal Soc. 426 (1989).
    16 *}
    16 \<close>
    17 
    17 
    18 type_synonym state = "event list"
    18 type_synonym state = "event list"
    19 
    19 
    20   (*The spy MAY say anything he CAN say.  We do not expect him to
    20   (*The spy MAY say anything he CAN say.  We do not expect him to
    21     invent new nonces here, but he can also use NS1.  Common to
    21     invent new nonces here, but he can also use NS1.  Common to
    61 
    61 
    62 declare spies_partsEs [elim]
    62 declare spies_partsEs [elim]
    63 declare analz_into_parts [dest]
    63 declare analz_into_parts [dest]
    64 declare Fake_parts_insert_in_Un  [dest]
    64 declare Fake_parts_insert_in_Un  [dest]
    65 
    65 
    66 text{*For other theories, e.g. Mutex and Lift, using [iff] slows proofs down.
    66 text\<open>For other theories, e.g. Mutex and Lift, using [iff] slows proofs down.
    67   Here, it facilitates re-use of the Auth proofs.*}
    67   Here, it facilitates re-use of the Auth proofs.\<close>
    68 
    68 
    69 declare Fake_def [THEN def_act_simp, iff]
    69 declare Fake_def [THEN def_act_simp, iff]
    70 declare NS1_def [THEN def_act_simp, iff]
    70 declare NS1_def [THEN def_act_simp, iff]
    71 declare NS2_def [THEN def_act_simp, iff]
    71 declare NS2_def [THEN def_act_simp, iff]
    72 declare NS3_def [THEN def_act_simp, iff]
    72 declare NS3_def [THEN def_act_simp, iff]
    73 
    73 
    74 declare Nprg_def [THEN def_prg_Init, simp]
    74 declare Nprg_def [THEN def_prg_Init, simp]
    75 
    75 
    76 
    76 
    77 text{*A "possibility property": there are traces that reach the end.
    77 text\<open>A "possibility property": there are traces that reach the end.
    78   Replace by LEADSTO proof!*}
    78   Replace by LEADSTO proof!\<close>
    79 lemma "A \<noteq> B ==>
    79 lemma "A \<noteq> B ==>
    80        \<exists>NB. \<exists>s \<in> reachable Nprg. Says A B (Crypt (pubK B) (Nonce NB)) \<in> set s"
    80        \<exists>NB. \<exists>s \<in> reachable Nprg. Says A B (Crypt (pubK B) (Nonce NB)) \<in> set s"
    81 apply (intro exI bexI)
    81 apply (intro exI bexI)
    82 apply (rule_tac [2] act = "totalize_act NS3" in reachable.Acts)
    82 apply (rule_tac [2] act = "totalize_act NS3" in reachable.Acts)
    83 apply (rule_tac [3] act = "totalize_act NS2" in reachable.Acts)
    83 apply (rule_tac [3] act = "totalize_act NS2" in reachable.Acts)
    86 apply (simp_all (no_asm_simp) add: Nprg_def totalize_act_def)
    86 apply (simp_all (no_asm_simp) add: Nprg_def totalize_act_def)
    87 apply auto
    87 apply auto
    88 done
    88 done
    89 
    89 
    90 
    90 
    91 subsection{*Inductive Proofs about @{term ns_public}*}
    91 subsection\<open>Inductive Proofs about @{term ns_public}\<close>
    92 
    92 
    93 lemma ns_constrainsI:
    93 lemma ns_constrainsI:
    94      "(!!act s s'. [| act \<in> {Id, Fake, NS1, NS2, NS3};
    94      "(!!act s s'. [| act \<in> {Id, Fake, NS1, NS2, NS3};
    95                       (s,s') \<in> act;  s \<in> A |] ==> s' \<in> A')
    95                       (s,s') \<in> act;  s \<in> A |] ==> s' \<in> A')
    96       ==> Nprg \<in> A co A'"
    96       ==> Nprg \<in> A co A'"
    97 apply (simp add: Nprg_def mk_total_program_def)
    97 apply (simp add: Nprg_def mk_total_program_def)
    98 apply (rule constrainsI, auto)
    98 apply (rule constrainsI, auto)
    99 done
    99 done
   100 
   100 
   101 
   101 
   102 text{*This ML code does the inductions directly.*}
   102 text\<open>This ML code does the inductions directly.\<close>
   103 ML{*
   103 ML\<open>
   104 fun ns_constrains_tac ctxt i =
   104 fun ns_constrains_tac ctxt i =
   105   SELECT_GOAL
   105   SELECT_GOAL
   106     (EVERY
   106     (EVERY
   107      [REPEAT (eresolve_tac ctxt @{thms Always_ConstrainsI} 1),
   107      [REPEAT (eresolve_tac ctxt @{thms Always_ConstrainsI} 1),
   108       REPEAT (resolve_tac ctxt [@{thm StableI}, @{thm stableI}, @{thm constrains_imp_Constrains}] 1),
   108       REPEAT (resolve_tac ctxt [@{thm StableI}, @{thm stableI}, @{thm constrains_imp_Constrains}] 1),
   119      [resolve_tac ctxt @{thms AlwaysI} 1,
   119      [resolve_tac ctxt @{thms AlwaysI} 1,
   120       force_tac ctxt 1,
   120       force_tac ctxt 1,
   121       (*"reachable" gets in here*)
   121       (*"reachable" gets in here*)
   122       resolve_tac ctxt [@{thm Always_reachable} RS @{thm Always_ConstrainsI} RS @{thm StableI}] 1,
   122       resolve_tac ctxt [@{thm Always_reachable} RS @{thm Always_ConstrainsI} RS @{thm StableI}] 1,
   123       ns_constrains_tac ctxt 1];
   123       ns_constrains_tac ctxt 1];
   124 *}
   124 \<close>
   125 
   125 
   126 method_setup ns_induct = {*
   126 method_setup ns_induct = \<open>
   127     Scan.succeed (SIMPLE_METHOD' o ns_induct_tac) *}
   127     Scan.succeed (SIMPLE_METHOD' o ns_induct_tac)\<close>
   128     "for inductive reasoning about the Needham-Schroeder protocol"
   128     "for inductive reasoning about the Needham-Schroeder protocol"
   129 
   129 
   130 text{*Converts invariants into statements about reachable states*}
   130 text\<open>Converts invariants into statements about reachable states\<close>
   131 lemmas Always_Collect_reachableD =
   131 lemmas Always_Collect_reachableD =
   132      Always_includes_reachable [THEN subsetD, THEN CollectD]
   132      Always_includes_reachable [THEN subsetD, THEN CollectD]
   133 
   133 
   134 text{*Spy never sees another agent's private key! (unless it's bad at start)*}
   134 text\<open>Spy never sees another agent's private key! (unless it's bad at start)\<close>
   135 lemma Spy_see_priK:
   135 lemma Spy_see_priK:
   136      "Nprg \<in> Always {s. (Key (priK A) \<in> parts (spies s)) = (A \<in> bad)}"
   136      "Nprg \<in> Always {s. (Key (priK A) \<in> parts (spies s)) = (A \<in> bad)}"
   137 apply ns_induct
   137 apply ns_induct
   138 apply blast
   138 apply blast
   139 done
   139 done
   143      "Nprg \<in> Always {s. (Key (priK A) \<in> analz (spies s)) = (A \<in> bad)}"
   143      "Nprg \<in> Always {s. (Key (priK A) \<in> analz (spies s)) = (A \<in> bad)}"
   144 by (rule Always_reachable [THEN Always_weaken], auto)
   144 by (rule Always_reachable [THEN Always_weaken], auto)
   145 declare Spy_analz_priK [THEN Always_Collect_reachableD, simp]
   145 declare Spy_analz_priK [THEN Always_Collect_reachableD, simp]
   146 
   146 
   147 
   147 
   148 subsection{*Authenticity properties obtained from NS2*}
   148 subsection\<open>Authenticity properties obtained from NS2\<close>
   149 
   149 
   150 text{*It is impossible to re-use a nonce in both NS1 and NS2 provided the
   150 text\<open>It is impossible to re-use a nonce in both NS1 and NS2 provided the
   151      nonce is secret.  (Honest users generate fresh nonces.)*}
   151      nonce is secret.  (Honest users generate fresh nonces.)\<close>
   152 lemma no_nonce_NS1_NS2:
   152 lemma no_nonce_NS1_NS2:
   153  "Nprg
   153  "Nprg
   154   \<in> Always {s. Crypt (pubK C) \<lbrace>NA', Nonce NA\<rbrace> \<in> parts (spies s) -->
   154   \<in> Always {s. Crypt (pubK C) \<lbrace>NA', Nonce NA\<rbrace> \<in> parts (spies s) -->
   155                 Crypt (pubK B) \<lbrace>Nonce NA, Agent A\<rbrace> \<in> parts (spies s) -->
   155                 Crypt (pubK B) \<lbrace>Nonce NA, Agent A\<rbrace> \<in> parts (spies s) -->
   156                 Nonce NA \<in> analz (spies s)}"
   156                 Nonce NA \<in> analz (spies s)}"
   157 apply ns_induct
   157 apply ns_induct
   158 apply (blast intro: analz_insertI)+
   158 apply (blast intro: analz_insertI)+
   159 done
   159 done
   160 
   160 
   161 text{*Adding it to the claset slows down proofs...*}
   161 text\<open>Adding it to the claset slows down proofs...\<close>
   162 lemmas no_nonce_NS1_NS2_reachable =
   162 lemmas no_nonce_NS1_NS2_reachable =
   163        no_nonce_NS1_NS2 [THEN Always_Collect_reachableD, rule_format]
   163        no_nonce_NS1_NS2 [THEN Always_Collect_reachableD, rule_format]
   164 
   164 
   165 
   165 
   166 text{*Unicity for NS1: nonce NA identifies agents A and B*}
   166 text\<open>Unicity for NS1: nonce NA identifies agents A and B\<close>
   167 lemma unique_NA_lemma:
   167 lemma unique_NA_lemma:
   168      "Nprg
   168      "Nprg
   169   \<in> Always {s. Nonce NA \<notin> analz (spies s) -->
   169   \<in> Always {s. Nonce NA \<notin> analz (spies s) -->
   170                 Crypt(pubK B) \<lbrace>Nonce NA, Agent A\<rbrace> \<in> parts(spies s) -->
   170                 Crypt(pubK B) \<lbrace>Nonce NA, Agent A\<rbrace> \<in> parts(spies s) -->
   171                 Crypt(pubK B') \<lbrace>Nonce NA, Agent A'\<rbrace> \<in> parts(spies s) -->
   171                 Crypt(pubK B') \<lbrace>Nonce NA, Agent A'\<rbrace> \<in> parts(spies s) -->
   172                 A=A' & B=B'}"
   172                 A=A' & B=B'}"
   173 apply ns_induct
   173 apply ns_induct
   174 apply auto
   174 apply auto
   175 txt{*Fake, NS1 are non-trivial*}
   175 txt\<open>Fake, NS1 are non-trivial\<close>
   176 done
   176 done
   177 
   177 
   178 text{*Unicity for NS1: nonce NA identifies agents A and B*}
   178 text\<open>Unicity for NS1: nonce NA identifies agents A and B\<close>
   179 lemma unique_NA:
   179 lemma unique_NA:
   180      "[| Crypt(pubK B)  \<lbrace>Nonce NA, Agent A\<rbrace> \<in> parts(spies s);
   180      "[| Crypt(pubK B)  \<lbrace>Nonce NA, Agent A\<rbrace> \<in> parts(spies s);
   181          Crypt(pubK B') \<lbrace>Nonce NA, Agent A'\<rbrace> \<in> parts(spies s);
   181          Crypt(pubK B') \<lbrace>Nonce NA, Agent A'\<rbrace> \<in> parts(spies s);
   182          Nonce NA \<notin> analz (spies s);
   182          Nonce NA \<notin> analz (spies s);
   183          s \<in> reachable Nprg |]
   183          s \<in> reachable Nprg |]
   184       ==> A=A' & B=B'"
   184       ==> A=A' & B=B'"
   185 by (blast dest: unique_NA_lemma [THEN Always_Collect_reachableD])
   185 by (blast dest: unique_NA_lemma [THEN Always_Collect_reachableD])
   186 
   186 
   187 
   187 
   188 text{*Secrecy: Spy does not see the nonce sent in msg NS1 if A and B are secure*}
   188 text\<open>Secrecy: Spy does not see the nonce sent in msg NS1 if A and B are secure\<close>
   189 lemma Spy_not_see_NA:
   189 lemma Spy_not_see_NA:
   190      "[| A \<notin> bad;  B \<notin> bad |]
   190      "[| A \<notin> bad;  B \<notin> bad |]
   191   ==> Nprg \<in> Always
   191   ==> Nprg \<in> Always
   192               {s. Says A B (Crypt(pubK B) \<lbrace>Nonce NA, Agent A\<rbrace>) \<in> set s
   192               {s. Says A B (Crypt(pubK B) \<lbrace>Nonce NA, Agent A\<rbrace>) \<in> set s
   193                   --> Nonce NA \<notin> analz (spies s)}"
   193                   --> Nonce NA \<notin> analz (spies s)}"
   194 apply ns_induct
   194 apply ns_induct
   195 txt{*NS3*}
   195 txt\<open>NS3\<close>
   196 prefer 4 apply (blast intro: no_nonce_NS1_NS2_reachable)
   196 prefer 4 apply (blast intro: no_nonce_NS1_NS2_reachable)
   197 txt{*NS2*}
   197 txt\<open>NS2\<close>
   198 prefer 3 apply (blast dest: unique_NA)
   198 prefer 3 apply (blast dest: unique_NA)
   199 txt{*NS1*}
   199 txt\<open>NS1\<close>
   200 prefer 2 apply blast
   200 prefer 2 apply blast
   201 txt{*Fake*}
   201 txt\<open>Fake\<close>
   202 apply spy_analz
   202 apply spy_analz
   203 done
   203 done
   204 
   204 
   205 
   205 
   206 text{*Authentication for A: if she receives message 2 and has used NA
   206 text\<open>Authentication for A: if she receives message 2 and has used NA
   207   to start a run, then B has sent message 2.*}
   207   to start a run, then B has sent message 2.\<close>
   208 lemma A_trusts_NS2:
   208 lemma A_trusts_NS2:
   209  "[| A \<notin> bad;  B \<notin> bad |]
   209  "[| A \<notin> bad;  B \<notin> bad |]
   210   ==> Nprg \<in> Always
   210   ==> Nprg \<in> Always
   211               {s. Says A B (Crypt(pubK B) \<lbrace>Nonce NA, Agent A\<rbrace>) \<in> set s &
   211               {s. Says A B (Crypt(pubK B) \<lbrace>Nonce NA, Agent A\<rbrace>) \<in> set s &
   212                   Crypt(pubK A) \<lbrace>Nonce NA, Nonce NB\<rbrace> \<in> parts (knows Spy s)
   212                   Crypt(pubK A) \<lbrace>Nonce NA, Nonce NB\<rbrace> \<in> parts (knows Spy s)
   215 apply (insert Spy_not_see_NA [of A B NA], simp, ns_induct)
   215 apply (insert Spy_not_see_NA [of A B NA], simp, ns_induct)
   216 apply (auto dest: unique_NA)
   216 apply (auto dest: unique_NA)
   217 done
   217 done
   218 
   218 
   219 
   219 
   220 text{*If the encrypted message appears then it originated with Alice in NS1*}
   220 text\<open>If the encrypted message appears then it originated with Alice in NS1\<close>
   221 lemma B_trusts_NS1:
   221 lemma B_trusts_NS1:
   222      "Nprg \<in> Always
   222      "Nprg \<in> Always
   223               {s. Nonce NA \<notin> analz (spies s) -->
   223               {s. Nonce NA \<notin> analz (spies s) -->
   224                   Crypt (pubK B) \<lbrace>Nonce NA, Agent A\<rbrace> \<in> parts (spies s)
   224                   Crypt (pubK B) \<lbrace>Nonce NA, Agent A\<rbrace> \<in> parts (spies s)
   225          --> Says A B (Crypt (pubK B) \<lbrace>Nonce NA, Agent A\<rbrace>) \<in> set s}"
   225          --> Says A B (Crypt (pubK B) \<lbrace>Nonce NA, Agent A\<rbrace>) \<in> set s}"
   226 apply ns_induct
   226 apply ns_induct
   227 apply blast
   227 apply blast
   228 done
   228 done
   229 
   229 
   230 
   230 
   231 subsection{*Authenticity properties obtained from NS2*}
   231 subsection\<open>Authenticity properties obtained from NS2\<close>
   232 
   232 
   233 text{*Unicity for NS2: nonce NB identifies nonce NA and agent A.
   233 text\<open>Unicity for NS2: nonce NB identifies nonce NA and agent A.
   234    Proof closely follows that of @{text unique_NA}.*}
   234    Proof closely follows that of \<open>unique_NA\<close>.\<close>
   235 lemma unique_NB_lemma:
   235 lemma unique_NB_lemma:
   236  "Nprg
   236  "Nprg
   237   \<in> Always {s. Nonce NB \<notin> analz (spies s)  -->
   237   \<in> Always {s. Nonce NB \<notin> analz (spies s)  -->
   238                 Crypt (pubK A) \<lbrace>Nonce NA, Nonce NB\<rbrace> \<in> parts (spies s) -->
   238                 Crypt (pubK A) \<lbrace>Nonce NA, Nonce NB\<rbrace> \<in> parts (spies s) -->
   239                 Crypt(pubK A') \<lbrace>Nonce NA', Nonce NB\<rbrace> \<in> parts(spies s) -->
   239                 Crypt(pubK A') \<lbrace>Nonce NA', Nonce NB\<rbrace> \<in> parts(spies s) -->
   240                 A=A' & NA=NA'}"
   240                 A=A' & NA=NA'}"
   241 apply ns_induct
   241 apply ns_induct
   242 apply auto
   242 apply auto
   243 txt{*Fake, NS2 are non-trivial*}
   243 txt\<open>Fake, NS2 are non-trivial\<close>
   244 done
   244 done
   245 
   245 
   246 lemma unique_NB:
   246 lemma unique_NB:
   247      "[| Crypt(pubK A) \<lbrace>Nonce NA, Nonce NB\<rbrace> \<in> parts(spies s);
   247      "[| Crypt(pubK A) \<lbrace>Nonce NA, Nonce NB\<rbrace> \<in> parts(spies s);
   248          Crypt(pubK A') \<lbrace>Nonce NA', Nonce NB\<rbrace> \<in> parts(spies s);
   248          Crypt(pubK A') \<lbrace>Nonce NA', Nonce NB\<rbrace> \<in> parts(spies s);
   251       ==> A=A' & NA=NA'"
   251       ==> A=A' & NA=NA'"
   252 apply (blast dest: unique_NB_lemma [THEN Always_Collect_reachableD])
   252 apply (blast dest: unique_NB_lemma [THEN Always_Collect_reachableD])
   253 done
   253 done
   254 
   254 
   255 
   255 
   256 text{*NB remains secret PROVIDED Alice never responds with round 3*}
   256 text\<open>NB remains secret PROVIDED Alice never responds with round 3\<close>
   257 lemma Spy_not_see_NB:
   257 lemma Spy_not_see_NB:
   258      "[| A \<notin> bad;  B \<notin> bad |]
   258      "[| A \<notin> bad;  B \<notin> bad |]
   259   ==> Nprg \<in> Always
   259   ==> Nprg \<in> Always
   260               {s. Says B A (Crypt (pubK A) \<lbrace>Nonce NA, Nonce NB\<rbrace>) \<in> set s &
   260               {s. Says B A (Crypt (pubK A) \<lbrace>Nonce NA, Nonce NB\<rbrace>) \<in> set s &
   261                   (ALL C. Says A C (Crypt (pubK C) (Nonce NB)) \<notin> set s)
   261                   (ALL C. Says A C (Crypt (pubK C) (Nonce NB)) \<notin> set s)
   262                   --> Nonce NB \<notin> analz (spies s)}"
   262                   --> Nonce NB \<notin> analz (spies s)}"
   263 apply ns_induct
   263 apply ns_induct
   264 apply (simp_all (no_asm_simp) add: all_conj_distrib)
   264 apply (simp_all (no_asm_simp) add: all_conj_distrib)
   265 txt{*NS3: because NB determines A*}
   265 txt\<open>NS3: because NB determines A\<close>
   266 prefer 4 apply (blast dest: unique_NB)
   266 prefer 4 apply (blast dest: unique_NB)
   267 txt{*NS2: by freshness and unicity of NB*}
   267 txt\<open>NS2: by freshness and unicity of NB\<close>
   268 prefer 3 apply (blast intro: no_nonce_NS1_NS2_reachable)
   268 prefer 3 apply (blast intro: no_nonce_NS1_NS2_reachable)
   269 txt{*NS1: by freshness*}
   269 txt\<open>NS1: by freshness\<close>
   270 prefer 2 apply blast
   270 prefer 2 apply blast
   271 txt{*Fake*}
   271 txt\<open>Fake\<close>
   272 apply spy_analz
   272 apply spy_analz
   273 done
   273 done
   274 
   274 
   275 
   275 
   276 
   276 
   277 text{*Authentication for B: if he receives message 3 and has used NB
   277 text\<open>Authentication for B: if he receives message 3 and has used NB
   278   in message 2, then A has sent message 3--to somebody....*}
   278   in message 2, then A has sent message 3--to somebody....\<close>
   279 lemma B_trusts_NS3:
   279 lemma B_trusts_NS3:
   280      "[| A \<notin> bad;  B \<notin> bad |]
   280      "[| A \<notin> bad;  B \<notin> bad |]
   281   ==> Nprg \<in> Always
   281   ==> Nprg \<in> Always
   282               {s. Crypt (pubK B) (Nonce NB) \<in> parts (spies s) &
   282               {s. Crypt (pubK B) (Nonce NB) \<in> parts (spies s) &
   283                   Says B A  (Crypt (pubK A) \<lbrace>Nonce NA, Nonce NB\<rbrace>) \<in> set s
   283                   Says B A  (Crypt (pubK A) \<lbrace>Nonce NA, Nonce NB\<rbrace>) \<in> set s
   284                   --> (\<exists>C. Says A C (Crypt (pubK C) (Nonce NB)) \<in> set s)}"
   284                   --> (\<exists>C. Says A C (Crypt (pubK C) (Nonce NB)) \<in> set s)}"
   285   (*insert an invariant for use in some of the subgoals*)
   285   (*insert an invariant for use in some of the subgoals*)
   286 apply (insert Spy_not_see_NB [of A B NA NB], simp, ns_induct)
   286 apply (insert Spy_not_see_NB [of A B NA NB], simp, ns_induct)
   287 apply (simp_all (no_asm_simp) add: ex_disj_distrib)
   287 apply (simp_all (no_asm_simp) add: ex_disj_distrib)
   288 apply auto
   288 apply auto
   289 txt{*NS3: because NB determines A. This use of @{text unique_NB} is robust.*}
   289 txt\<open>NS3: because NB determines A. This use of \<open>unique_NB\<close> is robust.\<close>
   290 apply (blast intro: unique_NB [THEN conjunct1])
   290 apply (blast intro: unique_NB [THEN conjunct1])
   291 done
   291 done
   292 
   292 
   293 
   293 
   294 text{*Can we strengthen the secrecy theorem?  NO*}
   294 text\<open>Can we strengthen the secrecy theorem?  NO\<close>
   295 lemma "[| A \<notin> bad;  B \<notin> bad |]
   295 lemma "[| A \<notin> bad;  B \<notin> bad |]
   296   ==> Nprg \<in> Always
   296   ==> Nprg \<in> Always
   297               {s. Says B A (Crypt (pubK A) \<lbrace>Nonce NA, Nonce NB\<rbrace>) \<in> set s
   297               {s. Says B A (Crypt (pubK A) \<lbrace>Nonce NA, Nonce NB\<rbrace>) \<in> set s
   298                   --> Nonce NB \<notin> analz (spies s)}"
   298                   --> Nonce NB \<notin> analz (spies s)}"
   299 apply ns_induct
   299 apply ns_induct
   300 apply auto
   300 apply auto
   301 txt{*Fake*}
   301 txt\<open>Fake\<close>
   302 apply spy_analz
   302 apply spy_analz
   303 txt{*NS2: by freshness and unicity of NB*}
   303 txt\<open>NS2: by freshness and unicity of NB\<close>
   304  apply (blast intro: no_nonce_NS1_NS2_reachable)
   304  apply (blast intro: no_nonce_NS1_NS2_reachable)
   305 txt{*NS3: unicity of NB identifies A and NA, but not B*}
   305 txt\<open>NS3: unicity of NB identifies A and NA, but not B\<close>
   306 apply (frule_tac A'=A in Says_imp_spies [THEN parts.Inj, THEN unique_NB])
   306 apply (frule_tac A'=A in Says_imp_spies [THEN parts.Inj, THEN unique_NB])
   307 apply (erule Says_imp_spies [THEN parts.Inj], auto)
   307 apply (erule Says_imp_spies [THEN parts.Inj], auto)
   308 apply (rename_tac s B' C)
   308 apply (rename_tac s B' C)
   309 txt{*This is the attack!
   309 txt\<open>This is the attack!
   310 @{subgoals[display,indent=0,margin=65]}
   310 @{subgoals[display,indent=0,margin=65]}
   311 *}
   311 \<close>
   312 oops
   312 oops
   313 
   313 
   314 
   314 
   315 (*
   315 (*
   316 THIS IS THE ATTACK!
   316 THIS IS THE ATTACK!