/usr/lib/ruby/vendor_ruby/net/ssh/transport/state.rb is in ruby-net-ssh 1:2.5.2-2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 | require 'zlib'
require 'net/ssh/transport/cipher_factory'
require 'net/ssh/transport/hmac'
module Net; module SSH; module Transport
# Encapsulates state information about one end of an SSH connection. Such
# state includes the packet sequence number, the algorithms in use, how
# many packets and blocks have been processed since the last reset, and so
# forth. This class will never be instantiated directly, but is used as
# part of the internal state of the PacketStream module.
class State
# The socket object that owns this state object.
attr_reader :socket
# The next packet sequence number for this socket endpoint.
attr_reader :sequence_number
# The hmac algorithm in use for this endpoint.
attr_reader :hmac
# The compression algorithm in use for this endpoint.
attr_reader :compression
# The compression level to use when compressing data (or nil, for the default).
attr_reader :compression_level
# The number of packets processed since the last call to #reset!
attr_reader :packets
# The number of data blocks processed since the last call to #reset!
attr_reader :blocks
# The cipher algorithm in use for this socket endpoint.
attr_reader :cipher
# The block size for the cipher
attr_reader :block_size
# The role that this state plays (either :client or :server)
attr_reader :role
# The maximum number of packets that this endpoint wants to process before
# needing a rekey.
attr_accessor :max_packets
# The maximum number of blocks that this endpoint wants to process before
# needing a rekey.
attr_accessor :max_blocks
# The user-specified maximum number of bytes that this endpoint ought to
# process before needing a rekey.
attr_accessor :rekey_limit
# Creates a new state object, belonging to the given socket. Initializes
# the algorithms to "none".
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
# A convenience method for quickly setting multiple values in a single
# command.
def set(values)
values.each do |key, value|
instance_variable_set("@#{key}", value)
end
reset!
end
def update_cipher(data)
result = cipher.update(data)
update_next_iv(role == :client ? result : data)
return result
end
def final_cipher
result = cipher.final
update_next_iv(role == :client ? result : "", true)
return result
end
# Increments the counters. The sequence number is incremented (and remapped
# so it always fits in a 32-bit integer). The number of packets and blocks
# are also incremented.
def increment(packet_length)
@sequence_number = (@sequence_number + 1) & 0xFFFFFFFF
@packets += 1
@blocks += (packet_length + 4) / @block_size
end
# The compressor object to use when compressing data. This takes into account
# the desired compression level.
def compressor
@compressor ||= Zlib::Deflate.new(compression_level || Zlib::DEFAULT_COMPRESSION)
end
# The decompressor object to use when decompressing data.
def decompressor
@decompressor ||= Zlib::Inflate.new(nil)
end
# Returns true if data compression/decompression is enabled. This will
# return true if :standard compression is selected, or if :delayed
# compression is selected and the :authenticated hint has been received
# by the socket.
def compression?
compression == :standard || (compression == :delayed && socket.hints[:authenticated])
end
# Compresses the data. If no compression is in effect, this will just return
# the data unmodified, otherwise it uses #compressor to compress the data.
def compress(data)
data = data.to_s
return data unless compression?
compressor.deflate(data, Zlib::SYNC_FLUSH)
end
# Deompresses the data. If no compression is in effect, this will just return
# the data unmodified, otherwise it uses #decompressor to decompress the data.
def decompress(data)
data = data.to_s
return data unless compression?
decompressor.inflate(data)
end
# Resets the counters on the state object, but leaves the sequence_number
# unchanged. It also sets defaults for and recomputes the max_packets and
# max_blocks values.
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
# Closes any the compressor and/or decompressor objects that have been
# instantiated.
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
# Returns true if the number of packets processed exceeds the maximum
# number of packets, or if the number of blocks processed exceeds the
# maximum number of blocks.
def needs_rekey?
max_packets && packets > max_packets ||
max_blocks && blocks > max_blocks
end
private
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
end
end; end; end
|