Merge lp:~jelmer/ubuntu/natty/paramiko/randompool+addressfamilies into lp:ubuntu/natty/paramiko

Proposed by Jelmer Vernooij
Status: Merged
Merge reported by: Jelmer Vernooij
Merged at revision: not available
Proposed branch: lp:~jelmer/ubuntu/natty/paramiko/randompool+addressfamilies
Merge into: lp:ubuntu/natty/paramiko
Diff against target: 857 lines (+828/-0)
5 files modified
debian/changelog (+15/-0)
debian/patches/01_no-randompool.patch (+780/-0)
debian/patches/02_addressfamilies.patch (+30/-0)
debian/patches/series (+2/-0)
debian/source/format (+1/-0)
To merge this branch: bzr merge lp:~jelmer/ubuntu/natty/paramiko/randompool+addressfamilies
Reviewer Review Type Date Requested Status
Steve Kowalik Approve
Review via email: mp+46669@code.launchpad.net

Description of the change

Cherry-pick two patches that have been forwarded upstream:

* paramiko does not try all available address families (bug 638675)
* Fix RandomPool Depreciation Warning from pycrypto (bug 271791)

To post a comment you must log in.
Revision history for this message
Steve Kowalik (stevenk) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'debian/changelog'
--- debian/changelog 2010-07-17 00:00:40 +0000
+++ debian/changelog 2011-01-18 19:52:31 +0000
@@ -1,3 +1,18 @@
1paramiko (1.7.6-5ubuntu1) natty; urgency=low
2
3 [ Jelmer Vernooij ]
4
5 * Avoid deprecated RandomPool. Patch by Gary van der Merwe. Closes:
6 #576697, LP: #271791, LP: #682600.
7 * Switch to source format 3.0 (quilt).
8
9 [ Andrew Bennetts ]
10
11 * Try connecting to each available address family until one succeeds.
12 LP: #579530
13
14 -- Jelmer Vernooij <jelmer@ubuntu.com> Fri, 14 Jan 2011 06:54:41 +0100
15
1paramiko (1.7.6-5) unstable; urgency=low16paramiko (1.7.6-5) unstable; urgency=low
217
3 * debian/control: Fix python-crypto version dependency18 * debian/control: Fix python-crypto version dependency
419
=== added directory 'debian/patches'
=== added file 'debian/patches/01_no-randompool.patch'
--- debian/patches/01_no-randompool.patch 1970-01-01 00:00:00 +0000
+++ debian/patches/01_no-randompool.patch 2011-01-18 19:52:31 +0000
@@ -0,0 +1,780 @@
1=== modified file 'a/paramiko/__init__.py'
2--- a/paramiko/__init__.py 2010-04-26 00:05:06 +0000
3+++ b/paramiko/__init__.py 2010-08-02 22:13:08 +0000
4@@ -66,7 +66,7 @@
5 __license__ = "GNU Lesser General Public License (LGPL)"
6
7
8-from transport import randpool, SecurityOptions, Transport
9+from transport import SecurityOptions, Transport
10 from client import SSHClient, MissingHostKeyPolicy, AutoAddPolicy, RejectPolicy, WarningPolicy
11 from auth_handler import AuthHandler
12 from channel import Channel, ChannelFile
13
14=== modified file 'a/paramiko/agent.py'
15--- a/paramiko/agent.py 2007-02-13 19:17:06 +0000
16+++ b/paramiko/agent.py 2010-08-02 22:13:08 +0000
17@@ -139,7 +139,7 @@
18 def get_name(self):
19 return self.name
20
21- def sign_ssh_data(self, randpool, data):
22+ def sign_ssh_data(self, rng, data):
23 msg = Message()
24 msg.add_byte(chr(SSH2_AGENTC_SIGN_REQUEST))
25 msg.add_string(self.blob)
26
27=== modified file 'a/paramiko/auth_handler.py'
28--- a/paramiko/auth_handler.py 2009-07-20 02:45:02 +0000
29+++ b/paramiko/auth_handler.py 2010-08-02 22:13:08 +0000
30@@ -206,7 +206,7 @@
31 m.add_string(self.private_key.get_name())
32 m.add_string(str(self.private_key))
33 blob = self._get_session_blob(self.private_key, 'ssh-connection', self.username)
34- sig = self.private_key.sign_ssh_data(self.transport.randpool, blob)
35+ sig = self.private_key.sign_ssh_data(self.transport.rng, blob)
36 m.add_string(str(sig))
37 elif self.auth_method == 'keyboard-interactive':
38 m.add_string('')
39
40=== modified file 'a/paramiko/channel.py'
41--- a/paramiko/channel.py 2009-11-01 00:55:52 +0000
42+++ b/paramiko/channel.py 2010-08-02 22:13:08 +0000
43@@ -364,7 +364,7 @@
44 if auth_protocol is None:
45 auth_protocol = 'MIT-MAGIC-COOKIE-1'
46 if auth_cookie is None:
47- auth_cookie = binascii.hexlify(self.transport.randpool.get_bytes(16))
48+ auth_cookie = binascii.hexlify(self.transport.rng.read(16))
49
50 m = Message()
51 m.add_byte(chr(MSG_CHANNEL_REQUEST))
52
53=== modified file 'a/paramiko/common.py'
54--- a/paramiko/common.py 2009-07-20 02:45:02 +0000
55+++ b/paramiko/common.py 2010-08-02 22:13:08 +0000
56@@ -95,10 +95,10 @@
57 DISCONNECT_SERVICE_NOT_AVAILABLE, DISCONNECT_AUTH_CANCELLED_BY_USER, \
58 DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE = 7, 13, 14
59
60-from rng import StrongLockingRandomPool
61+from Crypto import Random
62
63 # keep a crypto-strong PRNG nearby
64-randpool = StrongLockingRandomPool()
65+rng = Random.new()
66
67 import sys
68 if sys.version_info < (2, 3):
69
70=== modified file 'a/paramiko/dsskey.py'
71--- a/paramiko/dsskey.py 2009-07-20 02:45:02 +0000
72+++ b/paramiko/dsskey.py 2010-08-02 22:13:08 +0000
73@@ -91,13 +91,13 @@
74 def can_sign(self):
75 return self.x is not None
76
77- def sign_ssh_data(self, rpool, data):
78+ def sign_ssh_data(self, rng, data):
79 digest = SHA.new(data).digest()
80 dss = DSA.construct((long(self.y), long(self.g), long(self.p), long(self.q), long(self.x)))
81 # generate a suitable k
82 qsize = len(util.deflate_long(self.q, 0))
83 while True:
84- k = util.inflate_long(rpool.get_bytes(qsize), 1)
85+ k = util.inflate_long(rng.read(qsize), 1)
86 if (k > 2) and (k < self.q):
87 break
88 r, s = dss.sign(util.inflate_long(digest, 1), k)
89@@ -161,8 +161,7 @@
90 @return: new private key
91 @rtype: L{DSSKey}
92 """
93- randpool.stir()
94- dsa = DSA.generate(bits, randpool.get_bytes, progress_func)
95+ dsa = DSA.generate(bits, rng.read, progress_func)
96 key = DSSKey(vals=(dsa.p, dsa.q, dsa.g, dsa.y))
97 key.x = dsa.x
98 return key
99
100=== modified file 'a/paramiko/hostkeys.py'
101--- a/paramiko/hostkeys.py 2009-11-02 05:33:13 +0000
102+++ b/paramiko/hostkeys.py 2010-08-02 22:13:08 +0000
103@@ -303,7 +303,7 @@
104 @rtype: str
105 """
106 if salt is None:
107- salt = randpool.get_bytes(SHA.digest_size)
108+ salt = rng.read(SHA.digest_size)
109 else:
110 if salt.startswith('|1|'):
111 salt = salt.split('|')[2]
112
113=== modified file 'a/paramiko/kex_gex.py'
114--- a/paramiko/kex_gex.py 2009-07-20 02:45:02 +0000
115+++ b/paramiko/kex_gex.py 2010-08-02 22:13:08 +0000
116@@ -101,8 +101,7 @@
117 qhbyte <<= 1
118 qmask >>= 1
119 while True:
120- self.transport.randpool.stir()
121- x_bytes = self.transport.randpool.get_bytes(bytes)
122+ x_bytes = self.transport.rng.read(bytes)
123 x_bytes = chr(ord(x_bytes[0]) & qmask) + x_bytes[1:]
124 x = util.inflate_long(x_bytes, 1)
125 if (x > 1) and (x < q):
126@@ -207,7 +206,7 @@
127 H = SHA.new(str(hm)).digest()
128 self.transport._set_K_H(K, H)
129 # sign it
130- sig = self.transport.get_server_key().sign_ssh_data(self.transport.randpool, H)
131+ sig = self.transport.get_server_key().sign_ssh_data(self.transport.rng, H)
132 # send reply
133 m = Message()
134 m.add_byte(chr(_MSG_KEXDH_GEX_REPLY))
135
136=== modified file 'a/paramiko/kex_group1.py'
137--- a/paramiko/kex_group1.py 2009-07-20 02:45:02 +0000
138+++ b/paramiko/kex_group1.py 2010-08-02 22:13:08 +0000
139@@ -79,8 +79,7 @@
140 # potential x where the first 63 bits are 1, because some of those will be
141 # larger than q (but this is a tiny tiny subset of potential x).
142 while 1:
143- self.transport.randpool.stir()
144- x_bytes = self.transport.randpool.get_bytes(128)
145+ x_bytes = self.transport.rng.read(128)
146 x_bytes = chr(ord(x_bytes[0]) & 0x7f) + x_bytes[1:]
147 if (x_bytes[:8] != '\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF') and \
148 (x_bytes[:8] != '\x00\x00\x00\x00\x00\x00\x00\x00'):
149@@ -125,7 +124,7 @@
150 H = SHA.new(str(hm)).digest()
151 self.transport._set_K_H(K, H)
152 # sign it
153- sig = self.transport.get_server_key().sign_ssh_data(self.transport.randpool, H)
154+ sig = self.transport.get_server_key().sign_ssh_data(self.transport.rng, H)
155 # send reply
156 m = Message()
157 m.add_byte(chr(_MSG_KEXDH_REPLY))
158
159=== modified file 'a/paramiko/packet.py'
160--- a/paramiko/packet.py 2010-04-14 01:51:45 +0000
161+++ b/paramiko/packet.py 2010-08-02 22:13:08 +0000
162@@ -311,9 +311,6 @@
163
164 self.__sent_bytes += len(out)
165 self.__sent_packets += 1
166- if (self.__sent_packets % 100) == 0:
167- # stirring the randpool takes 30ms on my ibook!!
168- randpool.stir()
169 if ((self.__sent_packets >= self.REKEY_PACKETS) or (self.__sent_bytes >= self.REKEY_BYTES)) \
170 and not self.__need_rekey:
171 # only ask once for rekeying
172@@ -359,7 +356,7 @@
173 raise SSHException('Mismatched MAC')
174 padding = ord(packet[0])
175 payload = packet[1:packet_size - padding]
176- randpool.add_event()
177+
178 if self.__dump_packets:
179 self._log(DEBUG, 'Got payload (%d bytes, %d padding)' % (packet_size, padding))
180
181@@ -476,7 +473,7 @@
182 packet = struct.pack('>IB', len(payload) + padding + 1, padding)
183 packet += payload
184 if self.__block_engine_out is not None:
185- packet += randpool.get_bytes(padding)
186+ packet += rng.read(padding)
187 else:
188 # cute trick i caught openssh doing: if we're not encrypting,
189 # don't waste random bytes for the padding
190
191=== modified file 'a/paramiko/pkey.py'
192--- a/paramiko/pkey.py 2009-07-20 02:45:02 +0000
193+++ b/paramiko/pkey.py 2010-08-02 22:13:08 +0000
194@@ -143,13 +143,13 @@
195 """
196 return base64.encodestring(str(self)).replace('\n', '')
197
198- def sign_ssh_data(self, randpool, data):
199+ def sign_ssh_data(self, rng, data):
200 """
201 Sign a blob of data with this private key, and return a L{Message}
202 representing an SSH signature message.
203
204- @param randpool: a secure random number generator.
205- @type randpool: L{Crypto.Util.randpool.RandomPool}
206+ @param rng: a secure random number generator.
207+ @type rng: L{Crypto.Util.rng.RandomPool}
208 @param data: the data to sign.
209 @type data: str
210 @return: an SSH signature message.
211@@ -360,11 +360,11 @@
212 keysize = self._CIPHER_TABLE[cipher_name]['keysize']
213 blocksize = self._CIPHER_TABLE[cipher_name]['blocksize']
214 mode = self._CIPHER_TABLE[cipher_name]['mode']
215- salt = randpool.get_bytes(8)
216+ salt = rng.read(8)
217 key = util.generate_key_bytes(MD5, salt, password, keysize)
218 if len(data) % blocksize != 0:
219 n = blocksize - len(data) % blocksize
220- #data += randpool.get_bytes(n)
221+ #data += rng.read(n)
222 # that would make more sense ^, but it confuses openssh.
223 data += '\0' * n
224 data = cipher.new(key, mode, salt).encrypt(data)
225
226=== modified file 'a/paramiko/primes.py'
227--- a/paramiko/primes.py 2009-07-20 02:45:02 +0000
228+++ b/paramiko/primes.py 2010-08-02 22:13:08 +0000
229@@ -26,12 +26,12 @@
230 from paramiko.ssh_exception import SSHException
231
232
233-def _generate_prime(bits, randpool):
234+def _generate_prime(bits, rng):
235 "primtive attempt at prime generation"
236 hbyte_mask = pow(2, bits % 8) - 1
237 while True:
238 # loop catches the case where we increment n into a higher bit-range
239- x = randpool.get_bytes((bits+7) // 8)
240+ x = rng.read((bits+7) // 8)
241 if hbyte_mask > 0:
242 x = chr(ord(x[0]) & hbyte_mask) + x[1:]
243 n = util.inflate_long(x, 1)
244@@ -43,7 +43,7 @@
245 break
246 return n
247
248-def _roll_random(rpool, n):
249+def _roll_random(rng, n):
250 "returns a random # from 0 to N-1"
251 bits = util.bit_length(n-1)
252 bytes = (bits + 7) // 8
253@@ -56,7 +56,7 @@
254 # fits, so i can't guarantee that this loop will ever finish, but the odds
255 # of it looping forever should be infinitesimal.
256 while True:
257- x = rpool.get_bytes(bytes)
258+ x = rng.read(bytes)
259 if hbyte_mask > 0:
260 x = chr(ord(x[0]) & hbyte_mask) + x[1:]
261 num = util.inflate_long(x, 1)
262@@ -75,7 +75,7 @@
263 # pack is a hash of: bits -> [ (generator, modulus) ... ]
264 self.pack = {}
265 self.discarded = []
266- self.randpool = rpool
267+ self.rng = rpool
268
269 def _parse_modulus(self, line):
270 timestamp, mod_type, tests, tries, size, generator, modulus = line.split()
271@@ -147,5 +147,5 @@
272 if min > good:
273 good = bitsizes[-1]
274 # now pick a random modulus of this bitsize
275- n = _roll_random(self.randpool, len(self.pack[good]))
276+ n = _roll_random(self.rng, len(self.pack[good]))
277 return self.pack[good][n]
278
279=== removed file 'a/paramiko/rng.py'
280--- a/paramiko/rng.py 2008-05-18 22:45:25 +0000
281+++ b/paramiko/rng.py 1970-01-01 00:00:00 +0000
282@@ -1,112 +0,0 @@
283-#!/usr/bin/python
284-# -*- coding: ascii -*-
285-# Copyright (C) 2008 Dwayne C. Litzenberger <dlitz@dlitz.net>
286-#
287-# This file is part of paramiko.
288-#
289-# Paramiko is free software; you can redistribute it and/or modify it under the
290-# terms of the GNU Lesser General Public License as published by the Free
291-# Software Foundation; either version 2.1 of the License, or (at your option)
292-# any later version.
293-#
294-# Paramiko is distrubuted in the hope that it will be useful, but WITHOUT ANY
295-# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
296-# A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
297-# details.
298-#
299-# You should have received a copy of the GNU Lesser General Public License
300-# along with Paramiko; if not, write to the Free Software Foundation, Inc.,
301-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
302-
303-import sys
304-import threading
305-from Crypto.Util.randpool import RandomPool as _RandomPool
306-
307-try:
308- import platform
309-except ImportError:
310- platform = None # Not available using Python 2.2
311-
312-def _strxor(a, b):
313- assert len(a) == len(b)
314- return "".join(map(lambda x, y: chr(ord(x) ^ ord(y)), a, b))
315-
316-##
317-## Find a strong random entropy source, depending on the detected platform.
318-## WARNING TO DEVELOPERS: This will fail on some systems, but do NOT use
319-## Crypto.Util.randpool.RandomPool as a fall-back. RandomPool will happily run
320-## with very little entropy, thus _silently_ defeating any security that
321-## Paramiko attempts to provide. (This is current as of PyCrypto 2.0.1).
322-## See http://www.lag.net/pipermail/paramiko/2008-January/000599.html
323-## and http://www.lag.net/pipermail/paramiko/2008-April/000678.html
324-##
325-
326-if ((platform is not None and platform.system().lower() == 'windows') or
327- sys.platform == 'win32'):
328- # MS Windows
329- from paramiko import rng_win32
330- rng_device = rng_win32.open_rng_device()
331-else:
332- # Assume POSIX (any system where /dev/urandom exists)
333- from paramiko import rng_posix
334- rng_device = rng_posix.open_rng_device()
335-
336-
337-class StrongLockingRandomPool(object):
338- """Wrapper around RandomPool guaranteeing strong random numbers.
339-
340- Crypto.Util.randpool.RandomPool will silently operate even if it is seeded
341- with little or no entropy, and it provides no prediction resistance if its
342- state is ever compromised throughout its runtime. It is also not thread-safe.
343-
344- This wrapper augments RandomPool by XORing its output with random bits from
345- the operating system, and by controlling access to the underlying
346- RandomPool using an exclusive lock.
347- """
348-
349- def __init__(self, instance=None):
350- if instance is None:
351- instance = _RandomPool()
352- self.randpool = instance
353- self.randpool_lock = threading.Lock()
354- self.entropy = rng_device
355-
356- # Stir 256 bits of entropy from the RNG device into the RandomPool.
357- self.randpool.stir(self.entropy.read(32))
358- self.entropy.randomize()
359-
360- def stir(self, s=''):
361- self.randpool_lock.acquire()
362- try:
363- self.randpool.stir(s)
364- finally:
365- self.randpool_lock.release()
366- self.entropy.randomize()
367-
368- def randomize(self, N=0):
369- self.randpool_lock.acquire()
370- try:
371- self.randpool.randomize(N)
372- finally:
373- self.randpool_lock.release()
374- self.entropy.randomize()
375-
376- def add_event(self, s=''):
377- self.randpool_lock.acquire()
378- try:
379- self.randpool.add_event(s)
380- finally:
381- self.randpool_lock.release()
382-
383- def get_bytes(self, N):
384- self.randpool_lock.acquire()
385- try:
386- randpool_data = self.randpool.get_bytes(N)
387- finally:
388- self.randpool_lock.release()
389- entropy_data = self.entropy.read(N)
390- result = _strxor(randpool_data, entropy_data)
391- assert len(randpool_data) == N and len(entropy_data) == N and len(result) == N
392- return result
393-
394-# vim:set ts=4 sw=4 sts=4 expandtab:
395
396=== removed file 'a/paramiko/rng_posix.py'
397--- a/paramiko/rng_posix.py 2009-11-02 05:33:13 +0000
398+++ b/paramiko/rng_posix.py 1970-01-01 00:00:00 +0000
399@@ -1,97 +0,0 @@
400-#!/usr/bin/python
401-# -*- coding: ascii -*-
402-# Copyright (C) 2008 Dwayne C. Litzenberger <dlitz@dlitz.net>
403-# Copyright (C) 2008 Open Systems Canada Limited
404-#
405-# This file is part of paramiko.
406-#
407-# Paramiko is free software; you can redistribute it and/or modify it under the
408-# terms of the GNU Lesser General Public License as published by the Free
409-# Software Foundation; either version 2.1 of the License, or (at your option)
410-# any later version.
411-#
412-# Paramiko is distrubuted in the hope that it will be useful, but WITHOUT ANY
413-# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
414-# A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
415-# details.
416-#
417-# You should have received a copy of the GNU Lesser General Public License
418-# along with Paramiko; if not, write to the Free Software Foundation, Inc.,
419-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
420-
421-import os
422-import stat
423-
424-class error(Exception):
425- pass
426-
427-class _RNG(object):
428- def __init__(self, file):
429- self.file = file
430-
431- def read(self, bytes):
432- return self.file.read(bytes)
433-
434- def close(self):
435- return self.file.close()
436-
437- def randomize(self):
438- return
439-
440-def open_rng_device(device_path=None):
441- """Open /dev/urandom and perform some sanity checks."""
442-
443- f = None
444- g = None
445-
446- if device_path is None:
447- device_path = "/dev/urandom"
448-
449- try:
450- # Try to open /dev/urandom now so that paramiko will be able to access
451- # it even if os.chroot() is invoked later.
452- try:
453- f = open(device_path, "rb", 0)
454- except EnvironmentError:
455- raise error("Unable to open /dev/urandom")
456-
457- # Open a second file descriptor for sanity checking later.
458- try:
459- g = open(device_path, "rb", 0)
460- except EnvironmentError:
461- raise error("Unable to open /dev/urandom")
462-
463- # Check that /dev/urandom is a character special device, not a regular file.
464- st = os.fstat(f.fileno()) # f
465- if stat.S_ISREG(st.st_mode) or not stat.S_ISCHR(st.st_mode):
466- raise error("/dev/urandom is not a character special device")
467-
468- st = os.fstat(g.fileno()) # g
469- if stat.S_ISREG(st.st_mode) or not stat.S_ISCHR(st.st_mode):
470- raise error("/dev/urandom is not a character special device")
471-
472- # Check that /dev/urandom always returns the number of bytes requested
473- x = f.read(20)
474- y = g.read(20)
475- if len(x) != 20 or len(y) != 20:
476- raise error("Error reading from /dev/urandom: input truncated")
477-
478- # Check that different reads return different data
479- if x == y:
480- raise error("/dev/urandom is broken; returning identical data: %r == %r" % (x, y))
481-
482- # Close the duplicate file object
483- g.close()
484-
485- # Return the first file object
486- return _RNG(f)
487-
488- except error:
489- if f is not None:
490- f.close()
491- if g is not None:
492- g.close()
493- raise
494-
495-# vim:set ts=4 sw=4 sts=4 expandtab:
496-
497
498=== removed file 'a/paramiko/rng_win32.py'
499--- a/paramiko/rng_win32.py 2008-05-18 22:45:25 +0000
500+++ b/paramiko/rng_win32.py 1970-01-01 00:00:00 +0000
501@@ -1,121 +0,0 @@
502-#!/usr/bin/python
503-# -*- coding: ascii -*-
504-# Copyright (C) 2008 Dwayne C. Litzenberger <dlitz@dlitz.net>
505-# Copyright (C) 2008 Open Systems Canada Limited
506-#
507-# This file is part of paramiko.
508-#
509-# Paramiko is free software; you can redistribute it and/or modify it under the
510-# terms of the GNU Lesser General Public License as published by the Free
511-# Software Foundation; either version 2.1 of the License, or (at your option)
512-# any later version.
513-#
514-# Paramiko is distrubuted in the hope that it will be useful, but WITHOUT ANY
515-# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
516-# A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
517-# details.
518-#
519-# You should have received a copy of the GNU Lesser General Public License
520-# along with Paramiko; if not, write to the Free Software Foundation, Inc.,
521-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
522-
523-class error(Exception):
524- pass
525-
526-# Try to import the "winrandom" module
527-try:
528- from Crypto.Util import winrandom as _winrandom
529-except ImportError:
530- _winrandom = None
531-
532-# Try to import the "urandom" module
533-try:
534- from os import urandom as _urandom
535-except ImportError:
536- _urandom = None
537-
538-
539-class _RNG(object):
540- def __init__(self, readfunc):
541- self.read = readfunc
542-
543- def randomize(self):
544- # According to "Cryptanalysis of the Random Number Generator of the
545- # Windows Operating System", by Leo Dorrendorf and Zvi Gutterman
546- # and Benny Pinkas <http://eprint.iacr.org/2007/419>,
547- # CryptGenRandom only updates its internal state using kernel-provided
548- # random data every 128KiB of output.
549- self.read(128*1024) # discard 128 KiB of output
550-
551-def _open_winrandom():
552- if _winrandom is None:
553- raise error("Crypto.Util.winrandom module not found")
554-
555- # Check that we can open the winrandom module
556- try:
557- r0 = _winrandom.new()
558- r1 = _winrandom.new()
559- except Exception, exc:
560- raise error("winrandom.new() failed: %s" % str(exc), exc)
561-
562- # Check that we can read from the winrandom module
563- try:
564- x = r0.get_bytes(20)
565- y = r1.get_bytes(20)
566- except Exception, exc:
567- raise error("winrandom get_bytes failed: %s" % str(exc), exc)
568-
569- # Check that the requested number of bytes are returned
570- if len(x) != 20 or len(y) != 20:
571- raise error("Error reading from winrandom: input truncated")
572-
573- # Check that different reads return different data
574- if x == y:
575- raise error("winrandom broken: returning identical data")
576-
577- return _RNG(r0.get_bytes)
578-
579-def _open_urandom():
580- if _urandom is None:
581- raise error("os.urandom function not found")
582-
583- # Check that we can read from os.urandom()
584- try:
585- x = _urandom(20)
586- y = _urandom(20)
587- except Exception, exc:
588- raise error("os.urandom failed: %s" % str(exc), exc)
589-
590- # Check that the requested number of bytes are returned
591- if len(x) != 20 or len(y) != 20:
592- raise error("os.urandom failed: input truncated")
593-
594- # Check that different reads return different data
595- if x == y:
596- raise error("os.urandom failed: returning identical data")
597-
598- return _RNG(_urandom)
599-
600-def open_rng_device():
601- # Try using the Crypto.Util.winrandom module
602- try:
603- return _open_winrandom()
604- except error:
605- pass
606-
607- # Several versions of PyCrypto do not contain the winrandom module, but
608- # Python >= 2.4 has os.urandom, so try to use that.
609- try:
610- return _open_urandom()
611- except error:
612- pass
613-
614- # SECURITY NOTE: DO NOT USE Crypto.Util.randpool.RandomPool HERE!
615- # If we got to this point, RandomPool will silently run with very little
616- # entropy. (This is current as of PyCrypto 2.0.1).
617- # See http://www.lag.net/pipermail/paramiko/2008-January/000599.html
618- # and http://www.lag.net/pipermail/paramiko/2008-April/000678.html
619-
620- raise error("Unable to find a strong random entropy source. You cannot run this software securely under the current configuration.")
621-
622-# vim:set ts=4 sw=4 sts=4 expandtab:
623
624=== modified file 'a/paramiko/rsakey.py'
625--- a/paramiko/rsakey.py 2009-07-20 02:45:02 +0000
626+++ b/paramiko/rsakey.py 2010-08-02 22:13:08 +0000
627@@ -137,8 +137,7 @@
628 @return: new private key
629 @rtype: L{RSAKey}
630 """
631- randpool.stir()
632- rsa = RSA.generate(bits, randpool.get_bytes, progress_func)
633+ rsa = RSA.generate(bits, rng.read, progress_func)
634 key = RSAKey(vals=(rsa.e, rsa.n))
635 key.d = rsa.d
636 key.p = rsa.p
637
638=== modified file 'a/paramiko/transport.py'
639--- a/paramiko/transport.py 2010-04-25 23:42:45 +0000
640+++ b/paramiko/transport.py 2010-08-02 22:13:08 +0000
641@@ -297,7 +297,7 @@
642 # okay, normal socket-ish flow here...
643 threading.Thread.__init__(self)
644 self.setDaemon(True)
645- self.randpool = randpool
646+ self.rng = rng
647 self.sock = sock
648 # Python < 2.3 doesn't have the settimeout method - RogerB
649 try:
650@@ -585,7 +585,7 @@
651
652 @note: This has no effect when used in client mode.
653 """
654- Transport._modulus_pack = ModulusPack(randpool)
655+ Transport._modulus_pack = ModulusPack(rng)
656 # places to look for the openssh "moduli" file
657 file_list = [ '/etc/ssh/moduli', '/usr/local/etc/moduli' ]
658 if filename is not None:
659@@ -837,10 +837,9 @@
660 """
661 m = Message()
662 m.add_byte(chr(MSG_IGNORE))
663- randpool.stir()
664 if bytes is None:
665- bytes = (ord(randpool.get_bytes(1)) % 32) + 10
666- m.add_bytes(randpool.get_bytes(bytes))
667+ bytes = (ord(rng.read(1)) % 32) + 10
668+ m.add_bytes(rng.read(bytes))
669 self._send_user_message(m)
670
671 def renegotiate_keys(self):
672@@ -1674,10 +1673,9 @@
673 else:
674 available_server_keys = self._preferred_keys
675
676- randpool.stir()
677 m = Message()
678 m.add_byte(chr(MSG_KEXINIT))
679- m.add_bytes(randpool.get_bytes(16))
680+ m.add_bytes(rng.read(16))
681 m.add_list(self._preferred_kex)
682 m.add_list(available_server_keys)
683 m.add_list(self._preferred_ciphers)
684
685=== modified file 'a/tests/test_kex.py'
686--- a/tests/test_kex.py 2009-07-20 02:45:02 +0000
687+++ b/tests/test_kex.py 2010-08-02 22:13:08 +0000
688@@ -28,17 +28,15 @@
689 from paramiko import Message
690
691
692-class FakeRandpool (object):
693- def stir(self):
694- pass
695- def get_bytes(self, n):
696+class FakeRng (object):
697+ def read(self, n):
698 return chr(0xcc) * n
699
700
701 class FakeKey (object):
702 def __str__(self):
703 return 'fake-key'
704- def sign_ssh_data(self, randpool, H):
705+ def sign_ssh_data(self, rng, H):
706 return 'fake-sig'
707
708
709@@ -50,7 +48,7 @@
710
711
712 class FakeTransport (object):
713- randpool = FakeRandpool()
714+ rng = FakeRng()
715 local_version = 'SSH-2.0-paramiko_1.0'
716 remote_version = 'SSH-2.0-lame'
717 local_kex_init = 'local-kex-init'
718
719=== modified file 'a/tests/test_pkey.py'
720--- a/tests/test_pkey.py 2009-07-20 02:45:02 +0000
721+++ b/tests/test_pkey.py 2010-08-02 22:13:08 +0000
722@@ -23,7 +23,8 @@
723 from binascii import hexlify, unhexlify
724 import StringIO
725 import unittest
726-from paramiko import RSAKey, DSSKey, Message, util, randpool
727+from paramiko import RSAKey, DSSKey, Message, util
728+from paramiko.common import rng
729
730 # from openssh's ssh-keygen
731 PUB_RSA = 'ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA049W6geFpmsljTwfvI1UmKWWJPNFI74+vNKTk4dmzkQY2yAMs6FhlvhlI8ysU4oj71ZsRYMecHbBbxdN79+JRFVYTKaLqjwGENeTd+yv4q+V2PvZv3fLnzApI3l7EJCqhWwJUHJ1jAkZzqDx0tyOL4uoZpww3nmE0kb3y21tH4c='
732@@ -151,7 +152,7 @@
733 def test_8_sign_rsa(self):
734 # verify that the rsa private key can sign and verify
735 key = RSAKey.from_private_key_file('tests/test_rsa.key')
736- msg = key.sign_ssh_data(randpool, 'ice weasels')
737+ msg = key.sign_ssh_data(rng, 'ice weasels')
738 self.assert_(type(msg) is Message)
739 msg.rewind()
740 self.assertEquals('ssh-rsa', msg.get_string())
741@@ -164,7 +165,7 @@
742 def test_9_sign_dss(self):
743 # verify that the dss private key can sign and verify
744 key = DSSKey.from_private_key_file('tests/test_dss.key')
745- msg = key.sign_ssh_data(randpool, 'ice weasels')
746+ msg = key.sign_ssh_data(rng, 'ice weasels')
747 self.assert_(type(msg) is Message)
748 msg.rewind()
749 self.assertEquals('ssh-dss', msg.get_string())
750@@ -178,12 +179,12 @@
751
752 def test_A_generate_rsa(self):
753 key = RSAKey.generate(1024)
754- msg = key.sign_ssh_data(randpool, 'jerri blank')
755+ msg = key.sign_ssh_data(rng, 'jerri blank')
756 msg.rewind()
757 self.assert_(key.verify_ssh_sig('jerri blank', msg))
758
759 def test_B_generate_dss(self):
760 key = DSSKey.generate(1024)
761- msg = key.sign_ssh_data(randpool, 'jerri blank')
762+ msg = key.sign_ssh_data(rng, 'jerri blank')
763 msg.rewind()
764 self.assert_(key.verify_ssh_sig('jerri blank', msg))
765
766=== modified file 'a/tests/test_util.py'
767--- a/tests/test_util.py 2009-07-20 02:45:02 +0000
768+++ b/tests/test_util.py 2010-08-02 22:13:08 +0000
769@@ -147,8 +147,8 @@
770 os.unlink('hostfile.temp')
771
772 def test_6_random(self):
773- from paramiko.common import randpool
774+ from paramiko.common import rng
775 # just verify that we can pull out 32 bytes and not get an exception.
776- x = randpool.get_bytes(32)
777+ x = rng.read(32)
778 self.assertEquals(len(x), 32)
779
780
0781
=== added file 'debian/patches/02_addressfamilies.patch'
--- debian/patches/02_addressfamilies.patch 1970-01-01 00:00:00 +0000
+++ debian/patches/02_addressfamilies.patch 2011-01-18 19:52:31 +0000
@@ -0,0 +1,30 @@
1=== modified file 'paramiko/transport.py'
2--- a/paramiko/transport.py 2009-12-16 08:15:36 +0000
3+++ ib/paramiko/transport.py 2011-01-14 06:01:07 +0000
4@@ -285,15 +285,21 @@
5 if type(sock) is tuple:
6 # connect to the given (host, port)
7 hostname, port = sock
8+ reason = 'No suitable address family'
9 for (family, socktype, proto, canonname, sockaddr) in socket.getaddrinfo(hostname, port, socket.AF_UNSPEC, socket.SOCK_STREAM):
10 if socktype == socket.SOCK_STREAM:
11 af = family
12 addr = sockaddr
13- break
14+ sock = socket.socket(af, socket.SOCK_STREAM)
15+ try:
16+ sock.connect((hostname, port))
17+ except socket.error, e:
18+ reason = str(e)
19+ else:
20+ break
21 else:
22- raise SSHException('No suitable address family for %s' % hostname)
23- sock = socket.socket(af, socket.SOCK_STREAM)
24- sock.connect((hostname, port))
25+ raise SSHException(
26+ 'Unable to connect to %s: %s' % (hostname, reason))
27 # okay, normal socket-ish flow here...
28 threading.Thread.__init__(self)
29 self.setDaemon(True)
30
031
=== added file 'debian/patches/series'
--- debian/patches/series 1970-01-01 00:00:00 +0000
+++ debian/patches/series 2011-01-18 19:52:31 +0000
@@ -0,0 +1,2 @@
101_no-randompool.patch
202_addressfamilies.patch
03
=== added directory 'debian/source'
=== added file 'debian/source/format'
--- debian/source/format 1970-01-01 00:00:00 +0000
+++ debian/source/format 2011-01-18 19:52:31 +0000
@@ -0,0 +1,1 @@
13.0 (quilt)

Subscribers

People subscribed via source and target branches