1
2
3
4
5
6
7
8 """cryptomath module
9
10 This module has basic math/crypto code."""
11 from __future__ import print_function
12 import os
13 import math
14 import base64
15 import binascii
16 import sys
17
18 from .poly1305 import Poly1305
19
20 from .compat import compat26Str, compatHMAC, compatLong
21
22
23
24
25
26
27
28 try:
29 from M2Crypto import m2
30 m2cryptoLoaded = True
31
32 try:
33 with open('/proc/sys/crypto/fips_enabled', 'r') as fipsFile:
34 if '1' in fipsFile.read():
35 m2cryptoLoaded = False
36 except (IOError, OSError):
37
38 m2cryptoLoaded = True
39
40 except ImportError:
41 m2cryptoLoaded = False
42
43
44 try:
45 import gmpy
46 gmpyLoaded = True
47 except ImportError:
48 gmpyLoaded = False
49
50
51 try:
52 import Crypto.Cipher.AES
53 pycryptoLoaded = True
54 except ImportError:
55 pycryptoLoaded = False
56
57
58
59
60
61
62
63 import zlib
64 assert len(zlib.compress(os.urandom(1000))) > 900
65
67 b = bytearray(os.urandom(howMany))
68 assert(len(b) == howMany)
69 return b
70
71 prngName = "os.urandom"
72
73
74
75
76
77 import hmac
78 from . import tlshashlib as hashlib
79
81 """Return a MD5 digest of data"""
82 return secureHash(b, 'md5')
83
85 """Return a SHA1 digest of data"""
86 return secureHash(b, 'sha1')
87
89 """Return a digest of `data` using `algorithm`"""
90 hashInstance = hashlib.new(algorithm)
91 hashInstance.update(compat26Str(data))
92 return bytearray(hashInstance.digest())
93
95 """Return a HMAC using `b` and `k` using `algorithm`"""
96 k = compatHMAC(k)
97 b = compatHMAC(b)
98 return bytearray(hmac.new(k, b, getattr(hashlib, algorithm)).digest())
99
102
105
108
111
113 N = Poly1305.divceil(L, getattr(hashlib, algorithm)().digest_size)
114 T = bytearray()
115 Titer = bytearray()
116 for x in range(1, N+2):
117 T += Titer
118 Titer = secureHMAC(PRK, Titer + info + bytearray([x]), algorithm)
119 return T[:L]
120
121
122
123
124
126 total = 0
127 multiplier = 1
128 for count in range(len(b)-1, -1, -1):
129 byte = b[count]
130 total += multiplier * byte
131 multiplier *= 256
132 return total
133
135 """Convert an integer into a bytearray, zero-pad to howManyBytes.
136
137 The returned bytearray may be smaller than howManyBytes, but will
138 not be larger. The returned bytearray will contain a big-endian
139 encoding of the input integer (n).
140 """
141 if howManyBytes == None:
142 howManyBytes = numBytes(n)
143 b = bytearray(howManyBytes)
144 for count in range(howManyBytes-1, -1, -1):
145 b[count] = int(n % 256)
146 n >>= 8
147 return b
148
150 if (ord(mpi[4]) & 0x80) !=0:
151 raise AssertionError()
152 b = bytearray(mpi[4:])
153 return bytesToNumber(b)
154
156 b = numberToByteArray(n)
157 ext = 0
158
159
160 if (numBits(n) & 0x7)==0:
161 ext = 1
162 length = numBytes(n) + ext
163 b = bytearray(4+ext) + b
164 b[0] = (length >> 24) & 0xFF
165 b[1] = (length >> 16) & 0xFF
166 b[2] = (length >> 8) & 0xFF
167 b[3] = length & 0xFF
168 return bytes(b)
169
170
171
172
173
174
176 """Return number of bits necessary to represent the integer in binary"""
177 if n==0:
178 return 0
179 if sys.version_info < (2, 7):
180
181
182 return len(bin(n))-2
183 else:
184 return n.bit_length()
185
187 """Return number of bytes necessary to represent the integer in bytes"""
188 if n==0:
189 return 0
190 bits = numBits(n)
191 return (bits + 7) // 8
192
193
194
195
196
198 if low >= high:
199 raise AssertionError()
200 howManyBits = numBits(high)
201 howManyBytes = numBytes(high)
202 lastBits = howManyBits % 8
203 while 1:
204 bytes = getRandomBytes(howManyBytes)
205 if lastBits:
206 bytes[0] = bytes[0] % (1 << lastBits)
207 n = bytesToNumber(bytes)
208 if n >= low and n < high:
209 return n
210
212 a, b = max(a,b), min(a,b)
213 while b:
214 a, b = b, a % b
215 return a
216
218 return (a * b) // gcd(a, b)
219
220
221
223 c, d = a, b
224 uc, ud = 1, 0
225 while c != 0:
226 q = d // c
227 c, d = d-(q*c), c
228 uc, ud = ud - (q * uc), uc
229 if d == 1:
230 return ud % b
231 return 0
232
233
234 if gmpyLoaded:
235 - def powMod(base, power, modulus):
236 base = gmpy.mpz(base)
237 power = gmpy.mpz(power)
238 modulus = gmpy.mpz(modulus)
239 result = pow(base, power, modulus)
240 return compatLong(result)
241
242 else:
243 - def powMod(base, power, modulus):
244 if power < 0:
245 result = pow(base, power*-1, modulus)
246 result = invMod(result, modulus)
247 return result
248 else:
249 return pow(base, power, modulus)
250
251
253 sieve = list(range(n))
254 for count in range(2, int(math.sqrt(n))+1):
255 if sieve[count] == 0:
256 continue
257 x = sieve[count] * 2
258 while x < len(sieve):
259 sieve[x] = 0
260 x += sieve[count]
261 sieve = [x for x in sieve[2:] if x]
262 return sieve
263
265
266 for x in sieve:
267 if x >= n: return True
268 if n % x == 0: return False
269
270
271
272 if display: print("*", end=' ')
273 s, t = n-1, 0
274 while s % 2 == 0:
275 s, t = s//2, t+1
276
277 a = 2
278 for count in range(iterations):
279 v = powMod(a, s, n)
280 if v==1:
281 continue
282 i = 0
283 while v != n-1:
284 if i == t-1:
285 return False
286 else:
287 v, i = powMod(v, 2, n), i+1
288 a = getRandomNumber(2, n)
289 return True
290
292 if bits < 10:
293 raise AssertionError()
294
295
296
297
298
299 low = ((2 ** (bits-1)) * 3) // 2
300 high = 2 ** bits - 30
301 p = getRandomNumber(low, high)
302 p += 29 - (p % 30)
303 while 1:
304 if display: print(".", end=' ')
305 p += 30
306 if p >= high:
307 p = getRandomNumber(low, high)
308 p += 29 - (p % 30)
309 if isPrime(p, display=display):
310 return p
311
312
314 if bits < 10:
315 raise AssertionError()
316
317
318
319
320
321 low = (2 ** (bits-2)) * 3//2
322 high = (2 ** (bits-1)) - 30
323 q = getRandomNumber(low, high)
324 q += 29 - (q % 30)
325 while 1:
326 if display: print(".", end=' ')
327 q += 30
328 if (q >= high):
329 q = getRandomNumber(low, high)
330 q += 29 - (q % 30)
331
332
333 if isPrime(q, 0, display=display):
334 p = (2 * q) + 1
335 if isPrime(p, display=display):
336 if isPrime(q, display=display):
337 return p
338