Package dns :: Module entropy
[hide private]
[frames] | no frames]

Source Code for Module dns.entropy

  1  # Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license 
  2   
  3  # Copyright (C) 2009-2017 Nominum, Inc. 
  4  # 
  5  # Permission to use, copy, modify, and distribute this software and its 
  6  # documentation for any purpose with or without fee is hereby granted, 
  7  # provided that the above copyright notice and this permission notice 
  8  # appear in all copies. 
  9  # 
 10  # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES 
 11  # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 
 12  # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR 
 13  # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 
 14  # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
 15  # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 
 16  # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
 17   
 18  import os 
 19  import random 
 20  import time 
 21  from ._compat import long, binary_type 
 22  try: 
 23      import threading as _threading 
 24  except ImportError: 
 25      import dummy_threading as _threading 
 26   
 27   
28 -class EntropyPool(object):
29 30 # This is an entropy pool for Python implementations that do not 31 # have a working SystemRandom. I'm not sure there are any, but 32 # leaving this code doesn't hurt anything as the library code 33 # is used if present. 34
35 - def __init__(self, seed=None):
36 self.pool_index = 0 37 self.digest = None 38 self.next_byte = 0 39 self.lock = _threading.Lock() 40 try: 41 import hashlib 42 self.hash = hashlib.sha1() 43 self.hash_len = 20 44 except ImportError: 45 try: 46 import sha 47 self.hash = sha.new() 48 self.hash_len = 20 49 except ImportError: 50 import md5 # pylint: disable=import-error 51 self.hash = md5.new() 52 self.hash_len = 16 53 self.pool = bytearray(b'\0' * self.hash_len) 54 if seed is not None: 55 self.stir(bytearray(seed)) 56 self.seeded = True 57 self.seed_pid = os.getpid() 58 else: 59 self.seeded = False 60 self.seed_pid = 0
61
62 - def stir(self, entropy, already_locked=False):
63 if not already_locked: 64 self.lock.acquire() 65 try: 66 for c in entropy: 67 if self.pool_index == self.hash_len: 68 self.pool_index = 0 69 b = c & 0xff 70 self.pool[self.pool_index] ^= b 71 self.pool_index += 1 72 finally: 73 if not already_locked: 74 self.lock.release()
75
76 - def _maybe_seed(self):
77 if not self.seeded or self.seed_pid != os.getpid(): 78 try: 79 seed = os.urandom(16) 80 except Exception: 81 try: 82 r = open('/dev/urandom', 'rb', 0) 83 try: 84 seed = r.read(16) 85 finally: 86 r.close() 87 except Exception: 88 seed = str(time.time()) 89 self.seeded = True 90 self.seed_pid = os.getpid() 91 self.digest = None 92 seed = bytearray(seed) 93 self.stir(seed, True)
94
95 - def random_8(self):
96 self.lock.acquire() 97 try: 98 self._maybe_seed() 99 if self.digest is None or self.next_byte == self.hash_len: 100 self.hash.update(binary_type(self.pool)) 101 self.digest = bytearray(self.hash.digest()) 102 self.stir(self.digest, True) 103 self.next_byte = 0 104 value = self.digest[self.next_byte] 105 self.next_byte += 1 106 finally: 107 self.lock.release() 108 return value
109
110 - def random_16(self):
111 return self.random_8() * 256 + self.random_8()
112
113 - def random_32(self):
114 return self.random_16() * 65536 + self.random_16()
115
116 - def random_between(self, first, last):
117 size = last - first + 1 118 if size > long(4294967296): 119 raise ValueError('too big') 120 if size > 65536: 121 rand = self.random_32 122 max = long(4294967295) 123 elif size > 256: 124 rand = self.random_16 125 max = 65535 126 else: 127 rand = self.random_8 128 max = 255 129 return first + size * rand() // (max + 1)
130 131 pool = EntropyPool() 132 133 try: 134 system_random = random.SystemRandom() 135 except Exception: 136 system_random = None 137
138 -def random_16():
139 if system_random is not None: 140 return system_random.randrange(0, 65536) 141 else: 142 return pool.random_16()
143
144 -def between(first, last):
145 if system_random is not None: 146 return system_random.randrange(first, last + 1) 147 else: 148 return pool.random_between(first, last)
149