home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / var / lib / python-support / python2.6 / gdata / Crypto / Util / randpool.pyc (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2009-04-20  |  13.8 KB  |  432 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.6)
  3.  
  4. __revision__ = '$Id: randpool.py,v 1.14 2004/05/06 12:56:54 akuchling Exp $'
  5. import time
  6. import array
  7. import types
  8. import warnings
  9. import os.path as os
  10. from Crypto.Util.number import long_to_bytes
  11.  
  12. try:
  13.     import Crypto.Util.winrandom as winrandom
  14. except:
  15.     winrandom = None
  16.  
  17. STIRNUM = 3
  18.  
  19. class RandomPool:
  20.     '''randpool.py : Cryptographically strong random number generation.
  21.  
  22.     The implementation here is similar to the one in PGP.  To be
  23.     cryptographically strong, it must be difficult to determine the RNG\'s
  24.     output, whether in the future or the past.  This is done by using
  25.     a cryptographic hash function to "stir" the random data.
  26.  
  27.     Entropy is gathered in the same fashion as PGP; the highest-resolution
  28.     clock around is read and the data is added to the random number pool.
  29.     A conservative estimate of the entropy is then kept.
  30.  
  31.     If a cryptographically secure random source is available (/dev/urandom
  32.     on many Unixes, Windows CryptGenRandom on most Windows), then use
  33.     it.
  34.  
  35.     Instance Attributes:
  36.     bits : int
  37.       Maximum size of pool in bits
  38.     bytes : int
  39.       Maximum size of pool in bytes
  40.     entropy : int
  41.       Number of bits of entropy in this pool.
  42.  
  43.     Methods:
  44.     add_event([s]) : add some entropy to the pool
  45.     get_bytes(int) : get N bytes of random data
  46.     randomize([N]) : get N bytes of randomness from external source
  47.     '''
  48.     
  49.     def __init__(self, numbytes = 160, cipher = None, hash = None):
  50.         if hash is None:
  51.             hash = SHA
  52.             import Crypto.Hash
  53.         
  54.         if cipher is not None:
  55.             warnings.warn("'cipher' parameter is no longer used")
  56.         
  57.         if isinstance(hash, types.StringType):
  58.             hash = __import__('Crypto.Hash.' + hash, None, None, [
  59.                 'new'])
  60.             warnings.warn("'hash' parameter should now be a hashing module")
  61.         
  62.         self.bytes = numbytes
  63.         self.bits = self.bytes * 8
  64.         self.entropy = 0
  65.         self._hash = hash
  66.         self._randpool = array.array('B', [
  67.             0] * self.bytes)
  68.         self._event1 = self._event2 = 0
  69.         self._addPos = 0
  70.         self._getPos = hash.digest_size
  71.         self._lastcounter = time.time()
  72.         self._RandomPool__counter = 0
  73.         self._measureTickSize()
  74.         self._randomize()
  75.  
  76.     
  77.     def _updateEntropyEstimate(self, nbits):
  78.         self.entropy += nbits
  79.         if self.entropy < 0:
  80.             self.entropy = 0
  81.         elif self.entropy > self.bits:
  82.             self.entropy = self.bits
  83.         
  84.  
  85.     
  86.     def _randomize(self, N = 0, devname = '/dev/urandom'):
  87.         '''_randomize(N, DEVNAME:device-filepath)
  88.         collects N bits of randomness from some entropy source (e.g.,
  89.         /dev/urandom on Unixes that have it, Windows CryptoAPI
  90.         CryptGenRandom, etc)
  91.         DEVNAME is optional, defaults to /dev/urandom.  You can change it
  92.         to /dev/random if you want to block till you get enough
  93.         entropy.
  94.         '''
  95.         data = ''
  96.         if N <= 0:
  97.             nbytes = int((self.bits - self.entropy) / 8 + 0.5)
  98.         else:
  99.             nbytes = int(N / 8 + 0.5)
  100.         if winrandom:
  101.             data = winrandom.new().get_bytes(nbytes)
  102.         elif os.path.exists(devname):
  103.             
  104.             try:
  105.                 f = open(devname)
  106.                 data = f.read(nbytes)
  107.                 f.close()
  108.             except IOError:
  109.                 (num, msg) = None
  110.                 if num != 2:
  111.                     raise IOError, (num, msg)
  112.                 num != 2
  113.             except:
  114.                 None<EXCEPTION MATCH>IOError
  115.             
  116.  
  117.         None<EXCEPTION MATCH>IOError
  118.         if data:
  119.             self._addBytes(data)
  120.             self._updateEntropyEstimate(8 * len(data))
  121.         
  122.         self.stir_n()
  123.  
  124.     
  125.     def randomize(self, N = 0):
  126.         '''randomize(N:int)
  127.         use the class entropy source to get some entropy data.
  128.         This is overridden by KeyboardRandomize().
  129.         '''
  130.         return self._randomize(N)
  131.  
  132.     
  133.     def stir_n(self, N = STIRNUM):
  134.         '''stir_n(N)
  135.         stirs the random pool N times
  136.         '''
  137.         for i in xrange(N):
  138.             self.stir()
  139.         
  140.  
  141.     
  142.     def stir(self, s = ''):
  143.         """stir(s:string)
  144.         Mix up the randomness pool.  This will call add_event() twice,
  145.         but out of paranoia the entropy attribute will not be
  146.         increased.  The optional 's' parameter is a string that will
  147.         be hashed with the randomness pool.
  148.         """
  149.         entropy = self.entropy
  150.         self.add_event()
  151.         for i in range(self.bytes / self._hash.digest_size):
  152.             h = self._hash.new(self._randpool)
  153.             h.update(str(self._RandomPool__counter) + str(i) + str(self._addPos) + s)
  154.             self._addBytes(h.digest())
  155.             self._RandomPool__counter = self._RandomPool__counter + 1 & 0xFFFFFFFFL
  156.         
  157.         self._addPos = 0
  158.         self._getPos = self._hash.digest_size
  159.         self.add_event()
  160.         self.entropy = entropy
  161.  
  162.     
  163.     def get_bytes(self, N):
  164.         '''get_bytes(N:int) : string
  165.         Return N bytes of random data.
  166.         '''
  167.         s = ''
  168.         i = self._getPos
  169.         pool = self._randpool
  170.         h = self._hash.new()
  171.         dsize = self._hash.digest_size
  172.         num = N
  173.         while num > 0:
  174.             h.update(self._randpool[i:i + dsize])
  175.             s = s + h.digest()
  176.             num = num - dsize
  177.             i = (i + dsize) % self.bytes
  178.             if i < dsize:
  179.                 self.stir()
  180.                 i = self._getPos
  181.                 continue
  182.         self._getPos = i
  183.         self._updateEntropyEstimate(-8 * N)
  184.         return s[:N]
  185.  
  186.     
  187.     def add_event(self, s = ''):
  188.         """add_event(s:string)
  189.         Add an event to the random pool.  The current time is stored
  190.         between calls and used to estimate the entropy.  The optional
  191.         's' parameter is a string that will also be XORed into the pool.
  192.         Returns the estimated number of additional bits of entropy gain.
  193.         """
  194.         event = time.time() * 1000
  195.         delta = self._noise()
  196.         s = s + long_to_bytes(event) + 4 * chr(170) + long_to_bytes(delta)
  197.         self._addBytes(s)
  198.         if event == self._event1 and event == self._event2:
  199.             bits = 0
  200.         else:
  201.             bits = 0
  202.             while delta:
  203.                 delta = delta >> 1
  204.                 bits = bits + 1
  205.             if bits > 8:
  206.                 bits = 8
  207.             
  208.         self._event1 = event
  209.         self._event2 = self._event1
  210.         self._updateEntropyEstimate(bits)
  211.         return bits
  212.  
  213.     
  214.     def _noise(self):
  215.         t = time.time()
  216.         delta = ((t - self._lastcounter) / self._ticksize) * 1e+06
  217.         self._lastcounter = t
  218.         self._addBytes(long_to_bytes(long(1000 * time.time())))
  219.         self._addBytes(long_to_bytes(long(1000 * time.clock())))
  220.         self._addBytes(long_to_bytes(long(1000 * time.time())))
  221.         self._addBytes(long_to_bytes(long(delta)))
  222.         delta = delta % 255
  223.         return int(delta)
  224.  
  225.     
  226.     def _measureTickSize(self):
  227.         interval = [
  228.             None] * 100
  229.         h = self._hash.new(`(id(self), id(interval))`)
  230.         t = time.time()
  231.         h.update(`t`)
  232.         i = 0
  233.         j = 0
  234.         while i < 100:
  235.             t2 = time.time()
  236.             h.update(`(i, j, t2)`)
  237.             j += 1
  238.             delta = int((t2 - t) * 1e+06)
  239.             if delta:
  240.                 interval[i] = delta
  241.                 i += 1
  242.                 t = t2
  243.                 continue
  244.         interval.sort()
  245.         self._ticksize = interval[len(interval) / 2]
  246.         h.update(`(interval, self._ticksize)`)
  247.         self.stir(h.digest())
  248.  
  249.     
  250.     def _addBytes(self, s):
  251.         '''XOR the contents of the string S into the random pool'''
  252.         i = self._addPos
  253.         pool = self._randpool
  254.         for j in range(0, len(s)):
  255.             pool[i] = pool[i] ^ ord(s[j])
  256.             i = (i + 1) % self.bytes
  257.         
  258.         self._addPos = i
  259.  
  260.     
  261.     def getBytes(self, N):
  262.         warnings.warn('getBytes() method replaced by get_bytes()', DeprecationWarning)
  263.         return self.get_bytes(N)
  264.  
  265.     
  266.     def addEvent(self, event, s = ''):
  267.         warnings.warn('addEvent() method replaced by add_event()', DeprecationWarning)
  268.         return self.add_event(s + str(event))
  269.  
  270.  
  271.  
  272. class PersistentRandomPool(RandomPool):
  273.     
  274.     def __init__(self, filename = None, *args, **kwargs):
  275.         RandomPool.__init__(self, *args, **kwargs)
  276.         self.filename = filename
  277.         if filename:
  278.             
  279.             try:
  280.                 f = open(filename, 'rb')
  281.                 self.add_event()
  282.                 data = f.read()
  283.                 self.add_event()
  284.                 self.stir(data)
  285.                 f.close()
  286.             except IOError:
  287.                 pass
  288.             except:
  289.                 None<EXCEPTION MATCH>IOError
  290.             
  291.  
  292.         None<EXCEPTION MATCH>IOError
  293.  
  294.     
  295.     def save(self):
  296.         if self.filename == '':
  297.             raise ValueError, 'No filename set for this object'
  298.         self.filename == ''
  299.         self.stir_n()
  300.         f = open(self.filename, 'wb')
  301.         self.add_event()
  302.         f.write(self._randpool.tostring())
  303.         f.close()
  304.         self.add_event()
  305.         self.stir()
  306.  
  307.  
  308. _kb = 0
  309. if not _kb:
  310.     
  311.     try:
  312.         import msvcrt
  313.         
  314.         class KeyboardEntry:
  315.             
  316.             def getch(self):
  317.                 c = msvcrt.getch()
  318.                 if c in ('\x00', '\xe0'):
  319.                     c += msvcrt.getch()
  320.                 
  321.                 return c
  322.  
  323.             
  324.             def close(self, delay = 0):
  325.                 if delay:
  326.                     time.sleep(delay)
  327.                     while msvcrt.kbhit():
  328.                         msvcrt.getch()
  329.                 
  330.  
  331.  
  332.         _kb = 1
  333.     except:
  334.         pass
  335.  
  336.  
  337. if not _kb:
  338.     
  339.     try:
  340.         import termios
  341.         
  342.         class KeyboardEntry:
  343.             
  344.             def __init__(self, fd = 0):
  345.                 self._fd = fd
  346.                 self._old = termios.tcgetattr(fd)
  347.                 new = termios.tcgetattr(fd)
  348.                 new[3] = new[3] & ~(termios.ICANON) & ~(termios.ECHO)
  349.                 termios.tcsetattr(fd, termios.TCSANOW, new)
  350.  
  351.             
  352.             def getch(self):
  353.                 termios.tcflush(0, termios.TCIFLUSH)
  354.                 return os.read(self._fd, 1)
  355.  
  356.             
  357.             def close(self, delay = 0):
  358.                 if delay:
  359.                     time.sleep(delay)
  360.                     termios.tcflush(self._fd, termios.TCIFLUSH)
  361.                 
  362.                 termios.tcsetattr(self._fd, termios.TCSAFLUSH, self._old)
  363.  
  364.  
  365.         _kb = 1
  366.     except:
  367.         pass
  368.  
  369.  
  370.  
  371. class KeyboardRandomPool(PersistentRandomPool):
  372.     
  373.     def __init__(self, *args, **kwargs):
  374.         PersistentRandomPool.__init__(self, *args, **kwargs)
  375.  
  376.     
  377.     def randomize(self, N = 0):
  378.         '''Adds N bits of entropy to random pool.  If N is 0, fill up pool.'''
  379.         import os
  380.         import string
  381.         import time
  382.         if N <= 0:
  383.             bits = self.bits - self.entropy
  384.         else:
  385.             bits = N * 8
  386.         if bits == 0:
  387.             return None
  388.         print bits, 'bits of entropy are now required.  Please type on the keyboard'
  389.         print 'until enough randomness has been accumulated.'
  390.         kb = KeyboardEntry()
  391.         s = ''
  392.         hash = self._hash
  393.         e = 0
  394.         
  395.         try:
  396.             while e < bits:
  397.                 temp = str(bits - e).rjust(6)
  398.                 os.write(1, temp)
  399.                 s = s + kb.getch()
  400.                 e += self.add_event(s)
  401.                 os.write(1, 6 * chr(8))
  402.             self.add_event(s + hash.new(s).digest())
  403.         finally:
  404.             kb.close()
  405.  
  406.         print '\n\x07 Enough.  Please wait a moment.\n'
  407.         self.stir_n()
  408.         kb.close(4)
  409.  
  410.  
  411. if __name__ == '__main__':
  412.     pool = RandomPool()
  413.     print 'random pool entropy', pool.entropy, 'bits'
  414.     pool.add_event('something')
  415.     print `pool.get_bytes(100)`
  416.     import tempfile
  417.     import os
  418.     fname = tempfile.mktemp()
  419.     pool = KeyboardRandomPool(filename = fname)
  420.     print 'keyboard random pool entropy', pool.entropy, 'bits'
  421.     pool.randomize()
  422.     print 'keyboard random pool entropy', pool.entropy, 'bits'
  423.     pool.randomize(128)
  424.     pool.save()
  425.     saved = open(fname, 'rb').read()
  426.     print 'saved', `saved`
  427.     print 'pool ', `pool._randpool.tostring()`
  428.     newpool = PersistentRandomPool(fname)
  429.     print 'persistent random pool entropy', pool.entropy, 'bits'
  430.     os.remove(fname)
  431.  
  432.