mirror of
https://github.com/theupdateframework/python-tuf
synced 2026-05-24 10:08:28 +00:00
Merge pull request #277 from vladimir-v-diaz/compare-digests-non-variable
Protect Against Timing Attacks When Comparing Digests
This commit is contained in:
commit
311dff2f6f
3 changed files with 86 additions and 1 deletions
|
|
@ -32,6 +32,7 @@
|
|||
import logging
|
||||
import tempfile
|
||||
import unittest
|
||||
import timeit
|
||||
|
||||
import tuf
|
||||
import tuf.log
|
||||
|
|
@ -577,6 +578,48 @@ def test_c6_get_compressed_length(self):
|
|||
|
||||
|
||||
|
||||
def test_digests_are_equal(self):
|
||||
digest = 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
|
||||
|
||||
# Normal case: test for digests that are equal.
|
||||
self.assertTrue(tuf.util.digests_are_equal(digest, digest))
|
||||
|
||||
# Normal case: test for digests that are unequal.
|
||||
self.assertFalse(tuf.util.digests_are_equal(digest, '0a8df1'))
|
||||
|
||||
# Test for invalid arguments.
|
||||
self.assertRaises(tuf.FormatError, tuf.util.digests_are_equal, 7,
|
||||
digest)
|
||||
self.assertRaises(tuf.FormatError, tuf.util.digests_are_equal, digest,
|
||||
7)
|
||||
|
||||
# Test that digests_are_equal() takes the same amount of time to compare
|
||||
# equal and unequal arguments.
|
||||
runtime = timeit.timeit('digests_are_equal("ab8df", "ab8df")',
|
||||
setup='from tuf.util import digests_are_equal',
|
||||
number=100000)
|
||||
|
||||
runtime2 = timeit.timeit('digests_are_equal("ab8df", "1b8df")',
|
||||
setup='from tuf.util import digests_are_equal',
|
||||
number=100000)
|
||||
|
||||
print('\nruntime1: ' + repr(runtime))
|
||||
print('runtime2: ' + repr(runtime2))
|
||||
|
||||
runtime3 = timeit.timeit('"ab8df" == "ab8df"', number=100000)
|
||||
|
||||
runtime4 = timeit.timeit('"ab8df" == "1b8df"', number=1000000)
|
||||
|
||||
# The ratio for the 'digest_are_equal' runtimes should be at or near 1.
|
||||
ratio_digests_are_equal = abs(runtime2 / runtime)
|
||||
|
||||
# The ratio for the variable-time runtimes should be (>1) & at or near 10?
|
||||
ratio_variable_compare = abs(runtime4 / runtime3)
|
||||
|
||||
self.assertTrue(ratio_digests_are_equal < ratio_variable_compare)
|
||||
|
||||
|
||||
|
||||
# Run unit test.
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
|||
|
|
@ -931,7 +931,7 @@ def _decrypt(file_contents, password):
|
|||
Crypto.Hash.SHA256)
|
||||
generated_hmac = generated_hmac_object.hexdigest()
|
||||
|
||||
if generated_hmac != hmac:
|
||||
if not tuf.util.digests_are_equal(generated_hmac, hmac):
|
||||
raise tuf.CryptoError('Decryption failed.')
|
||||
|
||||
# The following decryption routine assumes 'ciphertext' was encrypted with
|
||||
|
|
|
|||
42
tuf/util.py
42
tuf/util.py
|
|
@ -950,3 +950,45 @@ def load_json_file(filepath):
|
|||
|
||||
finally:
|
||||
fileobject.close()
|
||||
|
||||
|
||||
|
||||
def digests_are_equal(digest1, digest2):
|
||||
"""
|
||||
<Purpose>
|
||||
While protecting against timing attacks, compare the hexadecimal arguments
|
||||
and determine if they are equal.
|
||||
|
||||
<Arguments>
|
||||
digest1:
|
||||
The first hexadecimal string value to compare.
|
||||
|
||||
digest2:
|
||||
The second hexadecimal string value to compare.
|
||||
|
||||
<Exceptions>
|
||||
tuf.FormatError: If the arguments are improperly formatted.
|
||||
|
||||
<Side Effects>
|
||||
None.
|
||||
|
||||
<Return>
|
||||
Return True if 'digest1' is equal to 'digest2', False otherwise.
|
||||
"""
|
||||
|
||||
# Ensure the arguments have the appropriate number of objects and object
|
||||
# types, and that all dict keys are properly named.
|
||||
# Raise 'tuf.FormatError' if there is a mismatch.
|
||||
tuf.formats.HEX_SCHEMA.check_match(digest1)
|
||||
tuf.formats.HEX_SCHEMA.check_match(digest2)
|
||||
|
||||
if len(digest1) != len(digest2):
|
||||
return False
|
||||
|
||||
are_equal = True
|
||||
|
||||
for element in range(len(digest1)):
|
||||
if digest1[element] != digest2[element]:
|
||||
are_equal = False
|
||||
|
||||
return are_equal
|
||||
|
|
|
|||
Loading…
Reference in a new issue