123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 |
- """Module containing a cryptographic-quality source of randomness and
- other cryptographically useful functionality
- Python 2.4 needs no external support for this module, nor does Python
- 2.3 on a system with /dev/urandom.
- 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
- """
- __all__ = [
- 'base64ToLong',
- 'binaryToLong',
- 'hmacSha1',
- 'hmacSha256',
- 'longToBase64',
- 'longToBinary',
- 'randomString',
- 'randrange',
- 'sha1',
- 'sha256',
- ]
- import hmac
- import os
- import random
- from openid.oidutil import toBase64, fromBase64
- import hashlib
- class HashContainer(object):
- def __init__(self, hash_constructor):
- self.new = hash_constructor
- self.digest_size = hash_constructor().digest_size
- sha1_module = HashContainer(hashlib.sha1)
- sha256_module = HashContainer(hashlib.sha256)
- def hmacSha1(key, text):
- if isinstance(key, str):
- key = bytes(key, encoding="utf-8")
- if isinstance(text, str):
- text = bytes(text, encoding="utf-8")
- return hmac.new(key, text, sha1_module).digest()
- def sha1(s):
- if isinstance(s, str):
- s = bytes(s, encoding="utf-8")
- return sha1_module.new(s).digest()
- def hmacSha256(key, text):
- if isinstance(key, str):
- key = bytes(key, encoding="utf-8")
- if isinstance(text, str):
- text = bytes(text, encoding="utf-8")
- return hmac.new(key, text, sha256_module).digest()
- def sha256(s):
- if isinstance(s, str):
- s = bytes(s, encoding="utf-8")
- return sha256_module.new(s).digest()
- SHA256_AVAILABLE = True
- try:
- from Crypto.Util.number import long_to_bytes, bytes_to_long
- except ImportError:
- # In the case where we don't have pycrypto installed, define substitute
- # functionality.
- import pickle
- def longToBinary(l):
- if l == 0:
- return b'\x00'
- b = bytearray(pickle.encode_long(l))
- b.reverse()
- return bytes(b)
- def binaryToLong(s):
- if isinstance(s, str):
- s = s.encode("utf-8")
- b = bytearray(s)
- b.reverse()
- return pickle.decode_long(bytes(b))
- else:
- # We have pycrypto, so wrap its functions instead.
- def longToBinary(l):
- if l < 0:
- raise ValueError('This function only supports positive integers')
- bytestring = long_to_bytes(l)
- if bytestring[0] > 127:
- return b'\x00' + bytestring
- else:
- return bytestring
- def binaryToLong(bytestring):
- if not bytestring:
- raise ValueError('Empty string passed to strToLong')
- if bytestring[0] > 127:
- raise ValueError('This function only supports positive integers')
- return bytes_to_long(bytestring)
- # A cryptographically safe source of random bytes
- getBytes = os.urandom
- # A randrange function that works for longs
- randrange = random.randrange
- def longToBase64(l):
- return toBase64(longToBinary(l))
- def base64ToLong(s):
- return binaryToLong(fromBase64(s))
- def randomString(length, chrs=None):
- """Produce a string of length random bytes, chosen from chrs."""
- if chrs is None:
- return getBytes(length)
- else:
- n = len(chrs)
- return ''.join([chrs[randrange(n)] for _ in range(length)])
- def const_eq(s1, s2):
- if len(s1) != len(s2):
- return False
- result = True
- for i in range(len(s1)):
- result = result and (s1[i] == s2[i])
- return result
|