Package paramiko :: Module rng |
[frames] | no frames]

# Source Code for Module paramiko.rng

      1  #!/usr/bin/python
      2  # -*- coding: ascii -*-
      3  # Copyright (C) 2008  Dwayne C. Litzenberger <dlitz@dlitz.net>
      4  #
      5  # This file is part of paramiko.
      6  #
      7  # Paramiko is free software; you can redistribute it and/or modify it under the
      8  # terms of the GNU Lesser General Public License as published by the Free
      9  # Software Foundation; either version 2.1 of the License, or (at your option)
     10  # any later version.
     11  #
     12  # Paramiko is distrubuted in the hope that it will be useful, but WITHOUT ANY
     13  # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     14  # A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
     15  # details.
     16  #
     17  # You should have received a copy of the GNU Lesser General Public License
     18  # along with Paramiko; if not, write to the Free Software Foundation, Inc.,
     19  # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
     20
     21  import sys
     22  import threading
     23  from Crypto.Util.randpool import RandomPool as _RandomPool
     24
     25  try:
     26      import platform
     27  except ImportError:
     28      platform = None     # Not available using Python 2.2
     29
     30 -def _strxor(a, b):
     31      assert len(a) == len(b)
     32      return "".join(map(lambda x, y: chr(ord(x) ^ ord(y)), a, b))
     33
     34  ##
     35  ## Find a strong random entropy source, depending on the detected platform.
     36  ## WARNING TO DEVELOPERS: This will fail on some systems, but do NOT use
     37  ## Crypto.Util.randpool.RandomPool as a fall-back.  RandomPool will happily run
     38  ## with very little entropy, thus _silently_ defeating any security that
     39  ## Paramiko attempts to provide.  (This is current as of PyCrypto 2.0.1).
     40  ## See http://www.lag.net/pipermail/paramiko/2008-January/000599.html
     41  ## and http://www.lag.net/pipermail/paramiko/2008-April/000678.html
     42  ##
     43
     44  if ((platform is not None and platform.system().lower() == 'windows') or
     45          sys.platform == 'win32'):
     46      # MS Windows
     47      from paramiko import rng_win32
     48      rng_device = rng_win32.open_rng_device()
     49  else:
     50      # Assume POSIX (any system where /dev/urandom exists)
     51      from paramiko import rng_posix
     52      rng_device = rng_posix.open_rng_device()
     53
     54
     55 -class StrongLockingRandomPool(object):
     56      """Wrapper around RandomPool guaranteeing strong random numbers.
     57
     58      Crypto.Util.randpool.RandomPool will silently operate even if it is seeded
     59      with little or no entropy, and it provides no prediction resistance if its
     60      state is ever compromised throughout its runtime.  It is also not thread-safe.
     61
     62      This wrapper augments RandomPool by XORing its output with random bits from
     63      the operating system, and by controlling access to the underlying
     64      RandomPool using an exclusive lock.
     65      """
     66
     67 -    def __init__(self, instance=None):
     68          if instance is None:
     69              instance = _RandomPool()
     70          self.randpool = instance
     71          self.randpool_lock = threading.Lock()
     72          self.entropy = rng_device
     73
     74          # Stir 256 bits of entropy from the RNG device into the RandomPool.
     75          self.randpool.stir(self.entropy.read(32))
     76          self.entropy.randomize()
     77
     78 -    def stir(self, s=''):
     79          self.randpool_lock.acquire()
     80          try:
     81              self.randpool.stir(s)
     82          finally:
     83              self.randpool_lock.release()
     84          self.entropy.randomize()
     85
     86 -    def randomize(self, N=0):
     87          self.randpool_lock.acquire()
     88          try:
     89              self.randpool.randomize(N)
     90          finally:
     91              self.randpool_lock.release()
     92          self.entropy.randomize()
     93
     94 -    def add_event(self, s=''):
     95          self.randpool_lock.acquire()
     96          try:
     97              self.randpool.add_event(s)
     98          finally:
     99              self.randpool_lock.release()
    100
    101 -    def get_bytes(self, N):
    102          self.randpool_lock.acquire()
    103          try:
    104              randpool_data = self.randpool.get_bytes(N)
    105          finally:
    106              self.randpool_lock.release()
    107          entropy_data = self.entropy.read(N)
    108          result = _strxor(randpool_data, entropy_data)
    109          assert len(randpool_data) == N and len(entropy_data) == N and len(result) == N
    110          return result
    111
    112  # vim:set ts=4 sw=4 sts=4 expandtab:
    113