This commit is contained in:
xenia 2021-04-25 23:04:48 -04:00
parent 9876dcff1f
commit bc068c75a4
3 changed files with 71 additions and 49 deletions

View File

@ -66,49 +66,50 @@ def align(db, ntraces):
alignments[i] = lag alignments[i] = lag
alignments -= numpy.min(alignments) alignments -= numpy.min(alignments)
max_start = max(alignments)
min_end = 700
traces = numpy.zeros((ntraces, 800), 'double') traces = numpy.zeros((ntraces, 800), 'double')
for i in range(ntraces): for i in range(ntraces):
traces[i, alignments[i]:alignments[i]+700] = db["traces"][i] traces[i, alignments[i]:alignments[i]+700] = db["traces"][i]
return traces return traces[:, max_start:min_end]
def main(db): # P - (n,m) array of n predictions for each of the m candidates
ntraces = 1000 # O - (n,t) array of n traces with t samples each
traces = align(db, ntraces) # returns an (m,t) correlation matrix of m traces t samples each
class Correlator:
def __init__(self, P):
self.P = P - numpy.mean(P, axis=0)
self.tmp1 = numpy.einsum("nm,nm->m", self.P, self.P, optimize='optimal')
self.P = self.P.transpose()
# for i in range(10): def corr_submatrix(self, O):
# plt.plot(traces[i], color=numpy.hstack((numpy.random.random(3), [0.5]))) O -= numpy.mean(O, axis=0)
# plt.show() numerator = self.P @ O
tmp2 = numpy.einsum("nt,nt->t", O, O, optimize='optimal')
denominator = numpy.sqrt(numpy.outer(self.tmp1, tmp2))
return numerator / denominator
logger.info("making model")
def attack_firstorder(db, traces, ntraces):
logger.info("making first order model")
model = numpy.repeat(numpy.arange(256, dtype='uint8'), ntraces).reshape((256, ntraces)) model = numpy.repeat(numpy.arange(256, dtype='uint8'), ntraces).reshape((256, ntraces))
for i in tqdm.trange(ntraces): for i in tqdm.trange(ntraces):
(pt, ct, key, mask, desync) = db["metadata"][i] (pt, ct, key, mask, desync) = db["metadata"][i]
pt_v = pt[2] pt_v = pt[2]
mask_v = mask[15] mask_v = mask[15]
model[:, i] = AES_SBOX[model[:, i] ^ pt_v] ^ mask_v model[:, i] = AES_SBOX[model[:, i] ^ pt_v] ^ mask_v
model = numpy_popcount.popcount(model).astype("double") model = numpy_popcount.popcount(model).astype("double").transpose()
# O - (n,t) array of n traces with t samples each
# P - (n,m) array of n predictions for each of the m candidates
# returns an (m,t) correaltion matrix of m traces t samples each
def corr_submatrix(O, P):
O -= numpy.mean(O, axis=0)
P -= numpy.mean(P, axis=0)
numerator = numpy.einsum("nm,nt->mt", P, O, optimize='optimal')
denominator = numpy.sqrt(numpy.outer((P * P).sum(axis=0), (O * O).sum(axis=0)))
return numerator / denominator
# boring, slow, uses too much RAM # boring, slow, uses too much RAM
# input_matrix = numpy.vstack((model, traces.transpose())) # input_matrix = numpy.vstack((model, traces.transpose()))
# coefs = numpy.corrcoef(input_matrix)[0:256, 256:] # coefs = numpy.corrcoef(input_matrix)[0:256, 256:]
# uwu # uwu
coefs = corr_submatrix(traces, model.transpose()) correlator = Correlator(model)
coefs = correlator.corr_submatrix(traces)
# plot absmax # plot absmax
coefs = numpy.abs(coefs) coefs = numpy.abs(coefs)
@ -116,35 +117,56 @@ def main(db):
plt.plot(max_by_key) plt.plot(max_by_key)
plt.show() plt.show()
# logger.info("making 2nd order")
# traces = traces.transpose() def attack_secondorder(db, traces, ntraces):
# traces_x = numpy.zeros((700*699//2, ntraces), 'double') logger.info("making second order model")
# tx_i = 0 model = numpy.repeat(numpy.arange(256, dtype='uint8'), ntraces).reshape((256, ntraces))
# for i in tqdm.trange(700): for i in tqdm.trange(ntraces):
# for j in range(i+1, 700): (pt, ct, key, mask, desync) = db["metadata"][i]
# traces_x[tx_i, :] = numpy.abs(traces[i, :] - traces[j, :]) pt_v = pt[2]
# tx_i += 1 mask_v = mask[15]
# model[:, i] = AES_SBOX[model[:, i] ^ pt_v]
# logger.info("doing corr") model = numpy_popcount.popcount(model).astype("double").transpose()
# ncolumns = 100
# step = traces_x.shape[0] // ncolumns logger.info("making second order combinations")
# all_coefs = None nticks = traces.shape[1]
# for i in tqdm.trange(ncolumns): traces_x = numpy.zeros((ntraces, nticks*(nticks - 1)//2), 'double')
# start = i * step tx_i = 0
# end = (i + 1) * step for i in tqdm.trange(nticks):
# input_matrix = numpy.vstack((model, traces_x[start:end, :])) for j in range(i+1, nticks):
# coefs = numpy.corrcoef(input_matrix)[0:256, 256:] traces_x[:, tx_i] = numpy.abs(traces[:, i] - traces[:, j])
# if all_coefs is None: tx_i += 1
# all_coefs = coefs
# else: logger.info("doing corr")
# all_coefs = numpy.hstack((all_coefs, coefs)) correlator = Correlator(model)
# ncolumns = 10
# step = traces_x.shape[1] // ncolumns
# all_coefs = numpy.abs(all_coefs) all_coefs = []
# max_by_key = numpy.max(all_coefs, axis=1) for i in tqdm.trange(ncolumns):
# plt.plot(max_by_key) start = i * step
end = (i + 1) * step
coefs = correlator.corr_submatrix(traces_x[:, start:end])
all_coefs.append(coefs)
all_coefs = numpy.hstack(all_coefs)
all_coefs = numpy.abs(all_coefs)
max_by_key = numpy.max(all_coefs, axis=1)
plt.plot(max_by_key)
plt.show()
def main(db):
ntraces = 2000
traces = align(db, ntraces)
# for i in range(10):
# plt.plot(traces[i], color=numpy.hstack((numpy.random.random(3), [0.5])))
# plt.show() # plt.show()
attack_firstorder(db, traces, ntraces)
attack_secondorder(db, traces, ntraces)
if __name__ == "__main__": if __name__ == "__main__":
from tqdm.contrib.logging import logging_redirect_tqdm from tqdm.contrib.logging import logging_redirect_tqdm

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 23 KiB

BIN
sca/ascad/second_order.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB