diff options
Diffstat (limited to 'paramiko/transport.py')
-rw-r--r-- | paramiko/transport.py | 85 |
1 files changed, 49 insertions, 36 deletions
diff --git a/paramiko/transport.py b/paramiko/transport.py index 764486a8..7906c9f2 100644 --- a/paramiko/transport.py +++ b/paramiko/transport.py @@ -30,6 +30,9 @@ import time import weakref from hashlib import md5, sha1, sha256, sha512 +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 @@ -65,11 +68,6 @@ from paramiko.ssh_exception import (SSHException, BadAuthenticationType, 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 @@ -93,6 +91,9 @@ class Transport (threading.Thread, ClosingContextManager): Instances of this class may be used as context managers. """ + _ENCRYPT = object() + _DECRYPT = object() + _PROTO_ID = '2.0' _CLIENT_ID = 'paramiko_%s' % paramiko.__version__ @@ -121,8 +122,7 @@ class Transport (threading.Thread, ClosingContextManager): _preferred_keys = ( 'ssh-rsa', 'ssh-dss', - 'ecdsa-sha2-nistp256', - ) + ) + tuple(ECDSAKey.supported_key_format_identifiers()) _preferred_kex = ( 'diffie-hellman-group1-sha1', 'diffie-hellman-group14-sha1', @@ -133,67 +133,68 @@ class Transport (threading.Thread, ClosingContextManager): _cipher_info = { 'aes128-ctr': { - 'class': AES, - 'mode': AES.MODE_CTR, + 'class': algorithms.AES, + 'mode': modes.CTR, 'block-size': 16, 'key-size': 16 }, 'aes192-ctr': { - 'class': AES, - 'mode': AES.MODE_CTR, + 'class': algorithms.AES, + 'mode': modes.CTR, 'block-size': 16, 'key-size': 24 }, 'aes256-ctr': { - 'class': AES, - 'mode': AES.MODE_CTR, + 'class': algorithms.AES, + 'mode': modes.CTR, 'block-size': 16, 'key-size': 32 }, 'blowfish-cbc': { - 'class': Blowfish, - 'mode': Blowfish.MODE_CBC, + 'class': algorithms.Blowfish, + 'mode': modes.CBC, 'block-size': 8, 'key-size': 16 }, 'aes128-cbc': { - 'class': AES, - 'mode': AES.MODE_CBC, + 'class': algorithms.AES, + 'mode': modes.CBC, 'block-size': 16, 'key-size': 16 }, 'aes192-cbc': { - 'class': AES, - 'mode': AES.MODE_CBC, + 'class': algorithms.AES, + 'mode': modes.CBC, 'block-size': 16, 'key-size': 24 }, 'aes256-cbc': { - 'class': AES, - 'mode': AES.MODE_CBC, + 'class': algorithms.AES, + 'mode': modes.CBC, 'block-size': 16, 'key-size': 32 }, '3des-cbc': { - 'class': DES3, - 'mode': DES3.MODE_CBC, + 'class': algorithms.TripleDES, + 'mode': modes.CBC, 'block-size': 8, 'key-size': 24 }, 'arcfour128': { - 'class': ARC4, + 'class': algorithms.ARC4, 'mode': None, 'block-size': 8, 'key-size': 16 }, 'arcfour256': { - 'class': ARC4, + '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}, @@ -1654,22 +1655,34 @@ class Transport (threading.Thread, ClosingContextManager): 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: @@ -2065,7 +2078,7 @@ class Transport (threading.Thread, ClosingContextManager): 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 @@ -2092,7 +2105,7 @@ class Transport (threading.Thread, ClosingContextManager): 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 |