net-ssh 6.1.0 → 7.3.0

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 (116) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.dockerignore +6 -0
  4. data/.github/FUNDING.yml +1 -0
  5. data/.github/config/rubocop_linter_action.yml +4 -0
  6. data/.github/workflows/ci-with-docker.yml +44 -0
  7. data/.github/workflows/ci.yml +94 -0
  8. data/.github/workflows/rubocop.yml +16 -0
  9. data/.gitignore +4 -0
  10. data/.rubocop.yml +12 -1
  11. data/.rubocop_todo.yml +475 -376
  12. data/CHANGES.txt +64 -3
  13. data/DEVELOPMENT.md +23 -0
  14. data/Dockerfile +29 -0
  15. data/Dockerfile.openssl3 +17 -0
  16. data/Gemfile +2 -0
  17. data/Gemfile.noed25519 +2 -0
  18. data/Gemfile.norbnacl +12 -0
  19. data/README.md +38 -22
  20. data/Rakefile +92 -0
  21. data/SECURITY.md +4 -0
  22. data/docker-compose.yml +25 -0
  23. data/lib/net/ssh/authentication/agent.rb +29 -13
  24. data/lib/net/ssh/authentication/certificate.rb +14 -11
  25. data/lib/net/ssh/authentication/constants.rb +0 -1
  26. data/lib/net/ssh/authentication/ed25519.rb +14 -11
  27. data/lib/net/ssh/authentication/ed25519_loader.rb +4 -7
  28. data/lib/net/ssh/authentication/key_manager.rb +65 -36
  29. data/lib/net/ssh/authentication/methods/abstract.rb +12 -3
  30. data/lib/net/ssh/authentication/methods/hostbased.rb +3 -5
  31. data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +2 -2
  32. data/lib/net/ssh/authentication/methods/none.rb +6 -9
  33. data/lib/net/ssh/authentication/methods/password.rb +2 -3
  34. data/lib/net/ssh/authentication/methods/publickey.rb +57 -17
  35. data/lib/net/ssh/authentication/pageant.rb +97 -97
  36. data/lib/net/ssh/authentication/pub_key_fingerprint.rb +3 -3
  37. data/lib/net/ssh/authentication/session.rb +25 -17
  38. data/lib/net/ssh/buffer.rb +71 -51
  39. data/lib/net/ssh/buffered_io.rb +25 -26
  40. data/lib/net/ssh/config.rb +33 -20
  41. data/lib/net/ssh/connection/channel.rb +84 -82
  42. data/lib/net/ssh/connection/constants.rb +0 -4
  43. data/lib/net/ssh/connection/event_loop.rb +30 -24
  44. data/lib/net/ssh/connection/keepalive.rb +12 -12
  45. data/lib/net/ssh/connection/session.rb +109 -108
  46. data/lib/net/ssh/connection/term.rb +56 -58
  47. data/lib/net/ssh/errors.rb +12 -12
  48. data/lib/net/ssh/key_factory.rb +7 -8
  49. data/lib/net/ssh/known_hosts.rb +86 -18
  50. data/lib/net/ssh/loggable.rb +8 -9
  51. data/lib/net/ssh/packet.rb +1 -1
  52. data/lib/net/ssh/prompt.rb +9 -11
  53. data/lib/net/ssh/proxy/command.rb +1 -1
  54. data/lib/net/ssh/proxy/errors.rb +2 -4
  55. data/lib/net/ssh/proxy/http.rb +18 -20
  56. data/lib/net/ssh/proxy/https.rb +8 -10
  57. data/lib/net/ssh/proxy/jump.rb +8 -10
  58. data/lib/net/ssh/proxy/socks4.rb +2 -4
  59. data/lib/net/ssh/proxy/socks5.rb +3 -5
  60. data/lib/net/ssh/service/forward.rb +7 -7
  61. data/lib/net/ssh/test/channel.rb +24 -26
  62. data/lib/net/ssh/test/extensions.rb +35 -35
  63. data/lib/net/ssh/test/kex.rb +6 -8
  64. data/lib/net/ssh/test/local_packet.rb +0 -2
  65. data/lib/net/ssh/test/packet.rb +3 -3
  66. data/lib/net/ssh/test/remote_packet.rb +6 -8
  67. data/lib/net/ssh/test/script.rb +25 -27
  68. data/lib/net/ssh/test/socket.rb +12 -15
  69. data/lib/net/ssh/test.rb +4 -5
  70. data/lib/net/ssh/transport/aes128_gcm.rb +40 -0
  71. data/lib/net/ssh/transport/aes256_gcm.rb +40 -0
  72. data/lib/net/ssh/transport/algorithms.rb +51 -19
  73. data/lib/net/ssh/transport/chacha20_poly1305_cipher.rb +117 -0
  74. data/lib/net/ssh/transport/chacha20_poly1305_cipher_loader.rb +17 -0
  75. data/lib/net/ssh/transport/cipher_factory.rb +56 -29
  76. data/lib/net/ssh/transport/constants.rb +3 -3
  77. data/lib/net/ssh/transport/ctr.rb +7 -7
  78. data/lib/net/ssh/transport/gcm_cipher.rb +207 -0
  79. data/lib/net/ssh/transport/hmac/abstract.rb +20 -5
  80. data/lib/net/ssh/transport/hmac/md5.rb +0 -2
  81. data/lib/net/ssh/transport/hmac/md5_96.rb +0 -2
  82. data/lib/net/ssh/transport/hmac/none.rb +0 -2
  83. data/lib/net/ssh/transport/hmac/ripemd160.rb +0 -2
  84. data/lib/net/ssh/transport/hmac/sha1.rb +0 -2
  85. data/lib/net/ssh/transport/hmac/sha1_96.rb +0 -2
  86. data/lib/net/ssh/transport/hmac.rb +12 -12
  87. data/lib/net/ssh/transport/identity_cipher.rb +19 -13
  88. data/lib/net/ssh/transport/kex/abstract.rb +12 -5
  89. data/lib/net/ssh/transport/kex/abstract5656.rb +1 -1
  90. data/lib/net/ssh/transport/kex/curve25519_sha256.rb +2 -1
  91. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +4 -4
  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 +21 -21
  94. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +1 -2
  95. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +2 -2
  96. data/lib/net/ssh/transport/kex.rb +8 -6
  97. data/lib/net/ssh/transport/key_expander.rb +7 -8
  98. data/lib/net/ssh/transport/openssl.rb +51 -26
  99. data/lib/net/ssh/transport/openssl_cipher_extensions.rb +8 -0
  100. data/lib/net/ssh/transport/packet_stream.rb +46 -26
  101. data/lib/net/ssh/transport/server_version.rb +17 -16
  102. data/lib/net/ssh/transport/session.rb +9 -7
  103. data/lib/net/ssh/transport/state.rb +44 -44
  104. data/lib/net/ssh/verifiers/accept_new.rb +0 -2
  105. data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +1 -2
  106. data/lib/net/ssh/verifiers/always.rb +6 -4
  107. data/lib/net/ssh/verifiers/never.rb +0 -2
  108. data/lib/net/ssh/version.rb +2 -2
  109. data/lib/net/ssh.rb +15 -8
  110. data/net-ssh-public_cert.pem +19 -18
  111. data/net-ssh.gemspec +7 -4
  112. data/support/ssh_tunnel_bug.rb +3 -3
  113. data.tar.gz.sig +0 -0
  114. metadata +76 -29
  115. metadata.gz.sig +0 -0
  116. data/.travis.yml +0 -52
@@ -0,0 +1,40 @@
1
+ require 'net/ssh/transport/hmac/abstract'
2
+ require 'net/ssh/transport/gcm_cipher'
3
+
4
+ module Net::SSH::Transport
5
+ ## Implements the aes256-gcm@openssh cipher
6
+ class AES256_GCM
7
+ extend ::Net::SSH::Transport::GCMCipher
8
+
9
+ ## Implicit HMAC, do need to do anything
10
+ class ImplicitHMac < ::Net::SSH::Transport::HMAC::Abstract
11
+ def aead
12
+ true
13
+ end
14
+
15
+ def key_length
16
+ 32
17
+ end
18
+ end
19
+
20
+ def implicit_mac
21
+ ImplicitHMac.new
22
+ end
23
+
24
+ def algo_name
25
+ 'aes-256-gcm'
26
+ end
27
+
28
+ def name
29
+ 'aes256-gcm@openssh.com'
30
+ end
31
+
32
+ #
33
+ # --- RFC 5647 ---
34
+ # K_LEN AES key length 32 octets
35
+ #
36
+ def self.key_length
37
+ 32
38
+ end
39
+ end
40
+ end
@@ -33,21 +33,33 @@ module Net
33
33
  ecdsa-sha2-nistp256
34
34
  ssh-rsa-cert-v01@openssh.com
35
35
  ssh-rsa-cert-v00@openssh.com
36
- ssh-rsa],
36
+ ssh-rsa
37
+ rsa-sha2-256
38
+ rsa-sha2-512],
37
39
 
38
40
  kex: %w[ecdh-sha2-nistp521
39
41
  ecdh-sha2-nistp384
40
42
  ecdh-sha2-nistp256
41
43
  diffie-hellman-group-exchange-sha256
44
+ diffie-hellman-group14-sha256
42
45
  diffie-hellman-group14-sha1],
43
46
 
44
- encryption: %w[aes256-ctr aes192-ctr aes128-ctr],
47
+ encryption: %w[aes256-ctr
48
+ aes192-ctr
49
+ aes128-ctr
50
+ aes256-gcm@openssh.com
51
+ aes128-gcm@openssh.com],
45
52
 
46
53
  hmac: %w[hmac-sha2-512-etm@openssh.com hmac-sha2-256-etm@openssh.com
47
54
  hmac-sha2-512 hmac-sha2-256
48
55
  hmac-sha1]
49
56
  }.freeze
50
57
 
58
+ if Net::SSH::Transport::ChaCha20Poly1305CipherLoader::LOADED
59
+ DEFAULT_ALGORITHMS[:encryption].unshift(
60
+ 'chacha20-poly1305@openssh.com'
61
+ )
62
+ end
51
63
  if Net::SSH::Authentication::ED25519Loader::LOADED
52
64
  DEFAULT_ALGORITHMS[:host_key].unshift(
53
65
  'ssh-ed25519-cert-v01@openssh.com',
@@ -143,7 +155,7 @@ module Net
143
155
 
144
156
  # Instantiates a new Algorithms object, and prepares the hash of preferred
145
157
  # algorithms based on the options parameter and the ALGORITHMS constant.
146
- def initialize(session, options={})
158
+ def initialize(session, options = {})
147
159
  @session = session
148
160
  @logger = session.logger
149
161
  @options = options
@@ -275,7 +287,7 @@ module Net
275
287
  # existing known key for the host has preference.
276
288
 
277
289
  existing_keys = session.host_keys
278
- host_keys = existing_keys.map { |key| key.ssh_type }.uniq
290
+ host_keys = existing_keys.flat_map { |key| key.respond_to?(:ssh_types) ? key.ssh_types : [key.ssh_type] }.uniq
279
291
  algorithms[:host_key].each do |name|
280
292
  host_keys << name unless host_keys.include?(name)
281
293
  end
@@ -366,10 +378,10 @@ module Net
366
378
  language = algorithms[:language].join(",")
367
379
 
368
380
  Net::SSH::Buffer.from(:byte, KEXINIT,
369
- :long, [rand(0xFFFFFFFF), rand(0xFFFFFFFF), rand(0xFFFFFFFF), rand(0xFFFFFFFF)],
370
- :mstring, [kex, host_key, encryption, encryption, hmac, hmac],
371
- :mstring, [compression, compression, language, language],
372
- :bool, false, :long, 0)
381
+ :long, [rand(0xFFFFFFFF), rand(0xFFFFFFFF), rand(0xFFFFFFFF), rand(0xFFFFFFFF)],
382
+ :mstring, [kex, host_key, encryption, encryption, hmac, hmac],
383
+ :mstring, [compression, compression, language, language],
384
+ :bool, false, :long, 0)
373
385
  end
374
386
 
375
387
  # Given the parsed server KEX packet, and the client's preferred algorithm
@@ -434,14 +446,15 @@ module Net
434
446
  def exchange_keys
435
447
  debug { "exchanging keys" }
436
448
 
449
+ need_bytes = kex_byte_requirement
437
450
  algorithm = Kex::MAP[kex].new(self, session,
438
- client_version_string: Net::SSH::Transport::ServerVersion::PROTO_VERSION,
439
- server_version_string: session.server_version.version,
440
- server_algorithm_packet: @server_packet,
441
- client_algorithm_packet: @client_packet,
442
- need_bytes: kex_byte_requirement,
443
- minimum_dh_bits: options[:minimum_dh_bits],
444
- logger: logger)
451
+ client_version_string: Net::SSH::Transport::ServerVersion::PROTO_VERSION,
452
+ server_version_string: session.server_version.version,
453
+ server_algorithm_packet: @server_packet,
454
+ client_algorithm_packet: @client_packet,
455
+ need_bytes: need_bytes,
456
+ minimum_dh_bits: options[:minimum_dh_bits],
457
+ logger: logger)
445
458
  result = algorithm.exchange_keys
446
459
 
447
460
  secret = result[:shared_secret].to_ssh
@@ -461,11 +474,30 @@ module Net
461
474
 
462
475
  parameters = { shared: secret, hash: hash, digester: digester }
463
476
 
464
- cipher_client = CipherFactory.get(encryption_client, parameters.merge(iv: iv_client, key: key_client, encrypt: true))
465
- cipher_server = CipherFactory.get(encryption_server, parameters.merge(iv: iv_server, key: key_server, decrypt: true))
477
+ cipher_client = CipherFactory.get(
478
+ encryption_client,
479
+ parameters.merge(iv: iv_client, key: key_client, encrypt: true)
480
+ )
481
+ cipher_server = CipherFactory.get(
482
+ encryption_server,
483
+ parameters.merge(iv: iv_server, key: key_server, decrypt: true)
484
+ )
485
+
486
+ mac_client =
487
+ if cipher_client.implicit_mac?
488
+ cipher_client.implicit_mac
489
+ else
490
+ HMAC.get(hmac_client, mac_key_client, parameters)
491
+ end
492
+ mac_server =
493
+ if cipher_server.implicit_mac?
494
+ cipher_server.implicit_mac
495
+ else
496
+ HMAC.get(hmac_server, mac_key_server, parameters)
497
+ end
466
498
 
467
- mac_client = HMAC.get(hmac_client, mac_key_client, parameters)
468
- mac_server = HMAC.get(hmac_server, mac_key_server, parameters)
499
+ cipher_client.nonce = iv_client if mac_client.respond_to?(:aead) && mac_client.aead
500
+ cipher_server.nonce = iv_server if mac_server.respond_to?(:aead) && mac_client.aead
469
501
 
470
502
  session.configure_client cipher: cipher_client, hmac: mac_client,
471
503
  compression: normalize_compression_name(compression_client),
@@ -0,0 +1,117 @@
1
+ require 'rbnacl'
2
+ require 'net/ssh/loggable'
3
+
4
+ module Net
5
+ module SSH
6
+ module Transport
7
+ ## Implements the chacha20-poly1305@openssh cipher
8
+ class ChaCha20Poly1305Cipher
9
+ include Net::SSH::Loggable
10
+
11
+ # Implicit HMAC, no need to do anything
12
+ class ImplicitHMac
13
+ def etm
14
+ # TODO: ideally this shouln't be called
15
+ true
16
+ end
17
+
18
+ def key_length
19
+ 64
20
+ end
21
+ end
22
+
23
+ def initialize(encrypt:, key:)
24
+ @chacha_hdr = OpenSSL::Cipher.new("chacha20")
25
+ key_len = @chacha_hdr.key_len
26
+ @chacha_main = OpenSSL::Cipher.new("chacha20")
27
+ @poly = RbNaCl::OneTimeAuths::Poly1305
28
+ if key.size < key_len * 2
29
+ error { "chacha20_poly1305: keylength doesn't match" }
30
+ raise "chacha20_poly1305: keylength doesn't match"
31
+ end
32
+ if encrypt
33
+ @chacha_hdr.encrypt
34
+ @chacha_main.encrypt
35
+ else
36
+ @chacha_hdr.decrypt
37
+ @chacha_main.decrypt
38
+ end
39
+ main_key = key[0...key_len]
40
+ @chacha_main.key = main_key
41
+ hdr_key = key[key_len...(2 * key_len)]
42
+ @chacha_hdr.key = hdr_key
43
+ end
44
+
45
+ def update_cipher_mac(payload, sequence_number)
46
+ iv_data = [0, 0, 0, sequence_number].pack("NNNN")
47
+ @chacha_main.iv = iv_data
48
+ poly_key = @chacha_main.update(([0] * 32).pack('C32'))
49
+
50
+ packet_length = payload.size
51
+ length_data = [packet_length].pack("N")
52
+ @chacha_hdr.iv = iv_data
53
+ packet = @chacha_hdr.update(length_data)
54
+
55
+ iv_data[0] = 1.chr
56
+ @chacha_main.iv = iv_data
57
+ unencrypted_data = payload
58
+ packet += @chacha_main.update(unencrypted_data)
59
+
60
+ packet += @poly.auth(poly_key, packet)
61
+ return packet
62
+ end
63
+
64
+ def read_length(data, sequence_number)
65
+ iv_data = [0, 0, 0, sequence_number].pack("NNNN")
66
+ @chacha_hdr.iv = iv_data
67
+ @chacha_hdr.update(data).unpack1("N")
68
+ end
69
+
70
+ def read_and_mac(data, mac, sequence_number)
71
+ iv_data = [0, 0, 0, sequence_number].pack("NNNN")
72
+ @chacha_main.iv = iv_data
73
+ poly_key = @chacha_main.update(([0] * 32).pack('C32'))
74
+
75
+ iv_data[0] = 1.chr
76
+ @chacha_main.iv = iv_data
77
+ unencrypted_data = @chacha_main.update(data[4..])
78
+ begin
79
+ ok = @poly.verify(poly_key, mac, data[0..])
80
+ raise Net::SSH::Exception, "corrupted hmac detected #{name}" unless ok
81
+ rescue RbNaCl::BadAuthenticatorError
82
+ raise Net::SSH::Exception, "corrupted hmac detected #{name}"
83
+ end
84
+ return unencrypted_data
85
+ end
86
+
87
+ def mac_length
88
+ 16
89
+ end
90
+
91
+ def block_size
92
+ 8
93
+ end
94
+
95
+ def name
96
+ "chacha20-poly1305@openssh.com"
97
+ end
98
+
99
+ def implicit_mac?
100
+ true
101
+ end
102
+
103
+ def implicit_mac
104
+ return ImplicitHMac.new
105
+ end
106
+
107
+ def self.block_size
108
+ 8
109
+ end
110
+
111
+ def self.key_length
112
+ 64
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,17 @@
1
+ module Net
2
+ module SSH
3
+ module Transport
4
+ # Loads chacha20 poly1305 support which requires optinal dependency rbnacl
5
+ module ChaCha20Poly1305CipherLoader
6
+ begin
7
+ require 'net/ssh/transport/chacha20_poly1305_cipher'
8
+ LOADED = true
9
+ ERROR = nil
10
+ rescue LoadError => e
11
+ ERROR = e
12
+ LOADED = false
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,57 +1,82 @@
1
1
  require 'openssl'
2
2
  require 'net/ssh/transport/ctr.rb'
3
+ require 'net/ssh/transport/aes128_gcm'
4
+ require 'net/ssh/transport/aes256_gcm'
3
5
  require 'net/ssh/transport/key_expander'
4
6
  require 'net/ssh/transport/identity_cipher'
7
+ require 'net/ssh/transport/chacha20_poly1305_cipher_loader'
8
+ require 'net/ssh/transport/openssl_cipher_extensions'
5
9
 
6
- module Net
7
- module SSH
10
+ module Net
11
+ module SSH
8
12
  module Transport
9
-
10
13
  # Implements a factory of OpenSSL cipher algorithms.
11
14
  class CipherFactory
12
15
  # Maps the SSH name of a cipher to it's corresponding OpenSSL name
13
16
  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",
17
+ "3des-cbc" => "des-ede3-cbc",
18
+ "blowfish-cbc" => "bf-cbc",
19
+ "aes256-cbc" => "aes-256-cbc",
20
+ "aes192-cbc" => "aes-192-cbc",
21
+ "aes128-cbc" => "aes-128-cbc",
22
+ "idea-cbc" => "idea-cbc",
23
+ "cast128-cbc" => "cast-cbc",
21
24
  "rijndael-cbc@lysator.liu.se" => "aes-256-cbc",
22
- "3des-ctr" => "des-ede3",
23
- "blowfish-ctr" => "bf-ecb",
25
+ "3des-ctr" => "des-ede3",
26
+ "blowfish-ctr" => "bf-ecb",
24
27
 
25
- 'aes256-ctr' => 'aes-256-ctr',
26
- 'aes192-ctr' => 'aes-192-ctr',
27
- 'aes128-ctr' => 'aes-128-ctr',
28
- 'cast128-ctr' => 'cast5-ecb',
28
+ "aes256-ctr" => ::OpenSSL::Cipher.ciphers.include?("aes-256-ctr") ? "aes-256-ctr" : "aes-256-ecb",
29
+ "aes192-ctr" => ::OpenSSL::Cipher.ciphers.include?("aes-192-ctr") ? "aes-192-ctr" : "aes-192-ecb",
30
+ "aes128-ctr" => ::OpenSSL::Cipher.ciphers.include?("aes-128-ctr") ? "aes-128-ctr" : "aes-128-ecb",
31
+ 'cast128-ctr' => 'cast5-ecb',
29
32
 
30
- 'none' => 'none'
33
+ 'none' => 'none'
31
34
  }
32
35
 
36
+ SSH_TO_CLASS = {
37
+ 'aes256-gcm@openssh.com' => Net::SSH::Transport::AES256_GCM,
38
+ 'aes128-gcm@openssh.com' => Net::SSH::Transport::AES128_GCM
39
+ }.tap do |hash|
40
+ if Net::SSH::Transport::ChaCha20Poly1305CipherLoader::LOADED
41
+ hash['chacha20-poly1305@openssh.com'] =
42
+ Net::SSH::Transport::ChaCha20Poly1305Cipher
43
+ end
44
+ end
45
+
33
46
  # Returns true if the underlying OpenSSL library supports the given cipher,
34
47
  # and false otherwise.
35
48
  def self.supported?(name)
49
+ return true if SSH_TO_CLASS.key?(name)
50
+
36
51
  ossl_name = SSH_TO_OSSL[name] or raise NotImplementedError, "unimplemented cipher `#{name}'"
37
52
  return true if ossl_name == "none"
38
- return OpenSSL::Cipher.ciphers.include?(ossl_name)
53
+
54
+ return SSH_TO_CLASS.key?(name) || OpenSSL::Cipher.ciphers.include?(ossl_name)
39
55
  end
40
-
56
+
41
57
  # Retrieves a new instance of the named algorithm. The new instance
42
58
  # will be initialized using an iv and key generated from the given
43
59
  # iv, key, shared, hash and digester values. Additionally, the
44
60
  # cipher will be put into encryption or decryption mode, based on the
45
61
  # value of the +encrypt+ parameter.
46
- def self.get(name, options={})
62
+ def self.get(name, options = {})
63
+ klass = SSH_TO_CLASS[name]
64
+ unless klass.nil?
65
+ key_len = klass.key_length
66
+ key = Net::SSH::Transport::KeyExpander.expand_key(key_len, options[:key], options)
67
+ return klass.new(encrypt: options[:encrypt], key: key)
68
+ end
69
+
47
70
  ossl_name = SSH_TO_OSSL[name] or raise NotImplementedError, "unimplemented cipher `#{name}'"
48
71
  return IdentityCipher if ossl_name == "none"
72
+
49
73
  cipher = OpenSSL::Cipher.new(ossl_name)
50
-
74
+
51
75
  cipher.send(options[:encrypt] ? :encrypt : :decrypt)
52
-
76
+
53
77
  cipher.padding = 0
54
-
78
+
79
+ cipher.extend(Net::SSH::Transport::OpenSSLCipherExtensions)
55
80
  if name =~ /-ctr(@openssh.org)?$/
56
81
  if ossl_name !~ /-ctr/
57
82
  cipher.extend(Net::SSH::Transport::CTR)
@@ -60,20 +85,23 @@ module Net
60
85
  end
61
86
  end
62
87
  cipher.iv = Net::SSH::Transport::KeyExpander.expand_key(cipher.iv_len, options[:iv], options)
63
-
88
+
64
89
  key_len = cipher.key_len
65
90
  cipher.key_len = key_len
66
91
  cipher.key = Net::SSH::Transport::KeyExpander.expand_key(key_len, options[:key], options)
67
-
92
+
68
93
  return cipher
69
94
  end
70
-
95
+
71
96
  # Returns a two-element array containing the [ key-length,
72
97
  # block-size ] for the named cipher algorithm. If the cipher
73
98
  # algorithm is unknown, or is "none", 0 is returned for both elements
74
99
  # of the tuple.
75
100
  # if :iv_len option is supplied the third return value will be ivlen
76
101
  def self.get_lengths(name, options = {})
102
+ klass = SSH_TO_CLASS[name]
103
+ return [klass.key_length, klass.block_size] unless klass.nil?
104
+
77
105
  ossl_name = SSH_TO_OSSL[name]
78
106
  if ossl_name.nil? || ossl_name == "none"
79
107
  result = [0, 0]
@@ -82,7 +110,7 @@ module Net
82
110
  cipher = OpenSSL::Cipher.new(ossl_name)
83
111
  key_len = cipher.key_len
84
112
  cipher.key_len = key_len
85
-
113
+
86
114
  block_size =
87
115
  case ossl_name
88
116
  when /\-ctr/
@@ -90,14 +118,13 @@ module Net
90
118
  else
91
119
  cipher.block_size
92
120
  end
93
-
121
+
94
122
  result = [key_len, block_size]
95
123
  result << cipher.iv_len if options[:iv_len]
96
124
  end
97
125
  result
98
126
  end
99
127
  end
100
-
101
128
  end
102
129
  end
103
130
  end
@@ -1,5 +1,5 @@
1
- module Net
2
- module SSH
1
+ module Net
2
+ module SSH
3
3
  module Transport
4
4
  module Constants
5
5
  #--
@@ -12,7 +12,7 @@ module Net
12
12
  DEBUG = 4
13
13
  SERVICE_REQUEST = 5
14
14
  SERVICE_ACCEPT = 6
15
-
15
+
16
16
  #--
17
17
  # Algorithm negotiation messages
18
18
  #++
@@ -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
@@ -89,13 +89,13 @@ module Net::SSH::Transport
89
89
 
90
90
  def final
91
91
  s = @remaining.empty? ? '' : xor!(@remaining, _update(@counter))
92
- @remaining = ""
92
+ @remaining = String.new
93
93
  s
94
94
  end
95
95
 
96
96
  def xor!(s1, s2)
97
97
  s = []
98
- 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) }
99
99
  s.pack('Q*')
100
100
  end
101
101
  singleton_class.send(:private, :xor!)