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

instantiated.
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)

the data unmodified, otherwise it uses #compressor to compress the 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?

by the socket.
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 desired compression level.
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)

the data unmodified, otherwise it uses #decompressor to decompress the 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

The decompressor object to use when decompressing data.
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)

are also incremented.
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)

the algorithms to "none".
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?

maximum number of blocks.
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!

max_blocks values.
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)

command.
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