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 .poly1305 import Poly1305 
 19   
 20  from .compat import compat26Str, compatHMAC, compatLong 
 21   
 22   
 23  # ************************************************************************** 
 24  # Load Optional Modules 
 25  # ************************************************************************** 
 26   
 27  # Try to load M2Crypto/OpenSSL 
 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          # looks like we're running in container, likely not FIPS mode 
 38          m2cryptoLoaded = True 
 39   
 40  except ImportError: 
 41      m2cryptoLoaded = False 
 42   
 43  #Try to load GMPY 
 44  try: 
 45      import gmpy 
 46      gmpyLoaded = True 
 47  except ImportError: 
 48      gmpyLoaded = False 
 49   
 50  #Try to load pycrypto 
 51  try: 
 52      import Crypto.Cipher.AES 
 53      pycryptoLoaded = True 
 54  except ImportError: 
 55      pycryptoLoaded = False 
 56   
 57   
 58  # ************************************************************************** 
 59  # PRNG Functions 
 60  # ************************************************************************** 
 61   
 62  # Check that os.urandom works 
 63  import zlib 
 64  assert len(zlib.compress(os.urandom(1000))) > 900 
 65   
66 -def getRandomBytes(howMany):
67 b = bytearray(os.urandom(howMany)) 68 assert(len(b) == howMany) 69 return b
70 71 prngName = "os.urandom" 72 73 # ************************************************************************** 74 # Simple hash functions 75 # ************************************************************************** 76 77 import hmac 78 from . import tlshashlib as hashlib 79
80 -def MD5(b):
81 """Return a MD5 digest of data""" 82 return secureHash(b, 'md5')
83
84 -def SHA1(b):
85 """Return a SHA1 digest of data""" 86 return secureHash(b, 'sha1')
87
88 -def secureHash(data, algorithm):
89 """Return a digest of `data` using `algorithm`""" 90 hashInstance = hashlib.new(algorithm) 91 hashInstance.update(compat26Str(data)) 92 return bytearray(hashInstance.digest())
93
94 -def secureHMAC(k, b, algorithm):
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
100 -def HMAC_MD5(k, b):
101 return secureHMAC(k, b, 'md5')
102
103 -def HMAC_SHA1(k, b):
104 return secureHMAC(k, b, 'sha1')
105
106 -def HMAC_SHA256(k, b):
107 return secureHMAC(k, b, 'sha256')
108
109 -def HMAC_SHA384(k, b):
110 return secureHMAC(k, b, 'sha384')
111
112 -def HKDF_expand(PRK, info, L, algorithm):
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 # Converter Functions 123 # ************************************************************************** 124
125 -def bytesToNumber(b):
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
134 -def numberToByteArray(n, howManyBytes=None):
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
149 -def mpiToNumber(mpi): #mpi is an openssl-format bignum string
150 if (ord(mpi[4]) & 0x80) !=0: #Make sure this is a positive number 151 raise AssertionError() 152 b = bytearray(mpi[4:]) 153 return bytesToNumber(b) 154
155 -def numberToMPI(n):
156 b = numberToByteArray(n) 157 ext = 0 158 #If the high-order bit is going to be set, 159 #add an extra byte of zeros 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 # Misc. Utility Functions 173 # ************************************************************************** 174
175 -def numBits(n):
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 # bit_length() was introduced in 2.7, and it is an order of magnitude 181 # faster than the below code 182 return len(bin(n))-2 183 else: 184 return n.bit_length()
185
186 -def numBytes(n):
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 # Big Number Math 195 # ************************************************************************** 196
197 -def getRandomNumber(low, high):
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
211 -def gcd(a,b):
212 a, b = max(a,b), min(a,b) 213 while b: 214 a, b = b, a % b 215 return a
216
217 -def lcm(a, b):
218 return (a * b) // gcd(a, b)
219 220 #Returns inverse of a mod b, zero if none 221 #Uses Extended Euclidean Algorithm
222 -def invMod(a, b):
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 #Pre-calculate a sieve of the ~100 primes < 1000:
252 -def makeSieve(n):
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
264 -def isPrime(n, iterations=5, display=False, sieve=makeSieve(1000)):
265 #Trial division with sieve 266 for x in sieve: 267 if x >= n: return True 268 if n % x == 0: return False 269 #Passed trial division, proceed to Rabin-Miller 270 #Rabin-Miller implemented per Ferguson & Schneier 271 #Compute s, t for Rabin-Miller 272 if display: print("*", end=' ') 273 s, t = n-1, 0 274 while s % 2 == 0: 275 s, t = s//2, t+1 276 #Repeat Rabin-Miller x times 277 a = 2 #Use 2 as a base for first iteration speedup, per HAC 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
291 -def getRandomPrime(bits, display=False):
292 if bits < 10: 293 raise AssertionError() 294 #The 1.5 ensures the 2 MSBs are set 295 #Thus, when used for p,q in RSA, n will have its MSB set 296 # 297 #Since 30 is lcm(2,3,5), we'll set our test numbers to 298 #29 % 30 and keep them there 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 #Unused at the moment...
313 -def getRandomSafePrime(bits, display=False):
314 if bits < 10: 315 raise AssertionError() 316 #The 1.5 ensures the 2 MSBs are set 317 #Thus, when used for p,q in RSA, n will have its MSB set 318 # 319 #Since 30 is lcm(2,3,5), we'll set our test numbers to 320 #29 % 30 and keep them there 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 #Ideas from Tom Wu's SRP code 332 #Do trial division on p and q before Rabin-Miller 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