Commit 856f31af5cbd36be041ad3bac7b1d5df0271dcd4

Authored by Brice Colombier
1 parent e639f9332b
Exists in master

Update .gitignore

Showing 2 changed files with 43 additions and 46 deletions

... ... @@ -4,4 +4,5 @@
4 4 *.m~
5 5 plots/
6 6 */__init__.py
  7 +data/
1st_order_CPA.py View file @ 856f31a
... ... @@ -14,15 +14,13 @@
14 14 import corr as corr
15 15  
16 16 import os
  17 +import tqdm
17 18  
18 19 log.basicConfig(format="%(levelname)s: %(message)s", level=log.INFO)
19 20  
20 21 # Hamming weight array
21 22 HW_array = np.array([str(bin(byte)).count('1') for byte in range(256)], dtype='uint8')
22 23  
23   -nb_bytes = 16
24   -nb_k_hyp = 256
25   -
26 24 Sbox_hex = [
27 25 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
28 26 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
29 27  
30 28  
... ... @@ -64,18 +62,17 @@
64 62 inv_Sbox_dec = np.array([int(s) for s in inv_Sbox_hex])
65 63  
66 64 def compute_predictions(nb_traces, plaintexts_filename):
67   - k_hyps = np.array(range(nb_k_hyp)) #0 to 255
68   -
  65 + k_hyps = np.array(range(256)) #0 to 255
69 66 if nb_traces == -1:
70 67 plaintexts = np.load(os.path.join(plaintexts_filename))
71 68 else:
72 69 plaintexts = np.load(os.path.join(plaintexts_filename))[:nb_traces,:]
73   - ref_value = np.zeros((np.shape(plaintexts)[0], np.shape(plaintexts)[1], nb_k_hyp), dtype='uint8')
  70 + ref_value = np.zeros((np.shape(plaintexts)+(256,)), dtype='uint8')
74 71 predictions = HW_array[np.bitwise_xor(Sbox_dec[np.bitwise_xor(plaintexts[:, :, np.newaxis], k_hyps)], ref_value)]
75 72 np.save('predictions.npy', predictions)
76 73 log.info("Predictions for intermediate value computed")
77 74  
78   -def compute_correlation(nb_traces, traces_filename, step, predictions_filename='predictions.npy'):
  75 +def compute_correlation(nb_traces, traces_filename, nb_bytes, step, predictions_filename='predictions.npy'):
79 76 predictions = np.load(predictions_filename)
80 77 log.info("Loaded predictions matrix of type {0} and size {1}".format(predictions.dtype, np.shape(predictions)))
81 78 if nb_traces == -1:
82 79  
... ... @@ -85,15 +82,15 @@
85 82 log.info("Loaded traces ("+traces_filename+") matrix of type {0} and size {1}".format(traces.dtype, np.shape(traces)))
86 83 nb_traces, nb_samples = np.shape(traces)
87 84 if step:
88   - correlation = np.zeros((nb_bytes, nb_traces//step, nb_samples, nb_k_hyp))
89   - else:
90   - correlation = np.zeros((nb_bytes, nb_samples, nb_k_hyp))
91   - for byte in range(nb_bytes):
92   - log.info("Computing correlation for byte {0}".format(byte))
93   - if step:
  85 + correlation = np.zeros((nb_bytes, nb_traces//step, nb_samples, 256))
  86 + for byte in tqdm.trange(nb_bytes, desc="Computing correlation for each byte"):
  87 + # log.info("Computing correlation for byte {0}".format(byte))
94 88 correlation[byte,:,:,:] = corr.fast_corr(traces, predictions[:,byte,:], step)
95 89 np.save('./correlations/corr_byte_'+str(byte)+'.npy', correlation[byte,:,:,:])
96   - else:
  90 + else:
  91 + correlation = np.zeros((nb_bytes, nb_samples, 256))
  92 + for byte in tqdm.trange(nb_bytes, desc="Computing correlation for each byte"):
  93 + # log.info("Computing correlation for byte {0}".format(byte))
97 94 correlation[byte,:,:] = corr.fast_corr(traces, predictions[:,byte,:])
98 95 np.save('./correlations/corr_byte_'+str(byte)+'.npy', correlation[byte,:,:])
99 96  
100 97  
101 98  
102 99  
103 100  
104 101  
105 102  
106 103  
107 104  
... ... @@ -101,44 +98,43 @@
101 98 correct_key = [correct_key[i:i+2] for i in range(0, len(correct_key), 2)]
102 99 guessed_key = ""
103 100 avg_position = 0
104   - for byte, correct_byte in enumerate(correct_key):
105   - corr = np.load('./correlations/corr_byte_'+str(byte)+'.npy')
  101 + for byte, correct_byte_hex in enumerate(correct_key):
  102 + corr = abs(np.load('./correlations/corr_byte_'+str(byte)+'.npy'))
106 103 if len(np.shape(corr)) == 3:
107 104 # Iterative correlation was computed, take only the last ones
108 105 corr = corr[-1,:,:]
109   - max_corr_per_key_byte = abs(corr).max(axis=0)
110   - max_corr_samples = abs(corr).max(axis=1)
  106 + sample_of_interest, most_probable_key_byte = np.argwhere(corr == np.max(corr))[0]
  107 + most_probable_hex_key_byte = hex(most_probable_key_byte)[2:].zfill(2)
  108 + max_corr = round(np.max(np.abs(corr)), 3)
  109 + log.info("=> Most probable key byte #{0} : \"{1}\", at t={2} with ρ={3}".format(str(byte).zfill(2), most_probable_hex_key_byte, sample_of_interest, max_corr))
111 110  
112   - most_probable_hex_key_byte = hex(np.argmax(max_corr_per_key_byte))[2:].zfill(2)
113   - sample_of_interest = np.argmax(max_corr_samples)
114   -
115   - corr = round(max(max_corr_per_key_byte), 3)
116   - log.info("=> Most probable key byte #{0} : \"{1}\", at t={2}".format(str(byte).zfill(2), most_probable_hex_key_byte, sample_of_interest))
117   - position_correct_byte = list(np.sort(max_corr_per_key_byte)[::-1]).index(max_corr_per_key_byte[int(correct_byte, 16)])
118   - log.info("=> Correct one is \"{0}\", ranked {1}/{2} with ρ={3}".format(correct_byte, position_correct_byte, nb_k_hyp, corr))
  111 + max_corr_per_k_hyp = np.max(corr, axis=0)
  112 + max_corr_correct_byte = max_corr_per_k_hyp[int(correct_byte_hex, 16)]
  113 + position_correct_byte = np.argwhere(np.sort(max_corr_per_k_hyp)[::-1] == max_corr_correct_byte)[0][0]
  114 + log.info("=> Correct one is \"{0}\", ranked {1}/{2}".format(correct_byte_hex, position_correct_byte, 256))
119 115 avg_position+=position_correct_byte
120 116 guessed_key+=most_probable_hex_key_byte
121   - print("=> Guessed key is \"{0}\", average rank is {1}".format(guessed_key, avg_position/nb_bytes))
  117 + print("=> Guessed key is \"{0}\", average rank is {1}".format(guessed_key, avg_position/len(correct_key)))
122 118  
123 119 def plot_results(target_bytes,
124 120 step,
  121 + correct_key,
125 122 correlations_path = './correlations'):
126 123 plot_path = "./plots"
127 124 if step:
128   - for byte in target_bytes:
129   - log.info("Plotting for byte {0}".format(byte))
  125 + correct_key = [correct_key[i:i+2] for i in range(0, len(correct_key), 2)]
  126 + for key_byte, byte in tqdm.tqdm(zip(correct_key, target_bytes), desc="Plotting iter for each byte", total=len(target_bytes)):
  127 + # log.info("Plotting for byte {0}".format(byte))
130 128 corr = abs(np.load(os.path.join(correlations_path, 'corr_byte_'+str(byte)+'.npy')))
131 129 nb_steps, nb_samples, nb_hyp = np.shape(corr)
132   - max_corr_per_key_byte = corr.max(axis=1)
133   - key_byte = np.argmax(max_corr_per_key_byte[-1,:])
134   - hex_key_byte = hex(key_byte)[2:].zfill(2)
  130 + max_corr_per_key_byte = abs(corr).max(axis=1)
135 131 plt.figure()
136 132 for k_hyp in list(range(nb_hyp)):
137   - if k_hyp == key_byte:
138   - plt.plot([step*i for i in range(nb_steps)], max_corr_per_key_byte[:,k_hyp], color='black')
  133 + if k_hyp == int(key_byte, 16):
  134 + plt.plot([step*i for i in range(1, nb_steps+1)], max_corr_per_key_byte[:,k_hyp], color='black', zorder=10)
139 135 else:
140   - plt.plot([step*i for i in range(nb_steps)], max_corr_per_key_byte[:,k_hyp], color='grey', alpha=0.25)
141   - plt.xlim(0, step*(nb_steps-1))
  136 + plt.plot([step*i for i in range(1, nb_steps+1)], max_corr_per_key_byte[:,k_hyp], color='grey', alpha=0.25)
  137 + plt.xlim(step, step*nb_steps)
142 138 plt.ylim(0, 1)
143 139 plt.xlabel("#Traces")
144 140 plt.ylabel("Maximum of correlation per key hypothesis")
145 141  
146 142  
... ... @@ -149,21 +145,20 @@
149 145 key_ranks = []
150 146 for i in range(nb_steps):
151 147 try:
152   - key_rank = np.where(sorted(max_corr_per_key_byte[i,:])[::-1] == max_corr_per_key_byte[i,key_byte])[0][-1]
  148 + key_rank = np.where(sorted(max_corr_per_key_byte[i,:])[::-1] == max_corr_per_key_byte[i,int(key_byte, 16)])[0][-1]
153 149 except:
154 150 raise ValueError("Could not compute the key rank, increase the step size !")
155 151 key_ranks.append(key_rank)
156   - plt.plot([step*i for i in range(nb_steps)], key_ranks)
157   - plt.xlim(0, step*(nb_steps-1))
  152 + plt.plot([step*i for i in range(1, nb_steps+1)], key_ranks)
  153 + plt.xlim(step, step*nb_steps)
158 154 plt.ylim(0, 255)
159 155 plt.xlabel("#Traces")
160 156 plt.ylabel("Key rank")
161 157 plt.savefig(os.path.join(plot_path, 'key_rank_byte_'+str(byte)+'.png'))
162 158 # plt.show()
163 159 plt.close()
164   - return
165   - for byte in target_bytes:
166   - log.info("Plotting for byte {0}".format(byte))
  160 + for byte in tqdm.tqdm(target_bytes, desc="Plotting for each byte", total=len(target_bytes)):
  161 + # log.info("Plotting for byte {0}".format(byte))
167 162 if step:
168 163 corr = abs(np.load(os.path.join(correlations_path, 'corr_byte_'+str(byte)+'.npy')))[-1,:,:]
169 164 else:
... ... @@ -200,7 +195,8 @@
200 195 if __name__ == "__main__":
201 196  
202 197 parser = argparse.ArgumentParser(description='Preprocess traces')
203   - parser.add_argument("-n", "--nb_traces", type=int, nargs='?', default=-1)
  198 + parser.add_argument("-n", "--nb_traces", type=int, default=-1)
  199 + parser.add_argument("-b", "--nb_bytes", type=int, default=16)
204 200 parser.add_argument("-p", "--plaintexts_filename", type=str, default='plaintexts.npy')
205 201 parser.add_argument("-t", "--traces_filename", type=str, default='traces.npy')
206 202 parser.add_argument("-i", "--incremental_step", type=int, nargs='?', default=0)
207 203  
... ... @@ -209,7 +205,7 @@
209 205 args = parser.parse_args()
210 206  
211 207 compute_predictions(args.nb_traces, args.plaintexts_filename)
212   - compute_correlation(args.nb_traces, args.traces_filename, args.incremental_step)
  208 + compute_correlation(args.nb_traces, args.traces_filename, args.nb_bytes, args.incremental_step)
213 209 display_results(args.correct_key)
214   - plot_results(range(16), args.incremental_step)
  210 + # plot_results(range(args.nb_bytes), args.incremental_step, args.correct_key)