1 """Module containing a cryptographic-quality source of randomness and
2 other cryptographically useful functionality
3
4 Python 2.4 needs no external support for this module, nor does Python
5 2.3 on a system with /dev/urandom.
6
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:
12
13 http://www.amk.ca/python/code/crypto
14 """
15
16 __all__ = ['randrange', 'hmacSha1', 'sha1', 'randomString',
17 'binaryToLong', 'longToBinary', 'longToBase64', 'base64ToLong',
18 'hmacSha256', 'sha256']
19
20 import hmac
21 import os
22 import random
23
24 from openid.oidutil import toBase64, fromBase64
25
26 try:
27 import hashlib
28 except ImportError:
29 import sha as sha1_module
30
31 try:
32 from Crypto.Hash import SHA256 as sha256_module
33 except ImportError:
34 sha256_module = None
35
36 else:
39 self.new = hash_constructor
40
41 sha1_module = HashContainer(hashlib.sha1)
42 sha256_module = HashContainer(hashlib.sha256)
43
45 return hmac.new(key, text, sha1_module).digest()
46
48 return sha1_module.new(s).digest()
49
50 if sha256_module is not None:
52 return hmac.new(key, text, sha256_module).digest()
53
55 return sha256_module.new(s).digest()
56
57 SHA256_AVAILABLE = True
58
59 else:
60 _no_sha256 = NotImplementedError(
61 'Use Python 2.5, install pycrypto or install hashlib to use SHA256')
62
65
68
69 SHA256_AVAILABLE = False
70
71 try:
72 from Crypto.Util.number import long_to_bytes, bytes_to_long
73 except ImportError:
74 import pickle
75 try:
76
77
78
79 pickle.encode_long
80 pickle.decode_long
81 except AttributeError:
82 raise ImportError(
83 'No functionality for serializing long integers found')
84
85
86 try:
87 reversed
88 except NameError:
90 return map(seq.__getitem__, xrange(len(seq) - 1, -1, -1))
91
93 if l == 0:
94 return '\x00'
95
96 return ''.join(reversed(pickle.encode_long(l)))
97
99 return pickle.decode_long(''.join(reversed(s)))
100 else:
101
102
104 if l < 0:
105 raise ValueError('This function only supports positive integers')
106
107 bytes = long_to_bytes(l)
108 if ord(bytes[0]) > 127:
109 return '\x00' + bytes
110 else:
111 return bytes
112
114 if not bytes:
115 raise ValueError('Empty string passed to strToLong')
116
117 if ord(bytes[0]) > 127:
118 raise ValueError('This function only supports positive integers')
119
120 return bytes_to_long(bytes)
121
122
123 try:
124 getBytes = os.urandom
125 except AttributeError:
126 try:
127 from Crypto.Util.randpool import RandomPool
128 except ImportError:
129
130
131
132 try:
133 _urandom = file('/dev/urandom', 'rb')
134 except OSError:
135 raise ImportError('No adequate source of randomness found!')
136 else:
138 bytes = []
139 while n:
140 chunk = _urandom.read(n)
141 n -= len(chunk)
142 bytes.append(chunk)
143 assert n >= 0
144 return ''.join(bytes)
145 else:
146 _pool = RandomPool()
148 if pool.entropy < n:
149 pool.randomize()
150 return pool.get_bytes(n)
151
152
153 try:
154 randrange = random.SystemRandom().randrange
155 except AttributeError:
156
157
158
159
160 from math import log, ceil
161
162 _duplicate_cache = {}
164 if stop is None:
165 stop = start
166 start = 0
167
168 r = (stop - start) // step
169 try:
170 (duplicate, nbytes) = _duplicate_cache[r]
171 except KeyError:
172 rbytes = longToBinary(r)
173 if rbytes[0] == '\x00':
174 nbytes = len(rbytes) - 1
175 else:
176 nbytes = len(rbytes)
177
178 mxrand = (256 ** nbytes)
179
180
181
182 duplicate = mxrand % r
183
184 if len(_duplicate_cache) > 10:
185 _duplicate_cache.clear()
186
187 _duplicate_cache[r] = (duplicate, nbytes)
188
189 while 1:
190 bytes = '\x00' + getBytes(nbytes)
191 n = binaryToLong(bytes)
192
193 if n >= duplicate:
194 break
195
196 return start + (n % r) * step
197
200
203
205 """Produce a string of length random bytes, chosen from chrs."""
206 if chrs is None:
207 return getBytes(length)
208 else:
209 n = len(chrs)
210 return ''.join([chrs[randrange(n)] for _ in xrange(length)])
211