def format_binary_line(data): left = ' '.join(['{:02X}'.format(byte_ord(c)) for c in data]) right = ''.join([ '.{:c}..'.format(byte_ord(c))[(byte_ord(c) + 63) // 95] for c in data ]) return '{:50s} {}'.format(left, right)
def deflate_long(n, add_sign_padding=True): """turns a long-int into a normalized byte string (adapted from Crypto.Util.number)""" # after much testing, this algorithm was deemed to be the fastest s = bytes() n = long(n) while (n != 0) and (n != -1): s = struct.pack('>I', n & xffffffff) + s n >>= 32 # strip off leading zeros, FFs for i in enumerate(s): if (n == 0) and (i[1] != deflate_zero): break if (n == -1) and (i[1] != deflate_ff): break else: # degenerate case, n was either 0 or -1 i = (0,) if n == 0: s = zero_byte else: s = max_byte s = s[i[0]:] if add_sign_padding: if (n == 0) and (byte_ord(s[0]) >= 0x80): s = zero_byte + s if (n == -1) and (byte_ord(s[0]) < 0x80): s = max_byte + s return s
def safe_string(s): out = '' for c in s: if (byte_ord(c) >= 32) and (byte_ord(c) <= 127): out += c else: out += '%%%02X' % byte_ord(c) return out
def constant_time_bytes_eq(a, b): if len(a) != len(b): return False res = 0 # noinspection PyUnresolvedReferences for i in (xrange if PY2 else range)(len(a)): res |= byte_ord(a[i]) ^ byte_ord(b[i]) return res == 0
def _read_packet(self): x = self._read_all(4) # most sftp servers won't accept packets larger than about 32k, so # anything with the high byte set (> 16MB) is just garbage. if byte_ord(x[0]): raise SFTPError('Garbage packet received') size = struct.unpack('>I', x)[0] data = self._read_all(size) if self.ultra_debug: self._log(DEBUG, util.format_binary(data, 'IN: ')) if size > 0: t = byte_ord(data[0]) return t, data[1:] return 0, bytes()
def decode_next(self): if self.idx >= len(self.content): return None ident = byte_ord(self.content[self.idx]) self.idx += 1 if (ident & 31) == 31: # identifier > 30 ident = 0 while self.idx < len(self.content): t = byte_ord(self.content[self.idx]) self.idx += 1 ident = (ident << 7) | (t & 0x7f) if not (t & 0x80): break if self.idx >= len(self.content): return None # now fetch length size = byte_ord(self.content[self.idx]) self.idx += 1 if size & 0x80: # more complimicated... # FIXME: theoretically should handle indefinite-length (0x80) t = size & 0x7f if self.idx + t > len(self.content): return None size = util.inflate_long( self.content[self.idx : self.idx + t], True ) self.idx += t if self.idx + size > len(self.content): # can't fit return None data = self.content[self.idx : self.idx + size] self.idx += size # now switch on id if ident == 0x30: # sequence return self.decode_sequence(data) elif ident == 2: # int return util.inflate_long(data) else: # 1: boolean (00 false, otherwise true) msg = "Unknown ber encoding type {:d} (robey is lazy)" raise BERException(msg.format(ident))
def safe_string(s): out = b"" for c in s: i = byte_ord(c) if 32 <= i <= 127: out += byte_chr(i) else: out += b("%{:02X}".format(i)) return out
def test_generate_key_bytes(self): x = paramiko.util.generate_key_bytes( sha1, b"ABCDEFGH", "This is my secret passphrase.", 64 ) hex = "".join(["%02x" % byte_ord(c) for c in x]) self.assertEqual( hex, "9110e2f6793b69363e58173e9436b13a5a4b339005741d5c680e505f57d871347b4239f14fb5c46e857d5e100424873ba849ac699cea98d729e57b3e84378e8b", )
def send_message(self, data): """ Write a block of data using the current cipher, as an SSH block. """ # encrypt this sucka data = asbytes(data) cmd = byte_ord(data[0]) if cmd in MSG_NAMES: cmd_name = MSG_NAMES[cmd] else: cmd_name = "${:x}".format(cmd) orig_len = len(data) self.__write_lock.acquire() try: if self.__compress_engine_out is not None: data = self.__compress_engine_out(data) packet = self._build_packet(data) if self.__dump_packets: self._log( DEBUG, "Write packet <{}>, length {}".format(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.update(packet) else: out = packet # + mac if self.__block_engine_out is not None: payload = ( struct.pack(">I", self.__sequence_number_out) + packet ) out += compute_hmac( self.__mac_key_out, payload, self.__mac_engine_out )[: self.__mac_size_out] self.__sequence_number_out = ( self.__sequence_number_out + 1 ) & xffffffff self.write_all(out) self.__sent_bytes += len(out) self.__sent_packets += 1 sent_too_much = ( self.__sent_packets >= self.REKEY_PACKETS or self.__sent_bytes >= self.REKEY_BYTES ) if sent_too_much and not self.__need_rekey: # only ask once for rekeying msg = "Rekeying (hit {} packets, {} bytes sent)" self._log( DEBUG, msg.format(self.__sent_packets, self.__sent_bytes) ) self.__received_bytes_overflow = 0 self.__received_packets_overflow = 0 self._trigger_rekey() finally: self.__write_lock.release()
def safe_string(s): out = b('') for c in s: i = byte_ord(c) if 32 <= i <= 127: out += byte_chr(i) else: out += b('%%%02X' % i) return out
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()
def bit_length(n): try: return n.bitlength() except AttributeError: norm = deflate_long(n, False) hbyte = byte_ord(norm[0]) if hbyte == 0: return 1 bitlen = len(norm) * 8 while not (hbyte & 0x80): hbyte <<= 1 bitlen -= 1 return bitlen
def send_message(self, data): """ Write a block of data using the current cipher, as an SSH block. """ # encrypt this sucka data = asbytes(data) cmd = byte_ord(data[0]) if cmd in MSG_NAMES: cmd_name = MSG_NAMES[cmd] else: cmd_name = '$%x' % cmd orig_len = len(data) self.__write_lock.acquire() try: if self.__compress_engine_out is not None: data = self.__compress_engine_out(data) packet = self._build_packet(data) if self.__dump_packets: dump_out = ( "{0}\n".format("=" * 50) + "Sent Packet: \n" + " Command Name: {0}\n".format(cmd_name) + " Command Number: {0}\n".format(cmd) + " Command Hex: {0}\n".format(hex(cmd)) + " Command Length: {0}\n".format(orig_len) + "{0}\n".format("-" * 50)) self._log(DEBUG, dump_out) self._log(DEBUG, util.format_binary(packet, 'OUT: ')) if self.__block_engine_out is not None: out = self.__block_engine_out.update(packet) else: out = packet # + mac if self.__block_engine_out is not None: payload = struct.pack('>I', self.__sequence_number_out) + packet out += compute_hmac(self.__mac_key_out, payload, self.__mac_engine_out)[:self.__mac_size_out] self.__sequence_number_out = (self.__sequence_number_out + 1) & xffffffff self.write_all(out) self.__sent_bytes += len(out) self.__sent_packets += 1 if (self.__sent_packets >= self.REKEY_PACKETS or self.__sent_bytes >= self.REKEY_BYTES)\ and not self.__need_rekey: # only ask once for rekeying self._log(DEBUG, 'Rekeying (hit %d packets, %d bytes sent)' % (self.__sent_packets, self.__sent_bytes)) self.__received_bytes_overflow = 0 self.__received_packets_overflow = 0 self._trigger_rekey() finally: self.__write_lock.release()
def _generate_x(self): # generate an "x" (1 < x < (p-1)/2). q = (self.p - 1) // 2 qnorm = util.deflate_long(q, 0) qhbyte = byte_ord(qnorm[0]) byte_count = len(qnorm) qmask = 0xff while not (qhbyte & 0x80): qhbyte <<= 1 qmask >>= 1 while True: x_bytes = os.urandom(byte_count) x_bytes = byte_mask(x_bytes[0], qmask) + x_bytes[1:] x = util.inflate_long(x_bytes, 1) if (x > 1) and (x < q): break self.x = x
def inflate_long(s, always_positive=False): """turns a normalized byte string into a long-int (adapted from Crypto.Util.number)""" out = long(0) negative = 0 if not always_positive and (len(s) > 0) and (byte_ord(s[0]) >= 0x80): negative = 1 if len(s) % 4: filler = zero_byte if negative: filler = max_byte # never convert this to ``s +=`` because this is a string, not a number # noinspection PyAugmentAssignment s = filler * (4 - len(s) % 4) + s for i in range(0, len(s), 4): out = (out << 32) + struct.unpack('>I', s[i:i+4])[0] if negative: out -= (long(1) << (8 * len(s))) return out
def send_message(self, data): """ Write a block of data using the current cipher, as an SSH block. """ # encrypt this sucka data = asbytes(data) cmd = byte_ord(data[0]) if cmd in MSG_NAMES: cmd_name = MSG_NAMES[cmd] else: cmd_name = '$%x' % cmd orig_len = len(data) self.__write_lock.acquire() try: if self.__compress_engine_out is not None: data = self.__compress_engine_out(data) packet = self._build_packet(data) if self.__dump_packets: 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.update(packet) else: out = packet # + mac if self.__block_engine_out is not None: payload = struct.pack('>I', self.__sequence_number_out) + packet out += compute_hmac(self.__mac_key_out, payload, self.__mac_engine_out)[:self.__mac_size_out] self.__sequence_number_out = (self.__sequence_number_out + 1) & xffffffff self.write_all(out) self.__sent_bytes += len(out) self.__sent_packets += 1 if (self.__sent_packets >= self.REKEY_PACKETS or self.__sent_bytes >= self.REKEY_BYTES)\ and not self.__need_rekey: # only ask once for rekeying self._log(DEBUG, 'Rekeying (hit %d packets, %d bytes sent)' % (self.__sent_packets, self.__sent_bytes)) self.__received_bytes_overflow = 0 self.__received_packets_overflow = 0 self._trigger_rekey() finally: self.__write_lock.release()
def _convert_address(self, family, addr): """ Convert packed IPv4/IPv6 address bytes to an human readable ASCII version """ if family is socket.AF_INET: addr = b".".join( ("%i" % (byte_ord(b), )).encode("ascii") for b in addr) elif family is socket.AF_INET6: hexaddr = binascii.b2a_hex(addr) addr = b":".join( ("%x" % (int(hexaddr[b:b + 4], 16), )).encode("ascii") for b in range(0, 32, 4)) elif family == socket.AF_UNIX: return addr.rstrip(b"\x00") else: raise ProxyProtocolException( "Unknown INET family : {}".format(family)) return self._is_valid_ip_address(family, addr)
def send_message(self, data): """ Write a block of data using the current cipher, as an SSH block. """ # encrypt this sucka data = asbytes(data) cmd = byte_ord(data[0]) if cmd in MSG_NAMES: cmd_name = MSG_NAMES[cmd] else: cmd_name = '$%x' % cmd orig_len = len(data) with self.__write_lock: if self.__compress_engine_out is not None: data = self.__compress_engine_out(data) packet = self._build_packet(data) if self.__dump_packets: 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) else: out = packet # + mac if self.__block_engine_out is not None: payload = struct.pack('>I', self.__sequence_number_out) + packet out += compute_hmac(self.__mac_key_out, payload, self.__mac_engine_out)[:self.__mac_size_out] self.__sequence_number_out = (self.__sequence_number_out + 1) & xffffffff self.write_all(out) self.__sent_bytes += len(out) self.__sent_packets += 1 if (self.__sent_packets >= self.REKEY_PACKETS or self.__sent_bytes >= self.REKEY_BYTES)\ and not self.__need_rekey: # only ask once for rekeying self._log(DEBUG, 'Rekeying (hit %d packets, %d bytes sent)' % (self.__sent_packets, self.__sent_bytes)) self.__received_bytes_overflow = 0 self.__received_packets_overflow = 0 self._trigger_rekey()
def test_4_generate_key_bytes(self): x = paramiko.util.generate_key_bytes(SHA, b'ABCDEFGH', 'This is my secret passphrase.', 64) hex = ''.join(['%02x' % byte_ord(c) for c in x]) self.assertEqual(hex, '9110e2f6793b69363e58173e9436b13a5a4b339005741d5c680e505f57d871347b4239f14fb5c46e857d5e100424873ba849ac699cea98d729e57b3e84378e8b')
def send_message(self, data): """ Write a block of data using the current cipher, as an SSH block. """ # encrypt this sucka data = asbytes(data) cmd = byte_ord(data[0]) if cmd in MSG_NAMES: cmd_name = MSG_NAMES[cmd] else: cmd_name = "${:x}".format(cmd) orig_len = len(data) self.__write_lock.acquire() try: if self.__compress_engine_out is not None: data = self.__compress_engine_out(data) packet = self._build_packet(data) if self.__dump_packets: self._log( DEBUG, "Write packet <{}>, length {}".format(cmd_name, orig_len), ) self._log(DEBUG, util.format_binary(packet, "OUT: ")) if self.__block_engine_out is not None: if self.__etm_out: # packet length is not encrypted in EtM out = packet[0:4] + self.__block_engine_out.update( packet[4:] ) else: out = self.__block_engine_out.update(packet) else: out = packet # + mac if self.__block_engine_out is not None: packed = struct.pack(">I", self.__sequence_number_out) payload = packed + (out if self.__etm_out else packet) out += compute_hmac( self.__mac_key_out, payload, self.__mac_engine_out )[: self.__mac_size_out] self.__sequence_number_out = ( self.__sequence_number_out + 1 ) & xffffffff self.write_all(out) self.__sent_bytes += len(out) self.__sent_packets += 1 sent_too_much = ( self.__sent_packets >= self.REKEY_PACKETS or self.__sent_bytes >= self.REKEY_BYTES ) if sent_too_much and not self.__need_rekey: # only ask once for rekeying msg = "Rekeying (hit {} packets, {} bytes sent)" self._log( DEBUG, msg.format(self.__sent_packets, self.__sent_bytes) ) self.__received_bytes_overflow = 0 self.__received_packets_overflow = 0 self._trigger_rekey() finally: self.__write_lock.release()
def read_message(self): """ Only one thread should ever be in this function (no other locking is done). :raises: `.SSHException` -- if the packet is mangled :raises: `.NeedRekeyException` -- if the transport should rekey """ header = self.read_all(self.__block_size_in, check_rekey=True) if self.__etm_in: packet_size = struct.unpack(">I", header[:4])[0] remaining = packet_size - self.__block_size_in + 4 packet = header[4:] + self.read_all(remaining, check_rekey=False) mac = self.read_all(self.__mac_size_in, check_rekey=False) mac_payload = ( struct.pack(">II", self.__sequence_number_in, packet_size) + packet ) my_mac = compute_hmac( self.__mac_key_in, mac_payload, self.__mac_engine_in )[: self.__mac_size_in] if not util.constant_time_bytes_eq(my_mac, mac): raise SSHException("Mismatched MAC") header = packet if self.__block_engine_in is not None: header = self.__block_engine_in.update(header) if self.__dump_packets: self._log(DEBUG, util.format_binary(header, "IN: ")) # When ETM is in play, we've already read the packet size & decrypted # everything, so just set the packet back to the header we obtained. if self.__etm_in: packet = header # Otherwise, use the older non-ETM logic else: packet_size = struct.unpack(">I", header[:4])[0] # leftover contains decrypted bytes from the first block (after the # length field) leftover = header[4:] if (packet_size - len(leftover)) % self.__block_size_in != 0: raise SSHException("Invalid packet blocking") buf = self.read_all( packet_size + self.__mac_size_in - len(leftover) ) 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.update(packet) packet = leftover + packet if self.__dump_packets: self._log(DEBUG, util.format_binary(packet, "IN: ")) if self.__mac_size_in > 0 and not self.__etm_in: mac = post_packet[: self.__mac_size_in] mac_payload = ( struct.pack(">II", self.__sequence_number_in, packet_size) + packet ) my_mac = compute_hmac( self.__mac_key_in, mac_payload, self.__mac_engine_in )[: self.__mac_size_in] if not util.constant_time_bytes_eq(my_mac, mac): raise SSHException("Mismatched MAC") padding = byte_ord(packet[0]) payload = packet[1 : packet_size - padding] if self.__dump_packets: self._log( DEBUG, "Got payload ({} bytes, {} padding)".format( packet_size, padding ), ) if self.__compress_engine_in is not None: payload = self.__compress_engine_in(payload) msg = Message(payload[1:]) msg.seqno = self.__sequence_number_in self.__sequence_number_in = (self.__sequence_number_in + 1) & xffffffff # check for rekey raw_packet_size = packet_size + self.__mac_size_in + 4 self.__received_bytes += raw_packet_size self.__received_packets += 1 if self.__need_rekey: # we've asked to rekey -- give them some packets to comply before # dropping the connection self.__received_bytes_overflow += raw_packet_size self.__received_packets_overflow += 1 if ( self.__received_packets_overflow >= self.REKEY_PACKETS_OVERFLOW_MAX ) or ( self.__received_bytes_overflow >= self.REKEY_BYTES_OVERFLOW_MAX ): raise SSHException( "Remote transport is ignoring rekey requests" ) elif (self.__received_packets >= self.REKEY_PACKETS) or ( self.__received_bytes >= self.REKEY_BYTES ): # only ask once for rekeying err = "Rekeying (hit {} packets, {} bytes received)" self._log( DEBUG, err.format(self.__received_packets, self.__received_bytes), ) self.__received_bytes_overflow = 0 self.__received_packets_overflow = 0 self._trigger_rekey() cmd = byte_ord(payload[0]) if cmd in MSG_NAMES: cmd_name = MSG_NAMES[cmd] else: cmd_name = "${:x}".format(cmd) if self.__dump_packets: self._log( DEBUG, "Read packet <{}>, length {}".format(cmd_name, len(payload)), ) return cmd, msg
def format_binary_line(data): left = " ".join(["{:02X}".format(byte_ord(c)) for c in data]) right = "".join([ ".{:c}..".format(byte_ord(c))[(byte_ord(c) + 63) // 95] for c in data ]) return "{:50s} {}".format(left, right)
def _read_private_key_openssh(self, lines, password): """ Read the new OpenSSH SSH2 private key format available since OpenSSH version 6.5 Reference: https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key """ try: data = decodebytes(b("".join(lines))) except base64.binascii.Error as e: raise SSHException("base64 decoding error: {}".format(e)) # read data struct auth_magic = data[:14] if auth_magic != b("openssh-key-v1"): raise SSHException("unexpected OpenSSH key header encountered") cstruct = self._uint32_cstruct_unpack(data[15:], "sssur") cipher, kdfname, kdf_options, num_pubkeys, remainder = cstruct # For now, just support 1 key. if num_pubkeys > 1: raise SSHException( "unsupported: private keyfile has multiple keys" ) pubkey, privkey_blob = self._uint32_cstruct_unpack(remainder, "ss") if kdfname == b("bcrypt"): if cipher == b("aes256-cbc"): mode = modes.CBC elif cipher == b("aes256-ctr"): mode = modes.CTR else: raise SSHException( "unknown cipher `{}` used in private key file".format( cipher.decode("utf-8") ) ) # Encrypted private key. # If no password was passed in, raise an exception pointing # out that we need one if password is None: raise PasswordRequiredException( "private key file is encrypted" ) # Unpack salt and rounds from kdfoptions salt, rounds = self._uint32_cstruct_unpack(kdf_options, "su") # run bcrypt kdf to derive key and iv/nonce (32 + 16 bytes) key_iv = bcrypt.kdf( b(password), b(salt), 48, rounds, # We can't control how many rounds are on disk, so no sense # warning about it. ignore_few_rounds=True, ) key = key_iv[:32] iv = key_iv[32:] # decrypt private key blob decryptor = Cipher( algorithms.AES(key), mode(iv), default_backend() ).decryptor() decrypted_privkey = decryptor.update(privkey_blob) decrypted_privkey += decryptor.finalize() elif cipher == b("none") and kdfname == b("none"): # Unencrypted private key decrypted_privkey = privkey_blob else: raise SSHException( "unknown cipher or kdf used in private key file" ) # Unpack private key and verify checkints cstruct = self._uint32_cstruct_unpack(decrypted_privkey, "uusr") checkint1, checkint2, keytype, keydata = cstruct if checkint1 != checkint2: raise SSHException( "OpenSSH private key file checkints do not match" ) # Remove padding padlen = byte_ord(keydata[len(keydata) - 1]) return keydata[: len(keydata) - padlen]
def format_binary_line(data): left = " ".join(["{:02X}".format(byte_ord(c)) for c in data]) right = "".join( [".{:c}..".format(byte_ord(c))[(byte_ord(c) + 63) // 95] for c in data] ) return "{:50s} {}".format(left, right)
def format_binary_line(data): left = " ".join(["%02X" % byte_ord(c) for c in data]) right = "".join([(".%c.." % c)[(byte_ord(c) + 63) // 95] for c in data]) return "%-50s %s" % (left, right)
def format_binary_line(data): left = ' '.join(['%02X' % byte_ord(c) for c in data]) right = ''.join([('.%c..' % c)[(byte_ord(c)+63)//95] for c in data]) return '%-50s %s' % (left, right)
def read_message(self): """ Only one thread should ever be in this function (no other locking is done). :raises SSHException: if the packet is mangled :raises NeedRekeyException: if the transport should rekey """ 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) if self.__dump_packets: self._log(DEBUG, util.format_binary(header, 'IN: ')) packet_size = struct.unpack('>I', header[:4])[0] # leftover contains decrypted bytes from the first block (after the length field) leftover = header[4:] if (packet_size - len(leftover)) % self.__block_size_in != 0: raise SSHException('Invalid packet blocking') buf = self.read_all(packet_size + self.__mac_size_in - len(leftover)) 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) if self.__dump_packets: self._log(DEBUG, util.format_binary(packet, 'IN: ')) packet = leftover + packet if self.__mac_size_in > 0: mac = post_packet[:self.__mac_size_in] mac_payload = struct.pack('>II', self.__sequence_number_in, packet_size) + packet my_mac = compute_hmac(self.__mac_key_in, mac_payload, self.__mac_engine_in)[:self.__mac_size_in] if not util.constant_time_bytes_eq(my_mac, mac): raise SSHException('Mismatched MAC') padding = byte_ord(packet[0]) payload = packet[1:packet_size - padding] if self.__dump_packets: self._log(DEBUG, 'Got payload (%d bytes, %d padding)' % (packet_size, padding)) if self.__compress_engine_in is not None: payload = self.__compress_engine_in(payload) msg = Message(payload[1:]) msg.seqno = self.__sequence_number_in self.__sequence_number_in = (self.__sequence_number_in + 1) & xffffffff # check for rekey raw_packet_size = packet_size + self.__mac_size_in + 4 self.__received_bytes += raw_packet_size self.__received_packets += 1 if self.__need_rekey: # we've asked to rekey -- give them some packets to comply before # dropping the connection self.__received_bytes_overflow += raw_packet_size self.__received_packets_overflow += 1 if (self.__received_packets_overflow >= self.REKEY_PACKETS_OVERFLOW_MAX) or \ (self.__received_bytes_overflow >= self.REKEY_BYTES_OVERFLOW_MAX): raise SSHException('Remote transport is ignoring rekey requests') elif (self.__received_packets >= self.REKEY_PACKETS) or \ (self.__received_bytes >= self.REKEY_BYTES): # only ask once for rekeying self._log(DEBUG, 'Rekeying (hit %d packets, %d bytes received)' % (self.__received_packets, self.__received_bytes)) self.__received_bytes_overflow = 0 self.__received_packets_overflow = 0 self._trigger_rekey() cmd = byte_ord(payload[0]) if cmd in MSG_NAMES: cmd_name = MSG_NAMES[cmd] else: cmd_name = '$%x' % cmd if self.__dump_packets: self._log(DEBUG, 'Read packet <%s>, length %d' % (cmd_name, len(payload))) return cmd, msg
def test_generate_key_bytes(self): x = paramiko.util.generate_key_bytes(sha1, b'ABCDEFGH', 'This is my secret passphrase.', 64) hex = ''.join(['%02x' % byte_ord(c) for c in x]) self.assertEqual(hex, '9110e2f6793b69363e58173e9436b13a5a4b339005741d5c680e505f57d871347b4239f14fb5c46e857d5e100424873ba849ac699cea98d729e57b3e84378e8b') # noqa: E501
def read_message(self): """ Only one thread should ever be in this function (no other locking is done). :raises SSHException: if the packet is mangled :raises NeedRekeyException: if the transport should rekey """ 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) if self.__dump_packets: self._log(DEBUG, util.format_binary(header, 'IN: ')) packet_size = struct.unpack('>I', header[:4])[0] # leftover contains decrypted bytes from the first block (after the # length field) leftover = header[4:] if (packet_size - len(leftover)) % self.__block_size_in != 0: raise SSHException('Invalid packet blocking') buf = self.read_all(packet_size + self.__mac_size_in - len(leftover)) 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) if self.__dump_packets: self._log(DEBUG, util.format_binary(packet, 'IN: ')) packet = leftover + packet if self.__mac_size_in > 0: mac = post_packet[:self.__mac_size_in] mac_payload = struct.pack('>II', self.__sequence_number_in, packet_size) + packet my_mac = compute_hmac(self.__mac_key_in, mac_payload, self.__mac_engine_in)[:self.__mac_size_in] if not util.constant_time_bytes_eq(my_mac, mac): raise SSHException('Mismatched MAC') padding = byte_ord(packet[0]) payload = packet[1:packet_size - padding] if self.__dump_packets: self._log( DEBUG, 'Got payload (%d bytes, %d padding)' % (packet_size, padding)) if self.__compress_engine_in is not None: payload = self.__compress_engine_in(payload) msg = Message(payload[1:]) msg.seqno = self.__sequence_number_in self.__sequence_number_in = (self.__sequence_number_in + 1) & xffffffff # check for rekey raw_packet_size = packet_size + self.__mac_size_in + 4 self.__received_bytes += raw_packet_size self.__received_packets += 1 if self.__need_rekey: # we've asked to rekey -- give them some packets to comply before # dropping the connection self.__received_bytes_overflow += raw_packet_size self.__received_packets_overflow += 1 if (self.__received_packets_overflow >= self.REKEY_PACKETS_OVERFLOW_MAX) or \ (self.__received_bytes_overflow >= self.REKEY_BYTES_OVERFLOW_MAX): raise SSHException( 'Remote transport is ignoring rekey requests') elif (self.__received_packets >= self.REKEY_PACKETS) or \ (self.__received_bytes >= self.REKEY_BYTES): # only ask once for rekeying self._log( DEBUG, 'Rekeying (hit %d packets, %d bytes received)' % (self.__received_packets, self.__received_bytes)) self.__received_bytes_overflow = 0 self.__received_packets_overflow = 0 self._trigger_rekey() cmd = byte_ord(payload[0]) if cmd in MSG_NAMES: cmd_name = MSG_NAMES[cmd] else: cmd_name = '$%x' % cmd if self.__dump_packets: self._log(DEBUG, 'Read packet <%s>, length %d' % (cmd_name, len(payload))) return cmd, msg