Created
January 10, 2017 12:07
-
-
Save NSkelsey/3a9cd2d68d2ec18b531a34823b5c32d9 to your computer and use it in GitHub Desktop.
Demonstrates lack of resolution in timing side channels
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
import string | |
import random | |
import timeit | |
#from globaleaks.handlers import authentication | |
from globaleaks.security import check_password, hash_password | |
guesses = 1000000 | |
def rand_pw(): | |
return ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(8)) | |
def default_pws(): | |
return | |
class TestFrame(object): | |
def __init__(self, pw_try=None): | |
self.correct_pass = ''.join(string.ascii_lowercase) | |
self.pw_try = pw_try | |
self.correct_pass_hash = hash_password(self.correct_pass, 'a-bit-of-salt') | |
def simple_cmp(self): | |
return self.correct_pass == self.pw_try | |
def zip_cmp(self): | |
result = 0 | |
for x, y in zip(self.correct_pass, self.pw_try): | |
result |= ord(x) ^ ord(y) | |
return result == 0 | |
def check_pw(self): | |
check_password(self.pw_try, 'a-bit-of-salt', self.correct_pass_hash) | |
def o(seconds): | |
return "%0.3f usec per eval" % ((seconds / guesses)*1e6) | |
def g(seconds): | |
return "%0.3f usec per eval" % ((seconds / 10)*1e6) | |
if __name__ == '__main__': | |
print("\ncheck_password: 100 runs\n") | |
res = timeit.timeit('tf.check_pw()', 'from __main__ import TestFrame; tf = TestFrame(pw_try="bbbbbbbbbbbbbbbbbbbbbbbbbb")', number=100) | |
print('first byte incorrect:\t%s'% g(res)) | |
res = timeit.timeit('tf.check_pw()', 'from __main__ import TestFrame; tf = TestFrame(pw_try="abbbbbbbbbbbbbbbbbbbbbbbbb")', number=100) | |
print('first byte correct:\t%s'% g(res)) | |
res = timeit.timeit('tf.check_pw()', 'from __main__ import TestFrame; tf = TestFrame(pw_try="abcdefghijklmnopqrstuvwxyg")', number=100) | |
print('very close pw time:\t%s'% g(res)) | |
res = timeit.timeit('tf.check_pw()', 'from __main__ import TestFrame; tf = TestFrame(pw_try="abcdefghijklmnopqrstuvwxyz")', number=100) | |
print('correct pw time:\t%s' % g(res)) | |
print("simple_cmp: 1 million runs\n") | |
res = timeit.timeit('tf.simple_cmp()', 'from __main__ import TestFrame; tf = TestFrame(pw_try="bbbbbbbbbbbbbbbbbbbbbbbbbb")', number=guesses) | |
print('first byte incorrect:\t%s'% o(res)) | |
res = timeit.timeit('tf.simple_cmp()', 'from __main__ import TestFrame; tf = TestFrame(pw_try="abbbbbbbbbbbbbbbbbbbbbbbbb")', number=guesses) | |
print('first byte correct:\t%s'% o(res)) | |
res = timeit.timeit('tf.simple_cmp()', 'from __main__ import TestFrame; tf = TestFrame(pw_try="abcdefghijklmnopqrstuvwxyg")', number=guesses) | |
print('very close pw time:\t%s'% o(res)) | |
res = timeit.timeit('tf.simple_cmp()', 'from __main__ import TestFrame; tf = TestFrame(pw_try="abcdefghijklmnopqrstuvwxyz")', number=guesses) | |
print('correct pw time:\t%s' % o(res)) | |
print("\nzip_cmp: 1 million runs\n") | |
res = timeit.timeit('tf.zip_cmp()', 'from __main__ import TestFrame; tf = TestFrame(pw_try="bbbbbbbbbbbbbbbbbbbbbbbbbb")', number=guesses) | |
print('first byte incorrect:\t%s'% o(res)) | |
res = timeit.timeit('tf.zip_cmp()', 'from __main__ import TestFrame; tf = TestFrame(pw_try="abbbbbbbbbbbbbbbbbbbbbbbbb")', number=guesses) | |
print('first byte correct:\t%s'% o(res)) | |
res = timeit.timeit('tf.zip_cmp()', 'from __main__ import TestFrame; tf = TestFrame(pw_try="abcdefghijklmnopqrstuvwxyg")', number=guesses) | |
print('very close pw time:\t%s'% o(res)) | |
res = timeit.timeit('tf.zip_cmp()', 'from __main__ import TestFrame; tf = TestFrame(pw_try="abcdefghijklmnopqrstuvwxyz")', number=guesses) | |
print('correct pw time:\t%s' % o(res)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment