summaryrefslogtreecommitdiff
path: root/openid
diff options
context:
space:
mode:
authorVlastimil Zíma <vlastimil.zima@nic.cz>2018-05-22 17:49:58 +0200
committerVlastimil Zíma <vlastimil.zima@nic.cz>2018-05-22 17:51:16 +0200
commitdae19740ac5c8887145ecee9d7c955390b431ea0 (patch)
treea1a2f2d6815068f990f4b673f7fa71304f1611dc /openid
parent74d2eed6fa17d3ec0ba3b5d32ab0f30f27ab7b8b (diff)
downloadopenid-dae19740ac5c8887145ecee9d7c955390b431ea0.tar.gz
Refactor bytes <-> int conversions
Diffstat (limited to 'openid')
-rw-r--r--openid/cryptutil.py83
-rw-r--r--openid/dh.py2
-rw-r--r--openid/test/test_cryptutil.py21
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."""