1 """Module containing a cryptographic-quality source of randomness and
2 other cryptographically useful functionality
4 Python 2.4 needs no external support for this module, nor does Python
5 2.3 on a system with /dev/urandom.
7 Other configurations will need a quality source of random bytes and
8 access to a function that will convert binary strings to long
9 integers. This module will work with the Python Cryptography Toolkit
10 (pycrypto) if it is present. pycrypto can be found with a search
11 engine, but is currently found at:
13 http://www.amk.ca/python/code/crypto
33 from openid
.oidutil
import toBase64
, fromBase64
38 import sha
as sha1_module
41 from Crypto
.Hash
import SHA256
as sha256_module
46 class HashContainer(object):
47 def __init__(self
, hash_constructor
):
48 self
.new
= hash_constructor
50 sha1_module
= HashContainer(hashlib
.sha1
)
51 sha256_module
= HashContainer(hashlib
.sha256
)
53 def hmacSha1(key
, text
):
54 return hmac
.new(key
, text
, sha1_module
).digest()
57 return sha1_module
.new(s
).digest()
59 if sha256_module
is not None:
60 def hmacSha256(key
, text
):
61 return hmac
.new(key
, text
, sha256_module
).digest()
64 return sha256_module
.new(s
).digest()
66 SHA256_AVAILABLE
= True
69 _no_sha256
= NotImplementedError(
70 'Use Python 2.5, install pycrypto or install hashlib to use SHA256')
72 def hmacSha256(unused_key
, unused_text
):
78 SHA256_AVAILABLE
= False
81 from Crypto
.Util
.number
import long_to_bytes
, bytes_to_long
85 # Check Python compatiblity by raising an exception on import
86 # if the needed functionality is not present. Present in
90 except AttributeError:
92 'No functionality for serializing long integers found')
94 # Present in Python >= 2.4
99 return map(seq
.__getitem
__, xrange(len(seq
) - 1, -1, -1))
105 return ''.join(reversed(pickle
.encode_long(l
)))
108 return pickle
.decode_long(''.join(reversed(s
)))
114 raise ValueError('This function only supports positive integers')
116 bytes
= long_to_bytes(l
)
117 if ord(bytes
[0]) > 127:
118 return '\x00' + bytes
122 def binaryToLong(bytes
):
124 raise ValueError('Empty string passed to strToLong')
126 if ord(bytes
[0]) > 127:
127 raise ValueError('This function only supports positive integers')
129 return bytes_to_long(bytes
)
131 # A cryptographically safe source of random bytes
133 getBytes
= os
.urandom
134 except AttributeError:
136 from Crypto
.Util
.randpool
import RandomPool
138 # Fall back on /dev/urandom, if present. It would be nice to
139 # have Windows equivalent here, but for now, require pycrypto
142 _urandom
= file('/dev/urandom', 'rb')
144 raise ImportError('No adequate source of randomness found!')
149 chunk
= _urandom
.read(n
)
153 return ''.join(bytes
)
156 def getBytes(n
, pool
=_pool
):
159 return pool
.get_bytes(n
)
161 # A randrange function that works for longs
163 randrange
= random
.SystemRandom().randrange
164 except AttributeError:
165 # In Python 2.2's random.Random, randrange does not support
166 # numbers larger than sys.maxint for randrange. For simplicity,
167 # use this implementation for any Python that does not have
168 # random.SystemRandom
169 from math
import log
, ceil
171 _duplicate_cache
= {}
172 def randrange(start
, stop
=None, step
=1):
177 r
= (stop
- start
) // step
179 (duplicate
, nbytes
) = _duplicate_cache
[r
]
181 rbytes
= longToBinary(r
)
182 if rbytes
[0] == '\x00':
183 nbytes
= len(rbytes
) - 1
187 mxrand
= (256 ** nbytes
)
189 # If we get a number less than this, then it is in the
191 duplicate
= mxrand
% r
193 if len(_duplicate_cache
) > 10:
194 _duplicate_cache
.clear()
196 _duplicate_cache
[r
] = (duplicate
, nbytes
)
199 bytes
= '\x00' + getBytes(nbytes
)
200 n
= binaryToLong(bytes
)
201 # Keep looping if this value is in the low duplicated range
205 return start
+ (n
% r
) * step
208 return toBase64(longToBinary(l
))
211 return binaryToLong(fromBase64(s
))
213 def randomString(length
, chrs
=None):
214 """Produce a string of length random bytes, chosen from chrs."""
216 return getBytes(length
)
219 return ''.join([chrs
[randrange(n
)] for _
in xrange(length
)])