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())