diff -r e5c1a87858fd -r d8924d870370 components/python/paramiko/patches/01-nopycrypto.patch
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/components/python/paramiko/patches/01-nopycrypto.patch Fri Jun 19 09:35:02 2015 +0100
@@ -0,0 +1,1613 @@
+External but not-yet-integrated patch that changes Paramiko to use
+"cryptography" rather than "PyCrypto". The changes have been modified
+from
+
+ https://github.com/paramiko/paramiko/pull/394/files
+
+to patch cleanly into Paramiko 1.15.2.
+This patch is a stop-gap and will be removed when the upstream Paramiko
+completes the transition to "cryptography".
+
+--- paramiko-1.15.2/README.~1~ 2014-12-19 15:01:22.000000000 -0800
++++ paramiko-1.15.2/README 2015-04-12 17:36:15.204911382 -0700
+@@ -25,7 +25,7 @@ channels to remote services across the e
+ works, for example).
+
+ it is written entirely in python (no C or platform-dependent code) and is
+-released under the GNU LGPL (lesser GPL).
++released under the GNU LGPL (lesser GPL).
+
+ the package and its API is fairly well documented in the "doc/" folder
+ that should have come with this archive.
+@@ -36,8 +36,8 @@ Requirements
+
+ - Python 2.6 or better - this includes Python
+ 3.2 and higher as well.
+- - pycrypto 2.1 or better
+- - ecdsa 0.9 or better
++ - Cryptography 0.8 or better
++ - pyasn1 0.1.7 or better
+
+ If you have setuptools, you can build and install paramiko and all its
+ dependencies with this command (as root)::
+--- paramiko-1.15.2/paramiko/_winapi.py.~1~ 2014-12-19 15:01:22.000000000 -0800
++++ paramiko-1.15.2/paramiko/_winapi.py 2015-04-12 17:36:15.205197752 -0700
+@@ -106,7 +106,7 @@ MapViewOfFile.restype = ctypes.wintypes.
+
+ class MemoryMap(object):
+ """
+- A memory map object which can have security attributes overrideden.
++ A memory map object which can have security attributes overridden.
+ """
+ def __init__(self, name, length, security_attributes=None):
+ self.name = name
+--- paramiko-1.15.2/paramiko/agent.py.~1~ 2014-12-19 15:01:22.000000000 -0800
++++ paramiko-1.15.2/paramiko/agent.py 2015-04-12 17:36:15.205474363 -0700
+@@ -32,7 +32,7 @@ from select import select
+ from paramiko.common import asbytes, io_sleep
+ from paramiko.py3compat import byte_chr
+
+-from paramiko.ssh_exception import SSHException
++from paramiko.ssh_exception import SSHException, AuthenticationException
+ from paramiko.message import Message
+ from paramiko.pkey import PKey
+ from paramiko.util import retry_on_signal
+@@ -109,9 +109,12 @@ class AgentProxyThread(threading.Thread)
+ def run(self):
+ try:
+ (r, addr) = self.get_connection()
++ # Found that r should be either a socket from the socket library or None
+ self.__inr = r
+- self.__addr = addr
++ self.__addr = addr # This should be an IP address as a string? or None
+ self._agent.connect()
++ if not isinstance(self._agent, int) and (self._agent._conn is None or not hasattr(self._agent._conn, 'fileno')):
++ raise AuthenticationException("Unable to connect to SSH agent")
+ self._communicate()
+ except:
+ #XXX Not sure what to do here ... raise or pass ?
+--- paramiko-1.15.2/paramiko/channel.py.~1~ 2014-12-19 15:01:22.000000000 -0800
++++ paramiko-1.15.2/paramiko/channel.py 2015-04-12 17:36:15.205880064 -0700
+@@ -337,7 +337,7 @@ class Channel (ClosingContextManager):
+ further x11 requests can be made from the server to the client,
+ when an x11 application is run in a shell session.
+
+- From RFC4254::
++ From :rfc:`4254`::
+
+ It is RECOMMENDED that the 'x11 authentication cookie' that is
+ sent be a fake, random cookie, and that the cookie be checked and
+--- paramiko-1.15.2/paramiko/client.py.~1~ 2014-12-19 15:01:22.000000000 -0800
++++ paramiko-1.15.2/paramiko/client.py 2015-04-12 17:36:15.206296235 -0700
+@@ -25,6 +25,7 @@ import getpass
+ import os
+ import socket
+ import warnings
++from errno import ECONNREFUSED, EHOSTUNREACH
+
+ from paramiko.agent import Agent
+ from paramiko.common import DEBUG
+@@ -35,7 +36,9 @@ from paramiko.hostkeys import HostKeys
+ from paramiko.py3compat import string_types
+ from paramiko.resource import ResourceManager
+ from paramiko.rsakey import RSAKey
+-from paramiko.ssh_exception import SSHException, BadHostKeyException
++from paramiko.ssh_exception import (
++ SSHException, BadHostKeyException, NoValidConnectionsError
++)
+ from paramiko.transport import Transport
+ from paramiko.util import retry_on_signal, ClosingContextManager
+
+@@ -172,10 +175,46 @@ class SSHClient (ClosingContextManager):
+ """
+ self._policy = policy
+
+- def connect(self, hostname, port=SSH_PORT, username=None, password=None, pkey=None,
+- key_filename=None, timeout=None, allow_agent=True, look_for_keys=True,
+- compress=False, sock=None, gss_auth=False, gss_kex=False,
+- gss_deleg_creds=True, gss_host=None, banner_timeout=None):
++ def _families_and_addresses(self, hostname, port):
++ """
++ Yield pairs of address families and addresses to try for connecting.
++
++ :param str hostname: the server to connect to
++ :param int port: the server port to connect to
++ :returns: Yields an iterable of ``(family, address)`` tuples
++ """
++ guess = True
++ addrinfos = socket.getaddrinfo(hostname, port, socket.AF_UNSPEC, socket.SOCK_STREAM)
++ for (family, socktype, proto, canonname, sockaddr) in addrinfos:
++ if socktype == socket.SOCK_STREAM:
++ yield family, sockaddr
++ guess = False
++
++ # some OS like AIX don't indicate SOCK_STREAM support, so just guess. :(
++ # We only do this if we did not get a single result marked as socktype == SOCK_STREAM.
++ if guess:
++ for family, _, _, _, sockaddr in addrinfos:
++ yield family, sockaddr
++
++ def connect(
++ self,
++ hostname,
++ port=SSH_PORT,
++ username=None,
++ password=None,
++ pkey=None,
++ key_filename=None,
++ timeout=None,
++ allow_agent=True,
++ look_for_keys=True,
++ compress=False,
++ sock=None,
++ gss_auth=False,
++ gss_kex=False,
++ gss_deleg_creds=True,
++ gss_host=None,
++ banner_timeout=None
++ ):
+ """
+ Connect to an SSH server and authenticate to it. The server's host key
+ is checked against the system host keys (see `load_system_host_keys`)
+@@ -206,8 +245,10 @@ class SSHClient (ClosingContextManager):
+ :param str key_filename:
+ the filename, or list of filenames, of optional private key(s) to
+ try for authentication
+- :param float timeout: an optional timeout (in seconds) for the TCP connect
+- :param bool allow_agent: set to False to disable connecting to the SSH agent
++ :param float timeout:
++ an optional timeout (in seconds) for the TCP connect
++ :param bool allow_agent:
++ set to False to disable connecting to the SSH agent
+ :param bool look_for_keys:
+ set to False to disable searching for discoverable private key
+ files in ``~/.ssh/``
+@@ -216,9 +257,11 @@ class SSHClient (ClosingContextManager):
+ an open socket or socket-like object (such as a `.Channel`) to use
+ for communication to the target host
+ :param bool gss_auth: ``True`` if you want to use GSS-API authentication
+- :param bool gss_kex: Perform GSS-API Key Exchange and user authentication
++ :param bool gss_kex:
++ Perform GSS-API Key Exchange and user authentication
+ :param bool gss_deleg_creds: Delegate GSS-API client credentials or not
+- :param str gss_host: The targets name in the kerberos database. default: hostname
++ :param str gss_host:
++ The targets name in the kerberos database. default: hostname
+ :param float banner_timeout: an optional timeout (in seconds) to wait
+ for the SSH banner to be presented.
+
+@@ -234,21 +277,37 @@ class SSHClient (ClosingContextManager):
+ ``gss_deleg_creds`` and ``gss_host`` arguments.
+ """
+ if not sock:
+- for (family, socktype, proto, canonname, sockaddr) in socket.getaddrinfo(hostname, port, socket.AF_UNSPEC, socket.SOCK_STREAM):
+- if socktype == socket.SOCK_STREAM:
+- af = family
+- addr = sockaddr
+- break
+- else:
+- # some OS like AIX don't indicate SOCK_STREAM support, so just guess. :(
+- af, _, _, _, addr = socket.getaddrinfo(hostname, port, socket.AF_UNSPEC, socket.SOCK_STREAM)
+- sock = socket.socket(af, socket.SOCK_STREAM)
+- if timeout is not None:
++ errors = {}
++ # Try multiple possible address families (e.g. IPv4 vs IPv6)
++ to_try = list(self._families_and_addresses(hostname, port))
++ for af, addr in to_try:
+ try:
+- sock.settimeout(timeout)
+- except:
+- pass
+- retry_on_signal(lambda: sock.connect(addr))
++ sock = socket.socket(af, socket.SOCK_STREAM)
++ if timeout is not None:
++ try:
++ sock.settimeout(timeout)
++ except:
++ pass
++ retry_on_signal(lambda: sock.connect(addr))
++ # Break out of the loop on success
++ break
++ except socket.error as e:
++ # Raise anything that isn't a straight up connection error
++ # (such as a resolution error)
++ if e.errno not in (ECONNREFUSED, EHOSTUNREACH):
++ raise
++ # Capture anything else so we know how the run looks once
++ # iteration is complete. Retain info about which attempt
++ # this was.
++ errors[addr] = e
++
++ # Make sure we explode usefully if no address family attempts
++ # succeeded. We've no way of knowing which error is the "right"
++ # one, so we construct a hybrid exception containing all the real
++ # ones, of a subclass that client code should still be watching for
++ # (socket.error)
++ if len(errors) == len(to_try):
++ raise NoValidConnectionsError(errors)
+
+ t = self._transport = Transport(sock, gss_kex=gss_kex, gss_deleg_creds=gss_deleg_creds)
+ t.use_compression(compress=compress)
+--- paramiko-1.15.2/paramiko/config.py.~1~ 2014-12-19 15:01:22.000000000 -0800
++++ paramiko-1.15.2/paramiko/config.py 2015-04-12 17:36:15.206521239 -0700
+@@ -98,7 +98,7 @@ class SSHConfig (object):
+
+ The host-matching rules of OpenSSH's ``ssh_config`` man page are used:
+ For each parameter, the first obtained value will be used. The
+- configuration files contain sections separated by ``Host''
++ configuration files contain sections separated by ``Host``
+ specifications, and that section is only applied for hosts that match
+ one of the patterns given in the specification.
+
+--- paramiko-1.15.2/paramiko/dsskey.py.~1~ 2014-12-19 15:01:22.000000000 -0800
++++ paramiko-1.15.2/paramiko/dsskey.py 2015-04-12 17:36:15.206846024 -0700
+@@ -20,21 +20,23 @@
+ DSS keys.
+ """
+
+-import os
+-from hashlib import sha1
+-
+-from Crypto.PublicKey import DSA
++from cryptography.exceptions import InvalidSignature
++from cryptography.hazmat.backends import default_backend
++from cryptography.hazmat.primitives import hashes, serialization
++from cryptography.hazmat.primitives.asymmetric import dsa
++from cryptography.hazmat.primitives.asymmetric.utils import (
++ decode_rfc6979_signature, encode_rfc6979_signature
++)
+
+ from paramiko import util
+ from paramiko.common import zero_byte
+-from paramiko.py3compat import long
+ from paramiko.ssh_exception import SSHException
+ from paramiko.message import Message
+ from paramiko.ber import BER, BERException
+ from paramiko.pkey import PKey
+
+
+-class DSSKey (PKey):
++class DSSKey(PKey):
+ """
+ Representation of a DSS key which can be used to sign an verify SSH2
+ data.
+@@ -98,15 +100,21 @@ class DSSKey (PKey):
+ return self.x is not None
+
+ def sign_ssh_data(self, data):
+- digest = sha1(data).digest()
+- dss = DSA.construct((long(self.y), long(self.g), long(self.p), long(self.q), long(self.x)))
+- # generate a suitable k
+- qsize = len(util.deflate_long(self.q, 0))
+- while True:
+- k = util.inflate_long(os.urandom(qsize), 1)
+- if (k > 2) and (k < self.q):
+- break
+- r, s = dss.sign(util.inflate_long(digest, 1), k)
++ key = dsa.DSAPrivateNumbers(
++ x=self.x,
++ public_numbers=dsa.DSAPublicNumbers(
++ y=self.y,
++ parameter_numbers=dsa.DSAParameterNumbers(
++ p=self.p,
++ q=self.q,
++ g=self.g
++ )
++ )
++ ).private_key(backend=default_backend())
++ signer = key.signer(hashes.SHA1())
++ signer.update(data)
++ r, s = decode_rfc6979_signature(signer.finalize())
++
+ m = Message()
+ m.add_string('ssh-dss')
+ # apparently, in rare cases, r or s may be shorter than 20 bytes!
+@@ -132,27 +140,65 @@ class DSSKey (PKey):
+ # pull out (r, s) which are NOT encoded as mpints
+ sigR = util.inflate_long(sig[:20], 1)
+ sigS = util.inflate_long(sig[20:], 1)
+- sigM = util.inflate_long(sha1(data).digest(), 1)
+
+- dss = DSA.construct((long(self.y), long(self.g), long(self.p), long(self.q)))
+- return dss.verify(sigM, (sigR, sigS))
++ signature = encode_rfc6979_signature(sigR, sigS)
+
+- def _encode_key(self):
+- if self.x is None:
+- raise SSHException('Not enough key information')
+- keylist = [0, self.p, self.q, self.g, self.y, self.x]
++ key = dsa.DSAPublicNumbers(
++ y=self.y,
++ parameter_numbers=dsa.DSAParameterNumbers(
++ p=self.p,
++ q=self.q,
++ g=self.g
++ )
++ ).public_key(backend=default_backend())
++ verifier = key.verifier(signature, hashes.SHA1())
++ verifier.update(data)
+ try:
+- b = BER()
+- b.encode(keylist)
+- except BERException:
+- raise SSHException('Unable to create ber encoding of key')
+- return b.asbytes()
++ verifier.verify()
++ except InvalidSignature:
++ return False
++ else:
++ return True
+
+ def write_private_key_file(self, filename, password=None):
+- self._write_private_key_file('DSA', filename, self._encode_key(), password)
++ key = dsa.DSAPrivateNumbers(
++ x=self.x,
++ public_numbers=dsa.DSAPublicNumbers(
++ y=self.y,
++ parameter_numbers=dsa.DSAParameterNumbers(
++ p=self.p,
++ q=self.q,
++ g=self.g
++ )
++ )
++ ).private_key(backend=default_backend())
++
++ self._write_private_key_file(
++ filename,
++ key,
++ serialization.PrivateFormat.TraditionalOpenSSL,
++ password=password
++ )
+
+ def write_private_key(self, file_obj, password=None):
+- self._write_private_key('DSA', file_obj, self._encode_key(), password)
++ key = dsa.DSAPrivateNumbers(
++ x=self.x,
++ public_numbers=dsa.DSAPublicNumbers(
++ y=self.y,
++ parameter_numbers=dsa.DSAParameterNumbers(
++ p=self.p,
++ q=self.q,
++ g=self.g
++ )
++ )
++ ).private_key(backend=default_backend())
++
++ self._write_private_key(
++ file_obj,
++ key,
++ serialization.PrivateFormat.TraditionalOpenSSL,
++ password=password
++ )
+
+ @staticmethod
+ def generate(bits=1024, progress_func=None):
+@@ -161,14 +207,19 @@ class DSSKey (PKey):
+ generate a new host key or authentication key.
+
+ :param int bits: number of bits the generated key should be.
+- :param function progress_func:
+- an optional function to call at key points in key generation (used
+- by ``pyCrypto.PublicKey``).
++ :param function progress_func: Unused
+ :return: new `.DSSKey` private key
+ """
+- dsa = DSA.generate(bits, os.urandom, progress_func)
+- key = DSSKey(vals=(dsa.p, dsa.q, dsa.g, dsa.y))
+- key.x = dsa.x
++ numbers = dsa.generate_private_key(
++ bits, backend=default_backend()
++ ).private_numbers()
++ key = DSSKey(vals=(
++ numbers.public_numbers.parameter_numbers.p,
++ numbers.public_numbers.parameter_numbers.q,
++ numbers.public_numbers.parameter_numbers.g,
++ numbers.public_numbers.y
++ ))
++ key.x = numbers.x
+ return key
+
+ ### internals...
+--- paramiko-1.15.2/paramiko/ecdsakey.py.~1~ 2014-12-19 15:01:22.000000000 -0800
++++ paramiko-1.15.2/paramiko/ecdsakey.py 2015-04-12 17:36:15.207208398 -0700
+@@ -21,18 +21,24 @@ ECDSA keys
+ """
+
+ import binascii
+-from hashlib import sha256
+
+-from ecdsa import SigningKey, VerifyingKey, der, curves
++from cryptography.exceptions import InvalidSignature
++from cryptography.hazmat.backends import default_backend
++from cryptography.hazmat.primitives import hashes, serialization
++from cryptography.hazmat.primitives.asymmetric import ec
++from cryptography.hazmat.primitives.asymmetric.utils import (
++ decode_rfc6979_signature, encode_rfc6979_signature
++)
+
+ from paramiko.common import four_byte, one_byte
+ from paramiko.message import Message
+ from paramiko.pkey import PKey
+-from paramiko.py3compat import byte_chr, u
++from paramiko.py3compat import byte_chr
+ from paramiko.ssh_exception import SSHException
++from paramiko.util import deflate_long, inflate_long
+
+
+-class ECDSAKey (PKey):
++class ECDSAKey(PKey):
+ """
+ Representation of an ECDSA key which can be used to sign and verify SSH2
+ data.
+@@ -65,9 +71,13 @@ class ECDSAKey (PKey):
+ if pointinfo[0:1] != four_byte:
+ raise SSHException('Point compression is being used: %s' %
+ binascii.hexlify(pointinfo))
+- self.verifying_key = VerifyingKey.from_string(pointinfo[1:],
+- curve=curves.NIST256p,
+- validate_point=validate_point)
++ curve = ec.SECP256R1()
++ numbers = ec.EllipticCurvePublicNumbers(
++ x=inflate_long(pointinfo[1:1 + curve.key_size // 8], always_positive=True),
++ y=inflate_long(pointinfo[1 + curve.key_size // 8:], always_positive=True),
++ curve=curve
++ )
++ self.verifying_key = numbers.public_key(backend=default_backend())
+ self.size = 256
+
+ def asbytes(self):
+@@ -76,8 +86,15 @@ class ECDSAKey (PKey):
+ m.add_string('ecdsa-sha2-nistp256')
+ m.add_string('nistp256')
+
+- point_str = four_byte + key.to_string()
++ numbers = key.public_numbers()
+
++ x_bytes = deflate_long(numbers.x, add_sign_padding=False)
++ x_bytes = b'\x00' * (len(x_bytes) - key.curve.key_size // 8) + x_bytes
++
++ y_bytes = deflate_long(numbers.y, add_sign_padding=False)
++ y_bytes = b'\x00' * (len(y_bytes) - key.curve.key_size // 8) + y_bytes
++
++ point_str = four_byte + x_bytes + y_bytes
+ m.add_string(point_str)
+ return m.asbytes()
+
+@@ -86,8 +103,8 @@ class ECDSAKey (PKey):
+
+ def __hash__(self):
+ h = hash(self.get_name())
+- h = h * 37 + hash(self.verifying_key.pubkey.point.x())
+- h = h * 37 + hash(self.verifying_key.pubkey.point.y())
++ h = h * 37 + hash(self.verifying_key.public_numbers().x)
++ h = h * 37 + hash(self.verifying_key.public_numbers().y)
+ return hash(h)
+
+ def get_name(self):
+@@ -100,46 +117,59 @@ class ECDSAKey (PKey):
+ return self.signing_key is not None
+
+ def sign_ssh_data(self, data):
+- sig = self.signing_key.sign_deterministic(
+- data, sigencode=self._sigencode, hashfunc=sha256)
++ signer = self.signing_key.signer(ec.ECDSA(hashes.SHA256()))
++ signer.update(data)
++ sig = signer.finalize()
++ r, s = decode_rfc6979_signature(sig)
++
+ m = Message()
+ m.add_string('ecdsa-sha2-nistp256')
+- m.add_string(sig)
++ m.add_string(self._sigencode(r, s))
+ return m
+
+ def verify_ssh_sig(self, data, msg):
+ if msg.get_text() != 'ecdsa-sha2-nistp256':
+ return False
+ sig = msg.get_binary()
++ sigR, sigS = self._sigdecode(sig)
++ signature = encode_rfc6979_signature(sigR, sigS)
+
+- # verify the signature by SHA'ing the data and encrypting it
+- # using the public key.
+- hash_obj = sha256(data).digest()
+- return self.verifying_key.verify_digest(sig, hash_obj,
+- sigdecode=self._sigdecode)
++ verifier = self.verifying_key.verifier(signature, ec.ECDSA(hashes.SHA256()))
++ verifier.update(data)
++ try:
++ verifier.verify()
++ except InvalidSignature:
++ return False
++ else:
++ return True
+
+ def write_private_key_file(self, filename, password=None):
+- key = self.signing_key or self.verifying_key
+- self._write_private_key_file('EC', filename, key.to_der(), password)
++ self._write_private_key_file(
++ filename,
++ self.signing_key,
++ serialization.PrivateFormat.TraditionalOpenSSL,
++ password=password
++ )
+
+ def write_private_key(self, file_obj, password=None):
+- key = self.signing_key or self.verifying_key
+- self._write_private_key('EC', file_obj, key.to_der(), password)
++ self._write_private_key(
++ file_obj,
++ self.signing_key,
++ serialization.PrivateFormat.TraditionalOpenSSL,
++ password=password
++ )
+
+ @staticmethod
+- def generate(curve=curves.NIST256p, progress_func=None):
++ def generate(curve=ec.SECP256R1(), progress_func=None):
+ """
+ Generate a new private RSA key. This factory function can be used to
+ generate a new host key or authentication key.
+
+- :param function progress_func:
+- an optional function to call at key points in key generation (used
+- by ``pyCrypto.PublicKey``).
++ :param function progress_func: Unused
+ :returns: A new private key (`.RSAKey`) object
+ """
+- signing_key = SigningKey.generate(curve)
+- key = ECDSAKey(vals=(signing_key, signing_key.get_verifying_key()))
+- return key
++ private_key = ec.generate_private_key(curve, backend=default_backend())
++ return ECDSAKey(vals=(private_key, private_key.public_key()))
+
+ ### internals...
+
+@@ -155,23 +185,18 @@ class ECDSAKey (PKey):
+ byte_chr(5) * 5, byte_chr(6) * 6, byte_chr(7) * 7]
+
+ def _decode_key(self, data):
+- s, padding = der.remove_sequence(data)
+- if padding:
+- if padding not in self.ALLOWED_PADDINGS:
+- raise ValueError("weird padding: %s" % u(binascii.hexlify(data)))
+- data = data[:-len(padding)]
+- key = SigningKey.from_der(data)
++ key = serialization.load_der_private_key(data, password=None, backend=default_backend())
+ self.signing_key = key
+- self.verifying_key = key.get_verifying_key()
+- self.size = 256
++ self.verifying_key = key.public_key()
++ self.size = key.curve.key_size
+
+- def _sigencode(self, r, s, order):
++ def _sigencode(self, r, s):
+ msg = Message()
+ msg.add_mpint(r)
+ msg.add_mpint(s)
+ return msg.asbytes()
+
+- def _sigdecode(self, sig, order):
++ def _sigdecode(self, sig):
+ msg = Message(sig)
+ r = msg.get_mpint()
+ s = msg.get_mpint()
+--- paramiko-1.15.2/paramiko/kex_gss.py.~1~ 2014-12-19 15:01:22.000000000 -0800
++++ paramiko-1.15.2/paramiko/kex_gss.py 2015-04-12 17:36:15.207554941 -0700
+@@ -21,14 +21,15 @@
+
+
+ """
+-This module provides GSS-API / SSPI Key Exchange as defined in RFC 4462.
++This module provides GSS-API / SSPI Key Exchange as defined in :rfc:`4462`.
+
+ .. note:: Credential delegation is not supported in server mode.
+
+ .. note::
+- `RFC 4462 Section 2.2 `_ says we are
+- not required to implement GSS-API error messages. Thus, in many methods
+- within this module, if an error occurs an exception will be thrown and the
++ `RFC 4462 Section 2.2
++ `_ says we are not
++ required to implement GSS-API error messages. Thus, in many methods within
++ this module, if an error occurs an exception will be thrown and the
+ connection will be terminated.
+
+ .. seealso:: :doc:`/api/ssh_gss`
+@@ -55,8 +56,8 @@ c_MSG_KEXGSS_GROUPREQ, c_MSG_KEXGSS_GROU
+
+ class KexGSSGroup1(object):
+ """
+- GSS-API / SSPI Authenticated Diffie-Hellman Key Exchange
+- as defined in `RFC 4462 Section 2 `_
++ GSS-API / SSPI Authenticated Diffie-Hellman Key Exchange as defined in `RFC
++ 4462 Section 2 `_
+ """
+ # draft-ietf-secsh-transport-09.txt, page 17
+ P = 0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF
+@@ -278,8 +279,9 @@ class KexGSSGroup1(object):
+
+ class KexGSSGroup14(KexGSSGroup1):
+ """
+- GSS-API / SSPI Authenticated Diffie-Hellman Group14 Key Exchange
+- as defined in `RFC 4462 Section 2 `_
++ GSS-API / SSPI Authenticated Diffie-Hellman Group14 Key Exchange as defined
++ in `RFC 4462 Section 2
++ `_
+ """
+ P = 0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF
+ G = 2
+@@ -288,8 +290,8 @@ class KexGSSGroup14(KexGSSGroup1):
+
+ class KexGSSGex(object):
+ """
+- GSS-API / SSPI Authenticated Diffie-Hellman Group Exchange
+- as defined in `RFC 4462 Section 2 `_
++ GSS-API / SSPI Authenticated Diffie-Hellman Group Exchange as defined in
++ `RFC 4462 Section 2 `_
+ """
+ NAME = "gss-gex-sha1-toWM5Slw5Ew8Mqkay+al2g=="
+ min_bits = 1024
+@@ -590,8 +592,9 @@ class KexGSSGex(object):
+
+ class NullHostKey(object):
+ """
+- This class represents the Null Host Key for GSS-API Key Exchange
+- as defined in `RFC 4462 Section 5 `_
++ This class represents the Null Host Key for GSS-API Key Exchange as defined
++ in `RFC 4462 Section 5
++ `_
+ """
+ def __init__(self):
+ self.key = ""
+--- paramiko-1.15.2/paramiko/packet.py.~1~ 2014-12-19 15:01:22.000000000 -0800
++++ paramiko-1.15.2/paramiko/packet.py 2015-04-12 17:36:15.207839345 -0700
+@@ -307,7 +307,7 @@ class Packetizer (object):
+ self._log(DEBUG, 'Write packet <%s>, length %d' % (cmd_name, orig_len))
+ self._log(DEBUG, util.format_binary(packet, 'OUT: '))
+ if self.__block_engine_out is not None:
+- out = self.__block_engine_out.encrypt(packet)
++ out = self.__block_engine_out.update(packet)
+ else:
+ out = packet
+ # + mac
+@@ -340,7 +340,7 @@ class Packetizer (object):
+ """
+ header = self.read_all(self.__block_size_in, check_rekey=True)
+ if self.__block_engine_in is not None:
+- header = self.__block_engine_in.decrypt(header)
++ header = self.__block_engine_in.update(header)
+ if self.__dump_packets:
+ self._log(DEBUG, util.format_binary(header, 'IN: '))
+ packet_size = struct.unpack('>I', header[:4])[0]
+@@ -352,7 +352,7 @@ class Packetizer (object):
+ packet = buf[:packet_size - len(leftover)]
+ post_packet = buf[packet_size - len(leftover):]
+ if self.__block_engine_in is not None:
+- packet = self.__block_engine_in.decrypt(packet)
++ packet = self.__block_engine_in.update(packet)
+ if self.__dump_packets:
+ self._log(DEBUG, util.format_binary(packet, 'IN: '))
+ packet = leftover + packet
+--- paramiko-1.15.2/paramiko/pkey.py.~1~ 2014-12-19 15:01:22.000000000 -0800
++++ paramiko-1.15.2/paramiko/pkey.py 2015-04-12 17:36:15.208139348 -0700
+@@ -21,27 +21,39 @@ Common API for all public keys.
+ """
+
+ import base64
+-from binascii import hexlify, unhexlify
++from binascii import unhexlify
+ import os
+ from hashlib import md5
+
+-from Crypto.Cipher import DES3, AES
++from cryptography.hazmat.backends import default_backend
++from cryptography.hazmat.primitives import serialization
++from cryptography.hazmat.primitives.ciphers import algorithms, modes, Cipher
+
+ from paramiko import util
+-from paramiko.common import o600, zero_byte
++from paramiko.common import o600
+ from paramiko.py3compat import u, encodebytes, decodebytes, b
+ from paramiko.ssh_exception import SSHException, PasswordRequiredException
+
+
+-class PKey (object):
++class PKey(object):
+ """
+ Base class for public keys.
+ """
+
+ # known encryption types for private key files:
+ _CIPHER_TABLE = {
+- 'AES-128-CBC': {'cipher': AES, 'keysize': 16, 'blocksize': 16, 'mode': AES.MODE_CBC},
+- 'DES-EDE3-CBC': {'cipher': DES3, 'keysize': 24, 'blocksize': 8, 'mode': DES3.MODE_CBC},
++ 'AES-128-CBC': {
++ 'cipher': algorithms.AES,
++ 'keysize': 16,
++ 'blocksize': 16,
++ 'mode': modes.CBC
++ },
++ 'DES-EDE3-CBC': {
++ 'cipher': algorithms.TripleDES,
++ 'keysize': 24,
++ 'blocksize': 8,
++ 'mode': modes.CBC
++ },
+ }
+
+ def __init__(self, msg=None, data=None):
+@@ -300,9 +312,12 @@ class PKey (object):
+ mode = self._CIPHER_TABLE[encryption_type]['mode']
+ salt = unhexlify(b(saltstr))
+ key = util.generate_key_bytes(md5, salt, password, keysize)
+- return cipher.new(key, mode, salt).decrypt(data)
++ decryptor = Cipher(
++ cipher(key), mode(salt), backend=default_backend()
++ ).decryptor()
++ return decryptor.update(data) + decryptor.finalize()
+
+- def _write_private_key_file(self, tag, filename, data, password=None):
++ def _write_private_key_file(self, filename, key, format, password=None):
+ """
+ Write an SSH2-format private key file in a form that can be read by
+ paramiko or openssh. If no password is given, the key is written in
+@@ -319,31 +334,16 @@ class PKey (object):
+ with open(filename, 'w', o600) as f:
+ # grrr... the mode doesn't always take hold
+ os.chmod(filename, o600)
+- self._write_private_key(tag, f, data, password)
++ self._write_private_key(f, key, format)
+
+- def _write_private_key(self, tag, f, data, password=None):
+- f.write('-----BEGIN %s PRIVATE KEY-----\n' % tag)
+- if password is not None:
+- cipher_name = list(self._CIPHER_TABLE.keys())[0]
+- cipher = self._CIPHER_TABLE[cipher_name]['cipher']
+- keysize = self._CIPHER_TABLE[cipher_name]['keysize']
+- blocksize = self._CIPHER_TABLE[cipher_name]['blocksize']
+- mode = self._CIPHER_TABLE[cipher_name]['mode']
+- salt = os.urandom(blocksize)
+- key = util.generate_key_bytes(md5, salt, password, keysize)
+- if len(data) % blocksize != 0:
+- n = blocksize - len(data) % blocksize
+- #data += os.urandom(n)
+- # that would make more sense ^, but it confuses openssh.
+- data += zero_byte * n
+- data = cipher.new(key, mode, salt).encrypt(data)
+- f.write('Proc-Type: 4,ENCRYPTED\n')
+- f.write('DEK-Info: %s,%s\n' % (cipher_name, u(hexlify(salt)).upper()))
+- f.write('\n')
+- s = u(encodebytes(data))
+- # re-wrap to 64-char lines
+- s = ''.join(s.split('\n'))
+- s = '\n'.join([s[i: i + 64] for i in range(0, len(s), 64)])
+- f.write(s)
+- f.write('\n')
+- f.write('-----END %s PRIVATE KEY-----\n' % tag)
++ def _write_private_key(self, f, key, format, password=None):
++ if password is None:
++ encryption = serialization.NoEncryption()
++ else:
++ encryption = serialization.BestEncryption(password)
++
++ f.write(key.private_bytes(
++ serialization.Encoding.PEM,
++ format,
++ encryption
++ ).decode())
+--- paramiko-1.15.2/paramiko/rsakey.py.~1~ 2014-12-19 15:01:22.000000000 -0800
++++ paramiko-1.15.2/paramiko/rsakey.py 2015-04-12 17:36:15.208516662 -0700
+@@ -20,34 +20,26 @@
+ RSA keys.
+ """
+
+-import os
+-from hashlib import sha1
++from cryptography.exceptions import InvalidSignature
++from cryptography.hazmat.backends import default_backend
++from cryptography.hazmat.primitives import hashes, serialization
++from cryptography.hazmat.primitives.asymmetric import rsa, padding
+
+-from Crypto.PublicKey import RSA
+-
+-from paramiko import util
+-from paramiko.common import max_byte, zero_byte, one_byte
+ from paramiko.message import Message
+-from paramiko.ber import BER, BERException
+ from paramiko.pkey import PKey
+-from paramiko.py3compat import long
+ from paramiko.ssh_exception import SSHException
+
+ SHA1_DIGESTINFO = b'\x30\x21\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05\x00\x04\x14'
+
+
+-class RSAKey (PKey):
++class RSAKey(PKey):
+ """
+ Representation of an RSA key which can be used to sign and verify SSH2
+ data.
+ """
+
+- def __init__(self, msg=None, data=None, filename=None, password=None, vals=None, file_obj=None):
+- self.n = None
+- self.e = None
+- self.d = None
+- self.p = None
+- self.q = None
++ def __init__(self, msg=None, data=None, filename=None, password=None, key=None, file_obj=None):
++ self.key = None
+ if file_obj is not None:
+ self._from_private_key(file_obj, password)
+ return
+@@ -56,22 +48,33 @@ class RSAKey (PKey):
+ return
+ if (msg is None) and (data is not None):
+ msg = Message(data)
+- if vals is not None:
+- self.e, self.n = vals
++ if key is not None:
++ self.key = key
+ else:
+ if msg is None:
+ raise SSHException('Key object may not be empty')
+ if msg.get_text() != 'ssh-rsa':
+ raise SSHException('Invalid key')
+- self.e = msg.get_mpint()
+- self.n = msg.get_mpint()
+- self.size = util.bit_length(self.n)
++ self.key = rsa.RSAPublicNumbers(
++ e=msg.get_mpint(), n=msg.get_mpint()
++ ).public_key(default_backend())
++
++ @property
++ def size(self):
++ return self.key.key_size
++
++ @property
++ def public_numbers(self):
++ if isinstance(self.key, rsa.RSAPrivateKey):
++ return self.key.private_numbers().public_numbers
++ else:
++ return self.key.public_numbers()
+
+ def asbytes(self):
+ m = Message()
+ m.add_string('ssh-rsa')
+- m.add_mpint(self.e)
+- m.add_mpint(self.n)
++ m.add_mpint(self.public_numbers.e)
++ m.add_mpint(self.public_numbers.n)
+ return m.asbytes()
+
+ def __str__(self):
+@@ -79,8 +82,8 @@ class RSAKey (PKey):
+
+ def __hash__(self):
+ h = hash(self.get_name())
+- h = h * 37 + hash(self.e)
+- h = h * 37 + hash(self.n)
++ h = h * 37 + hash(self.public_numbers.e)
++ h = h * 37 + hash(self.public_numbers.n)
+ return hash(h)
+
+ def get_name(self):
+@@ -90,12 +93,16 @@ class RSAKey (PKey):
+ return self.size
+
+ def can_sign(self):
+- return self.d is not None
++ return isinstance(self.key, rsa.RSAPrivateKey)
+
+ def sign_ssh_data(self, data):
+- digest = sha1(data).digest()
+- rsa = RSA.construct((long(self.n), long(self.e), long(self.d)))
+- sig = util.deflate_long(rsa.sign(self._pkcs1imify(digest), bytes())[0], 0)
++ signer = self.key.signer(
++ padding=padding.PKCS1v15(),
++ algorithm=hashes.SHA1(),
++ )
++ signer.update(data)
++ sig = signer.finalize()
++
+ m = Message()
+ m.add_string('ssh-rsa')
+ m.add_string(sig)
+@@ -104,32 +111,38 @@ class RSAKey (PKey):
+ def verify_ssh_sig(self, data, msg):
+ if msg.get_text() != 'ssh-rsa':
+ return False
+- sig = util.inflate_long(msg.get_binary(), True)
+- # verify the signature by SHA'ing the data and encrypting it using the
+- # public key. some wackiness ensues where we "pkcs1imify" the 20-byte
+- # hash into a string as long as the RSA key.
+- hash_obj = util.inflate_long(self._pkcs1imify(sha1(data).digest()), True)
+- rsa = RSA.construct((long(self.n), long(self.e)))
+- return rsa.verify(hash_obj, (sig,))
+-
+- def _encode_key(self):
+- if (self.p is None) or (self.q is None):
+- raise SSHException('Not enough key info to write private key file')
+- keylist = [0, self.n, self.e, self.d, self.p, self.q,
+- self.d % (self.p - 1), self.d % (self.q - 1),
+- util.mod_inverse(self.q, self.p)]
++ key = self.key
++ if isinstance(key, rsa.RSAPrivateKey):
++ key = key.public_key()
++
++ verifier = key.verifier(
++ signature=msg.get_binary(),
++ padding=padding.PKCS1v15(),
++ algorithm=hashes.SHA1(),
++ )
++ verifier.update(data)
+ try:
+- b = BER()
+- b.encode(keylist)
+- except BERException:
+- raise SSHException('Unable to create ber encoding of key')
+- return b.asbytes()
++ verifier.verify()
++ except InvalidSignature:
++ return False
++ else:
++ return True
+
+ 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(
++ filename,
++ self.key,
++ serialization.PrivateFormat.TraditionalOpenSSL,
++ password=password
++ )
+
+ def write_private_key(self, file_obj, password=None):
+- self._write_private_key('RSA', file_obj, self._encode_key(), password)
++ self._write_private_key(
++ file_obj,
++ self.key,
++ serialization.PrivateFormat.TraditionalOpenSSL,
++ password=password
++ )
+
+ @staticmethod
+ def generate(bits, progress_func=None):
+@@ -138,29 +151,16 @@ class RSAKey (PKey):
+ generate a new host key or authentication key.
+
+ :param int bits: number of bits the generated key should be.
+- :param function progress_func:
+- an optional function to call at key points in key generation (used
+- by ``pyCrypto.PublicKey``).
++ :param function progress_func: Unused
+ :return: new `.RSAKey` private key
+ """
+- rsa = RSA.generate(bits, os.urandom, progress_func)
+- key = RSAKey(vals=(rsa.e, rsa.n))
+- key.d = rsa.d
+- key.p = rsa.p
+- key.q = rsa.q
+- return key
++ key = rsa.generate_private_key(
++ public_exponent=65537, key_size=bits, backend=default_backend()
++ )
++ return RSAKey(key=key)
+
+ ### internals...
+
+- def _pkcs1imify(self, data):
+- """
+- turn a 20-byte SHA1 hash into a blob of data as large as the key's N,
+- using PKCS1's \"emsa-pkcs1-v1_5\" encoding. totally bizarre.
+- """
+- size = len(util.deflate_long(self.n, 0))
+- filler = max_byte * (size - len(SHA1_DIGESTINFO) - len(data) - 3)
+- return zero_byte + one_byte + filler + zero_byte + SHA1_DIGESTINFO + data
+-
+ def _from_private_key_file(self, filename, password):
+ data = self._read_private_key_file('RSA', filename, password)
+ self._decode_key(data)
+@@ -170,18 +170,8 @@ class RSAKey (PKey):
+ self._decode_key(data)
+
+ def _decode_key(self, data):
+- # private key file contains:
+- # RSAPrivateKey = { version = 0, n, e, d, p, q, d mod p-1, d mod q-1, q**-1 mod p }
+- try:
+- keylist = BER(data).decode()
+- except BERException:
+- raise SSHException('Unable to parse key file')
+- if (type(keylist) is not list) or (len(keylist) < 4) or (keylist[0] != 0):
+- raise SSHException('Not a valid RSA private key file (bad ber encoding)')
+- self.n = keylist[1]
+- self.e = keylist[2]
+- self.d = keylist[3]
+- # not really needed
+- self.p = keylist[4]
+- self.q = keylist[5]
+- self.size = util.bit_length(self.n)
++ key = serialization.load_der_private_key(
++ data, password=None, backend=default_backend()
++ )
++ assert isinstance(key, rsa.RSAPrivateKey)
++ self.key = key
+--- paramiko-1.15.2/paramiko/ssh_exception.py.~1~ 2014-09-08 10:42:16.000000000 -0700
++++ paramiko-1.15.2/paramiko/ssh_exception.py 2015-04-12 17:36:15.208756832 -0700
+@@ -16,6 +16,8 @@
+ # along with Paramiko; if not, write to the Free Software Foundation, Inc.,
+ # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+
++import socket
++
+
+ class SSHException (Exception):
+ """
+@@ -129,3 +131,39 @@ class ProxyCommandFailure (SSHException)
+ self.error = error
+ # for unpickling
+ self.args = (command, error, )
++
++
++class NoValidConnectionsError(socket.error):
++ """
++ Multiple connection attempts were made and no families succeeded.
++
++ This exception class wraps multiple "real" underlying connection errors,
++ all of which represent failed connection attempts. Because these errors are
++ not guaranteed to all be of the same error type (i.e. different errno,
++ class, message, etc) we expose a single unified error message and a
++ ``None`` errno so that instances of this class match most normal handling
++ of `socket.error` objects.
++
++ To see the wrapped exception objects, access the ``errors`` attribute.
++ ``errors`` is a dict whose keys are address tuples (e.g. ``('127.0.0.1',
++ 22)``) and whose values are the exception encountered trying to connect to
++ that address.
++
++ It is implied/assumed that all the errors given to a single instance of
++ this class are from connecting to the same hostname + port (and thus that
++ the differences are in the resolution of the hostname - e.g. IPv4 vs v6).
++ """
++ def __init__(self, errors):
++ """
++ :param dict errors:
++ The errors dict to store, as described by class docstring.
++ """
++ addrs = errors.keys()
++ body = ', '.join([x[0] for x in addrs[:-1]])
++ tail = addrs[-1][0]
++ msg = "Unable to connect to port {0} on {1} or {2}"
++ super(NoValidConnectionsError, self).__init__(
++ None, # stand-in for errno
++ msg.format(addrs[0][1], body, tail)
++ )
++ self.errors = errors
+--- paramiko-1.15.2/paramiko/ssh_gss.py.~1~ 2014-12-19 15:01:22.000000000 -0800
++++ paramiko-1.15.2/paramiko/ssh_gss.py 2015-04-12 17:36:15.209036497 -0700
+@@ -20,7 +20,7 @@
+
+
+ """
+-This module provides GSS-API / SSPI authentication as defined in RFC 4462.
++This module provides GSS-API / SSPI authentication as defined in :rfc:`4462`.
+
+ .. note:: Credential delegation is not supported in server mode.
+
+@@ -39,22 +39,8 @@ import sys
+ """
+ GSS_AUTH_AVAILABLE = True
+
+-try:
+- from pyasn1.type.univ import ObjectIdentifier
+- from pyasn1.codec.der import encoder, decoder
+-except ImportError:
+- GSS_AUTH_AVAILABLE = False
+- class ObjectIdentifier(object):
+- def __init__(self, *args):
+- raise NotImplementedError("Module pyasn1 not importable")
+-
+- class decoder(object):
+- def decode(self):
+- raise NotImplementedError("Module pyasn1 not importable")
+-
+- class encoder(object):
+- def encode(self):
+- raise NotImplementedError("Module pyasn1 not importable")
++from pyasn1.type.univ import ObjectIdentifier
++from pyasn1.codec.der import encoder, decoder
+
+ from paramiko.common import MSG_USERAUTH_REQUEST
+ from paramiko.ssh_exception import SSHException
+--- paramiko-1.15.2/paramiko/transport.py.~1~ 2014-12-19 15:01:22.000000000 -0800
++++ paramiko-1.15.2/paramiko/transport.py 2015-04-12 17:36:15.209751892 -0700
+@@ -28,6 +28,9 @@ import time
+ import weakref
+ from hashlib import md5, sha1
+
++from cryptography.hazmat.backends import default_backend
++from cryptography.hazmat.primitives.ciphers import algorithms, Cipher, modes
++
+ import paramiko
+ from paramiko import util
+ from paramiko.auth_handler import AuthHandler
+@@ -63,11 +66,6 @@ from paramiko.ssh_exception import (SSHE
+ ChannelException, ProxyCommandFailure)
+ from paramiko.util import retry_on_signal, ClosingContextManager, clamp_value
+
+-from Crypto.Cipher import Blowfish, AES, DES3, ARC4
+-try:
+- from Crypto.Util import Counter
+-except ImportError:
+- from paramiko.util import Counter
+
+
+ # for thread cleanup
+@@ -91,6 +89,9 @@ class Transport (threading.Thread, Closi
+
+ Instances of this class may be used as context managers.
+ """
++ _ENCRYPT = object()
++ _DECRYPT = object()
++
+ _PROTO_ID = '2.0'
+ _CLIENT_ID = 'paramiko_%s' % paramiko.__version__
+
+@@ -102,16 +103,57 @@ class Transport (threading.Thread, Closi
+ _preferred_compression = ('none',)
+
+ _cipher_info = {
+- 'aes128-ctr': {'class': AES, 'mode': AES.MODE_CTR, 'block-size': 16, 'key-size': 16},
+- 'aes256-ctr': {'class': AES, 'mode': AES.MODE_CTR, 'block-size': 16, 'key-size': 32},
+- 'blowfish-cbc': {'class': Blowfish, 'mode': Blowfish.MODE_CBC, 'block-size': 8, 'key-size': 16},
+- 'aes128-cbc': {'class': AES, 'mode': AES.MODE_CBC, 'block-size': 16, 'key-size': 16},
+- 'aes256-cbc': {'class': AES, 'mode': AES.MODE_CBC, 'block-size': 16, 'key-size': 32},
+- '3des-cbc': {'class': DES3, 'mode': DES3.MODE_CBC, 'block-size': 8, 'key-size': 24},
+- 'arcfour128': {'class': ARC4, 'mode': None, 'block-size': 8, 'key-size': 16},
+- 'arcfour256': {'class': ARC4, 'mode': None, 'block-size': 8, 'key-size': 32},
++ 'aes128-ctr': {
++ 'class': algorithms.AES,
++ 'mode': modes.CTR,
++ 'block-size': 16,
++ 'key-size': 16
++ },
++ 'aes256-ctr': {
++ 'class': algorithms.AES,
++ 'mode': modes.CTR,
++ 'block-size': 16,
++ 'key-size': 32
++ },
++ 'blowfish-cbc': {
++ 'class': algorithms.Blowfish,
++ 'mode': modes.CBC,
++ 'block-size': 8,
++ 'key-size': 16
++ },
++ 'aes128-cbc': {
++ 'class': algorithms.AES,
++ 'mode': modes.CBC,
++ 'block-size': 16,
++ 'key-size': 16
++ },
++ 'aes256-cbc': {
++ 'class': algorithms.AES,
++ 'mode': modes.CBC,
++ 'block-size': 16,
++ 'key-size': 32
++ },
++ '3des-cbc': {
++ 'class': algorithms.TripleDES,
++ 'mode': modes.CBC,
++ 'block-size': 8,
++ 'key-size': 24
++ },
++ 'arcfour128': {
++ 'class': algorithms.ARC4,
++ 'mode': None,
++ 'block size': 8,
++ 'key-size': 16
++ },
++ 'arcfour256': {
++ 'class': algorithms.ARC4,
++ 'mode': None,
++ 'block size': 8,
++ 'key-size': 32
++ },
+ }
+
++
+ _mac_info = {
+ 'hmac-sha1': {'class': sha1, 'size': 20},
+ 'hmac-sha1-96': {'class': sha1, 'size': 12},
+@@ -1508,22 +1550,34 @@ class Transport (threading.Thread, Closi
+ sofar += digest
+ return out[:nbytes]
+
+- def _get_cipher(self, name, key, iv):
++ def _get_cipher(self, name, key, iv, operation):
+ if name not in self._cipher_info:
+ raise SSHException('Unknown client cipher ' + name)
+ if name in ('arcfour128', 'arcfour256'):
+ # arcfour cipher
+- cipher = self._cipher_info[name]['class'].new(key)
++ cipher = Cipher(
++ self._cipher_info[name]['class'](key),
++ None,
++ backend=default_backend()
++ )
++ if operation is self._ENCRYPT:
++ engine = cipher.encryptor()
++ else:
++ engine = cipher.decryptor()
+ # as per RFC 4345, the first 1536 bytes of keystream
+ # generated by the cipher MUST be discarded
+- cipher.encrypt(" " * 1536)
+- return cipher
+- elif name.endswith("-ctr"):
+- # CTR modes, we need a counter
+- counter = Counter.new(nbits=self._cipher_info[name]['block-size'] * 8, initial_value=util.inflate_long(iv, True))
+- return self._cipher_info[name]['class'].new(key, self._cipher_info[name]['mode'], iv, counter)
++ engine.encrypt(" " * 1536)
++ return engine
+ else:
+- return self._cipher_info[name]['class'].new(key, self._cipher_info[name]['mode'], iv)
++ cipher = Cipher(
++ self._cipher_info[name]['class'](key),
++ self._cipher_info[name]['mode'](iv),
++ backend=default_backend(),
++ )
++ if operation is self._ENCRYPT:
++ return cipher.encryptor()
++ else:
++ return cipher.decryptor()
+
+ def _set_forward_agent_handler(self, handler):
+ if handler is None:
+@@ -1879,7 +1933,7 @@ class Transport (threading.Thread, Closi
+ else:
+ IV_in = self._compute_key('B', block_size)
+ key_in = self._compute_key('D', self._cipher_info[self.remote_cipher]['key-size'])
+- engine = self._get_cipher(self.remote_cipher, key_in, IV_in)
++ engine = self._get_cipher(self.remote_cipher, key_in, IV_in, self._DECRYPT)
+ mac_size = self._mac_info[self.remote_mac]['size']
+ mac_engine = self._mac_info[self.remote_mac]['class']
+ # initial mac keys are done in the hash's natural size (not the potentially truncated
+@@ -1906,7 +1960,7 @@ class Transport (threading.Thread, Closi
+ else:
+ IV_out = self._compute_key('A', block_size)
+ key_out = self._compute_key('C', self._cipher_info[self.local_cipher]['key-size'])
+- engine = self._get_cipher(self.local_cipher, key_out, IV_out)
++ engine = self._get_cipher(self.local_cipher, key_out, IV_out, self._ENCRYPT)
+ mac_size = self._mac_info[self.local_mac]['size']
+ mac_engine = self._mac_info[self.local_mac]['class']
+ # initial mac keys are done in the hash's natural size (not the potentially truncated
+--- paramiko-1.15.2/paramiko/util.py.~1~ 2014-12-19 15:01:22.000000000 -0800
++++ paramiko-1.15.2/paramiko/util.py 2015-04-12 17:36:15.210034924 -0700
+@@ -22,7 +22,6 @@ Useful functions used by the rest of par
+
+ from __future__ import generators
+
+-import array
+ import errno
+ import sys
+ import struct
+@@ -31,7 +30,7 @@ import threading
+ import logging
+
+ from paramiko.common import DEBUG, zero_byte, xffffffff, max_byte
+-from paramiko.py3compat import PY2, long, byte_ord, b, byte_chr
++from paramiko.py3compat import PY2, long, byte_chr, byte_ord, b
+ from paramiko.config import SSHConfig
+
+
+@@ -273,37 +272,6 @@ def retry_on_signal(function):
+ raise
+
+
+-class Counter (object):
+- """Stateful counter for CTR mode crypto"""
+- def __init__(self, nbits, initial_value=long(1), overflow=long(0)):
+- self.blocksize = nbits / 8
+- self.overflow = overflow
+- # start with value - 1 so we don't have to store intermediate values when counting
+- # could the iv be 0?
+- if initial_value == 0:
+- self.value = array.array('c', max_byte * self.blocksize)
+- else:
+- x = deflate_long(initial_value - 1, add_sign_padding=False)
+- self.value = array.array('c', zero_byte * (self.blocksize - len(x)) + x)
+-
+- def __call__(self):
+- """Increament the counter and return the new value"""
+- i = self.blocksize - 1
+- while i > -1:
+- c = self.value[i] = byte_chr((byte_ord(self.value[i]) + 1) % 256)
+- if c != zero_byte:
+- return self.value.tostring()
+- i -= 1
+- # counter reset
+- x = deflate_long(self.overflow, add_sign_padding=False)
+- self.value = array.array('c', zero_byte * (self.blocksize - len(x)) + x)
+- return self.value.tostring()
+-
+- @classmethod
+- def new(cls, nbits, initial_value=long(1), overflow=long(0)):
+- return cls(nbits, initial_value=initial_value, overflow=overflow)
+-
+-
+ def constant_time_bytes_eq(a, b):
+ if len(a) != len(b):
+ return False
+--- paramiko-1.15.2/setup.py.~1~ 2014-12-19 15:01:22.000000000 -0800
++++ paramiko-1.15.2/setup.py 2015-04-12 17:36:15.210254883 -0700
+@@ -24,7 +24,7 @@ connections between python scripts. All
+ are supported. SFTP client and server mode are both supported too.
+
+ Required packages:
+- pyCrypto
++ Cryptography
+
+ To install the `in-development version
+ `_, use
+@@ -41,8 +41,8 @@ try:
+ from setuptools import setup
+ kw = {
+ 'install_requires': [
+- 'pycrypto >= 2.1, != 2.4',
+- 'ecdsa >= 0.11',
++ 'cryptography >= 0.8',
++ 'pyasn1 >= 0.1.7',
+ ],
+ }
+ except ImportError:
+--- paramiko-1.15.2/tests/test_auth.py.~1~ 2014-12-19 15:01:22.000000000 -0800
++++ paramiko-1.15.2/tests/test_auth.py 2015-04-12 17:36:15.210519848 -0700
+@@ -83,13 +83,13 @@ class NullServer (ServerInterface):
+ return AUTH_SUCCESSFUL
+ return AUTH_PARTIALLY_SUCCESSFUL
+ return AUTH_FAILED
+-
++
+ def check_auth_interactive(self, username, submethods):
+ if username == 'commie':
+ self.username = username
+ return InteractiveQuery('password', 'Please enter a password.', ('Password', False))
+ return AUTH_FAILED
+-
++
+ def check_auth_interactive_response(self, responses):
+ if self.username == 'commie':
+ if (len(responses) == 1) and (responses[0] == 'cat'):
+@@ -111,7 +111,7 @@ class AuthTest (unittest.TestCase):
+ self.ts.close()
+ self.socks.close()
+ self.sockc.close()
+-
++
+ def start_server(self):
+ host_key = RSAKey.from_private_key_file(test_path('test_rsa.key'))
+ self.public_host_key = RSAKey(data=host_key.asbytes())
+@@ -120,7 +120,7 @@ class AuthTest (unittest.TestCase):
+ self.server = NullServer()
+ self.assertTrue(not self.event.is_set())
+ self.ts.start_server(self.event, self.server)
+-
++
+ def verify_finished(self):
+ self.event.wait(1.0)
+ self.assertTrue(self.event.is_set())
+@@ -156,7 +156,7 @@ class AuthTest (unittest.TestCase):
+ self.assertTrue(issubclass(etype, AuthenticationException))
+ self.tc.auth_password(username='slowdive', password='pygmalion')
+ self.verify_finished()
+-
++
+ def test_3_multipart_auth(self):
+ """
+ verify that multipart auth works.
+@@ -187,7 +187,7 @@ class AuthTest (unittest.TestCase):
+ self.assertEqual(self.got_prompts, [('Password', False)])
+ self.assertEqual([], remain)
+ self.verify_finished()
+-
++
+ def test_5_interactive_auth_fallback(self):
+ """
+ verify that a password auth attempt will fallback to "interactive"
+--- paramiko-1.15.2/tests/test_client.py.~1~ 2014-12-19 15:01:22.000000000 -0800
++++ paramiko-1.15.2/tests/test_client.py 2015-04-12 17:36:15.210808627 -0700
+@@ -22,6 +22,8 @@ Some unit tests for SSHClient.
+
+ from __future__ import with_statement
+
++import gc
++import platform
+ import socket
+ from tempfile import mkstemp
+ import threading
+@@ -31,8 +33,9 @@ import warnings
+ import os
+ import time
+ from tests.util import test_path
++
+ import paramiko
+-from paramiko.common import PY2, b
++from paramiko.common import PY2
+ from paramiko.ssh_exception import SSHException
+
+
+@@ -266,14 +269,13 @@ class SSHClientTest (unittest.TestCase):
+ transport's packetizer) is closed.
+ """
+ # Unclear why this is borked on Py3, but it is, and does not seem worth
+- # pursuing at the moment.
++ # pursuing at the moment. Skipped on PyPy because it fails on travis
++ # for unknown reasons, works fine locally.
+ # XXX: It's the release of the references to e.g packetizer that fails
+ # in py3...
+- if not PY2:
++ if not PY2 or platform.python_implementation() == "PyPy":
+ return
+ threading.Thread(target=self._run).start()
+- host_key = paramiko.RSAKey.from_private_key_file(test_path('test_rsa.key'))
+- public_host_key = paramiko.RSAKey(data=host_key.asbytes())
+
+ self.tc = paramiko.SSHClient()
+ self.tc.set_missing_host_key_policy(paramiko.AutoAddPolicy())
+@@ -289,14 +291,10 @@ class SSHClientTest (unittest.TestCase):
+ self.tc.close()
+ del self.tc
+
+- # hrm, sometimes p isn't cleared right away. why is that?
+- #st = time.time()
+- #while (time.time() - st < 5.0) and (p() is not None):
+- # time.sleep(0.1)
+-
+- # instead of dumbly waiting for the GC to collect, force a collection
+- # to see whether the SSHClient object is deallocated correctly
+- import gc
++ # force a collection to see whether the SSHClient object is deallocated
++ # correctly. 2 GCs are needed to make sure it's really collected on
++ # PyPy
++ gc.collect()
+ gc.collect()
+
+ self.assertTrue(p() is None)
+@@ -306,8 +304,6 @@ class SSHClientTest (unittest.TestCase):
+ verify that an SSHClient can be used a context manager
+ """
+ threading.Thread(target=self._run).start()
+- host_key = paramiko.RSAKey.from_private_key_file(test_path('test_rsa.key'))
+- public_host_key = paramiko.RSAKey(data=host_key.asbytes())
+
+ with paramiko.SSHClient() as tc:
+ self.tc = tc
+--- paramiko-1.15.2/tests/test_packetizer.py.~1~ 2014-12-19 15:01:22.000000000 -0800
++++ paramiko-1.15.2/tests/test_packetizer.py 2015-04-12 17:36:15.211084420 -0700
+@@ -23,9 +23,10 @@ Some unit tests for the ssh2 protocol in
+ import unittest
+ from hashlib import sha1
+
+-from tests.loop import LoopSocket
++from cryptography.hazmat.backends import default_backend
++from cryptography.hazmat.primitives.ciphers import algorithms, Cipher, modes
+
+-from Crypto.Cipher import AES
++from tests.loop import LoopSocket
+
+ from paramiko import Message, Packetizer, util
+ from paramiko.common import byte_chr, zero_byte
+@@ -43,8 +44,12 @@ class PacketizerTest (unittest.TestCase)
+ p = Packetizer(wsock)
+ p.set_log(util.get_logger('paramiko.transport'))
+ p.set_hexdump(True)
+- cipher = AES.new(zero_byte * 16, AES.MODE_CBC, x55 * 16)
+- p.set_outbound_cipher(cipher, 16, sha1, 12, x1f * 20)
++ encryptor = Cipher(
++ algorithms.AES(zero_byte * 16),
++ modes.CBC(x55 * 16),
++ backend=default_backend()
++ ).encryptor()
++ p.set_outbound_cipher(encryptor, 16, sha1, 12, x1f * 20)
+
+ # message has to be at least 16 bytes long, so we'll have at least one
+ # block of data encrypted that contains zero random padding bytes
+@@ -66,8 +71,12 @@ class PacketizerTest (unittest.TestCase)
+ p = Packetizer(rsock)
+ p.set_log(util.get_logger('paramiko.transport'))
+ p.set_hexdump(True)
+- cipher = AES.new(zero_byte * 16, AES.MODE_CBC, x55 * 16)
+- p.set_inbound_cipher(cipher, 16, sha1, 12, x1f * 20)
++ decryptor = Cipher(
++ algorithms.AES(zero_byte * 16),
++ modes.CBC(x55 * 16),
++ backend=default_backend()
++ ).decryptor()
++ p.set_inbound_cipher(decryptor, 16, sha1, 12, x1f * 20)
+ wsock.send(b'\x43\x91\x97\xbd\x5b\x50\xac\x25\x87\xc2\xc4\x6b\xc7\xe9\x38\xc0\x90\xd2\x16\x56\x0d\x71\x73\x61\x38\x7c\x4c\x3d\xfb\x97\x7d\xe2\x6e\x03\xb1\xa0\xc2\x1c\xd6\x41\x41\x4c\xb4\x59')
+ cmd, m = p.read_message()
+ self.assertEqual(100, cmd)
+@@ -82,8 +91,12 @@ class PacketizerTest (unittest.TestCase)
+ p = Packetizer(wsock)
+ p.set_log(util.get_logger('paramiko.transport'))
+ p.set_hexdump(True)
+- cipher = AES.new(zero_byte * 16, AES.MODE_CBC, x55 * 16)
+- p.set_outbound_cipher(cipher, 16, sha1, 12, x1f * 20)
++ encryptor = Cipher(
++ algorithms.AES(zero_byte * 16),
++ modes.CBC(x55 * 16),
++ backend=default_backend()
++ ).encryptor()
++ p.set_outbound_cipher(encryptor, 16, sha1, 12, x1f * 20)
+
+ # message has to be at least 16 bytes long, so we'll have at least one
+ # block of data encrypted that contains zero random padding bytes
+--- paramiko-1.15.2/tests/test_pkey.py.~1~ 2014-12-19 15:01:22.000000000 -0800
++++ paramiko-1.15.2/tests/test_pkey.py 2015-04-12 17:36:15.211328345 -0700
+@@ -42,34 +42,34 @@ SIGNED_RSA = '20:d7:8a:31:21:cb:f7:92:12
+
+ RSA_PRIVATE_OUT = """\
+ -----BEGIN RSA PRIVATE KEY-----
+-MIICXAIBAAKCAIEA049W6geFpmsljTwfvI1UmKWWJPNFI74+vNKTk4dmzkQY2yAM
+-s6FhlvhlI8ysU4oj71ZsRYMecHbBbxdN79+JRFVYTKaLqjwGENeTd+yv4q+V2PvZ
+-v3fLnzApI3l7EJCqhWwJUHJ1jAkZzqDx0tyOL4uoZpww3nmE0kb3y21tH4cCASMC
+-ggCAEiI6plhqipt4P05L3PYr0pHZq2VPEbE4k9eI/gRKo/c1VJxY3DJnc1cenKsk
+-trQRtW3OxCEufqsX5PNec6VyKkW+Ox6beJjMKm4KF8ZDpKi9Nw6MdX3P6Gele9D9
+-+ieyhVFljrnAqcXsgChTBOYlL2imqCs3qRGAJ3cMBIAx3VsCQQD3pIFVYW398kE0
+-n0e1icEpkbDRV4c5iZVhu8xKy2yyfy6f6lClSb2+Ub9uns7F3+b5v0pYSHbE9+/r
+-OpRq83AfAkEA2rMZlr8SnMXgnyka2LuggA9QgMYy18hyao1dUxySubNDa9N+q2QR
+-mwDisTUgRFHKIlDHoQmzPbXAmYZX1YlDmQJBAPCRLS5epV0XOAc7pL762OaNhzHC
+-veAfQKgVhKBt105PqaKpGyQ5AXcNlWQlPeTK4GBTbMrKDPna6RBkyrEJvV8CQBK+
+-5O+p+kfztCrmRCE0p1tvBuZ3Y3GU1ptrM+KNa6mEZN1bRV8l1Z+SXJLYqv6Kquz/
+-nBUeFq2Em3rfoSDugiMCQDyG3cxD5dKX3IgkhLyBWls/FLDk4x/DQ+NUTu0F1Cu6
+-JJye+5ARLkL0EweMXf0tmIYfWItDLsWB0fKg/56h0js=
++MIICWgIBAAKBgQDTj1bqB4WmayWNPB+8jVSYpZYk80Ujvj680pOTh2bORBjbIAyz
++oWGW+GUjzKxTiiPvVmxFgx5wdsFvF03v34lEVVhMpouqPAYQ15N37K/ir5XY+9m/
++d8ufMCkjeXsQkKqFbAlQcnWMCRnOoPHS3I4vi6hmnDDeeYTSRvfLbW0fhwIBIwKB
++gBIiOqZYaoqbeD9OS9z2K9KR2atlTxGxOJPXiP4ESqP3NVScWNwyZ3NXHpyrJLa0
++EbVtzsQhLn6rF+TzXnOlcipFvjsem3iYzCpuChfGQ6SovTcOjHV9z+hnpXvQ/fon
++soVRZY65wKnF7IAoUwTmJS9opqgrN6kRgCd3DASAMd1bAkEA96SBVWFt/fJBNJ9H
++tYnBKZGw0VeHOYmVYbvMSstssn8un+pQpUm9vlG/bp7Oxd/m+b9KWEh2xPfv6zqU
++avNwHwJBANqzGZa/EpzF4J8pGti7oIAPUIDGMtfIcmqNXVMckrmzQ2vTfqtkEZsA
++4rE1IERRyiJQx6EJsz21wJmGV9WJQ5kCQQDwkS0uXqVdFzgHO6S++tjmjYcxwr3g
++H0CoFYSgbddOT6miqRskOQF3DZVkJT3kyuBgU2zKygz52ukQZMqxCb1fAkASvuTv
++qfpH87Qq5kQhNKdbbwbmd2NxlNabazPijWuphGTdW0VfJdWfklyS2Kr+iqrs/5wV
++HhathJt636Eg7oIjAkA8ht3MQ+XSl9yIJIS8gVpbPxSw5OMfw0PjVE7tBdQruiSc
++nvuQES5C9BMHjF39LZiGH1iLQy7FgdHyoP+eodI7
+ -----END RSA PRIVATE KEY-----
+ """
+
+ DSS_PRIVATE_OUT = """\
+ -----BEGIN DSA PRIVATE KEY-----
+-MIIBvgIBAAKCAIEA54GmA2d9HOv+3CYBBG7ZfBYCncIW2tWe6Dqzp+DCP+guNhtW
+-2MDLqmX+HQQoJbHat/Uh63I2xPFaueID0jod4OPrlfUXIOSDqDy28Kdo0Hxen9RS
+-G7Me4awwiKlHEHHD0sXrTwSplyPUTfK2S2hbkHk5yOuQSjPfEbsL6ukiNi8CFQDw
+-z4UnmsGiSNu5iqjn3uTzwUpshwKCAIEAkxfFeY8P2wZpDjX0MimZl5wkoFQDL25c
+-PzGBuB4OnB8NoUk/yjAHIIpEShw8V+LzouMK5CTJQo5+Ngw3qIch/WgRmMHy4kBq
+-1SsXMjQCte1So6HBMvBPIW5SiMTmjCfZZiw4AYHK+B/JaOwaG9yRg2Ejg4Ok10+X
+-FDxlqZo8Y+wCggCARmR7CCPjodxASvRbIyzaVpZoJ/Z6x7dAumV+ysrV1BVYd0lY
+-ukmnjO1kKBWApqpH1ve9XDQYN8zgxM4b16L21kpoWQnZtXrY3GZ4/it9kUgyB7+N
+-wacIBlXa8cMDL7Q/69o0d54U0X/NeX5QxuYR6OMJlrkQB7oiW/P/1mwjQgECFGI9
+-QPSch9pT9XHqn+1rZ4bK+QGA
++MIIBuwIBAAKBgQDngaYDZ30c6/7cJgEEbtl8FgKdwhba1Z7oOrOn4MI/6C42G1bY
++wMuqZf4dBCglsdq39SHrcjbE8Vq54gPSOh3g4+uV9Rcg5IOoPLbwp2jQfF6f1FIb
++sx7hrDCIqUcQccPSxetPBKmXI9RN8rZLaFuQeTnI65BKM98Ruwvq6SI2LwIVAPDP
++hSeawaJI27mKqOfe5PPBSmyHAoGBAJMXxXmPD9sGaQ419DIpmZecJKBUAy9uXD8x
++gbgeDpwfDaFJP8owByCKREocPFfi86LjCuQkyUKOfjYMN6iHIf1oEZjB8uJAatUr
++FzI0ArXtUqOhwTLwTyFuUojE5own2WYsOAGByvgfyWjsGhvckYNhI4ODpNdPlxQ8
++ZamaPGPsAoGARmR7CCPjodxASvRbIyzaVpZoJ/Z6x7dAumV+ysrV1BVYd0lYukmn
++jO1kKBWApqpH1ve9XDQYN8zgxM4b16L21kpoWQnZtXrY3GZ4/it9kUgyB7+NwacI
++BlXa8cMDL7Q/69o0d54U0X/NeX5QxuYR6OMJlrkQB7oiW/P/1mwjQgECFGI9QPSc
++h9pT9XHqn+1rZ4bK+QGA
+ -----END DSA PRIVATE KEY-----
+ """
+
+@@ -121,7 +121,7 @@ class KeyTest (unittest.TestCase):
+ self.assertEqual(exp_rsa, my_rsa)
+ self.assertEqual(PUB_RSA.split()[1], key.get_base64())
+ self.assertEqual(1024, key.get_bits())
+-
++
+ def test_4_load_dss(self):
+ key = DSSKey.from_private_key_file(test_path('test_dss.key'))
+ self.assertEqual('ssh-dss', key.get_name())