|
| 1 | +Require Export floyd.proofauto. |
| 2 | +Require Export floyd.reassoc_seq. |
| 3 | +Require Export aes.aes. |
| 4 | +Require Export aes.GF_ops_LL. |
| 5 | +Require Export aes.tablesLL. |
| 6 | +Require Export aes.spec_utils_LL. |
| 7 | +Require Export aes.list_utils. |
| 8 | +Require Export aes.spec_encryption_LL. |
| 9 | + |
| 10 | +Instance CompSpecs : compspecs. |
| 11 | +Proof. make_compspecs prog. Defined. |
| 12 | +Definition Vprog : varspecs. mk_varspecs prog. Defined. |
| 13 | + |
| 14 | +Definition t_struct_aesctx := Tstruct _mbedtls_aes_context_struct noattr. |
| 15 | +Definition t_struct_tables := Tstruct _aes_tables_struct noattr. |
| 16 | + |
| 17 | +Definition tables_initialized (tables : val) := data_at Ews t_struct_tables |
| 18 | + (map Vint FSb, (map Vint FT0, (map Vint FT1, (map Vint FT2, (map Vint FT3, |
| 19 | + (map Vint RSb, (map Vint RT0, (map Vint RT1, (map Vint RT2, (map Vint RT3, |
| 20 | + (map Vint RCON))))))))))) tables. |
| 21 | + |
| 22 | +Definition Vundef256 : list val := repeat Vundef 256%nat. |
| 23 | + |
| 24 | +Definition tables_uninitialized tables := data_at Ews t_struct_tables (Vundef256, |
| 25 | + (Vundef256, (Vundef256, (Vundef256, (Vundef256, (Vundef256, |
| 26 | + (Vundef256, (Vundef256, (Vundef256, (Vundef256, |
| 27 | + (repeat Vundef 10))))))))))) tables. |
| 28 | + |
| 29 | +Definition gen_tables_spec := |
| 30 | + DECLARE _aes_gen_tables |
| 31 | + WITH tables : val |
| 32 | + PRE [ ] |
| 33 | + PROP () |
| 34 | + LOCAL (gvar _tables tables) |
| 35 | + SEP (tables_uninitialized tables) |
| 36 | + POST [ tvoid ] |
| 37 | + PROP () |
| 38 | + LOCAL () |
| 39 | + SEP (tables_initialized tables) |
| 40 | +. |
| 41 | + |
| 42 | + |
| 43 | +(* TODO replace this HL spec by a LL spec, and move HL spec to actual spec *) |
| 44 | + |
| 45 | +Definition word_to_int (w : (int * int * int * int)) : int := |
| 46 | + match w with (b0, b1, b2, b3) => |
| 47 | + (Int.or (Int.or (Int.or |
| 48 | + b0 |
| 49 | + (Int.shl b1 (Int.repr 8))) |
| 50 | + (Int.shl b2 (Int.repr 16))) |
| 51 | + (Int.shl b3 (Int.repr 24))) |
| 52 | + end. |
| 53 | + |
| 54 | +(* SubWord function from section 5.2: apply S-box to each byte in a word *) |
| 55 | +Definition SubWord (w: int) : int := word_to_int ( |
| 56 | + (Znth (byte0 w) FSb Int.zero), |
| 57 | + (Znth (byte1 w) FSb Int.zero), |
| 58 | + (Znth (byte2 w) FSb Int.zero), |
| 59 | + (Znth (byte3 w) FSb Int.zero) |
| 60 | +). |
| 61 | + |
| 62 | +Definition RotWord(i: int): int := |
| 63 | + Int.or (Int.and (Int.shl i (Int.repr 8)) (Int.repr (-1))) (Int.shru i (Int.repr 24)). |
| 64 | + |
| 65 | +(* round constant (RCon) array, described in section 5.2 and explicitly written |
| 66 | + * out in appendix A.3 (256-bit key expansion example) *) |
| 67 | +Definition RCon : list int := map (fun i => Int.shl i (Int.repr 24)) [ |
| 68 | + (* 0x01000000 *) (Int.repr 1); |
| 69 | + (* 0x02000000 *) (Int.repr 2); |
| 70 | + (* 0x04000000 *) (Int.repr 4); |
| 71 | + (* 0x08000000 *) (Int.repr 8); |
| 72 | + (* 0x10000000 *) (Int.repr 16); |
| 73 | + (* 0x20000000 *) (Int.repr 32); |
| 74 | + (* 0x40000000 *) (Int.repr 64) |
| 75 | +]. |
| 76 | + |
| 77 | +Definition GrowKeyByOne(w: list int): list int := |
| 78 | + let i := Zlength w in |
| 79 | + let temp := (Znth (i-1) w Int.zero) in |
| 80 | + let temp' := if (i mod Nk =? 0) then |
| 81 | + Int.xor (SubWord (RotWord temp)) (Znth (i/Nk) RCon Int.zero) |
| 82 | + else if (i mod Nk =? 4) then |
| 83 | + SubWord temp |
| 84 | + else |
| 85 | + temp |
| 86 | + in |
| 87 | + w ++ [Int.xor (Znth (i-8) w Int.zero) temp']. |
| 88 | + |
| 89 | +Fixpoint pow_fun{T: Type}(f: T -> T)(n: nat)(a: T): T := match n with |
| 90 | +| O => a |
| 91 | +| S m => f (pow_fun f m a) |
| 92 | +end. |
| 93 | + |
| 94 | +(* +2 because 1 is for the initial round which is not counted, and 1 superfluous round key is |
| 95 | + created in the last loop iteration, because each iteration creates 2 round keys. |
| 96 | + -Nk because the first two round keys are just the unexpanded key. |
| 97 | + Note that (Nb*(Nr+2)-Nk) = 56. *) |
| 98 | +Definition KeyExpansion2: list int -> list int := pow_fun GrowKeyByOne (Z.to_nat (Nb*(Nr+2)-Nk)). |
| 99 | + |
| 100 | +(* arr: list of bytes *) |
| 101 | +Definition get_uint32_le (arr: list Z) (i: Z) : int := |
| 102 | + (Int.or (Int.or (Int.or |
| 103 | + (Int.repr (Znth i arr 0)) |
| 104 | + (Int.shl (Int.repr (Znth (i+1) arr 0)) (Int.repr 8))) |
| 105 | + (Int.shl (Int.repr (Znth (i+2) arr 0)) (Int.repr 16))) |
| 106 | + (Int.shl (Int.repr (Znth (i+3) arr 0)) (Int.repr 24))). |
| 107 | + |
| 108 | +Definition key_bytes_to_key_words(key_bytes: list Z): list int := |
| 109 | + fill_list 8 (fun i => get_uint32_le key_bytes (i*4)). |
| 110 | + |
| 111 | +(* end TODO *) |
| 112 | + |
| 113 | +(* Note: clightgen turns global variables of type int to pointers to int, to make them addressable, |
| 114 | + so aes_init_done is a pointer to int, not an int! *) |
| 115 | +Definition key_expansion_spec := |
| 116 | + DECLARE _mbedtls_aes_setkey_enc |
| 117 | + WITH ctx : val, key : val, ctx_sh : share, key_sh : share, key_chars : list Z, |
| 118 | + tables : val, aes_init_done: val, init_done : Z, ish: share |
| 119 | + PRE [ _ctx OF (tptr t_struct_aesctx), _key OF (tptr tuchar), _keybits OF tuint ] |
| 120 | + PROP (writable_share ctx_sh; readable_share key_sh; readable_share ish; |
| 121 | + Zlength key_chars = 32; |
| 122 | + init_done = 1 (*TODO also prove case where init_done=0*)) |
| 123 | + LOCAL (temp _ctx ctx; temp _key key; temp _keybits (Vint (Int.repr 256)); |
| 124 | + gvar _aes_init_done aes_init_done; |
| 125 | + gvar _tables tables) |
| 126 | + SEP (data_at ctx_sh t_struct_aesctx |
| 127 | + (Vint Int.zero, |
| 128 | + (nullval, |
| 129 | + (map Vint (repeat_op_table 68 Int.zero id)))) ctx; |
| 130 | + data_at key_sh (tarray tuchar (4*8)) (map Vint (map Int.repr key_chars)) key; |
| 131 | + (*if init_done ?= 1 then tables_initialized tables else tables_uninitialized tables*) |
| 132 | + data_at ish tint (Vint (Int.repr init_done)) aes_init_done; |
| 133 | + tables_initialized tables) |
| 134 | + POST [ tint ] |
| 135 | + PROP () |
| 136 | + LOCAL (temp ret_temp (Vint Int.zero)) |
| 137 | + SEP (data_at key_sh (tarray tuchar (4*8)) (map Vint (map Int.repr key_chars)) key; |
| 138 | + data_at ctx_sh t_struct_aesctx |
| 139 | + (Vint (Int.repr 14), |
| 140 | + ((field_address t_struct_aesctx [StructField _buf] ctx), |
| 141 | + (map Vint (KeyExpansion2 (key_bytes_to_key_words key_chars)) |
| 142 | + ++ (repeat_op_table 4 (Vint Int.zero) id)))) ctx; |
| 143 | + data_at ish tint (Vint (Int.repr init_done)) aes_init_done; |
| 144 | + tables_initialized tables). |
| 145 | + |
| 146 | + |
| 147 | +Definition encryption_spec_ll := |
| 148 | + DECLARE _mbedtls_aes_encrypt |
| 149 | + WITH ctx : val, input : val, output : val, (* arguments *) |
| 150 | + ctx_sh : share, in_sh : share, out_sh : share, (* shares *) |
| 151 | + plaintext : list Z, (* 16 chars *) |
| 152 | + exp_key : list Z, (* expanded key, 4*(Nr+1)=60 32-bit integers *) |
| 153 | + tables : val (* global var *) |
| 154 | + PRE [ _ctx OF (tptr t_struct_aesctx), _input OF (tptr tuchar), _output OF (tptr tuchar) ] |
| 155 | + PROP (Zlength plaintext = 16; Zlength exp_key = 60; |
| 156 | + readable_share ctx_sh; readable_share in_sh; writable_share out_sh) |
| 157 | + LOCAL (temp _ctx ctx; temp _input input; temp _output output; gvar _tables tables) |
| 158 | + SEP (data_at ctx_sh (t_struct_aesctx) ( |
| 159 | + (Vint (Int.repr Nr)), |
| 160 | + ((field_address t_struct_aesctx [StructField _buf] ctx), |
| 161 | + (map Vint (map Int.repr (exp_key ++ (list_repeat (8%nat) 0))))) |
| 162 | + (* The following weaker precondition would also be provable, but less conveniently, and *) |
| 163 | + (* since mbedtls_aes_init zeroes the whole buffer, we exploit this to simplify the proof *) |
| 164 | + (* ((map Vint (map Int.repr exp_key)) ++ (list_repeat (8%nat) Vundef))) *) |
| 165 | + ) ctx; |
| 166 | + data_at in_sh (tarray tuchar 16) (map Vint (map Int.repr plaintext)) input; |
| 167 | + data_at_ out_sh (tarray tuchar 16) output; |
| 168 | + tables_initialized tables) |
| 169 | + POST [ tvoid ] |
| 170 | + PROP() LOCAL() |
| 171 | + SEP (data_at ctx_sh (t_struct_aesctx) ( |
| 172 | + (Vint (Int.repr Nr)), |
| 173 | + ((field_address t_struct_aesctx [StructField _buf] ctx), |
| 174 | + (map Vint (map Int.repr (exp_key ++ (list_repeat (8%nat) 0))))) |
| 175 | + ) ctx; |
| 176 | + data_at in_sh (tarray tuchar 16) |
| 177 | + (map Vint (map Int.repr plaintext)) input; |
| 178 | + data_at out_sh (tarray tuchar 16) |
| 179 | + (map Vint (mbed_tls_aes_enc plaintext (exp_key ++ (list_repeat (8%nat) 0)))) output; |
| 180 | + tables_initialized tables). |
| 181 | + |
| 182 | +Definition Gprog : funspecs := ltac:(with_library prog [ |
| 183 | + gen_tables_spec; key_expansion_spec; encryption_spec_ll |
| 184 | +]). |
| 185 | + |
| 186 | +(* This is to make sure do_compute_expr (invoked by load_tac and others), which calls hnf on the |
| 187 | + expression it's computing, does not unfold field_address. |
| 188 | + TODO floyd: Ideally, we'd have "Global Opaque field_address field_address0" in the library, |
| 189 | + but some proofs want to unfold field_address (they shouldn't, though). *) |
| 190 | +Global Opaque field_address. |
| 191 | + |
| 192 | +(* entailer! calls simpl, and if simpl tries to evaluate a column of the final AES encryption result, |
| 193 | + it takes forever, so we have to prevent this: *) |
| 194 | +Arguments col _ _ : simpl never. |
| 195 | +(* Same problem with "Z.land _ 255" *) |
| 196 | +Arguments Z.land _ _ : simpl never. |
| 197 | + |
| 198 | +(* This one is to prevent simplification of "12 - _", which is fast, but produces silly verbose goals *) |
| 199 | +Arguments Nat.sub _ _ : simpl never. |
0 commit comments