diff options
author | Vlastimil Zíma <vlastimil.zima@nic.cz> | 2018-05-22 17:49:58 +0200 |
---|---|---|
committer | Vlastimil Zíma <vlastimil.zima@nic.cz> | 2018-05-22 17:51:16 +0200 |
commit | dae19740ac5c8887145ecee9d7c955390b431ea0 (patch) | |
tree | a1a2f2d6815068f990f4b673f7fa71304f1611dc /openid | |
parent | 74d2eed6fa17d3ec0ba3b5d32ab0f30f27ab7b8b (diff) | |
download | openid-dae19740ac5c8887145ecee9d7c955390b431ea0.tar.gz |
Refactor bytes <-> int conversions
Diffstat (limited to 'openid')
-rw-r--r-- | openid/cryptutil.py | 83 | ||||
-rw-r--r-- | openid/dh.py | 2 | ||||
-rw-r--r-- | openid/test/test_cryptutil.py | 21 |
3 files changed, 62 insertions, 44 deletions
diff --git a/openid/cryptutil.py b/openid/cryptutil.py index 86c3e86..c7de35f 100644 --- a/openid/cryptutil.py +++ b/openid/cryptutil.py @@ -3,18 +3,18 @@ other cryptographically useful functionality Other configurations will need a quality source of random bytes and access to a function that will convert binary strings to long -integers. This module will work with the Python Cryptography Toolkit -(pycrypto) if it is present. pycrypto can be found with a search -engine, but is currently found at: - -http://www.amk.ca/python/code/crypto +integers. """ from __future__ import unicode_literals +import codecs import hashlib import hmac import os import random +import warnings + +import six from openid.oidutil import fromBase64, string_to_text, toBase64 @@ -28,6 +28,8 @@ __all__ = [ 'randrange', 'sha1', 'sha256', + 'int_to_bytes', + 'bytes_to_int', ] @@ -85,48 +87,43 @@ def sha256(s): return sha256_module.new(s).digest() -try: - from Crypto.Util.number import long_to_bytes, bytes_to_long -except ImportError: - import pickle +def bytes_to_int(value): + """ + Convert byte string to integer. - def longToBinary(value): - if value == 0: - return b'\x00' + @type value: six.binary_type + @rtype: Union[six.integer_types] + """ + return int(codecs.encode(value, 'hex'), 16) - return pickle.encode_long(value)[::-1] - def binaryToLong(s): - return pickle.decode_long(s[::-1]) -else: - # We have pycrypto +def int_to_bytes(value): + """ + Convert integer to byte string. - def longToBinary(value): - if value < 0: - raise ValueError('This function only supports positive integers') + @type value: Union[six.integer_types] + @rtype: six.binary_type + """ + hex_value = '{:x}'.format(value) + if len(hex_value) % 2: + hex_value = '0' + hex_value + array = bytearray.fromhex(hex_value) + # First bit must be zero. If it isn't, the bytes must be prepended by zero byte. + # See http://openid.net/specs/openid-authentication-2_0.html#btwoc for details. + if array[0] > 127: + array = bytearray([0]) + array + return six.binary_type(array) - output = long_to_bytes(value) - if isinstance(output[0], int): - ord_first = output[0] - else: - ord_first = ord(output[0]) - if ord_first > 127: - return b'\x00' + output - else: - return output - def binaryToLong(s): - if not s: - raise ValueError('Empty string passed to strToLong') +# Deprecated versions of bytes <--> int conversions +def longToBinary(value): + warnings.warn("Function longToBinary is deprecated in favor of int_to_bytes.", DeprecationWarning) + return int_to_bytes(value) - if isinstance(s[0], int): - ord_first = s[0] - else: - ord_first = ord(s[0]) - if ord_first > 127: - raise ValueError('This function only supports positive integers') - return bytes_to_long(s) +def binaryToLong(s): + warnings.warn("Function binaryToLong is deprecated in favor of bytes_to_int.", DeprecationWarning) + return bytes_to_int(s) # A randrange function that works for longs @@ -149,7 +146,7 @@ except AttributeError: try: (duplicate, nbytes) = _duplicate_cache[r] except KeyError: - rbytes = longToBinary(r) + rbytes = int_to_bytes(r) if rbytes[0] == '\x00': nbytes = len(rbytes) - 1 else: @@ -168,7 +165,7 @@ except AttributeError: while True: bytes = '\x00' + os.urandom(nbytes) - n = binaryToLong(bytes) + n = bytes_to_int(bytes) # Keep looping if this value is in the low duplicated range if n >= duplicate: break @@ -177,8 +174,8 @@ except AttributeError: def longToBase64(l): - return toBase64(longToBinary(l)) + return toBase64(int_to_bytes(l)) def base64ToLong(s): - return binaryToLong(fromBase64(s)) + return bytes_to_int(fromBase64(s)) diff --git a/openid/dh.py b/openid/dh.py index 28ff403..46a05ed 100644 --- a/openid/dh.py +++ b/openid/dh.py @@ -60,5 +60,5 @@ class DiffieHellman(object): def xorSecret(self, composite, secret, hash_func): dh_shared = self.getSharedSecret(composite) - hashed_dh_shared = hash_func(cryptutil.longToBinary(dh_shared)) + hashed_dh_shared = hash_func(cryptutil.int_to_bytes(dh_shared)) return strxor(secret, hashed_dh_shared) diff --git a/openid/test/test_cryptutil.py b/openid/test/test_cryptutil.py index 5d5cc5f..5159575 100644 --- a/openid/test/test_cryptutil.py +++ b/openid/test/test_cryptutil.py @@ -70,6 +70,27 @@ class TestLongBinary(unittest.TestCase): assert s == s_prime, (n, s, s_prime) +class TestBytesIntConversion(unittest.TestCase): + """Test bytes <-> int conversions.""" + + # Examples from http://openid.net/specs/openid-authentication-2_0.html#btwoc + cases = [ + (b'\x00', 0), + (b'\x01', 1), + (b'\x7F', 127), + (b'\x00\xFF', 255), + (b'\x00\x80', 128), + (b'\x00\x81', 129), + (b'\x00\x80\x00', 32768), + (b'OpenID is cool', 1611215304203901150134421257416556) + ] + + def test_conversions(self): + for string, number in self.cases: + self.assertEqual(cryptutil.bytes_to_int(string), number) + self.assertEqual(cryptutil.int_to_bytes(number), string) + + class TestLongToBase64(unittest.TestCase): """Test `longToBase64` function.""" |