-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathprocess_data.py
More file actions
executable file
·138 lines (112 loc) · 4.91 KB
/
process_data.py
File metadata and controls
executable file
·138 lines (112 loc) · 4.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#!/usr/bin/python3
from arduino_inter import BS
import numpy
import pandas
import matplotlib.pyplot as plt
N_SAMPLES = 10000
MEASUREMENTS = 10_000 #7500 needed for attack to work with multi_bit
MULTI_BIT = True
class FileParser:
def __init__(self, samples_file="captures", ct_file="ciphertext"):
print("Reading file...")
all_dfs = pandas.read_csv(samples_file, nrows=MEASUREMENTS * N_SAMPLES, squeeze=True, usecols=[1], header=None, names=["S", "V"], engine="c")
print("Done")
assert len(all_dfs) % N_SAMPLES == 0
print("Splitting Arrays...")
self.measurements = numpy.split(all_dfs.values, MEASUREMENTS)
print("Done")
self.n = len(self.measurements)
print("Reading Ciphertext...")
with open(ct_file, 'rb') as f:
raw_ct = f.read()
self.ct = [raw_ct[i * BS : (i + 1) * BS] for i in range(self.n)]
print("Done")
inverse_sbox = [0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D]
#https://stackoverflow.com/questions/15540798/count-number-of-ones-in-a-given-integer
def h_weight(number):
weight = 0
while(number):
weight += 1
number &= number - 1
return weight
def selector_function(ciphertext, guess, n, i):
pre_add_roundkey = ciphertext[n] ^ guess
#no need to reverse shift rows, sub bytes doesn't care about order
pre_sbox = inverse_sbox[pre_add_roundkey]
return bool(pre_sbox & 2**i)
def DPA_bytes(parser, n):
current_samples = []
print("0% Done", end="")
for guess in range(256):
if(guess % 3 == 0):
print("\r%d%% Done" % (guess * 100 / 255), end="")
sel_1 = numpy.zeros(N_SAMPLES)
sel_1_cnt = 0
sel_0 = numpy.zeros(N_SAMPLES)
sel_0_cnt = 0
limit = 8 if MULTI_BIT else 1
for current_measurement in range(parser.n):
for i in range(limit):
if(selector_function(parser.ct[current_measurement], guess, n, i)):
sel_1 += parser.measurements[current_measurement]
sel_1_cnt += 1
else:
sel_0 += parser.measurements[current_measurement]
sel_0_cnt += 1
current_samples.append(sel_1 / sel_1_cnt - sel_0 / sel_0_cnt)
print("\nDone!")
return current_samples
def gen_H_con(parser, n):
H = numpy.zeros([parser.n, 256])
for cur_mes in range(parser.n):
for cand_key in range(256):
weight = h_weight(inverse_sbox[cand_key ^ parser.cs[cur_mes]])
H[cur_mes][cand_key] = selector_function(parser.ct[cur_mes], cand_key, n)
def DPA(parser):
print("Starting DPA attack on whole key (16 bytes)")
key = []
for byte in range(16):
print("Attacking byte %d" % byte)
guesses = DPA_bytes(parser, byte)
key.append(guesses)
print("DPA attack done")
return key
def performance_eval(a):
global MULTI_BIT
for n in range(10_000, 0, -1000):
print("Running with n = %d" % n)
a.n = n
MULTI_BIT = True
result = DPA(a)
numpy.save("DPA_array_%d_multi" % n, result)
print("Running with false")
MULTI_BIT = False
result = DPA(a)
numpy.save("DPA_array_%d_single" %n, result)
if(__name__ == "__main__"):
a = FileParser()
#b = DPA(a)
#b = DPA_bytes(a, 14)
#numpy.save("DPA_array", b)
#performance_eval(a)
a.n = 10_000
MULTI_BIT = False
#DPA(a)
r = DPA_bytes(a, 0)
plt.plot(r[177])
plt.savefig("random.png")