Last active
January 13, 2023 06:06
-
-
Save levigross/8691015 to your computer and use it in GitHub Desktop.
Constant Time Comparison functions
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
; Taken from https://github.com/weavejester/crypto-equality/blob/master/src/crypto/equality.clj | |
(ns crypto.equality | |
"Securely test sequences of data for equality.") | |
(defn eq? | |
"Test whether two sequences of characters or bytes are equal in a way that | |
protects against timing attacks. Note that this does not prevent an attacker | |
from discovering the *length* of the data being compared." | |
[a b] | |
(let [a (map int a), b (map int b)] | |
(if (and a b (= (count a) (count b))) | |
(zero? (reduce bit-or (map bit-xor a b))) | |
false))) |
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
#Taken from Django | |
def constant_time_compare(val1, val2): | |
""" | |
Returns True if the two strings are equal, False otherwise. | |
The time taken is independent of the number of characters that match. | |
For the sake of simplicity, this function executes in constant time only | |
when the two strings have the same length. It short-circuits when they | |
have different lengths. | |
""" | |
if len(val1) != len(val2): | |
return False | |
result = 0 | |
for x, y in zip(val1, val2): | |
result |= ord(x) ^ ord(y) | |
return result == 0 |
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
#This is included within the stdlib in Py3k for an C alternative for Python 2.7.x see https://github.com/levigross/constant_time_compare/ | |
from operator import _compare_digest as constant_time_compare | |
# Or you can use this function taken from Django | |
def constant_time_compare(val1, val2): | |
""" | |
Returns True if the two strings are equal, False otherwise. | |
The time taken is independent of the number of characters that match. | |
For the sake of simplicity, this function executes in constant time only | |
when the two strings have the same length. It short-circuits when they | |
have different lengths. | |
""" | |
if len(val1) != len(val2): | |
return False | |
result = 0 | |
for x, y in zip(val1, val2): | |
result |= x ^ y | |
return result == 0 |
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
import Data.Bits | |
import Data.Char | |
import Data.List | |
import Data.Function | |
-- Thank you Yan for this snippet | |
constantTimeCompare a b = | |
((==) `on` length) a b && 0 == (foldl1 (.|.) joined) | |
where | |
joined = zipWith (xor `on` ord) a b |
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
// Taken from http://codahale.com/a-lesson-in-timing-attacks/ | |
public static boolean isEqual(byte[] a, byte[] b) { | |
if (a.length != b.length) { | |
return false; | |
} | |
int result = 0; | |
for (int i = 0; i < a.length; i++) { | |
result |= a[i] ^ b[i] | |
} | |
return result == 0; | |
} |
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
def secure_compare(a, b) | |
return false if a.empty? || b.empty? || a.bytesize != b.bytesize | |
l = a.unpack "C#{a.bytesize}" | |
res = 0 | |
b.each_byte { |byte| res |= byte ^ l.shift } | |
res == 0 | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The python code is not constant time in practice: https://securitypitfalls.wordpress.com/2018/08/03/constant-time-compare-in-python/