class Net::SSH::Transport::State
part of the internal state of the PacketStream module.
forth. This class will never be instantiated directly, but is used as
many packets and blocks have been processed since the last reset, and so
state includes the packet sequence number, the algorithms in use, how
Encapsulates state information about one end of an SSH connection. Such
def cleanup
Closes any the compressor and/or decompressor objects that have been
def cleanup if @compressor @compressor.finish if !@compressor.finished? @compressor.close end if @decompressor # we call reset here so that we don't get warnings when we try to # close the decompressor @decompressor.reset @decompressor.close end @compressor = @decompressor = nil end
def compress(data)
Compresses the data. If no compression is in effect, this will just return
def compress(data) data = data.to_s return data unless compression? compressor.deflate(data, Zlib::SYNC_FLUSH) end
def compression?
compression is selected and the :authenticated hint has been received
return true if :standard compression is selected, or if :delayed
Returns true if data compression/decompression is enabled. This will
def compression? compression == :standard || (compression == :delayed && socket.hints[:authenticated]) end
def compressor
The compressor object to use when compressing data. This takes into account
def compressor @compressor ||= Zlib::Deflate.new(compression_level || Zlib::DEFAULT_COMPRESSION) end
def decompress(data)
Deompresses the data. If no compression is in effect, this will just return
def decompress(data) data = data.to_s return data unless compression? decompressor.inflate(data) end
def decompressor
def decompressor @decompressor ||= Zlib::Inflate.new(nil) end
def final_cipher
def final_cipher result = cipher.final update_next_iv(role == :client ? result : "", true) return result end
def increment(packet_length)
so it always fits in a 32-bit integer). The number of packets and blocks
Increments the counters. The sequence number is incremented (and remapped
def increment(packet_length) @sequence_number = (@sequence_number + 1) & 0xFFFFFFFF @packets += 1 @blocks += (packet_length + 4) / @block_size end
def initialize(socket, role)
Creates a new state object, belonging to the given socket. Initializes
def initialize(socket, role) @socket = socket @role = role @sequence_number = @packets = @blocks = 0 @cipher = CipherFactory.get("none") @block_size = 8 @hmac = HMAC.get("none") @compression = nil @compressor = @decompressor = nil @next_iv = "" end
def needs_rekey?
number of packets, or if the number of blocks processed exceeds the
Returns true if the number of packets processed exceeds the maximum
def needs_rekey? max_packets && packets > max_packets || max_blocks && blocks > max_blocks end
def reset!
unchanged. It also sets defaults for and recomputes the max_packets and
Resets the counters on the state object, but leaves the sequence_number
def reset! @packets = @blocks = 0 @max_packets ||= 1 << 31 @block_size = cipher.name == "RC4" ? 8 : cipher.block_size if max_blocks.nil? # cargo-culted from openssh. the idea is that "the 2^(blocksize*2) # limit is too expensive for 3DES, blowfish, etc., so enforce a 1GB # limit for small blocksizes." if @block_size >= 16 @max_blocks = 1 << (@block_size * 2) else @max_blocks = (1 << 30) / @block_size end # if a limit on the # of bytes has been given, convert that into a # minimum number of blocks processed. if rekey_limit @max_blocks = [@max_blocks, rekey_limit / @block_size].min end end cleanup end
def set(values)
A convenience method for quickly setting multiple values in a single
def set(values) values.each do |key, value| instance_variable_set("@#{key}", value) end reset! end
def update_cipher(data)
def update_cipher(data) result = cipher.update(data) update_next_iv(role == :client ? result : data) return result end
def update_next_iv(data, reset=false)
def update_next_iv(data, reset=false) @next_iv << data @next_iv = @next_iv[-cipher.iv_len..-1] if reset cipher.reset cipher.iv = @next_iv end return data end