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