-
Notifications
You must be signed in to change notification settings - Fork 25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add a distributed implementation of the correlation-enhanced collision attack #28
Conversation
Signed-off-by: Alphan Ulusoy <alphan@google.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @alphan for this PR, it's awesome work!
LGTM, I just have a couple of minor comments.
As an extension in a follow up PR, do you think it would be possible to implement a sweep over the number of traces? This would provide the useful information of when the attack starts to succeed, i.e., what the resistance in terms of number of traces actually is. Anyway, worst case we can just wrap your attack with a sweep script. Yours is so incredibly fast now that this would still be okay I guess.
diff_corrcoefs = corrcoefs[alphas, 256 + betas].sum(axis=1) | ||
best_diff = diff_corrcoefs.argmax() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not fully clear how your implementation works but you basically managed to skip three more loops (compared to mine) which is great 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What I am wondering: you don't seem to normalize the correlation coefficients BEFORE doing the argmax. If I remember correctly, this was necessary in my implementation. But still yours works correctly....
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What I am wondering: you don't seem to normalize the correlation coefficients BEFORE doing the argmax. If I remember correctly, this was necessary in my implementation. But still yours works correctly....
IIUC, you are referring to this snippet (lines 98-104 in correlation-enhanced_collision_attack.py
):
for i in range(256):
for j in range(256):
delta = i ^ j
rho_avg_delta[delta] += rho_mat[i, j]
rho_avg_delta_num[delta] += 1
for delta in range(256): # redundant
rho_avg_delta[delta] /= rho_avg_delta_num[delta] # redundant
# Normalize correlations.
mean = rho_avg_delta.mean()
rho_avg_delta /= mean
Unless I'm missing something, it looks like the loop marked by redundant
doesn't really do anything, maybe except for introducing some tiny numerical error due to floating point operations. Since rho_avg_delta_num[delta]
is 256
for all values of delta
, i.e. [0, 255] and rho_avg_delta
is normalized again, this loop is basically dividing all entries by some constant before they are normalized.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not fully clear how your implementation works but you basically managed to skip three more loops (compared to mine) which is great 👍
Thanks :) The main point here is to minimize the back and forth between python and numpy as much as possible, e.g. by avoiding unnecessary (nested) loops that can be handled by numpy much more efficiently. In a nutshell:
alphas
is a (256,) row array,diffs
is a (256, 1) col array (so that broadcasting works out), andbetas
is a (256, 256) array wherebetas[i,j] = diffs[i] ^ alphas[j]
.- Defining
betas
this way is important because this lets us pick the values we want from thenp.corrcoeff
result using just a single indexing operation and asum(axis=1)
as opposed to tworange(0, 256)
nested loops.
I hope this helps and please let me know if you have any other questions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the clarification @alphan .
Regarding the redundant loop above: I added this (before doing the real normalization) because I wasn't sure if there are equally many combinations of i
and j
that result in the same delta
. But yes, I think with the real normalization in place this loop can actually be dropped.
cw/cw305/ceca.py
Outdated
# TODO: Analyze the effect of /diff_corrcoefs.mean() below. | ||
pairwise_diffs_scores[(a, b), (b, a)] = (best_diff, | ||
diff_corrcoefs[best_diff] / | ||
diff_corrcoefs.mean()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, here comes the normalization. I think you need this to make all the pairwise_diffs_scores
comparable. There are pairs for which the correlation is almost flat but constantly higher than the highest peaks of another pair. You need the normalization to "downvote" this flat correlation for find_best_diffs()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think so too but I left a TODO nevertheless because IIRC I was able to recover the key without this a couple of times and would like to check how the results look like when running batch attacks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, great work!
""" | ||
|
||
|
||
def timer(): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just noticed we are not being consistent across scripts on indentation. Should we use 2 or 4 spaces?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer 4 spaces to align with PEP8 and leave these to automated tools. I think black
is a good choice. What do you think?
…n attack This change adds a distributed implementation of the correlation-enhanced power analysis collision attack described in "Correlation-Enhanced Power Analysis Collision Attack" by A. Moradi, O. Mischke, and T. Eisenbarth (https://eprint.iacr.org/2010/297.pdf). Signed-off-by: Alphan Ulusoy <alphan@google.com>
This PR adds a distributed implementation of the correlation-enhanced power analysis collision attack described in "Correlation-Enhanced Power Analysis Collision Attack" by A. Moradi, O. Mischke, and T. Eisenbarth (https://eprint.iacr.org/2010/297.pdf).
In addition to using Ray (https://docs.ray.io/en/master/index.html) for distributed computation, this implementation also uses a modified version of Dijkstra's shortest path algorithm to utilize all available information on differences between key bytes. This implementation also optimizes several operations for improved performance, e.g. various
numpy
operations and encrypting with multiple keys in parallel usingscared
to check if the attack was successful, etc.I get the following numbers when I run this on my workstation (12 cores @ 3.7 GHz according to
/proc/cpuinfo
) using the traces inaes_unhardened_1mio_traces_cw305.tar.bz2
captured by @vogelpi:The difference between
main()
andperform_attack()
is Ray's initialization overhead.I am aware that some of the code can be moved to utility libraries, I plan to revisit those after running this on GCP.
Looking forward to your feedback!