Package tlslite :: Package utils :: Module cryptomath
[hide private]
[frames] | no frames]

Source Code for Module tlslite.utils.cryptomath

  1  # Authors:  
  2  #   Trevor Perrin 
  3  #   Martin von Loewis - python 3 port 
  4  # 
  5  # See the LICENSE file for legal information regarding use of this file. 
  6   
  7  """cryptomath module 
  8   
  9  This module has basic math/crypto code.""" 
 10  from __future__ import print_function 
 11  import os 
 12  import math 
 13  import base64 
 14  import binascii 
 15   
 16  from .compat import * 
 17   
 18   
 19  # ************************************************************************** 
 20  # Load Optional Modules 
 21  # ************************************************************************** 
 22   
 23  # Try to load M2Crypto/OpenSSL 
 24  try: 
 25      from M2Crypto import m2 
 26      m2cryptoLoaded = True 
 27   
 28  except ImportError: 
 29      m2cryptoLoaded = False 
 30   
 31  #Try to load GMPY 
 32  try: 
 33      import gmpy 
 34      gmpyLoaded = True 
 35  except ImportError: 
 36      gmpyLoaded = False 
 37   
 38  #Try to load pycrypto 
 39  try: 
 40      import Crypto.Cipher.AES 
 41      pycryptoLoaded = True 
 42  except ImportError: 
 43      pycryptoLoaded = False 
 44   
 45   
 46  # ************************************************************************** 
 47  # PRNG Functions 
 48  # ************************************************************************** 
 49   
 50  # Check that os.urandom works 
 51  import zlib 
 52  length = len(zlib.compress(os.urandom(1000))) 
 53  assert(length > 900) 
 54   
55 -def getRandomBytes(howMany):
56 b = bytearray(os.urandom(howMany)) 57 assert(len(b) == howMany) 58 return b
59 60 prngName = "os.urandom" 61 62 # ************************************************************************** 63 # Simple hash functions 64 # ************************************************************************** 65 66 import hmac 67 import hashlib 68
69 -def MD5(b):
70 return bytearray(hashlib.md5(compat26Str(b)).digest())
71
72 -def SHA1(b):
73 return bytearray(hashlib.sha1(compat26Str(b)).digest())
74
75 -def HMAC_MD5(k, b):
76 k = compatHMAC(k) 77 b = compatHMAC(b) 78 return bytearray(hmac.new(k, b, hashlib.md5).digest())
79
80 -def HMAC_SHA1(k, b):
81 k = compatHMAC(k) 82 b = compatHMAC(b) 83 return bytearray(hmac.new(k, b, hashlib.sha1).digest())
84
85 -def HMAC_SHA256(k, b):
86 k = compatHMAC(k) 87 b = compatHMAC(b) 88 return bytearray(hmac.new(k, b, hashlib.sha256).digest())
89 90 # ************************************************************************** 91 # Converter Functions 92 # ************************************************************************** 93
94 -def bytesToNumber(b):
95 total = 0 96 multiplier = 1 97 for count in range(len(b)-1, -1, -1): 98 byte = b[count] 99 total += multiplier * byte 100 multiplier *= 256 101 return total
102
103 -def numberToByteArray(n, howManyBytes=None):
104 """Convert an integer into a bytearray, zero-pad to howManyBytes. 105 106 The returned bytearray may be smaller than howManyBytes, but will 107 not be larger. The returned bytearray will contain a big-endian 108 encoding of the input integer (n). 109 """ 110 if howManyBytes == None: 111 howManyBytes = numBytes(n) 112 b = bytearray(howManyBytes) 113 for count in range(howManyBytes-1, -1, -1): 114 b[count] = int(n % 256) 115 n >>= 8 116 return b
117
118 -def mpiToNumber(mpi): #mpi is an openssl-format bignum string
119 if (ord(mpi[4]) & 0x80) !=0: #Make sure this is a positive number 120 raise AssertionError() 121 b = bytearray(mpi[4:]) 122 return bytesToNumber(b) 123
124 -def numberToMPI(n):
125 b = numberToByteArray(n) 126 ext = 0 127 #If the high-order bit is going to be set, 128 #add an extra byte of zeros 129 if (numBits(n) & 0x7)==0: 130 ext = 1 131 length = numBytes(n) + ext 132 b = bytearray(4+ext) + b 133 b[0] = (length >> 24) & 0xFF 134 b[1] = (length >> 16) & 0xFF 135 b[2] = (length >> 8) & 0xFF 136 b[3] = length & 0xFF 137 return bytes(b)
138 139 140 # ************************************************************************** 141 # Misc. Utility Functions 142 # ************************************************************************** 143
144 -def numBits(n):
145 if n==0: 146 return 0 147 s = "%x" % n 148 return ((len(s)-1)*4) + \ 149 {'0':0, '1':1, '2':2, '3':2, 150 '4':3, '5':3, '6':3, '7':3, 151 '8':4, '9':4, 'a':4, 'b':4, 152 'c':4, 'd':4, 'e':4, 'f':4, 153 }[s[0]] 154 return int(math.floor(math.log(n, 2))+1)
155
156 -def numBytes(n):
157 if n==0: 158 return 0 159 bits = numBits(n) 160 return int(math.ceil(bits / 8.0))
161 162 # ************************************************************************** 163 # Big Number Math 164 # ************************************************************************** 165
166 -def getRandomNumber(low, high):
167 if low >= high: 168 raise AssertionError() 169 howManyBits = numBits(high) 170 howManyBytes = numBytes(high) 171 lastBits = howManyBits % 8 172 while 1: 173 bytes = getRandomBytes(howManyBytes) 174 if lastBits: 175 bytes[0] = bytes[0] % (1 << lastBits) 176 n = bytesToNumber(bytes) 177 if n >= low and n < high: 178 return n
179
180 -def gcd(a,b):
181 a, b = max(a,b), min(a,b) 182 while b: 183 a, b = b, a % b 184 return a
185
186 -def lcm(a, b):
187 return (a * b) // gcd(a, b)
188 189 #Returns inverse of a mod b, zero if none 190 #Uses Extended Euclidean Algorithm
191 -def invMod(a, b):
192 c, d = a, b 193 uc, ud = 1, 0 194 while c != 0: 195 q = d // c 196 c, d = d-(q*c), c 197 uc, ud = ud - (q * uc), uc 198 if d == 1: 199 return ud % b 200 return 0
201 202 203 if gmpyLoaded:
204 - def powMod(base, power, modulus):
205 base = gmpy.mpz(base) 206 power = gmpy.mpz(power) 207 modulus = gmpy.mpz(modulus) 208 result = pow(base, power, modulus) 209 return long(result)
210 211 else:
212 - def powMod(base, power, modulus):
213 if power < 0: 214 result = pow(base, power*-1, modulus) 215 result = invMod(result, modulus) 216 return result 217 else: 218 return pow(base, power, modulus)
219 220 #Pre-calculate a sieve of the ~100 primes < 1000:
221 -def makeSieve(n):
222 sieve = list(range(n)) 223 for count in range(2, int(math.sqrt(n))+1): 224 if sieve[count] == 0: 225 continue 226 x = sieve[count] * 2 227 while x < len(sieve): 228 sieve[x] = 0 229 x += sieve[count] 230 sieve = [x for x in sieve[2:] if x] 231 return sieve
232 233 sieve = makeSieve(1000) 234
235 -def isPrime(n, iterations=5, display=False):
236 #Trial division with sieve 237 for x in sieve: 238 if x >= n: return True 239 if n % x == 0: return False 240 #Passed trial division, proceed to Rabin-Miller 241 #Rabin-Miller implemented per Ferguson & Schneier 242 #Compute s, t for Rabin-Miller 243 if display: print("*", end=' ') 244 s, t = n-1, 0 245 while s % 2 == 0: 246 s, t = s//2, t+1 247 #Repeat Rabin-Miller x times 248 a = 2 #Use 2 as a base for first iteration speedup, per HAC 249 for count in range(iterations): 250 v = powMod(a, s, n) 251 if v==1: 252 continue 253 i = 0 254 while v != n-1: 255 if i == t-1: 256 return False 257 else: 258 v, i = powMod(v, 2, n), i+1 259 a = getRandomNumber(2, n) 260 return True
261
262 -def getRandomPrime(bits, display=False):
263 if bits < 10: 264 raise AssertionError() 265 #The 1.5 ensures the 2 MSBs are set 266 #Thus, when used for p,q in RSA, n will have its MSB set 267 # 268 #Since 30 is lcm(2,3,5), we'll set our test numbers to 269 #29 % 30 and keep them there 270 low = ((2 ** (bits-1)) * 3) // 2 271 high = 2 ** bits - 30 272 p = getRandomNumber(low, high) 273 p += 29 - (p % 30) 274 while 1: 275 if display: print(".", end=' ') 276 p += 30 277 if p >= high: 278 p = getRandomNumber(low, high) 279 p += 29 - (p % 30) 280 if isPrime(p, display=display): 281 return p
282 283 #Unused at the moment...
284 -def getRandomSafePrime(bits, display=False):
285 if bits < 10: 286 raise AssertionError() 287 #The 1.5 ensures the 2 MSBs are set 288 #Thus, when used for p,q in RSA, n will have its MSB set 289 # 290 #Since 30 is lcm(2,3,5), we'll set our test numbers to 291 #29 % 30 and keep them there 292 low = (2 ** (bits-2)) * 3//2 293 high = (2 ** (bits-1)) - 30 294 q = getRandomNumber(low, high) 295 q += 29 - (q % 30) 296 while 1: 297 if display: print(".", end=' ') 298 q += 30 299 if (q >= high): 300 q = getRandomNumber(low, high) 301 q += 29 - (q % 30) 302 #Ideas from Tom Wu's SRP code 303 #Do trial division on p and q before Rabin-Miller 304 if isPrime(q, 0, display=display): 305 p = (2 * q) + 1 306 if isPrime(p, display=display): 307 if isPrime(q, display=display): 308 return p
309