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

Source Code for Module dns.entropy

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