diff options
-rw-r--r-- | paramiko/common.py | 16 | ||||
-rw-r--r-- | paramiko/osrandom.py | 93 |
2 files changed, 95 insertions, 14 deletions
diff --git a/paramiko/common.py b/paramiko/common.py index 2dffad1b..89b34cf5 100644 --- a/paramiko/common.py +++ b/paramiko/common.py @@ -95,22 +95,10 @@ CONNECTION_FAILED_CODE = { DISCONNECT_SERVICE_NOT_AVAILABLE, DISCONNECT_AUTH_CANCELLED_BY_USER, \ DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE = 7, 13, 14 - -from Crypto.Util.randpool import PersistentRandomPool, RandomPool +from osrandom import OSRandomPool # keep a crypto-strong PRNG nearby -import os -try: - randpool = PersistentRandomPool(os.path.join(os.path.expanduser('~'), '/.randpool')) -except: - # the above will likely fail on Windows - fall back to non-persistent random pool - randpool = RandomPool() - -try: - randpool.randomize() -except: - # earlier versions of pyCrypto (pre-2.0) don't have randomize() - pass +randpool = OSRandomPool() import sys if sys.version_info < (2, 3): diff --git a/paramiko/osrandom.py b/paramiko/osrandom.py new file mode 100644 index 00000000..47c8f443 --- /dev/null +++ b/paramiko/osrandom.py @@ -0,0 +1,93 @@ +#!/usr/bin/python +# -*- coding: ascii -*- +# Copyright (C) 2008 Dwayne C. Litzenberger <dlitz@dlitz.net> +# +# This file is part of paramiko. +# +# Paramiko is free software; you can redistribute it and/or modify it under the +# terms of the GNU Lesser General Public License as published by the Free +# Software Foundation; either version 2.1 of the License, or (at your option) +# any later version. +# +# Paramiko is distrubuted in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Paramiko; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +import sys + +# Detect an OS random number source +osrandom_source = None + +# Try os.urandom +if osrandom_source is None: + try: + from os import urandom + osrandom_source = "os.urandom" + except ImportError: + pass + +# Try winrandom +if osrandom_source is None: + try: + from Crypto.Util import winrandom + osrandom_source = "winrandom" + except ImportError: + pass + +# Try /dev/urandom +if osrandom_source is None: + try: + _dev_urandom = open("/dev/urandom", "rb", 0) + def urandom(bytes): + return _def_urandom.read(bytes) + osrandom_source = "/dev/urandom" + except (OSError, IOError): + pass + +# Give up +if osrandom_source is None: + raise ImportError("Cannot find OS entropy source") + +class BaseOSRandomPool(object): + def __init__(self, numbytes=160, cipher=None, hash=None): + pass + + def stir(self, s=''): + # According to "Cryptanalysis of the Random Number Generator of the + # Windows Operating System", by Leo Dorrendorf and Zvi Gutterman + # and Benny Pinkas <http://eprint.iacr.org/2007/419>, + # CryptGenRandom only updates its internal state using kernel-provided + # random data every 128KiB of output. + if osrandom_source == 'winrandom' or sys.platform == 'win32': + self.get_bytes(128*1024) # discard 128 KiB of output + + def randomize(self, N=0): + self.stir() + + def add_event(self, s=None): + pass + +class WinrandomOSRandomPool(BaseOSRandomPool): + def __init__(self, numbytes=160, cipher=None, hash=None): + self._wr = winrandom.new() + self.get_bytes = self._wr.get_bytes + self.randomize() + +class UrandomOSRandomPool(BaseOSRandomPool): + def __init__(self, numbytes=160, cipher=None, hash=None): + self.get_bytes = urandom + self.randomize() + +if osrandom_source in ("/dev/urandom", "os.urandom"): + OSRandomPool = UrandomOSRandomPool +elif osrandom_source == "winrandom": + OSRandomPool = WinrandomOSRandomPool +else: + raise AssertionError("Unrecognized osrandom_source %r" % (osrandom_source,)) + +# vim:set ts=4 sw=4 sts=4 expandtab: |