summaryrefslogtreecommitdiff
path: root/paramiko/rng.py
diff options
context:
space:
mode:
authorJeremy T. Bouse <jbouse@debian.org>2009-11-27 16:20:12 -0500
committerJeremy T. Bouse <jbouse@debian.org>2009-11-27 16:20:12 -0500
commited280d5ac360e2af796e9bd973d7b4df89f0c449 (patch)
treece892d6ce9dad8c0ecbc9cbe73f8095195bef0b4 /paramiko/rng.py
parent176c6caf4ea7918e1698438634b237fab8456471 (diff)
downloadpython-paramiko-ed280d5ac360e2af796e9bd973d7b4df89f0c449.tar
python-paramiko-ed280d5ac360e2af796e9bd973d7b4df89f0c449.tar.gz
Imported Upstream version 1.7.4upstream/1.7.4
Diffstat (limited to 'paramiko/rng.py')
-rw-r--r--paramiko/rng.py112
1 files changed, 112 insertions, 0 deletions
diff --git a/paramiko/rng.py b/paramiko/rng.py
new file mode 100644
index 0000000..46329d1
--- /dev/null
+++ b/paramiko/rng.py
@@ -0,0 +1,112 @@
+#!/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
+import threading
+from Crypto.Util.randpool import RandomPool as _RandomPool
+
+try:
+ import platform
+except ImportError:
+ platform = None # Not available using Python 2.2
+
+def _strxor(a, b):
+ assert len(a) == len(b)
+ return "".join(map(lambda x, y: chr(ord(x) ^ ord(y)), a, b))
+
+##
+## Find a strong random entropy source, depending on the detected platform.
+## WARNING TO DEVELOPERS: This will fail on some systems, but do NOT use
+## Crypto.Util.randpool.RandomPool as a fall-back. RandomPool will happily run
+## with very little entropy, thus _silently_ defeating any security that
+## Paramiko attempts to provide. (This is current as of PyCrypto 2.0.1).
+## See http://www.lag.net/pipermail/paramiko/2008-January/000599.html
+## and http://www.lag.net/pipermail/paramiko/2008-April/000678.html
+##
+
+if ((platform is not None and platform.system().lower() == 'windows') or
+ sys.platform == 'win32'):
+ # MS Windows
+ from paramiko import rng_win32
+ rng_device = rng_win32.open_rng_device()
+else:
+ # Assume POSIX (any system where /dev/urandom exists)
+ from paramiko import rng_posix
+ rng_device = rng_posix.open_rng_device()
+
+
+class StrongLockingRandomPool(object):
+ """Wrapper around RandomPool guaranteeing strong random numbers.
+
+ Crypto.Util.randpool.RandomPool will silently operate even if it is seeded
+ with little or no entropy, and it provides no prediction resistance if its
+ state is ever compromised throughout its runtime. It is also not thread-safe.
+
+ This wrapper augments RandomPool by XORing its output with random bits from
+ the operating system, and by controlling access to the underlying
+ RandomPool using an exclusive lock.
+ """
+
+ def __init__(self, instance=None):
+ if instance is None:
+ instance = _RandomPool()
+ self.randpool = instance
+ self.randpool_lock = threading.Lock()
+ self.entropy = rng_device
+
+ # Stir 256 bits of entropy from the RNG device into the RandomPool.
+ self.randpool.stir(self.entropy.read(32))
+ self.entropy.randomize()
+
+ def stir(self, s=''):
+ self.randpool_lock.acquire()
+ try:
+ self.randpool.stir(s)
+ finally:
+ self.randpool_lock.release()
+ self.entropy.randomize()
+
+ def randomize(self, N=0):
+ self.randpool_lock.acquire()
+ try:
+ self.randpool.randomize(N)
+ finally:
+ self.randpool_lock.release()
+ self.entropy.randomize()
+
+ def add_event(self, s=''):
+ self.randpool_lock.acquire()
+ try:
+ self.randpool.add_event(s)
+ finally:
+ self.randpool_lock.release()
+
+ def get_bytes(self, N):
+ self.randpool_lock.acquire()
+ try:
+ randpool_data = self.randpool.get_bytes(N)
+ finally:
+ self.randpool_lock.release()
+ entropy_data = self.entropy.read(N)
+ result = _strxor(randpool_data, entropy_data)
+ assert len(randpool_data) == N and len(entropy_data) == N and len(result) == N
+ return result
+
+# vim:set ts=4 sw=4 sts=4 expandtab: