Switch from using PyCrypto's Random to using os.urandom.

There's several reasons for this change:

1) It's faster for reads up to 1024 bytes (nearly 10x faster for 16 byte reads)
2) It receives considerably more security review since it's in the kernel.
3) It's yet another step towards running on PyPy.
4) Using userspace CSPRNGs is considered something of an anti-pattern. See:
   http://sockpuppet.org/blog/2014/02/25/safely-generate-random-numbers/
   http://webcache.googleusercontent.com/search?q=cache:2nTvpCgKZXIJ:www.2uo.de/myths-about-urandom/+&cd=3&hl=en&ct=clnk&gl=us
This commit is contained in:
Alex Gaynor 2014-03-29 19:22:36 -07:00
parent 5a430def22
commit 6f211115f4
18 changed files with 84 additions and 84 deletions

View File

@ -364,7 +364,7 @@ class AgentKey(PKey):
def get_name(self): def get_name(self):
return self.name return self.name
def sign_ssh_data(self, rng, data): def sign_ssh_data(self, data):
msg = Message() msg = Message()
msg.add_byte(cSSH2_AGENTC_SIGN_REQUEST) msg.add_byte(cSSH2_AGENTC_SIGN_REQUEST)
msg.add_string(self.blob) msg.add_string(self.blob)

View File

@ -206,7 +206,7 @@ class AuthHandler (object):
m.add_string(self.private_key.get_name()) m.add_string(self.private_key.get_name())
m.add_string(self.private_key) m.add_string(self.private_key)
blob = self._get_session_blob(self.private_key, 'ssh-connection', self.username) blob = self._get_session_blob(self.private_key, 'ssh-connection', self.username)
sig = self.private_key.sign_ssh_data(self.transport.rng, blob) sig = self.private_key.sign_ssh_data(blob)
m.add_string(sig) m.add_string(sig)
elif self.auth_method == 'keyboard-interactive': elif self.auth_method == 'keyboard-interactive':
m.add_string('') m.add_string('')

View File

@ -21,9 +21,10 @@ Abstraction for an SSH2 channel.
""" """
import binascii import binascii
import os
import socket
import time import time
import threading import threading
import socket
from paramiko import util from paramiko import util
from paramiko.common import cMSG_CHANNEL_REQUEST, cMSG_CHANNEL_WINDOW_ADJUST, \ from paramiko.common import cMSG_CHANNEL_REQUEST, cMSG_CHANNEL_WINDOW_ADJUST, \
@ -358,7 +359,7 @@ class Channel (object):
if auth_protocol is None: if auth_protocol is None:
auth_protocol = 'MIT-MAGIC-COOKIE-1' auth_protocol = 'MIT-MAGIC-COOKIE-1'
if auth_cookie is None: if auth_cookie is None:
auth_cookie = binascii.hexlify(self.transport.rng.read(16)) auth_cookie = binascii.hexlify(os.urandom(16))
m = Message() m = Message()
m.add_byte(cMSG_CHANNEL_REQUEST) m.add_byte(cMSG_CHANNEL_REQUEST)

View File

@ -126,11 +126,6 @@ CONNECTION_FAILED_CODE = {
DISCONNECT_SERVICE_NOT_AVAILABLE, DISCONNECT_AUTH_CANCELLED_BY_USER, \ DISCONNECT_SERVICE_NOT_AVAILABLE, DISCONNECT_AUTH_CANCELLED_BY_USER, \
DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE = 7, 13, 14 DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE = 7, 13, 14
from Crypto import Random
# keep a crypto-strong PRNG nearby
rng = Random.new()
zero_byte = byte_chr(0) zero_byte = byte_chr(0)
one_byte = byte_chr(1) one_byte = byte_chr(1)
four_byte = byte_chr(4) four_byte = byte_chr(4)

View File

@ -20,11 +20,13 @@
DSS keys. DSS keys.
""" """
import os
from Crypto.PublicKey import DSA from Crypto.PublicKey import DSA
from Crypto.Hash import SHA from Crypto.Hash import SHA
from paramiko import util from paramiko import util
from paramiko.common import zero_byte, rng from paramiko.common import zero_byte
from paramiko.py3compat import long from paramiko.py3compat import long
from paramiko.ssh_exception import SSHException from paramiko.ssh_exception import SSHException
from paramiko.message import Message from paramiko.message import Message
@ -91,17 +93,17 @@ class DSSKey (PKey):
def get_bits(self): def get_bits(self):
return self.size return self.size
def can_sign(self): def can_sign(self):
return self.x is not None return self.x is not None
def sign_ssh_data(self, rng, data): def sign_ssh_data(self, data):
digest = SHA.new(data).digest() digest = SHA.new(data).digest()
dss = DSA.construct((long(self.y), long(self.g), long(self.p), long(self.q), long(self.x))) dss = DSA.construct((long(self.y), long(self.g), long(self.p), long(self.q), long(self.x)))
# generate a suitable k # generate a suitable k
qsize = len(util.deflate_long(self.q, 0)) qsize = len(util.deflate_long(self.q, 0))
while True: while True:
k = util.inflate_long(rng.read(qsize), 1) k = util.inflate_long(os.urandom(qsize), 1)
if (k > 2) and (k < self.q): if (k > 2) and (k < self.q):
break break
r, s = dss.sign(util.inflate_long(digest, 1), k) r, s = dss.sign(util.inflate_long(digest, 1), k)
@ -163,7 +165,7 @@ class DSSKey (PKey):
by ``pyCrypto.PublicKey``). by ``pyCrypto.PublicKey``).
:return: new `.DSSKey` private key :return: new `.DSSKey` private key
""" """
dsa = DSA.generate(bits, rng.read, progress_func) dsa = DSA.generate(bits, os.urandom, progress_func)
key = DSSKey(vals=(dsa.p, dsa.q, dsa.g, dsa.y)) key = DSSKey(vals=(dsa.p, dsa.q, dsa.g, dsa.y))
key.x = dsa.x key.x = dsa.x
return key return key
@ -174,11 +176,11 @@ class DSSKey (PKey):
def _from_private_key_file(self, filename, password): def _from_private_key_file(self, filename, password):
data = self._read_private_key_file('DSA', filename, password) data = self._read_private_key_file('DSA', filename, password)
self._decode_key(data) self._decode_key(data)
def _from_private_key(self, file_obj, password): def _from_private_key(self, file_obj, password):
data = self._read_private_key('DSA', file_obj, password) data = self._read_private_key('DSA', file_obj, password)
self._decode_key(data) self._decode_key(data)
def _decode_key(self, data): def _decode_key(self, data):
# private key file contains: # private key file contains:
# DSAPrivateKey = { version = 0, p, q, g, y, x } # DSAPrivateKey = { version = 0, p, q, g, y, x }

View File

@ -21,11 +21,14 @@ L{ECDSAKey}
""" """
import binascii import binascii
from ecdsa import SigningKey, VerifyingKey, der, curves import os
from Crypto.Hash import SHA256
from ecdsa.test_pyecdsa import ECDSA
from paramiko.common import four_byte, one_byte
from ecdsa import SigningKey, VerifyingKey, der, curves
from ecdsa.test_pyecdsa import ECDSA
from Crypto.Hash import SHA256
from paramiko.common import four_byte, one_byte
from paramiko.message import Message from paramiko.message import Message
from paramiko.pkey import PKey from paramiko.pkey import PKey
from paramiko.py3compat import byte_chr, u from paramiko.py3compat import byte_chr, u
@ -97,9 +100,9 @@ class ECDSAKey (PKey):
def can_sign(self): def can_sign(self):
return self.signing_key is not None return self.signing_key is not None
def sign_ssh_data(self, rpool, data): def sign_ssh_data(self, data):
digest = SHA256.new(data).digest() digest = SHA256.new(data).digest()
sig = self.signing_key.sign_digest(digest, entropy=rpool.read, sig = self.signing_key.sign_digest(digest, entropy=os.urandom,
sigencode=self._sigencode) sigencode=self._sigencode)
m = Message() m = Message()
m.add_string('ecdsa-sha2-nistp256') m.add_string('ecdsa-sha2-nistp256')

View File

@ -18,8 +18,10 @@
import binascii import binascii
import os
from Crypto.Hash import SHA, HMAC from Crypto.Hash import SHA, HMAC
from paramiko.common import rng
from paramiko.py3compat import b, u, encodebytes, decodebytes from paramiko.py3compat import b, u, encodebytes, decodebytes
try: try:
@ -262,7 +264,7 @@ class HostKeys (MutableMapping):
:return: the hashed hostname as a `str` :return: the hashed hostname as a `str`
""" """
if salt is None: if salt is None:
salt = rng.read(SHA.digest_size) salt = os.urandom(SHA.digest_size)
else: else:
if salt.startswith('|1|'): if salt.startswith('|1|'):
salt = salt.split('|')[2] salt = salt.split('|')[2]

View File

@ -22,6 +22,8 @@ generator "g" are provided by the server. A bit more work is required on the
client side, and a B{lot} more on the server side. client side, and a B{lot} more on the server side.
""" """
import os
from Crypto.Hash import SHA from Crypto.Hash import SHA
from paramiko import util from paramiko import util
@ -101,7 +103,7 @@ class KexGex (object):
qhbyte <<= 1 qhbyte <<= 1
qmask >>= 1 qmask >>= 1
while True: while True:
x_bytes = self.transport.rng.read(byte_count) x_bytes = os.urandom(byte_count)
x_bytes = byte_mask(x_bytes[0], qmask) + x_bytes[1:] x_bytes = byte_mask(x_bytes[0], qmask) + x_bytes[1:]
x = util.inflate_long(x_bytes, 1) x = util.inflate_long(x_bytes, 1)
if (x > 1) and (x < q): if (x > 1) and (x < q):
@ -206,7 +208,7 @@ class KexGex (object):
H = SHA.new(hm.asbytes()).digest() H = SHA.new(hm.asbytes()).digest()
self.transport._set_K_H(K, H) self.transport._set_K_H(K, H)
# sign it # sign it
sig = self.transport.get_server_key().sign_ssh_data(self.transport.rng, H) sig = self.transport.get_server_key().sign_ssh_data(H)
# send reply # send reply
m = Message() m = Message()
m.add_byte(c_MSG_KEXDH_GEX_REPLY) m.add_byte(c_MSG_KEXDH_GEX_REPLY)
@ -215,7 +217,7 @@ class KexGex (object):
m.add_string(sig) m.add_string(sig)
self.transport._send_message(m) self.transport._send_message(m)
self.transport._activate_outbound() self.transport._activate_outbound()
def _parse_kexdh_gex_reply(self, m): def _parse_kexdh_gex_reply(self, m):
host_key = m.get_string() host_key = m.get_string()
self.f = m.get_mpint() self.f = m.get_mpint()

View File

@ -21,6 +21,8 @@ Standard SSH key exchange ("kex" if you wanna sound cool). Diffie-Hellman of
1024 bit key halves, using a known "p" prime and "g" generator. 1024 bit key halves, using a known "p" prime and "g" generator.
""" """
import os
from Crypto.Hash import SHA from Crypto.Hash import SHA
from paramiko import util from paramiko import util
@ -82,7 +84,7 @@ class KexGroup1(object):
# potential x where the first 63 bits are 1, because some of those will be # potential x where the first 63 bits are 1, because some of those will be
# larger than q (but this is a tiny tiny subset of potential x). # larger than q (but this is a tiny tiny subset of potential x).
while 1: while 1:
x_bytes = self.transport.rng.read(128) x_bytes = os.urandom(128)
x_bytes = byte_mask(x_bytes[0], 0x7f) + x_bytes[1:] x_bytes = byte_mask(x_bytes[0], 0x7f) + x_bytes[1:]
if (x_bytes[:8] != b7fffffffffffffff and if (x_bytes[:8] != b7fffffffffffffff and
x_bytes[:8] != b0000000000000000): x_bytes[:8] != b0000000000000000):
@ -127,7 +129,7 @@ class KexGroup1(object):
H = SHA.new(hm.asbytes()).digest() H = SHA.new(hm.asbytes()).digest()
self.transport._set_K_H(K, H) self.transport._set_K_H(K, H)
# sign it # sign it
sig = self.transport.get_server_key().sign_ssh_data(self.transport.rng, H) sig = self.transport.get_server_key().sign_ssh_data(H)
# send reply # send reply
m = Message() m = Message()
m.add_byte(c_MSG_KEXDH_REPLY) m.add_byte(c_MSG_KEXDH_REPLY)

View File

@ -21,6 +21,7 @@ Packet handling
""" """
import errno import errno
import os
import socket import socket
import struct import struct
import threading import threading
@ -28,7 +29,7 @@ import time
from paramiko import util from paramiko import util
from paramiko.common import linefeed_byte, cr_byte_value, asbytes, MSG_NAMES, \ from paramiko.common import linefeed_byte, cr_byte_value, asbytes, MSG_NAMES, \
DEBUG, xffffffff, zero_byte, rng DEBUG, xffffffff, zero_byte
from paramiko.py3compat import u, byte_ord from paramiko.py3compat import u, byte_ord
from paramiko.ssh_exception import SSHException, ProxyCommandFailure from paramiko.ssh_exception import SSHException, ProxyCommandFailure
from paramiko.message import Message from paramiko.message import Message
@ -455,7 +456,7 @@ class Packetizer (object):
# don't waste random bytes for the padding # don't waste random bytes for the padding
packet += (zero_byte * padding) packet += (zero_byte * padding)
else: else:
packet += rng.read(padding) packet += os.urandom(padding)
return packet return packet
def _trigger_rekey(self): def _trigger_rekey(self):

View File

@ -28,7 +28,7 @@ from Crypto.Hash import MD5
from Crypto.Cipher import DES3, AES from Crypto.Cipher import DES3, AES
from paramiko import util from paramiko import util
from paramiko.common import o600, rng, zero_byte from paramiko.common import o600, zero_byte
from paramiko.py3compat import u, encodebytes, decodebytes, b from paramiko.py3compat import u, encodebytes, decodebytes, b
from paramiko.ssh_exception import SSHException, PasswordRequiredException from paramiko.ssh_exception import SSHException, PasswordRequiredException
@ -138,12 +138,11 @@ class PKey (object):
""" """
return u(encodebytes(self.asbytes())).replace('\n', '') return u(encodebytes(self.asbytes())).replace('\n', '')
def sign_ssh_data(self, rng, data): def sign_ssh_data(self, data):
""" """
Sign a blob of data with this private key, and return a `.Message` Sign a blob of data with this private key, and return a `.Message`
representing an SSH signature message. representing an SSH signature message.
:param .Crypto.Util.rng.RandomPool rng: a secure random number generator.
:param str data: the data to sign. :param str data: the data to sign.
:return: an SSH signature `message <.Message>`. :return: an SSH signature `message <.Message>`.
""" """
@ -331,11 +330,11 @@ class PKey (object):
keysize = self._CIPHER_TABLE[cipher_name]['keysize'] keysize = self._CIPHER_TABLE[cipher_name]['keysize']
blocksize = self._CIPHER_TABLE[cipher_name]['blocksize'] blocksize = self._CIPHER_TABLE[cipher_name]['blocksize']
mode = self._CIPHER_TABLE[cipher_name]['mode'] mode = self._CIPHER_TABLE[cipher_name]['mode']
salt = rng.read(16) salt = os.urandom(16)
key = util.generate_key_bytes(MD5, salt, password, keysize) key = util.generate_key_bytes(MD5, salt, password, keysize)
if len(data) % blocksize != 0: if len(data) % blocksize != 0:
n = blocksize - len(data) % blocksize n = blocksize - len(data) % blocksize
#data += rng.read(n) #data += os.urandom(n)
# that would make more sense ^, but it confuses openssh. # that would make more sense ^, but it confuses openssh.
data += zero_byte * n data += zero_byte * n
data = cipher.new(key, mode, salt).encrypt(data) data = cipher.new(key, mode, salt).encrypt(data)

View File

@ -20,6 +20,8 @@
Utility functions for dealing with primes. Utility functions for dealing with primes.
""" """
import os
from Crypto.Util import number from Crypto.Util import number
from paramiko import util from paramiko import util
@ -27,12 +29,12 @@ from paramiko.py3compat import byte_mask, long
from paramiko.ssh_exception import SSHException from paramiko.ssh_exception import SSHException
def _generate_prime(bits, rng): def _generate_prime(bits):
"""primtive attempt at prime generation""" """primtive attempt at prime generation"""
hbyte_mask = pow(2, bits % 8) - 1 hbyte_mask = pow(2, bits % 8) - 1
while True: while True:
# loop catches the case where we increment n into a higher bit-range # loop catches the case where we increment n into a higher bit-range
x = rng.read((bits + 7) // 8) x = os.urandom((bits + 7) // 8)
if hbyte_mask > 0: if hbyte_mask > 0:
x = byte_mask(x[0], hbyte_mask) + x[1:] x = byte_mask(x[0], hbyte_mask) + x[1:]
n = util.inflate_long(x, 1) n = util.inflate_long(x, 1)
@ -45,7 +47,7 @@ def _generate_prime(bits, rng):
return n return n
def _roll_random(rng, n): def _roll_random(n):
"""returns a random # from 0 to N-1""" """returns a random # from 0 to N-1"""
bits = util.bit_length(n - 1) bits = util.bit_length(n - 1)
byte_count = (bits + 7) // 8 byte_count = (bits + 7) // 8
@ -58,7 +60,7 @@ def _roll_random(rng, n):
# fits, so i can't guarantee that this loop will ever finish, but the odds # fits, so i can't guarantee that this loop will ever finish, but the odds
# of it looping forever should be infinitesimal. # of it looping forever should be infinitesimal.
while True: while True:
x = rng.read(byte_count) x = os.urandom(byte_count)
if hbyte_mask > 0: if hbyte_mask > 0:
x = byte_mask(x[0], hbyte_mask) + x[1:] x = byte_mask(x[0], hbyte_mask) + x[1:]
num = util.inflate_long(x, 1) num = util.inflate_long(x, 1)
@ -73,11 +75,10 @@ class ModulusPack (object):
on systems that have such a file. on systems that have such a file.
""" """
def __init__(self, rpool): def __init__(self):
# pack is a hash of: bits -> [ (generator, modulus) ... ] # pack is a hash of: bits -> [ (generator, modulus) ... ]
self.pack = {} self.pack = {}
self.discarded = [] self.discarded = []
self.rng = rpool
def _parse_modulus(self, line): def _parse_modulus(self, line):
timestamp, mod_type, tests, tries, size, generator, modulus = line.split() timestamp, mod_type, tests, tries, size, generator, modulus = line.split()
@ -147,5 +148,5 @@ class ModulusPack (object):
if min > good: if min > good:
good = bitsizes[-1] good = bitsizes[-1]
# now pick a random modulus of this bitsize # now pick a random modulus of this bitsize
n = _roll_random(self.rng, len(self.pack[good])) n = _roll_random(len(self.pack[good]))
return self.pack[good][n] return self.pack[good][n]

View File

@ -20,11 +20,13 @@
RSA keys. RSA keys.
""" """
import os
from Crypto.PublicKey import RSA from Crypto.PublicKey import RSA
from Crypto.Hash import SHA from Crypto.Hash import SHA
from paramiko import util from paramiko import util
from paramiko.common import rng, max_byte, zero_byte, one_byte from paramiko.common import max_byte, zero_byte, one_byte
from paramiko.message import Message from paramiko.message import Message
from paramiko.ber import BER, BERException from paramiko.ber import BER, BERException
from paramiko.pkey import PKey from paramiko.pkey import PKey
@ -90,7 +92,7 @@ class RSAKey (PKey):
def can_sign(self): def can_sign(self):
return self.d is not None return self.d is not None
def sign_ssh_data(self, rpool, data): def sign_ssh_data(self, data):
digest = SHA.new(data).digest() digest = SHA.new(data).digest()
rsa = RSA.construct((long(self.n), long(self.e), long(self.d))) rsa = RSA.construct((long(self.n), long(self.e), long(self.d)))
sig = util.deflate_long(rsa.sign(self._pkcs1imify(digest), bytes())[0], 0) sig = util.deflate_long(rsa.sign(self._pkcs1imify(digest), bytes())[0], 0)
@ -125,7 +127,7 @@ class RSAKey (PKey):
def write_private_key_file(self, filename, password=None): def write_private_key_file(self, filename, password=None):
self._write_private_key_file('RSA', filename, self._encode_key(), password) self._write_private_key_file('RSA', filename, self._encode_key(), password)
def write_private_key(self, file_obj, password=None): def write_private_key(self, file_obj, password=None):
self._write_private_key('RSA', file_obj, self._encode_key(), password) self._write_private_key('RSA', file_obj, self._encode_key(), password)
@ -140,7 +142,7 @@ class RSAKey (PKey):
by ``pyCrypto.PublicKey``). by ``pyCrypto.PublicKey``).
:return: new `.RSAKey` private key :return: new `.RSAKey` private key
""" """
rsa = RSA.generate(bits, rng.read, progress_func) rsa = RSA.generate(bits, os.urandom, progress_func)
key = RSAKey(vals=(rsa.e, rsa.n)) key = RSAKey(vals=(rsa.e, rsa.n))
key.d = rsa.d key.d = rsa.d
key.p = rsa.p key.p = rsa.p
@ -162,11 +164,11 @@ class RSAKey (PKey):
def _from_private_key_file(self, filename, password): def _from_private_key_file(self, filename, password):
data = self._read_private_key_file('RSA', filename, password) data = self._read_private_key_file('RSA', filename, password)
self._decode_key(data) self._decode_key(data)
def _from_private_key(self, file_obj, password): def _from_private_key(self, file_obj, password):
data = self._read_private_key('RSA', file_obj, password) data = self._read_private_key('RSA', file_obj, password)
self._decode_key(data) self._decode_key(data)
def _decode_key(self, data): def _decode_key(self, data):
# private key file contains: # private key file contains:
# RSAPrivateKey = { version = 0, n, e, d, p, q, d mod p-1, d mod q-1, q**-1 mod p } # RSAPrivateKey = { version = 0, n, e, d, p, q, d mod p-1, d mod q-1, q**-1 mod p }

View File

@ -20,6 +20,7 @@
Core protocol implementation Core protocol implementation
""" """
import os
import socket import socket
import sys import sys
import threading import threading
@ -30,7 +31,7 @@ import paramiko
from paramiko import util from paramiko import util
from paramiko.auth_handler import AuthHandler from paramiko.auth_handler import AuthHandler
from paramiko.channel import Channel from paramiko.channel import Channel
from paramiko.common import rng, xffffffff, cMSG_CHANNEL_OPEN, cMSG_IGNORE, \ from paramiko.common import xffffffff, cMSG_CHANNEL_OPEN, cMSG_IGNORE, \
cMSG_GLOBAL_REQUEST, DEBUG, MSG_KEXINIT, MSG_IGNORE, MSG_DISCONNECT, \ cMSG_GLOBAL_REQUEST, DEBUG, MSG_KEXINIT, MSG_IGNORE, MSG_DISCONNECT, \
MSG_DEBUG, ERROR, WARNING, cMSG_UNIMPLEMENTED, INFO, cMSG_KEXINIT, \ MSG_DEBUG, ERROR, WARNING, cMSG_UNIMPLEMENTED, INFO, cMSG_KEXINIT, \
cMSG_NEWKEYS, MSG_NEWKEYS, cMSG_REQUEST_SUCCESS, cMSG_REQUEST_FAILURE, \ cMSG_NEWKEYS, MSG_NEWKEYS, cMSG_REQUEST_SUCCESS, cMSG_REQUEST_FAILURE, \
@ -57,7 +58,6 @@ from paramiko.ssh_exception import (SSHException, BadAuthenticationType,
ChannelException, ProxyCommandFailure) ChannelException, ProxyCommandFailure)
from paramiko.util import retry_on_signal from paramiko.util import retry_on_signal
from Crypto import Random
from Crypto.Cipher import Blowfish, AES, DES3, ARC4 from Crypto.Cipher import Blowfish, AES, DES3, ARC4
from Crypto.Hash import SHA, MD5 from Crypto.Hash import SHA, MD5
try: try:
@ -192,7 +192,6 @@ class Transport (threading.Thread):
# okay, normal socket-ish flow here... # okay, normal socket-ish flow here...
threading.Thread.__init__(self) threading.Thread.__init__(self)
self.setDaemon(True) self.setDaemon(True)
self.rng = rng
self.sock = sock self.sock = sock
# Python < 2.3 doesn't have the settimeout method - RogerB # Python < 2.3 doesn't have the settimeout method - RogerB
try: try:
@ -339,7 +338,6 @@ class Transport (threading.Thread):
# synchronous, wait for a result # synchronous, wait for a result
self.completion_event = event = threading.Event() self.completion_event = event = threading.Event()
self.start() self.start()
Random.atfork()
while True: while True:
event.wait(0.1) event.wait(0.1)
if not self.active: if not self.active:
@ -475,7 +473,7 @@ class Transport (threading.Thread):
.. note:: This has no effect when used in client mode. .. note:: This has no effect when used in client mode.
""" """
Transport._modulus_pack = ModulusPack(rng) Transport._modulus_pack = ModulusPack()
# places to look for the openssh "moduli" file # places to look for the openssh "moduli" file
file_list = ['/etc/ssh/moduli', '/usr/local/etc/moduli'] file_list = ['/etc/ssh/moduli', '/usr/local/etc/moduli']
if filename is not None: if filename is not None:
@ -732,8 +730,8 @@ class Transport (threading.Thread):
m = Message() m = Message()
m.add_byte(cMSG_IGNORE) m.add_byte(cMSG_IGNORE)
if byte_count is None: if byte_count is None:
byte_count = (byte_ord(rng.read(1)) % 32) + 10 byte_count = (byte_ord(os.urandom(1)) % 32) + 10
m.add_bytes(rng.read(byte_count)) m.add_bytes(os.urandom(byte_count))
self._send_user_message(m) self._send_user_message(m)
def renegotiate_keys(self): def renegotiate_keys(self):
@ -1402,10 +1400,6 @@ class Transport (threading.Thread):
# interpreter shutdown. # interpreter shutdown.
self.sys = sys self.sys = sys
# Required to prevent RNG errors when running inside many subprocess
# containers.
Random.atfork()
# active=True occurs before the thread is launched, to avoid a race # active=True occurs before the thread is launched, to avoid a race
_active_threads.append(self) _active_threads.append(self)
if self.server_mode: if self.server_mode:
@ -1590,7 +1584,7 @@ class Transport (threading.Thread):
m = Message() m = Message()
m.add_byte(cMSG_KEXINIT) m.add_byte(cMSG_KEXINIT)
m.add_bytes(rng.read(16)) m.add_bytes(os.urandom(16))
m.add_list(self._preferred_kex) m.add_list(self._preferred_kex)
m.add_list(available_server_keys) m.add_list(available_server_keys)
m.add_list(self._preferred_ciphers) m.add_list(self._preferred_ciphers)

View File

@ -101,12 +101,12 @@ def main():
parser.add_option('-P', '--sftp-passwd', dest='password', type='string', default=default_passwd, parser.add_option('-P', '--sftp-passwd', dest='password', type='string', default=default_passwd,
metavar='<password>', metavar='<password>',
help='[with -R] (optional) password to unlock the private key for remote sftp tests') help='[with -R] (optional) password to unlock the private key for remote sftp tests')
options, args = parser.parse_args() options, args = parser.parse_args()
# setup logging # setup logging
paramiko.util.log_to_file('test.log') paramiko.util.log_to_file('test.log')
if options.use_sftp: if options.use_sftp:
from tests.test_sftp import SFTPTest from tests.test_sftp import SFTPTest
if options.use_loopback_sftp: if options.use_loopback_sftp:

View File

@ -21,7 +21,9 @@ Some unit tests for the key exchange protocols.
""" """
from binascii import hexlify from binascii import hexlify
import os
import unittest import unittest
import paramiko.util import paramiko.util
from paramiko.kex_group1 import KexGroup1 from paramiko.kex_group1 import KexGroup1
from paramiko.kex_gex import KexGex from paramiko.kex_gex import KexGex
@ -29,9 +31,8 @@ from paramiko import Message
from paramiko.common import byte_chr from paramiko.common import byte_chr
class FakeRng (object): def dummy_urandom(n):
def read(self, n): return byte_chr(0xcc) * n
return byte_chr(0xcc) * n
class FakeKey (object): class FakeKey (object):
@ -41,7 +42,7 @@ class FakeKey (object):
def asbytes(self): def asbytes(self):
return b'fake-key' return b'fake-key'
def sign_ssh_data(self, rng, H): def sign_ssh_data(self, H):
return b'fake-sig' return b'fake-sig'
@ -53,8 +54,7 @@ class FakeModulusPack (object):
return self.G, self.P return self.G, self.P
class FakeTransport (object): class FakeTransport(object):
rng = FakeRng()
local_version = 'SSH-2.0-paramiko_1.0' local_version = 'SSH-2.0-paramiko_1.0'
remote_version = 'SSH-2.0-lame' remote_version = 'SSH-2.0-lame'
local_kex_init = 'local-kex-init' local_kex_init = 'local-kex-init'
@ -91,10 +91,11 @@ class KexTest (unittest.TestCase):
K = 14730343317708716439807310032871972459448364195094179797249681733965528989482751523943515690110179031004049109375612685505881911274101441415545039654102474376472240501616988799699744135291070488314748284283496055223852115360852283821334858541043710301057312858051901453919067023103730011648890038847384890504 K = 14730343317708716439807310032871972459448364195094179797249681733965528989482751523943515690110179031004049109375612685505881911274101441415545039654102474376472240501616988799699744135291070488314748284283496055223852115360852283821334858541043710301057312858051901453919067023103730011648890038847384890504
def setUp(self): def setUp(self):
pass self._original_urandom = os.urandom
os.urandom = dummy_urandom
def tearDown(self): def tearDown(self):
pass os.urandom = self._original_urandom
def test_1_group1_client(self): def test_1_group1_client(self):
transport = FakeTransport() transport = FakeTransport()

View File

@ -22,9 +22,10 @@ Some unit tests for public/private key objects.
from binascii import hexlify from binascii import hexlify
import unittest import unittest
from paramiko import RSAKey, DSSKey, ECDSAKey, Message, util from paramiko import RSAKey, DSSKey, ECDSAKey, Message, util
from paramiko.py3compat import StringIO, byte_chr, b, bytes from paramiko.py3compat import StringIO, byte_chr, b, bytes
from paramiko.common import rng
from tests.util import test_path from tests.util import test_path
# from openssh's ssh-keygen # from openssh's ssh-keygen
@ -166,7 +167,7 @@ class KeyTest (unittest.TestCase):
def test_8_sign_rsa(self): def test_8_sign_rsa(self):
# verify that the rsa private key can sign and verify # verify that the rsa private key can sign and verify
key = RSAKey.from_private_key_file(test_path('test_rsa.key')) key = RSAKey.from_private_key_file(test_path('test_rsa.key'))
msg = key.sign_ssh_data(rng, b'ice weasels') msg = key.sign_ssh_data(b'ice weasels')
self.assertTrue(type(msg) is Message) self.assertTrue(type(msg) is Message)
msg.rewind() msg.rewind()
self.assertEqual('ssh-rsa', msg.get_text()) self.assertEqual('ssh-rsa', msg.get_text())
@ -179,7 +180,7 @@ class KeyTest (unittest.TestCase):
def test_9_sign_dss(self): def test_9_sign_dss(self):
# verify that the dss private key can sign and verify # verify that the dss private key can sign and verify
key = DSSKey.from_private_key_file(test_path('test_dss.key')) key = DSSKey.from_private_key_file(test_path('test_dss.key'))
msg = key.sign_ssh_data(rng, b'ice weasels') msg = key.sign_ssh_data(b'ice weasels')
self.assertTrue(type(msg) is Message) self.assertTrue(type(msg) is Message)
msg.rewind() msg.rewind()
self.assertEqual('ssh-dss', msg.get_text()) self.assertEqual('ssh-dss', msg.get_text())
@ -193,13 +194,13 @@ class KeyTest (unittest.TestCase):
def test_A_generate_rsa(self): def test_A_generate_rsa(self):
key = RSAKey.generate(1024) key = RSAKey.generate(1024)
msg = key.sign_ssh_data(rng, b'jerri blank') msg = key.sign_ssh_data(b'jerri blank')
msg.rewind() msg.rewind()
self.assertTrue(key.verify_ssh_sig(b'jerri blank', msg)) self.assertTrue(key.verify_ssh_sig(b'jerri blank', msg))
def test_B_generate_dss(self): def test_B_generate_dss(self):
key = DSSKey.generate(1024) key = DSSKey.generate(1024)
msg = key.sign_ssh_data(rng, b'jerri blank') msg = key.sign_ssh_data(b'jerri blank')
msg.rewind() msg.rewind()
self.assertTrue(key.verify_ssh_sig(b'jerri blank', msg)) self.assertTrue(key.verify_ssh_sig(b'jerri blank', msg))
@ -240,7 +241,7 @@ class KeyTest (unittest.TestCase):
def test_13_sign_ecdsa(self): def test_13_sign_ecdsa(self):
# verify that the rsa private key can sign and verify # verify that the rsa private key can sign and verify
key = ECDSAKey.from_private_key_file(test_path('test_ecdsa.key')) key = ECDSAKey.from_private_key_file(test_path('test_ecdsa.key'))
msg = key.sign_ssh_data(rng, b'ice weasels') msg = key.sign_ssh_data(b'ice weasels')
self.assertTrue(type(msg) is Message) self.assertTrue(type(msg) is Message)
msg.rewind() msg.rewind()
self.assertEqual('ecdsa-sha2-nistp256', msg.get_text()) self.assertEqual('ecdsa-sha2-nistp256', msg.get_text())

View File

@ -153,12 +153,6 @@ class UtilTest(ParamikoTest):
finally: finally:
os.unlink('hostfile.temp') os.unlink('hostfile.temp')
def test_6_random(self):
from paramiko.common import rng
# just verify that we can pull out 32 bytes and not get an exception.
x = rng.read(32)
self.assertEqual(len(x), 32)
def test_7_host_config_expose_issue_33(self): def test_7_host_config_expose_issue_33(self):
test_config_file = """ test_config_file = """
Host www13.* Host www13.*