net-ssh 5.2.0 → 7.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data/.dockerignore +6 -0
  4. data/.github/config/rubocop_linter_action.yml +4 -0
  5. data/.github/workflows/ci-with-docker.yml +44 -0
  6. data/.github/workflows/ci.yml +87 -0
  7. data/.github/workflows/rubocop.yml +13 -0
  8. data/.gitignore +3 -0
  9. data/.rubocop.yml +16 -2
  10. data/.rubocop_todo.yml +623 -511
  11. data/CHANGES.txt +50 -2
  12. data/Dockerfile +27 -0
  13. data/Dockerfile.openssl3 +17 -0
  14. data/Gemfile +2 -0
  15. data/Gemfile.noed25519 +2 -0
  16. data/Manifest +0 -1
  17. data/README.md +293 -0
  18. data/Rakefile +6 -2
  19. data/appveyor.yml +4 -2
  20. data/docker-compose.yml +23 -0
  21. data/lib/net/ssh/authentication/agent.rb +29 -13
  22. data/lib/net/ssh/authentication/certificate.rb +19 -7
  23. data/lib/net/ssh/authentication/constants.rb +0 -1
  24. data/lib/net/ssh/authentication/ed25519.rb +13 -8
  25. data/lib/net/ssh/authentication/ed25519_loader.rb +5 -8
  26. data/lib/net/ssh/authentication/key_manager.rb +73 -32
  27. data/lib/net/ssh/authentication/methods/abstract.rb +12 -3
  28. data/lib/net/ssh/authentication/methods/hostbased.rb +3 -5
  29. data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +5 -3
  30. data/lib/net/ssh/authentication/methods/none.rb +6 -9
  31. data/lib/net/ssh/authentication/methods/password.rb +2 -3
  32. data/lib/net/ssh/authentication/methods/publickey.rb +56 -16
  33. data/lib/net/ssh/authentication/pageant.rb +97 -97
  34. data/lib/net/ssh/authentication/pub_key_fingerprint.rb +2 -3
  35. data/lib/net/ssh/authentication/session.rb +27 -23
  36. data/lib/net/ssh/buffer.rb +51 -40
  37. data/lib/net/ssh/buffered_io.rb +24 -26
  38. data/lib/net/ssh/config.rb +82 -50
  39. data/lib/net/ssh/connection/channel.rb +101 -87
  40. data/lib/net/ssh/connection/constants.rb +0 -4
  41. data/lib/net/ssh/connection/event_loop.rb +30 -25
  42. data/lib/net/ssh/connection/keepalive.rb +12 -12
  43. data/lib/net/ssh/connection/session.rb +115 -111
  44. data/lib/net/ssh/connection/term.rb +56 -58
  45. data/lib/net/ssh/errors.rb +12 -12
  46. data/lib/net/ssh/key_factory.rb +10 -13
  47. data/lib/net/ssh/known_hosts.rb +106 -39
  48. data/lib/net/ssh/loggable.rb +10 -11
  49. data/lib/net/ssh/packet.rb +1 -1
  50. data/lib/net/ssh/prompt.rb +9 -11
  51. data/lib/net/ssh/proxy/command.rb +1 -2
  52. data/lib/net/ssh/proxy/errors.rb +2 -4
  53. data/lib/net/ssh/proxy/http.rb +18 -20
  54. data/lib/net/ssh/proxy/https.rb +8 -10
  55. data/lib/net/ssh/proxy/jump.rb +8 -10
  56. data/lib/net/ssh/proxy/socks4.rb +2 -4
  57. data/lib/net/ssh/proxy/socks5.rb +3 -6
  58. data/lib/net/ssh/service/forward.rb +9 -8
  59. data/lib/net/ssh/test/channel.rb +24 -26
  60. data/lib/net/ssh/test/extensions.rb +35 -35
  61. data/lib/net/ssh/test/kex.rb +6 -8
  62. data/lib/net/ssh/test/local_packet.rb +0 -2
  63. data/lib/net/ssh/test/packet.rb +3 -3
  64. data/lib/net/ssh/test/remote_packet.rb +6 -8
  65. data/lib/net/ssh/test/script.rb +25 -27
  66. data/lib/net/ssh/test/socket.rb +12 -15
  67. data/lib/net/ssh/test.rb +7 -7
  68. data/lib/net/ssh/transport/algorithms.rb +100 -58
  69. data/lib/net/ssh/transport/cipher_factory.rb +34 -50
  70. data/lib/net/ssh/transport/constants.rb +13 -9
  71. data/lib/net/ssh/transport/ctr.rb +8 -14
  72. data/lib/net/ssh/transport/hmac/abstract.rb +20 -5
  73. data/lib/net/ssh/transport/hmac/md5.rb +0 -2
  74. data/lib/net/ssh/transport/hmac/md5_96.rb +0 -2
  75. data/lib/net/ssh/transport/hmac/none.rb +0 -2
  76. data/lib/net/ssh/transport/hmac/ripemd160.rb +0 -2
  77. data/lib/net/ssh/transport/hmac/sha1.rb +0 -2
  78. data/lib/net/ssh/transport/hmac/sha1_96.rb +0 -2
  79. data/lib/net/ssh/transport/hmac/sha2_256.rb +7 -11
  80. data/lib/net/ssh/transport/hmac/sha2_256_96.rb +4 -8
  81. data/lib/net/ssh/transport/hmac/sha2_256_etm.rb +12 -0
  82. data/lib/net/ssh/transport/hmac/sha2_512.rb +6 -9
  83. data/lib/net/ssh/transport/hmac/sha2_512_96.rb +4 -8
  84. data/lib/net/ssh/transport/hmac/sha2_512_etm.rb +12 -0
  85. data/lib/net/ssh/transport/hmac.rb +13 -11
  86. data/lib/net/ssh/transport/identity_cipher.rb +11 -13
  87. data/lib/net/ssh/transport/kex/abstract.rb +130 -0
  88. data/lib/net/ssh/transport/kex/abstract5656.rb +72 -0
  89. data/lib/net/ssh/transport/kex/curve25519_sha256.rb +39 -0
  90. data/lib/net/ssh/transport/kex/curve25519_sha256_loader.rb +30 -0
  91. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +5 -19
  92. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
  93. data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +30 -139
  94. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +1 -8
  95. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +5 -9
  96. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +20 -81
  97. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +5 -4
  98. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +5 -4
  99. data/lib/net/ssh/transport/kex.rb +15 -10
  100. data/lib/net/ssh/transport/key_expander.rb +7 -8
  101. data/lib/net/ssh/transport/openssl.rb +149 -127
  102. data/lib/net/ssh/transport/packet_stream.rb +50 -16
  103. data/lib/net/ssh/transport/server_version.rb +17 -16
  104. data/lib/net/ssh/transport/session.rb +9 -7
  105. data/lib/net/ssh/transport/state.rb +44 -44
  106. data/lib/net/ssh/verifiers/accept_new.rb +0 -2
  107. data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +1 -2
  108. data/lib/net/ssh/verifiers/always.rb +6 -4
  109. data/lib/net/ssh/verifiers/never.rb +0 -2
  110. data/lib/net/ssh/version.rb +3 -3
  111. data/lib/net/ssh.rb +12 -8
  112. data/net-ssh-public_cert.pem +8 -8
  113. data/net-ssh.gemspec +9 -7
  114. data/support/ssh_tunnel_bug.rb +3 -3
  115. data.tar.gz.sig +0 -0
  116. metadata +55 -30
  117. metadata.gz.sig +0 -0
  118. data/.travis.yml +0 -53
  119. data/Gemfile.noed25519.lock +0 -41
  120. data/README.rdoc +0 -194
  121. data/lib/net/ssh/ruby_compat.rb +0 -13
  122. data/support/arcfour_check.rb +0 -20
@@ -5,13 +5,13 @@ require 'net/ssh/transport/cipher_factory'
5
5
  require 'net/ssh/transport/constants'
6
6
  require 'net/ssh/transport/hmac'
7
7
  require 'net/ssh/transport/kex'
8
+ require 'net/ssh/transport/kex/curve25519_sha256_loader'
8
9
  require 'net/ssh/transport/server_version'
9
10
  require 'net/ssh/authentication/ed25519_loader'
10
11
 
11
12
  module Net
12
13
  module SSH
13
14
  module Transport
14
-
15
15
  # Implements the higher-level logic behind an SSH key-exchange. It handles
16
16
  # both the initial exchange, as well as subsequent re-exchanges (as needed).
17
17
  # It also encapsulates the negotiation of the algorithms, and provides a
@@ -23,56 +23,75 @@ module Net
23
23
  include Loggable
24
24
  include Constants
25
25
 
26
- # Define the default algorithms, in order of preference, supported by
27
- # Net::SSH.
28
- ALGORITHMS = {
29
- host_key: %w[ssh-rsa-cert-v01@openssh.com
26
+ # Define the default algorithms, in order of preference, supported by Net::SSH.
27
+ DEFAULT_ALGORITHMS = {
28
+ host_key: %w[ecdsa-sha2-nistp521-cert-v01@openssh.com
29
+ ecdsa-sha2-nistp384-cert-v01@openssh.com
30
+ ecdsa-sha2-nistp256-cert-v01@openssh.com
31
+ ecdsa-sha2-nistp521
32
+ ecdsa-sha2-nistp384
33
+ ecdsa-sha2-nistp256
34
+ ssh-rsa-cert-v01@openssh.com
30
35
  ssh-rsa-cert-v00@openssh.com
31
- ssh-rsa ssh-dss],
32
- kex: %w[diffie-hellman-group-exchange-sha256
33
- diffie-hellman-group-exchange-sha1
34
- diffie-hellman-group14-sha1
36
+ ssh-rsa
37
+ rsa-sha2-256
38
+ rsa-sha2-512],
39
+
40
+ kex: %w[ecdh-sha2-nistp521
41
+ ecdh-sha2-nistp384
42
+ ecdh-sha2-nistp256
43
+ diffie-hellman-group-exchange-sha256
44
+ diffie-hellman-group14-sha256
45
+ diffie-hellman-group14-sha1],
46
+
47
+ encryption: %w[aes256-ctr aes192-ctr aes128-ctr],
48
+
49
+ hmac: %w[hmac-sha2-512-etm@openssh.com hmac-sha2-256-etm@openssh.com
50
+ hmac-sha2-512 hmac-sha2-256
51
+ hmac-sha1]
52
+ }.freeze
53
+
54
+ if Net::SSH::Authentication::ED25519Loader::LOADED
55
+ DEFAULT_ALGORITHMS[:host_key].unshift(
56
+ 'ssh-ed25519-cert-v01@openssh.com',
57
+ 'ssh-ed25519'
58
+ )
59
+ end
60
+
61
+ if Net::SSH::Transport::Kex::Curve25519Sha256Loader::LOADED
62
+ DEFAULT_ALGORITHMS[:kex].unshift(
63
+ 'curve25519-sha256',
64
+ 'curve25519-sha256@libssh.org'
65
+ )
66
+ end
67
+
68
+ # Define all algorithms, with the deprecated, supported by Net::SSH.
69
+ ALGORITHMS = {
70
+ host_key: DEFAULT_ALGORITHMS[:host_key] + %w[ssh-dss],
71
+
72
+ kex: DEFAULT_ALGORITHMS[:kex] +
73
+ %w[diffie-hellman-group-exchange-sha1
35
74
  diffie-hellman-group1-sha1],
36
- encryption: %w[aes256-ctr aes192-ctr aes128-ctr
37
- aes256-cbc aes192-cbc aes128-cbc
75
+
76
+ encryption: DEFAULT_ALGORITHMS[:encryption] +
77
+ %w[aes256-cbc aes192-cbc aes128-cbc
38
78
  rijndael-cbc@lysator.liu.se
39
79
  blowfish-ctr blowfish-cbc
40
80
  cast128-ctr cast128-cbc
41
81
  3des-ctr 3des-cbc
42
- idea-cbc arcfour256 arcfour128 arcfour
82
+ idea-cbc
43
83
  none],
44
84
 
45
- hmac: %w[hmac-sha2-512 hmac-sha2-256
46
- hmac-sha2-512-96 hmac-sha2-256-96
47
- hmac-sha1 hmac-sha1-96
85
+ hmac: DEFAULT_ALGORITHMS[:hmac] +
86
+ %w[hmac-sha2-512-96 hmac-sha2-256-96
87
+ hmac-sha1-96
48
88
  hmac-ripemd160 hmac-ripemd160@openssh.com
49
89
  hmac-md5 hmac-md5-96
50
90
  none],
51
91
 
52
92
  compression: %w[none zlib@openssh.com zlib],
53
93
  language: %w[]
54
- }
55
- if defined?(OpenSSL::PKey::EC)
56
- ALGORITHMS[:host_key].unshift(
57
- "ecdsa-sha2-nistp521-cert-v01@openssh.com",
58
- "ecdsa-sha2-nistp384-cert-v01@openssh.com",
59
- "ecdsa-sha2-nistp256-cert-v01@openssh.com",
60
- "ecdsa-sha2-nistp521",
61
- "ecdsa-sha2-nistp384",
62
- "ecdsa-sha2-nistp256"
63
- )
64
- if Net::SSH::Authentication::ED25519Loader::LOADED
65
- ALGORITHMS[:host_key].unshift(
66
- "ssh-ed25519-cert-v01@openssh.com",
67
- "ssh-ed25519"
68
- )
69
- end
70
- ALGORITHMS[:kex].unshift(
71
- "ecdh-sha2-nistp521",
72
- "ecdh-sha2-nistp384",
73
- "ecdh-sha2-nistp256"
74
- )
75
- end
94
+ }.freeze
76
95
 
77
96
  # The underlying transport layer session that supports this object
78
97
  attr_reader :session
@@ -127,7 +146,7 @@ module Net
127
146
 
128
147
  # Instantiates a new Algorithms object, and prepares the hash of preferred
129
148
  # algorithms based on the options parameter and the ALGORITHMS constant.
130
- def initialize(session, options={})
149
+ def initialize(session, options = {})
131
150
  @session = session
132
151
  @logger = session.logger
133
152
  @options = options
@@ -140,6 +159,7 @@ module Net
140
159
  # Start the algorithm negotation
141
160
  def start
142
161
  raise ArgumentError, "Cannot call start if it's negotiation started or done" if @pending || @initialized
162
+
143
163
  send_kexinit
144
164
  end
145
165
 
@@ -197,8 +217,8 @@ module Net
197
217
 
198
218
  def host_key_format
199
219
  case host_key
200
- when "ssh-rsa-cert-v01@openssh.com", "ssh-rsa-cert-v00@openssh.com"
201
- "ssh-rsa"
220
+ when /^([a-z0-9-]+)-cert-v\d{2}@openssh.com$/
221
+ Regexp.last_match[1]
202
222
  else
203
223
  host_key
204
224
  end
@@ -239,7 +259,10 @@ module Net
239
259
  options[:compression] = %w[zlib@openssh.com zlib] if options[:compression] == true
240
260
 
241
261
  ALGORITHMS.each do |algorithm, supported|
242
- algorithms[algorithm] = compose_algorithm_list(supported, options[algorithm], options[:append_all_supported_algorithms])
262
+ algorithms[algorithm] = compose_algorithm_list(
263
+ supported, options[algorithm] || DEFAULT_ALGORITHMS[algorithm],
264
+ options[:append_all_supported_algorithms]
265
+ )
243
266
  end
244
267
 
245
268
  # for convention, make sure our list has the same keys as the server
@@ -255,7 +278,7 @@ module Net
255
278
  # existing known key for the host has preference.
256
279
 
257
280
  existing_keys = session.host_keys
258
- host_keys = existing_keys.map { |key| key.ssh_type }.uniq
281
+ host_keys = existing_keys.flat_map { |key| key.respond_to?(:ssh_types) ? key.ssh_types : [key.ssh_type] }.uniq
259
282
  algorithms[:host_key].each do |name|
260
283
  host_keys << name unless host_keys.include?(name)
261
284
  end
@@ -270,10 +293,24 @@ module Net
270
293
  list = []
271
294
  option = Array(option).compact.uniq
272
295
 
273
- if option.first && option.first.start_with?('+')
296
+ if option.first && option.first.start_with?('+', '-')
274
297
  list = supported.dup
275
- list << option.first[1..-1]
276
- list.concat(option[1..-1])
298
+
299
+ appends = option.select { |opt| opt.start_with?('+') }.map { |opt| opt[1..-1] }
300
+ deletions = option.select { |opt| opt.start_with?('-') }.map { |opt| opt[1..-1] }
301
+
302
+ list.concat(appends)
303
+
304
+ deletions.each do |opt|
305
+ if opt.include?('*')
306
+ opt_escaped = Regexp.escape(opt)
307
+ algo_re = /\A#{opt_escaped.gsub('\*', '[A-Za-z\d\-@\.]*')}\z/
308
+ list.delete_if { |existing_opt| algo_re.match(existing_opt) }
309
+ else
310
+ list.delete(opt)
311
+ end
312
+ end
313
+
277
314
  list.uniq!
278
315
  else
279
316
  list = option
@@ -332,10 +369,10 @@ module Net
332
369
  language = algorithms[:language].join(",")
333
370
 
334
371
  Net::SSH::Buffer.from(:byte, KEXINIT,
335
- :long, [rand(0xFFFFFFFF), rand(0xFFFFFFFF), rand(0xFFFFFFFF), rand(0xFFFFFFFF)],
336
- :mstring, [kex, host_key, encryption, encryption, hmac, hmac],
337
- :mstring, [compression, compression, language, language],
338
- :bool, false, :long, 0)
372
+ :long, [rand(0xFFFFFFFF), rand(0xFFFFFFFF), rand(0xFFFFFFFF), rand(0xFFFFFFFF)],
373
+ :mstring, [kex, host_key, encryption, encryption, hmac, hmac],
374
+ :mstring, [compression, compression, language, language],
375
+ :bool, false, :long, 0)
339
376
  end
340
377
 
341
378
  # Given the parsed server KEX packet, and the client's preferred algorithm
@@ -356,7 +393,8 @@ module Net
356
393
 
357
394
  debug do
358
395
  "negotiated:\n" +
359
- %i[kex host_key encryption_server encryption_client hmac_client hmac_server compression_client compression_server language_client language_server].map do |key|
396
+ %i[kex host_key encryption_server encryption_client hmac_client hmac_server
397
+ compression_client compression_server language_client language_server].map do |key|
360
398
  "* #{key}: #{instance_variable_get("@#{key}")}"
361
399
  end.join("\n")
362
400
  end
@@ -368,7 +406,11 @@ module Net
368
406
  def negotiate(algorithm)
369
407
  match = self[algorithm].find { |item| @server_data[algorithm].include?(item) }
370
408
 
371
- raise Net::SSH::Exception, "could not settle on #{algorithm} algorithm" if match.nil?
409
+ if match.nil?
410
+ raise Net::SSH::Exception, "could not settle on #{algorithm} algorithm\n"\
411
+ "Server #{algorithm} preferences: #{@server_data[algorithm].join(',')}\n"\
412
+ "Client #{algorithm} preferences: #{self[algorithm].join(',')}"
413
+ end
372
414
 
373
415
  return match
374
416
  end
@@ -396,13 +438,13 @@ module Net
396
438
  debug { "exchanging keys" }
397
439
 
398
440
  algorithm = Kex::MAP[kex].new(self, session,
399
- client_version_string: Net::SSH::Transport::ServerVersion::PROTO_VERSION,
400
- server_version_string: session.server_version.version,
401
- server_algorithm_packet: @server_packet,
402
- client_algorithm_packet: @client_packet,
403
- need_bytes: kex_byte_requirement,
404
- minimum_dh_bits: options[:minimum_dh_bits],
405
- logger: logger)
441
+ client_version_string: Net::SSH::Transport::ServerVersion::PROTO_VERSION,
442
+ server_version_string: session.server_version.version,
443
+ server_algorithm_packet: @server_packet,
444
+ client_algorithm_packet: @client_packet,
445
+ need_bytes: kex_byte_requirement,
446
+ minimum_dh_bits: options[:minimum_dh_bits],
447
+ logger: logger)
406
448
  result = algorithm.exchange_keys
407
449
 
408
450
  secret = result[:shared_secret].to_ssh
@@ -3,68 +3,56 @@ require 'net/ssh/transport/ctr.rb'
3
3
  require 'net/ssh/transport/key_expander'
4
4
  require 'net/ssh/transport/identity_cipher'
5
5
 
6
- module Net
7
- module SSH
6
+ module Net
7
+ module SSH
8
8
  module Transport
9
-
10
9
  # Implements a factory of OpenSSL cipher algorithms.
11
10
  class CipherFactory
12
11
  # Maps the SSH name of a cipher to it's corresponding OpenSSL name
13
12
  SSH_TO_OSSL = {
14
- "3des-cbc" => "des-ede3-cbc",
15
- "blowfish-cbc" => "bf-cbc",
16
- "aes256-cbc" => "aes-256-cbc",
17
- "aes192-cbc" => "aes-192-cbc",
18
- "aes128-cbc" => "aes-128-cbc",
19
- "idea-cbc" => "idea-cbc",
20
- "cast128-cbc" => "cast-cbc",
13
+ "3des-cbc" => "des-ede3-cbc",
14
+ "blowfish-cbc" => "bf-cbc",
15
+ "aes256-cbc" => "aes-256-cbc",
16
+ "aes192-cbc" => "aes-192-cbc",
17
+ "aes128-cbc" => "aes-128-cbc",
18
+ "idea-cbc" => "idea-cbc",
19
+ "cast128-cbc" => "cast-cbc",
21
20
  "rijndael-cbc@lysator.liu.se" => "aes-256-cbc",
22
- "arcfour128" => "rc4",
23
- "arcfour256" => "rc4",
24
- "arcfour512" => "rc4",
25
- "arcfour" => "rc4",
26
-
27
- "3des-ctr" => "des-ede3",
28
- "blowfish-ctr" => "bf-ecb",
29
-
30
- "aes256-ctr" => ::OpenSSL::Cipher.ciphers.include?("aes-256-ctr") ? "aes-256-ctr" : "aes-256-ecb",
31
- "aes192-ctr" => ::OpenSSL::Cipher.ciphers.include?("aes-192-ctr") ? "aes-192-ctr" : "aes-192-ecb",
32
- "aes128-ctr" => ::OpenSSL::Cipher.ciphers.include?("aes-128-ctr") ? "aes-128-ctr" : "aes-128-ecb",
33
- "cast128-ctr" => "cast5-ecb",
34
-
35
- "none" => "none"
36
- }
37
-
38
- # Ruby's OpenSSL bindings always return a key length of 16 for RC4 ciphers
39
- # resulting in the error: OpenSSL::CipherError: key length too short.
40
- # The following ciphers will override this key length.
41
- KEY_LEN_OVERRIDE = {
42
- "arcfour256" => 32,
43
- "arcfour512" => 64
21
+ "3des-ctr" => "des-ede3",
22
+ "blowfish-ctr" => "bf-ecb",
23
+
24
+ "aes256-ctr" => ::OpenSSL::Cipher.ciphers.include?("aes-256-ctr") ? "aes-256-ctr" : "aes-256-ecb",
25
+ "aes192-ctr" => ::OpenSSL::Cipher.ciphers.include?("aes-192-ctr") ? "aes-192-ctr" : "aes-192-ecb",
26
+ "aes128-ctr" => ::OpenSSL::Cipher.ciphers.include?("aes-128-ctr") ? "aes-128-ctr" : "aes-128-ecb",
27
+ 'cast128-ctr' => 'cast5-ecb',
28
+
29
+ 'none' => 'none'
44
30
  }
45
-
31
+
46
32
  # Returns true if the underlying OpenSSL library supports the given cipher,
47
33
  # and false otherwise.
48
34
  def self.supported?(name)
49
35
  ossl_name = SSH_TO_OSSL[name] or raise NotImplementedError, "unimplemented cipher `#{name}'"
50
36
  return true if ossl_name == "none"
37
+
51
38
  return OpenSSL::Cipher.ciphers.include?(ossl_name)
52
39
  end
53
-
40
+
54
41
  # Retrieves a new instance of the named algorithm. The new instance
55
42
  # will be initialized using an iv and key generated from the given
56
43
  # iv, key, shared, hash and digester values. Additionally, the
57
44
  # cipher will be put into encryption or decryption mode, based on the
58
45
  # value of the +encrypt+ parameter.
59
- def self.get(name, options={})
46
+ def self.get(name, options = {})
60
47
  ossl_name = SSH_TO_OSSL[name] or raise NotImplementedError, "unimplemented cipher `#{name}'"
61
48
  return IdentityCipher if ossl_name == "none"
49
+
62
50
  cipher = OpenSSL::Cipher.new(ossl_name)
63
-
51
+
64
52
  cipher.send(options[:encrypt] ? :encrypt : :decrypt)
65
-
53
+
66
54
  cipher.padding = 0
67
-
55
+
68
56
  if name =~ /-ctr(@openssh.org)?$/
69
57
  if ossl_name !~ /-ctr/
70
58
  cipher.extend(Net::SSH::Transport::CTR)
@@ -72,16 +60,15 @@ module Net
72
60
  cipher = Net::SSH::Transport::OpenSSLAESCTR.new(cipher)
73
61
  end
74
62
  end
75
- cipher.iv = Net::SSH::Transport::KeyExpander.expand_key(cipher.iv_len, options[:iv], options) if ossl_name != "rc4"
76
-
77
- key_len = KEY_LEN_OVERRIDE[name] || cipher.key_len
63
+ cipher.iv = Net::SSH::Transport::KeyExpander.expand_key(cipher.iv_len, options[:iv], options)
64
+
65
+ key_len = cipher.key_len
78
66
  cipher.key_len = key_len
79
67
  cipher.key = Net::SSH::Transport::KeyExpander.expand_key(key_len, options[:key], options)
80
- cipher.update(" " * 1536) if (ossl_name == "rc4" && name != "arcfour")
81
-
68
+
82
69
  return cipher
83
70
  end
84
-
71
+
85
72
  # Returns a two-element array containing the [ key-length,
86
73
  # block-size ] for the named cipher algorithm. If the cipher
87
74
  # algorithm is unknown, or is "none", 0 is returned for both elements
@@ -94,26 +81,23 @@ module Net
94
81
  result << 0 if options[:iv_len]
95
82
  else
96
83
  cipher = OpenSSL::Cipher.new(ossl_name)
97
- key_len = KEY_LEN_OVERRIDE[name] || cipher.key_len
84
+ key_len = cipher.key_len
98
85
  cipher.key_len = key_len
99
-
86
+
100
87
  block_size =
101
88
  case ossl_name
102
- when "rc4"
103
- 8
104
89
  when /\-ctr/
105
90
  Net::SSH::Transport::OpenSSLAESCTR.block_size
106
91
  else
107
92
  cipher.block_size
108
93
  end
109
-
94
+
110
95
  result = [key_len, block_size]
111
96
  result << cipher.iv_len if options[:iv_len]
112
97
  end
113
98
  result
114
99
  end
115
100
  end
116
-
117
101
  end
118
102
  end
119
103
  end
@@ -1,35 +1,39 @@
1
- module Net
2
- module SSH
1
+ module Net
2
+ module SSH
3
3
  module Transport
4
4
  module Constants
5
-
6
5
  #--
7
6
  # Transport layer generic messages
8
7
  #++
9
-
8
+
10
9
  DISCONNECT = 1
11
10
  IGNORE = 2
12
11
  UNIMPLEMENTED = 3
13
12
  DEBUG = 4
14
13
  SERVICE_REQUEST = 5
15
14
  SERVICE_ACCEPT = 6
16
-
15
+
17
16
  #--
18
17
  # Algorithm negotiation messages
19
18
  #++
20
-
19
+
21
20
  KEXINIT = 20
22
21
  NEWKEYS = 21
23
-
22
+
24
23
  #--
25
24
  # Key exchange method specific messages
26
25
  #++
27
-
26
+
28
27
  KEXDH_INIT = 30
29
28
  KEXDH_REPLY = 31
30
-
29
+
31
30
  KEXECDH_INIT = 30
32
31
  KEXECDH_REPLY = 31
32
+
33
+ KEXDH_GEX_GROUP = 31
34
+ KEXDH_GEX_INIT = 32
35
+ KEXDH_GEX_REPLY = 33
36
+ KEXDH_GEX_REQUEST = 34
33
37
  end
34
38
  end
35
39
  end
@@ -2,7 +2,7 @@ require 'openssl'
2
2
  require 'delegate'
3
3
 
4
4
  module Net::SSH::Transport
5
- #:nodoc:
5
+ # :nodoc:
6
6
  class OpenSSLAESCTR < SimpleDelegator
7
7
  def initialize(original)
8
8
  super
@@ -26,13 +26,13 @@ module Net::SSH::Transport
26
26
  end
27
27
  end
28
28
 
29
- #:nodoc:
29
+ # :nodoc:
30
30
  # Pure-Ruby implementation of Stateful Decryption Counter(SDCTR) Mode
31
31
  # for Block Ciphers. See RFC4344 for detail.
32
32
  module CTR
33
33
  def self.extended(orig)
34
34
  orig.instance_eval {
35
- @remaining = ""
35
+ @remaining = String.new
36
36
  @counter = nil
37
37
  @counter_len = orig.block_size
38
38
  orig.encrypt
@@ -67,13 +67,13 @@ module Net::SSH::Transport
67
67
  end
68
68
 
69
69
  def reset
70
- @remaining = ""
70
+ @remaining = String.new
71
71
  end
72
72
 
73
73
  def update(data)
74
74
  @remaining += data
75
75
 
76
- encrypted = ""
76
+ encrypted = String.new
77
77
 
78
78
  offset = 0
79
79
  while (@remaining.bytesize - offset) >= block_size
@@ -88,20 +88,14 @@ module Net::SSH::Transport
88
88
  end
89
89
 
90
90
  def final
91
- unless @remaining.empty?
92
- s = xor!(@remaining, _update(@counter))
93
- else
94
- s = ""
95
- end
96
-
97
- @remaining = ""
98
-
91
+ s = @remaining.empty? ? '' : xor!(@remaining, _update(@counter))
92
+ @remaining = String.new
99
93
  s
100
94
  end
101
95
 
102
96
  def xor!(s1, s2)
103
97
  s = []
104
- s1.unpack('Q*').zip(s2.unpack('Q*')) {|a,b| s.push(a ^ b) }
98
+ s1.unpack('Q*').zip(s2.unpack('Q*')) {|a, b| s.push(a ^ b) }
105
99
  s.pack('Q*')
106
100
  end
107
101
  singleton_class.send(:private, :xor!)
@@ -5,10 +5,21 @@ module Net
5
5
  module SSH
6
6
  module Transport
7
7
  module HMAC
8
-
9
8
  # The base class of all OpenSSL-based HMAC algorithm wrappers.
10
9
  class Abstract
11
- class <<self
10
+ class << self
11
+ def etm(*v)
12
+ @etm = false if !defined?(@etm)
13
+ if v.empty?
14
+ @etm = superclass.etm if @etm.nil? && superclass.respond_to?(:etm)
15
+ return @etm
16
+ elsif v.length == 1
17
+ @etm = v.first
18
+ else
19
+ raise ArgumentError, "wrong number of arguments (#{v.length} for 1)"
20
+ end
21
+ end
22
+
12
23
  def key_length(*v)
13
24
  @key_length = nil if !defined?(@key_length)
14
25
  if v.empty?
@@ -46,6 +57,10 @@ module Net
46
57
  end
47
58
  end
48
59
 
60
+ def etm
61
+ self.class.etm
62
+ end
63
+
49
64
  def key_length
50
65
  self.class.key_length
51
66
  end
@@ -61,19 +76,19 @@ module Net
61
76
  # The key in use for this instance.
62
77
  attr_reader :key
63
78
 
64
- def initialize(key=nil)
79
+ def initialize(key = nil)
65
80
  self.key = key
66
81
  end
67
82
 
68
83
  # Sets the key to the given value, truncating it so that it is the correct
69
84
  # length.
70
85
  def key=(value)
71
- @key = value ? value.to_s[0,key_length] : nil
86
+ @key = value ? value.to_s[0, key_length] : nil
72
87
  end
73
88
 
74
89
  # Compute the HMAC digest for the given data string.
75
90
  def digest(data)
76
- OpenSSL::HMAC.digest(digest_class.new, key, data)[0,mac_length]
91
+ OpenSSL::HMAC.digest(digest_class.new, key, data)[0, mac_length]
77
92
  end
78
93
  end
79
94
  end
@@ -1,12 +1,10 @@
1
1
  require 'net/ssh/transport/hmac/abstract'
2
2
 
3
3
  module Net::SSH::Transport::HMAC
4
-
5
4
  # The MD5 HMAC algorithm.
6
5
  class MD5 < Abstract
7
6
  mac_length 16
8
7
  key_length 16
9
8
  digest_class OpenSSL::Digest::MD5
10
9
  end
11
-
12
10
  end
@@ -1,11 +1,9 @@
1
1
  require 'net/ssh/transport/hmac/md5'
2
2
 
3
3
  module Net::SSH::Transport::HMAC
4
-
5
4
  # The MD5-96 HMAC algorithm. This returns only the first 12 bytes of
6
5
  # the digest.
7
6
  class MD5_96 < MD5
8
7
  mac_length 12
9
8
  end
10
-
11
9
  end
@@ -1,7 +1,6 @@
1
1
  require 'net/ssh/transport/hmac/abstract'
2
2
 
3
3
  module Net::SSH::Transport::HMAC
4
-
5
4
  # The "none" algorithm. This has a key and mac length of 0.
6
5
  class None < Abstract
7
6
  key_length 0
@@ -11,5 +10,4 @@ module Net::SSH::Transport::HMAC
11
10
  ""
12
11
  end
13
12
  end
14
-
15
13
  end
@@ -1,7 +1,6 @@
1
1
  require 'net/ssh/transport/hmac/abstract'
2
2
 
3
3
  module Net::SSH::Transport::HMAC
4
-
5
4
  # The RIPEMD-160 HMAC algorithm. This has a mac and key length of 20, and
6
5
  # uses the RIPEMD-160 digest algorithm.
7
6
  class RIPEMD160 < Abstract
@@ -9,5 +8,4 @@ module Net::SSH::Transport::HMAC
9
8
  key_length 20
10
9
  digest_class OpenSSL::Digest::RIPEMD160
11
10
  end
12
-
13
11
  end
@@ -1,7 +1,6 @@
1
1
  require 'net/ssh/transport/hmac/abstract'
2
2
 
3
3
  module Net::SSH::Transport::HMAC
4
-
5
4
  # The SHA1 HMAC algorithm. This has a mac and key length of 20, and
6
5
  # uses the SHA1 digest algorithm.
7
6
  class SHA1 < Abstract
@@ -9,5 +8,4 @@ module Net::SSH::Transport::HMAC
9
8
  key_length 20
10
9
  digest_class OpenSSL::Digest::SHA1
11
10
  end
12
-
13
11
  end
@@ -1,11 +1,9 @@
1
1
  require 'net/ssh/transport/hmac/sha1'
2
2
 
3
3
  module Net::SSH::Transport::HMAC
4
-
5
4
  # The SHA1-96 HMAC algorithm. This returns only the first 12 bytes of
6
5
  # the digest.
7
6
  class SHA1_96 < SHA1
8
7
  mac_length 12
9
8
  end
10
-
11
9
  end