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  try: 
 19      import threading as _threading 
 20  except ImportError: 
 21      import dummy_threading as _threading 
 22   
23 -class EntropyPool(object):
24 - def __init__(self, seed=None):
25 self.pool_index = 0 26 self.digest = None 27 self.next_byte = 0 28 self.lock = _threading.Lock() 29 try: 30 import hashlib 31 self.hash = hashlib.sha1() 32 self.hash_len = 20 33 except: 34 try: 35 import sha 36 self.hash = sha.new() 37 self.hash_len = 20 38 except: 39 import md5 40 self.hash = md5.new() 41 self.hash_len = 16 42 self.pool = bytearray(self.hash_len) 43 if not seed is None: 44 self.stir(seed) 45 self.seeded = True 46 else: 47 self.seeded = False
48
49 - def stir(self, entropy, already_locked=False):
50 if not already_locked: 51 self.lock.acquire() 52 try: 53 for c in entropy: 54 if self.pool_index == self.hash_len: 55 self.pool_index = 0 56 self.pool[self.pool_index] ^= c 57 self.pool_index += 1 58 finally: 59 if not already_locked: 60 self.lock.release()
61
62 - def _maybe_seed(self):
63 if not self.seeded: 64 try: 65 seed = os.urandom(16) 66 except: 67 try: 68 r = open('/dev/urandom', 'rb', 0) 69 try: 70 seed = r.read(16) 71 finally: 72 r.close() 73 except: 74 seed = str(time.time()).encode('utf-8') 75 self.seeded = True 76 self.stir(seed, True)
77
78 - def random_8(self):
79 self.lock.acquire() 80 self._maybe_seed() 81 try: 82 if self.digest is None or self.next_byte == self.hash_len: 83 self.hash.update(self.pool) 84 self.digest = self.hash.digest() 85 self.stir(self.digest, True) 86 self.next_byte = 0 87 value = self.digest[self.next_byte] 88 self.next_byte += 1 89 finally: 90 self.lock.release() 91 return value
92
93 - def random_16(self):
94 return self.random_8() * 256 + self.random_8()
95
96 - def random_32(self):
97 return self.random_16() * 65536 + self.random_16()
98
99 - def random_between(self, first, last):
100 size = last - first + 1 101 if size > 4294967296: 102 raise ValueError('too big') 103 if size > 65536: 104 rand = self.random_32 105 max = 4294967295 106 elif size > 256: 107 rand = self.random_16 108 max = 65535 109 else: 110 rand = self.random_8 111 max = 255 112 return (first + size * rand() // (max + 1))
113 114 pool = EntropyPool() 115
116 -def random_16():
117 return pool.random_16()
118
119 -def between(first, last):
120 return pool.random_between(first, last)
121