net-ssh 2.7.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 (199) hide show
  1. checksums.yaml +7 -0
  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 +15 -0
  10. data/.rubocop.yml +22 -0
  11. data/.rubocop_todo.yml +1081 -0
  12. data/CHANGES.txt +387 -0
  13. data/DEVELOPMENT.md +23 -0
  14. data/Dockerfile +29 -0
  15. data/Dockerfile.openssl3 +17 -0
  16. data/Gemfile +13 -0
  17. data/Gemfile.noed25519 +12 -0
  18. data/Gemfile.norbnacl +12 -0
  19. data/ISSUE_TEMPLATE.md +30 -0
  20. data/Manifest +4 -5
  21. data/README.md +303 -0
  22. data/Rakefile +174 -40
  23. data/SECURITY.md +4 -0
  24. data/THANKS.txt +25 -0
  25. data/appveyor.yml +58 -0
  26. data/docker-compose.yml +25 -0
  27. data/lib/net/ssh/authentication/agent.rb +279 -18
  28. data/lib/net/ssh/authentication/certificate.rb +183 -0
  29. data/lib/net/ssh/authentication/constants.rb +17 -15
  30. data/lib/net/ssh/authentication/ed25519.rb +184 -0
  31. data/lib/net/ssh/authentication/ed25519_loader.rb +31 -0
  32. data/lib/net/ssh/authentication/key_manager.rb +125 -54
  33. data/lib/net/ssh/authentication/methods/abstract.rb +67 -48
  34. data/lib/net/ssh/authentication/methods/hostbased.rb +34 -37
  35. data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +19 -12
  36. data/lib/net/ssh/authentication/methods/none.rb +16 -19
  37. data/lib/net/ssh/authentication/methods/password.rb +56 -19
  38. data/lib/net/ssh/authentication/methods/publickey.rb +96 -55
  39. data/lib/net/ssh/authentication/pageant.rb +483 -246
  40. data/lib/net/ssh/authentication/pub_key_fingerprint.rb +43 -0
  41. data/lib/net/ssh/authentication/session.rb +138 -120
  42. data/lib/net/ssh/buffer.rb +399 -300
  43. data/lib/net/ssh/buffered_io.rb +154 -150
  44. data/lib/net/ssh/config.rb +361 -166
  45. data/lib/net/ssh/connection/channel.rb +640 -596
  46. data/lib/net/ssh/connection/constants.rb +29 -29
  47. data/lib/net/ssh/connection/event_loop.rb +123 -0
  48. data/lib/net/ssh/connection/keepalive.rb +59 -0
  49. data/lib/net/ssh/connection/session.rb +628 -548
  50. data/lib/net/ssh/connection/term.rb +125 -123
  51. data/lib/net/ssh/errors.rb +101 -95
  52. data/lib/net/ssh/key_factory.rb +198 -100
  53. data/lib/net/ssh/known_hosts.rb +221 -98
  54. data/lib/net/ssh/loggable.rb +50 -49
  55. data/lib/net/ssh/packet.rb +83 -79
  56. data/lib/net/ssh/prompt.rb +50 -81
  57. data/lib/net/ssh/proxy/command.rb +108 -60
  58. data/lib/net/ssh/proxy/errors.rb +12 -10
  59. data/lib/net/ssh/proxy/http.rb +82 -78
  60. data/lib/net/ssh/proxy/https.rb +50 -0
  61. data/lib/net/ssh/proxy/jump.rb +54 -0
  62. data/lib/net/ssh/proxy/socks4.rb +5 -8
  63. data/lib/net/ssh/proxy/socks5.rb +18 -20
  64. data/lib/net/ssh/service/forward.rb +383 -255
  65. data/lib/net/ssh/test/channel.rb +145 -136
  66. data/lib/net/ssh/test/extensions.rb +131 -110
  67. data/lib/net/ssh/test/kex.rb +34 -32
  68. data/lib/net/ssh/test/local_packet.rb +46 -44
  69. data/lib/net/ssh/test/packet.rb +89 -70
  70. data/lib/net/ssh/test/remote_packet.rb +32 -30
  71. data/lib/net/ssh/test/script.rb +156 -142
  72. data/lib/net/ssh/test/socket.rb +49 -48
  73. data/lib/net/ssh/test.rb +82 -77
  74. data/lib/net/ssh/transport/aes128_gcm.rb +40 -0
  75. data/lib/net/ssh/transport/aes256_gcm.rb +40 -0
  76. data/lib/net/ssh/transport/algorithms.rb +472 -348
  77. data/lib/net/ssh/transport/chacha20_poly1305_cipher.rb +117 -0
  78. data/lib/net/ssh/transport/chacha20_poly1305_cipher_loader.rb +17 -0
  79. data/lib/net/ssh/transport/cipher_factory.rb +124 -100
  80. data/lib/net/ssh/transport/constants.rb +32 -24
  81. data/lib/net/ssh/transport/ctr.rb +42 -22
  82. data/lib/net/ssh/transport/gcm_cipher.rb +207 -0
  83. data/lib/net/ssh/transport/hmac/abstract.rb +97 -63
  84. data/lib/net/ssh/transport/hmac/md5.rb +0 -2
  85. data/lib/net/ssh/transport/hmac/md5_96.rb +0 -2
  86. data/lib/net/ssh/transport/hmac/none.rb +0 -2
  87. data/lib/net/ssh/transport/hmac/ripemd160.rb +0 -2
  88. data/lib/net/ssh/transport/hmac/sha1.rb +0 -2
  89. data/lib/net/ssh/transport/hmac/sha1_96.rb +0 -2
  90. data/lib/net/ssh/transport/hmac/sha2_256.rb +7 -11
  91. data/lib/net/ssh/transport/hmac/sha2_256_96.rb +4 -8
  92. data/lib/net/ssh/transport/hmac/sha2_256_etm.rb +12 -0
  93. data/lib/net/ssh/transport/hmac/sha2_512.rb +6 -9
  94. data/lib/net/ssh/transport/hmac/sha2_512_96.rb +4 -8
  95. data/lib/net/ssh/transport/hmac/sha2_512_etm.rb +12 -0
  96. data/lib/net/ssh/transport/hmac.rb +14 -12
  97. data/lib/net/ssh/transport/identity_cipher.rb +54 -44
  98. data/lib/net/ssh/transport/kex/abstract.rb +130 -0
  99. data/lib/net/ssh/transport/kex/abstract5656.rb +72 -0
  100. data/lib/net/ssh/transport/kex/curve25519_sha256.rb +39 -0
  101. data/lib/net/ssh/transport/kex/curve25519_sha256_loader.rb +30 -0
  102. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +33 -40
  103. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
  104. data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +119 -213
  105. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +53 -61
  106. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +5 -9
  107. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +36 -90
  108. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +18 -10
  109. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +18 -10
  110. data/lib/net/ssh/transport/kex.rb +15 -12
  111. data/lib/net/ssh/transport/key_expander.rb +24 -20
  112. data/lib/net/ssh/transport/openssl.rb +161 -124
  113. data/lib/net/ssh/transport/openssl_cipher_extensions.rb +8 -0
  114. data/lib/net/ssh/transport/packet_stream.rb +246 -183
  115. data/lib/net/ssh/transport/server_version.rb +57 -51
  116. data/lib/net/ssh/transport/session.rb +307 -235
  117. data/lib/net/ssh/transport/state.rb +178 -176
  118. data/lib/net/ssh/verifiers/accept_new.rb +33 -0
  119. data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +33 -0
  120. data/lib/net/ssh/verifiers/always.rb +58 -0
  121. data/lib/net/ssh/verifiers/never.rb +19 -0
  122. data/lib/net/ssh/version.rb +57 -51
  123. data/lib/net/ssh.rb +140 -40
  124. data/net-ssh-public_cert.pem +21 -0
  125. data/net-ssh.gemspec +39 -184
  126. data/support/ssh_tunnel_bug.rb +5 -5
  127. data.tar.gz.sig +0 -0
  128. metadata +205 -99
  129. metadata.gz.sig +0 -0
  130. data/README.rdoc +0 -219
  131. data/Rudyfile +0 -96
  132. data/gem-public_cert.pem +0 -20
  133. data/lib/net/ssh/authentication/agent/java_pageant.rb +0 -85
  134. data/lib/net/ssh/authentication/agent/socket.rb +0 -170
  135. data/lib/net/ssh/ruby_compat.rb +0 -51
  136. data/lib/net/ssh/verifiers/lenient.rb +0 -30
  137. data/lib/net/ssh/verifiers/null.rb +0 -12
  138. data/lib/net/ssh/verifiers/secure.rb +0 -54
  139. data/lib/net/ssh/verifiers/strict.rb +0 -24
  140. data/setup.rb +0 -1585
  141. data/support/arcfour_check.rb +0 -20
  142. data/test/README.txt +0 -47
  143. data/test/authentication/methods/common.rb +0 -28
  144. data/test/authentication/methods/test_abstract.rb +0 -51
  145. data/test/authentication/methods/test_hostbased.rb +0 -114
  146. data/test/authentication/methods/test_keyboard_interactive.rb +0 -100
  147. data/test/authentication/methods/test_none.rb +0 -41
  148. data/test/authentication/methods/test_password.rb +0 -52
  149. data/test/authentication/methods/test_publickey.rb +0 -148
  150. data/test/authentication/test_agent.rb +0 -205
  151. data/test/authentication/test_key_manager.rb +0 -218
  152. data/test/authentication/test_session.rb +0 -108
  153. data/test/common.rb +0 -108
  154. data/test/configs/eqsign +0 -3
  155. data/test/configs/exact_match +0 -8
  156. data/test/configs/host_plus +0 -10
  157. data/test/configs/multihost +0 -4
  158. data/test/configs/nohost +0 -19
  159. data/test/configs/numeric_host +0 -4
  160. data/test/configs/send_env +0 -2
  161. data/test/configs/substitutes +0 -8
  162. data/test/configs/wild_cards +0 -14
  163. data/test/connection/test_channel.rb +0 -467
  164. data/test/connection/test_session.rb +0 -526
  165. data/test/known_hosts/github +0 -1
  166. data/test/manual/test_forward.rb +0 -223
  167. data/test/start/test_options.rb +0 -36
  168. data/test/start/test_transport.rb +0 -28
  169. data/test/test_all.rb +0 -11
  170. data/test/test_buffer.rb +0 -433
  171. data/test/test_buffered_io.rb +0 -63
  172. data/test/test_config.rb +0 -151
  173. data/test/test_key_factory.rb +0 -173
  174. data/test/test_known_hosts.rb +0 -13
  175. data/test/transport/hmac/test_md5.rb +0 -41
  176. data/test/transport/hmac/test_md5_96.rb +0 -27
  177. data/test/transport/hmac/test_none.rb +0 -34
  178. data/test/transport/hmac/test_ripemd160.rb +0 -36
  179. data/test/transport/hmac/test_sha1.rb +0 -36
  180. data/test/transport/hmac/test_sha1_96.rb +0 -27
  181. data/test/transport/hmac/test_sha2_256.rb +0 -37
  182. data/test/transport/hmac/test_sha2_256_96.rb +0 -27
  183. data/test/transport/hmac/test_sha2_512.rb +0 -37
  184. data/test/transport/hmac/test_sha2_512_96.rb +0 -27
  185. data/test/transport/kex/test_diffie_hellman_group14_sha1.rb +0 -13
  186. data/test/transport/kex/test_diffie_hellman_group1_sha1.rb +0 -146
  187. data/test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb +0 -92
  188. data/test/transport/kex/test_diffie_hellman_group_exchange_sha256.rb +0 -34
  189. data/test/transport/kex/test_ecdh_sha2_nistp256.rb +0 -161
  190. data/test/transport/kex/test_ecdh_sha2_nistp384.rb +0 -38
  191. data/test/transport/kex/test_ecdh_sha2_nistp521.rb +0 -38
  192. data/test/transport/test_algorithms.rb +0 -330
  193. data/test/transport/test_cipher_factory.rb +0 -443
  194. data/test/transport/test_hmac.rb +0 -34
  195. data/test/transport/test_identity_cipher.rb +0 -40
  196. data/test/transport/test_packet_stream.rb +0 -1755
  197. data/test/transport/test_server_version.rb +0 -78
  198. data/test/transport/test_session.rb +0 -319
  199. data/test/transport/test_state.rb +0 -181
@@ -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,106 +1,130 @@
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'
5
-
6
- module Net; module SSH; module Transport
7
-
8
- # Implements a factory of OpenSSL cipher algorithms.
9
- class CipherFactory
10
- # Maps the SSH name of a cipher to it's corresponding OpenSSL name
11
- SSH_TO_OSSL = {
12
- "3des-cbc" => "des-ede3-cbc",
13
- "blowfish-cbc" => "bf-cbc",
14
- "aes256-cbc" => "aes-256-cbc",
15
- "aes192-cbc" => "aes-192-cbc",
16
- "aes128-cbc" => "aes-128-cbc",
17
- "idea-cbc" => "idea-cbc",
18
- "cast128-cbc" => "cast-cbc",
19
- "rijndael-cbc@lysator.liu.se" => "aes-256-cbc",
20
- "arcfour128" => "rc4",
21
- "arcfour256" => "rc4",
22
- "arcfour512" => "rc4",
23
- "arcfour" => "rc4",
24
- "camellia128-cbc" => "camellia-128-cbc",
25
- "camellia192-cbc" => "camellia-192-cbc",
26
- "camellia256-cbc" => "camellia-256-cbc",
27
- "camellia128-cbc@openssh.org" => "camellia-128-cbc",
28
- "camellia192-cbc@openssh.org" => "camellia-192-cbc",
29
- "camellia256-cbc@openssh.org" => "camellia-256-cbc",
30
-
31
- "3des-ctr" => "des-ede3",
32
- "blowfish-ctr" => "bf-ecb",
33
- "aes256-ctr" => "aes-256-ecb",
34
- "aes192-ctr" => "aes-192-ecb",
35
- "aes128-ctr" => "aes-128-ecb",
36
- "cast128-ctr" => "cast5-ecb",
37
- "camellia128-ctr" => "camellia-128-ecb",
38
- "camellia192-ctr" => "camellia-192-ecb",
39
- "camellia256-ctr" => "camellia-256-ecb",
40
- "camellia128-ctr@openssh.org" => "camellia-128-ecb",
41
- "camellia192-ctr@openssh.org" => "camellia-192-ecb",
42
- "camellia256-ctr@openssh.org" => "camellia-256-ecb",
43
-
44
- "none" => "none",
45
- }
46
-
47
- # Ruby's OpenSSL bindings always return a key length of 16 for RC4 ciphers
48
- # resulting in the error: OpenSSL::CipherError: key length too short.
49
- # The following ciphers will override this key length.
50
- KEY_LEN_OVERRIDE = {
51
- "arcfour256" => 32,
52
- "arcfour512" => 64
53
- }
54
-
55
-
56
- # Returns true if the underlying OpenSSL library supports the given cipher,
57
- # and false otherwise.
58
- def self.supported?(name)
59
- ossl_name = SSH_TO_OSSL[name] or raise NotImplementedError, "unimplemented cipher `#{name}'"
60
- return true if ossl_name == "none"
61
- return OpenSSL::Cipher.ciphers.include?(ossl_name)
62
- end
63
-
64
- # Retrieves a new instance of the named algorithm. The new instance
65
- # will be initialized using an iv and key generated from the given
66
- # iv, key, shared, hash and digester values. Additionally, the
67
- # cipher will be put into encryption or decryption mode, based on the
68
- # value of the +encrypt+ parameter.
69
- def self.get(name, options={})
70
- ossl_name = SSH_TO_OSSL[name] or raise NotImplementedError, "unimplemented cipher `#{name}'"
71
- return IdentityCipher if ossl_name == "none"
72
- cipher = OpenSSL::Cipher::Cipher.new(ossl_name)
73
-
74
- cipher.send(options[:encrypt] ? :encrypt : :decrypt)
75
-
76
- cipher.padding = 0
77
-
78
- cipher.extend(Net::SSH::Transport::CTR) if (name =~ /-ctr(@openssh.org)?$/)
79
-
80
- cipher.iv = Net::SSH::Transport::KeyExpander.expand_key(cipher.iv_len, options[:iv], options) if ossl_name != "rc4"
81
-
82
- key_len = KEY_LEN_OVERRIDE[name] || cipher.key_len
83
- cipher.key_len = key_len
84
- cipher.key = Net::SSH::Transport::KeyExpander.expand_key(key_len, options[:key], options)
85
- cipher.update(" " * 1536) if (ossl_name == "rc4" && name != "arcfour")
86
-
87
- return cipher
88
- end
89
-
90
- # Returns a two-element array containing the [ key-length,
91
- # block-size ] for the named cipher algorithm. If the cipher
92
- # algorithm is unknown, or is "none", 0 is returned for both elements
93
- # of the tuple.
94
- def self.get_lengths(name)
95
- ossl_name = SSH_TO_OSSL[name]
96
- return [0, 0] if ossl_name.nil? || ossl_name == "none"
97
-
98
- cipher = OpenSSL::Cipher::Cipher.new(ossl_name)
99
- key_len = KEY_LEN_OVERRIDE[name] || cipher.key_len
100
- cipher.key_len = key_len
101
-
102
- return [key_len, ossl_name=="rc4" ? 8 : cipher.block_size]
7
+ require 'net/ssh/transport/chacha20_poly1305_cipher_loader'
8
+ require 'net/ssh/transport/openssl_cipher_extensions'
9
+
10
+ module Net
11
+ module SSH
12
+ module Transport
13
+ # Implements a factory of OpenSSL cipher algorithms.
14
+ class CipherFactory
15
+ # Maps the SSH name of a cipher to it's corresponding OpenSSL name
16
+ SSH_TO_OSSL = {
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",
24
+ "rijndael-cbc@lysator.liu.se" => "aes-256-cbc",
25
+ "3des-ctr" => "des-ede3",
26
+ "blowfish-ctr" => "bf-ecb",
27
+
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',
32
+
33
+ 'none' => 'none'
34
+ }
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
+
46
+ # Returns true if the underlying OpenSSL library supports the given cipher,
47
+ # and false otherwise.
48
+ def self.supported?(name)
49
+ return true if SSH_TO_CLASS.key?(name)
50
+
51
+ ossl_name = SSH_TO_OSSL[name] or raise NotImplementedError, "unimplemented cipher `#{name}'"
52
+ return true if ossl_name == "none"
53
+
54
+ return SSH_TO_CLASS.key?(name) || OpenSSL::Cipher.ciphers.include?(ossl_name)
55
+ end
56
+
57
+ # Retrieves a new instance of the named algorithm. The new instance
58
+ # will be initialized using an iv and key generated from the given
59
+ # iv, key, shared, hash and digester values. Additionally, the
60
+ # cipher will be put into encryption or decryption mode, based on the
61
+ # value of the +encrypt+ parameter.
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
+
70
+ ossl_name = SSH_TO_OSSL[name] or raise NotImplementedError, "unimplemented cipher `#{name}'"
71
+ return IdentityCipher if ossl_name == "none"
72
+
73
+ cipher = OpenSSL::Cipher.new(ossl_name)
74
+
75
+ cipher.send(options[:encrypt] ? :encrypt : :decrypt)
76
+
77
+ cipher.padding = 0
78
+
79
+ cipher.extend(Net::SSH::Transport::OpenSSLCipherExtensions)
80
+ if name =~ /-ctr(@openssh.org)?$/
81
+ if ossl_name !~ /-ctr/
82
+ cipher.extend(Net::SSH::Transport::CTR)
83
+ else
84
+ cipher = Net::SSH::Transport::OpenSSLAESCTR.new(cipher)
85
+ end
86
+ end
87
+ cipher.iv = Net::SSH::Transport::KeyExpander.expand_key(cipher.iv_len, options[:iv], options)
88
+
89
+ key_len = cipher.key_len
90
+ cipher.key_len = key_len
91
+ cipher.key = Net::SSH::Transport::KeyExpander.expand_key(key_len, options[:key], options)
92
+
93
+ return cipher
94
+ end
95
+
96
+ # Returns a two-element array containing the [ key-length,
97
+ # block-size ] for the named cipher algorithm. If the cipher
98
+ # algorithm is unknown, or is "none", 0 is returned for both elements
99
+ # of the tuple.
100
+ # if :iv_len option is supplied the third return value will be ivlen
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
+
105
+ ossl_name = SSH_TO_OSSL[name]
106
+ if ossl_name.nil? || ossl_name == "none"
107
+ result = [0, 0]
108
+ result << 0 if options[:iv_len]
109
+ else
110
+ cipher = OpenSSL::Cipher.new(ossl_name)
111
+ key_len = cipher.key_len
112
+ cipher.key_len = key_len
113
+
114
+ block_size =
115
+ case ossl_name
116
+ when /\-ctr/
117
+ Net::SSH::Transport::OpenSSLAESCTR.block_size
118
+ else
119
+ cipher.block_size
120
+ end
121
+
122
+ result = [key_len, block_size]
123
+ result << cipher.iv_len if options[:iv_len]
124
+ end
125
+ result
126
+ end
127
+ end
103
128
  end
104
129
  end
105
-
106
- end; end; end
130
+ end
@@ -1,32 +1,40 @@
1
- module Net; module SSH; module Transport
2
- module Constants
1
+ module Net
2
+ module SSH
3
+ module Transport
4
+ module Constants
5
+ #--
6
+ # Transport layer generic messages
7
+ #++
3
8
 
4
- #--
5
- # Transport layer generic messages
6
- #++
9
+ DISCONNECT = 1
10
+ IGNORE = 2
11
+ UNIMPLEMENTED = 3
12
+ DEBUG = 4
13
+ SERVICE_REQUEST = 5
14
+ SERVICE_ACCEPT = 6
7
15
 
8
- DISCONNECT = 1
9
- IGNORE = 2
10
- UNIMPLEMENTED = 3
11
- DEBUG = 4
12
- SERVICE_REQUEST = 5
13
- SERVICE_ACCEPT = 6
16
+ #--
17
+ # Algorithm negotiation messages
18
+ #++
14
19
 
15
- #--
16
- # Algorithm negotiation messages
17
- #++
20
+ KEXINIT = 20
21
+ NEWKEYS = 21
18
22
 
19
- KEXINIT = 20
20
- NEWKEYS = 21
23
+ #--
24
+ # Key exchange method specific messages
25
+ #++
21
26
 
22
- #--
23
- # Key exchange method specific messages
24
- #++
27
+ KEXDH_INIT = 30
28
+ KEXDH_REPLY = 31
25
29
 
26
- KEXDH_INIT = 30
27
- KEXDH_REPLY = 31
30
+ KEXECDH_INIT = 30
31
+ KEXECDH_REPLY = 31
28
32
 
29
- KEXECDH_INIT = 30
30
- KEXECDH_REPLY = 31
33
+ KEXDH_GEX_GROUP = 31
34
+ KEXDH_GEX_INIT = 32
35
+ KEXDH_GEX_REPLY = 33
36
+ KEXDH_GEX_REQUEST = 34
37
+ end
38
+ end
31
39
  end
32
- end; end; end
40
+ end
@@ -1,23 +1,46 @@
1
1
  require 'openssl'
2
+ require 'delegate'
2
3
 
3
4
  module Net::SSH::Transport
5
+ # :nodoc:
6
+ class OpenSSLAESCTR < SimpleDelegator
7
+ def initialize(original)
8
+ super
9
+ @was_reset = false
10
+ end
11
+
12
+ def block_size
13
+ 16
14
+ end
15
+
16
+ def self.block_size
17
+ 16
18
+ end
19
+
20
+ def reset
21
+ @was_reset = true
22
+ end
23
+
24
+ def iv=(iv_s)
25
+ super unless @was_reset
26
+ end
27
+ end
4
28
 
29
+ # :nodoc:
5
30
  # Pure-Ruby implementation of Stateful Decryption Counter(SDCTR) Mode
6
31
  # for Block Ciphers. See RFC4344 for detail.
7
32
  module CTR
8
33
  def self.extended(orig)
9
34
  orig.instance_eval {
10
- @remaining = ""
35
+ @remaining = String.new
11
36
  @counter = nil
12
37
  @counter_len = orig.block_size
13
38
  orig.encrypt
14
39
  orig.padding = 0
15
- }
16
40
 
17
- class <<orig
18
- alias :_update :update
19
- private :_update
20
- undef :update
41
+ singleton_class.send(:alias_method, :_update, :update)
42
+ singleton_class.send(:private, :_update)
43
+ singleton_class.send(:undef_method, :update)
21
44
 
22
45
  def iv
23
46
  @counter
@@ -44,42 +67,38 @@ module Net::SSH::Transport
44
67
  end
45
68
 
46
69
  def reset
47
- @remaining = ""
70
+ @remaining = String.new
48
71
  end
49
72
 
50
73
  def update(data)
51
74
  @remaining += data
52
75
 
53
- encrypted = ""
76
+ encrypted = String.new
54
77
 
55
- while @remaining.bytesize >= block_size
56
- encrypted += xor!(@remaining.slice!(0, block_size),
78
+ offset = 0
79
+ while (@remaining.bytesize - offset) >= block_size
80
+ encrypted += xor!(@remaining.slice(offset, block_size),
57
81
  _update(@counter))
58
82
  increment_counter!
83
+ offset += block_size
59
84
  end
85
+ @remaining = @remaining.slice(offset..-1)
60
86
 
61
87
  encrypted
62
88
  end
63
89
 
64
90
  def final
65
- unless @remaining.empty?
66
- s = xor!(@remaining, _update(@counter))
67
- else
68
- s = ""
69
- end
70
-
71
- @remaining = ""
72
-
91
+ s = @remaining.empty? ? '' : xor!(@remaining, _update(@counter))
92
+ @remaining = String.new
73
93
  s
74
94
  end
75
95
 
76
- private
77
-
78
96
  def xor!(s1, s2)
79
97
  s = []
80
- 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) }
81
99
  s.pack('Q*')
82
100
  end
101
+ singleton_class.send(:private, :xor!)
83
102
 
84
103
  def increment_counter!
85
104
  c = @counter_len
@@ -89,7 +108,8 @@ module Net::SSH::Transport
89
108
  end
90
109
  end
91
110
  end
92
- end
111
+ singleton_class.send(:private, :increment_counter!)
112
+ }
93
113
  end
94
114
  end
95
115
  end