--- a/components/python/paramiko/patches/01-nopycrypto.patch Thu Aug 25 13:31:12 2016 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1613 +0,0 @@
-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 <http://www.python.org/> - this includes Python
- 3.2 and higher as well.
-- - pycrypto 2.1 or better <https://www.dlitz.net/software/pycrypto/>
-- - ecdsa 0.9 or better <https://pypi.python.org/pypi/ecdsa>
-+ - Cryptography 0.8 or better <https://cryptography.io>
-+ - pyasn1 0.1.7 or better <https://pypi.python.org/pypi/pyasn1>
-
- 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 <http://www.ietf.org/rfc/rfc4462.txt>`_ 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
-+ <https://tools.ietf.org/html/rfc4462.html#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 <http://www.ietf.org/rfc/rfc4462.txt>`_
-+ GSS-API / SSPI Authenticated Diffie-Hellman Key Exchange as defined in `RFC
-+ 4462 Section 2 <https://tools.ietf.org/html/rfc4462.html#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 <http://www.ietf.org/rfc/rfc4462.txt>`_
-+ GSS-API / SSPI Authenticated Diffie-Hellman Group14 Key Exchange as defined
-+ in `RFC 4462 Section 2
-+ <https://tools.ietf.org/html/rfc4462.html#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 <http://www.ietf.org/rfc/rfc4462.txt>`_
-+ GSS-API / SSPI Authenticated Diffie-Hellman Group Exchange as defined in
-+ `RFC 4462 Section 2 <https://tools.ietf.org/html/rfc4462.html#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 <http://www.ietf.org/rfc/rfc4462.txt>`_
-+ This class represents the Null Host Key for GSS-API Key Exchange as defined
-+ in `RFC 4462 Section 5
-+ <https://tools.ietf.org/html/rfc4462.html#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
- <https://github.com/paramiko/paramiko/tarball/master#egg=paramiko-dev>`_, 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())