diff options
Diffstat (limited to 'paramiko/transport.py')
-rw-r--r-- | paramiko/transport.py | 122 |
1 files changed, 107 insertions, 15 deletions
diff --git a/paramiko/transport.py b/paramiko/transport.py index ecd8c7bc..a80ad9ef 100644 --- a/paramiko/transport.py +++ b/paramiko/transport.py @@ -30,7 +30,7 @@ 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 +from cryptography.hazmat.primitives.ciphers import algorithms, Cipher, modes, aead import paramiko from paramiko import util @@ -179,6 +179,8 @@ class Transport(threading.Thread, ClosingContextManager): "aes192-cbc", "aes256-cbc", "3des-cbc", + "aes128-gcm@openssh.com", + "aes256-gcm@openssh.com", ) _preferred_macs = ( "hmac-sha2-256", @@ -237,44 +239,66 @@ class Transport(threading.Thread, ClosingContextManager): "class": algorithms.AES, "mode": modes.CTR, "block-size": 16, + "iv-size": 16, "key-size": 16, }, "aes192-ctr": { "class": algorithms.AES, "mode": modes.CTR, "block-size": 16, + "iv-size": 16, "key-size": 24, }, "aes256-ctr": { "class": algorithms.AES, "mode": modes.CTR, "block-size": 16, + "iv-size": 16, "key-size": 32, }, "aes128-cbc": { "class": algorithms.AES, "mode": modes.CBC, "block-size": 16, + "iv-size": 16, "key-size": 16, }, "aes192-cbc": { "class": algorithms.AES, "mode": modes.CBC, "block-size": 16, + "iv-size": 16, "key-size": 24, }, "aes256-cbc": { "class": algorithms.AES, "mode": modes.CBC, "block-size": 16, + "iv-size": 16, "key-size": 32, }, "3des-cbc": { "class": TripleDES, "mode": modes.CBC, "block-size": 8, + "iv-size": 8, "key-size": 24, }, + # aead cipher + "aes128-gcm@openssh.com": { + "class": aead.AESGCM, + "block-size": 16, + "iv-size": 12, + "key-size": 16, + "is_aead": True, + }, + "aes256-gcm@openssh.com": { + "class": aead.AESGCM, + "block-size": 16, + "iv-size": 12, + "key-size": 32, + "is_aead": True, + }, } _mac_info = { @@ -2039,6 +2063,10 @@ class Transport(threading.Thread, ClosingContextManager): else: return cipher.decryptor() + def _get_aead_cipher(self, name, key): + aead_cipher = self._cipher_info[name]["class"](key) + return aead_cipher + def _set_forward_agent_handler(self, handler): if handler is None: @@ -2707,18 +2735,32 @@ class Transport(threading.Thread, ClosingContextManager): inbound traffic""" block_size = self._cipher_info[self.remote_cipher]["block-size"] if self.server_mode: - IV_in = self._compute_key("A", block_size) + IV_in = self._compute_key( + "A", self._cipher_info[self.remote_cipher]["iv-size"] + ) key_in = self._compute_key( "C", self._cipher_info[self.remote_cipher]["key-size"] ) else: - IV_in = self._compute_key("B", block_size) + IV_in = self._compute_key( + "B", self._cipher_info[self.remote_cipher]["iv-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, self._DECRYPT + + is_aead = ( + True + if self._cipher_info[self.remote_cipher].get("is_aead") + else False ) + + if is_aead: + engine = self._get_aead_cipher(self.remote_cipher, key_in) + else: + engine = self._get_cipher( + self.remote_cipher, key_in, IV_in, self._DECRYPT + ) etm = "etm@openssh.com" in self.remote_mac mac_size = self._mac_info[self.remote_mac]["size"] mac_engine = self._mac_info[self.remote_mac]["class"] @@ -2728,9 +2770,24 @@ class Transport(threading.Thread, ClosingContextManager): mac_key = self._compute_key("E", mac_engine().digest_size) else: mac_key = self._compute_key("F", mac_engine().digest_size) - self.packetizer.set_inbound_cipher( - engine, block_size, mac_engine, mac_size, mac_key, etm=etm - ) + + if is_aead: + self._log(DEBUG, "use aead-cipher, so set mac to None") + self.packetizer.set_inbound_cipher( + engine, + block_size, + None, + 16, + bytes(), + etm=False, + aead=is_aead, + iv_in=IV_in, + ) + else: + self.packetizer.set_inbound_cipher( + engine, block_size, mac_engine, mac_size, mac_key, etm=etm + ) + compress_in = self._compression_info[self.remote_compression][1] if compress_in is not None and ( self.remote_compression != "zlib@openssh.com" or self.authenticated @@ -2760,18 +2817,32 @@ class Transport(threading.Thread, ClosingContextManager): self.packetizer.reset_seqno_out() block_size = self._cipher_info[self.local_cipher]["block-size"] if self.server_mode: - IV_out = self._compute_key("B", block_size) + IV_out = self._compute_key( + "B", self._cipher_info[self.local_cipher]["iv-size"] + ) key_out = self._compute_key( "D", self._cipher_info[self.local_cipher]["key-size"] ) else: - IV_out = self._compute_key("A", block_size) + IV_out = self._compute_key( + "A", self._cipher_info[self.local_cipher]["iv-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, self._ENCRYPT + + is_aead = ( + True + if self._cipher_info[self.local_cipher].get("is_aead") + else False ) + + if is_aead: + engine = self._get_aead_cipher(self.local_cipher, key_out) + else: + engine = self._get_cipher( + self.local_cipher, key_out, IV_out, self._ENCRYPT + ) etm = "etm@openssh.com" in self.local_mac mac_size = self._mac_info[self.local_mac]["size"] mac_engine = self._mac_info[self.local_mac]["class"] @@ -2782,9 +2853,30 @@ class Transport(threading.Thread, ClosingContextManager): else: mac_key = self._compute_key("E", mac_engine().digest_size) sdctr = self.local_cipher.endswith("-ctr") - self.packetizer.set_outbound_cipher( - engine, block_size, mac_engine, mac_size, mac_key, sdctr, etm=etm - ) + + if is_aead: + self.packetizer.set_outbound_cipher( + engine, + block_size, + None, + 16, + bytes(), + sdctr, + etm=False, + aead=is_aead, + iv_out=IV_out, + ) + else: + self.packetizer.set_outbound_cipher( + engine, + block_size, + mac_engine, + mac_size, + mac_key, + sdctr, + etm=etm, + ) + compress_out = self._compression_info[self.local_compression][0] if compress_out is not None and ( self.local_compression != "zlib@openssh.com" or self.authenticated |