From 70a64b6b1aac0670ecd07ed6cd19fa451f96b5ee Mon Sep 17 00:00:00 2001 From: Andrew Date: Wed, 21 May 2014 15:30:26 -0700 Subject: [PATCH] Use constant-time string comparison (fixes #3) Note: this isn't 100% constant-time, as can be seen here: http://bugs.python.org/issue15061 Specifically: "Note that it takes different time to create a result of ord() depending whether it's <=100 or > 100 due to caching of small numbers." --- onionshare.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/onionshare.py b/onionshare.py index 9c2cd758..a8c57332 100755 --- a/onionshare.py +++ b/onionshare.py @@ -15,18 +15,21 @@ app = Flask(__name__) auth_username = auth_password = filename = filehash = filesize = '' -def check_auth(username, password): - global auth_username, auth_password - - if len(username) != 16 or len(password) != 16: +def is_equal(a, b): + """Constant-time string comparison""" + if len(a) != len(b): return False - # constant time string comparison, to prevent timing attacks - valid = True - for i in range(16): - if username[i] != auth_username[i] or password[i] != auth_password[i]: - valid = False - return valid + result = 0 + for x, y in zip(a, b): + result |= ord(x) ^ ord(y) + return result == 0 + +def check_auth(username, password): + global auth_username, auth_password + usernames_equal = is_equal(username, auth_username) + passwords_equal = is_equal(password, auth_password) + return usernames_equal & passwords_equal def authenticate(): return Response(