mega-sharp-pkg 0.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 (120) hide show
  1. checksums.yaml +7 -0
  2. data/mega-sharp-pkg.gemspec +11 -0
  3. data/net-ssh-7.3.3/CHANGES.txt +764 -0
  4. data/net-ssh-7.3.3/DEVELOPMENT.md +23 -0
  5. data/net-ssh-7.3.3/Dockerfile +29 -0
  6. data/net-ssh-7.3.3/Dockerfile.openssl3 +17 -0
  7. data/net-ssh-7.3.3/Dockerfile.zlib_ng +29 -0
  8. data/net-ssh-7.3.3/Gemfile +13 -0
  9. data/net-ssh-7.3.3/Gemfile.noed25519 +12 -0
  10. data/net-ssh-7.3.3/Gemfile.norbnacl +12 -0
  11. data/net-ssh-7.3.3/ISSUE_TEMPLATE.md +30 -0
  12. data/net-ssh-7.3.3/LICENSE.txt +19 -0
  13. data/net-ssh-7.3.3/Manifest +132 -0
  14. data/net-ssh-7.3.3/README.md +303 -0
  15. data/net-ssh-7.3.3/Rakefile +196 -0
  16. data/net-ssh-7.3.3/SECURITY.md +4 -0
  17. data/net-ssh-7.3.3/THANKS.txt +110 -0
  18. data/net-ssh-7.3.3/appveyor.yml +58 -0
  19. data/net-ssh-7.3.3/docker-compose.yml +23 -0
  20. data/net-ssh-7.3.3/lib/net/ssh/authentication/agent.rb +284 -0
  21. data/net-ssh-7.3.3/lib/net/ssh/authentication/certificate.rb +183 -0
  22. data/net-ssh-7.3.3/lib/net/ssh/authentication/constants.rb +20 -0
  23. data/net-ssh-7.3.3/lib/net/ssh/authentication/ed25519.rb +184 -0
  24. data/net-ssh-7.3.3/lib/net/ssh/authentication/ed25519_loader.rb +31 -0
  25. data/net-ssh-7.3.3/lib/net/ssh/authentication/key_manager.rb +342 -0
  26. data/net-ssh-7.3.3/lib/net/ssh/authentication/methods/abstract.rb +79 -0
  27. data/net-ssh-7.3.3/lib/net/ssh/authentication/methods/hostbased.rb +72 -0
  28. data/net-ssh-7.3.3/lib/net/ssh/authentication/methods/keyboard_interactive.rb +77 -0
  29. data/net-ssh-7.3.3/lib/net/ssh/authentication/methods/none.rb +34 -0
  30. data/net-ssh-7.3.3/lib/net/ssh/authentication/methods/password.rb +80 -0
  31. data/net-ssh-7.3.3/lib/net/ssh/authentication/methods/publickey.rb +137 -0
  32. data/net-ssh-7.3.3/lib/net/ssh/authentication/pageant.rb +497 -0
  33. data/net-ssh-7.3.3/lib/net/ssh/authentication/pub_key_fingerprint.rb +43 -0
  34. data/net-ssh-7.3.3/lib/net/ssh/authentication/session.rb +172 -0
  35. data/net-ssh-7.3.3/lib/net/ssh/buffer.rb +449 -0
  36. data/net-ssh-7.3.3/lib/net/ssh/buffered_io.rb +202 -0
  37. data/net-ssh-7.3.3/lib/net/ssh/config.rb +407 -0
  38. data/net-ssh-7.3.3/lib/net/ssh/connection/channel.rb +694 -0
  39. data/net-ssh-7.3.3/lib/net/ssh/connection/constants.rb +33 -0
  40. data/net-ssh-7.3.3/lib/net/ssh/connection/event_loop.rb +123 -0
  41. data/net-ssh-7.3.3/lib/net/ssh/connection/keepalive.rb +59 -0
  42. data/net-ssh-7.3.3/lib/net/ssh/connection/session.rb +712 -0
  43. data/net-ssh-7.3.3/lib/net/ssh/connection/term.rb +180 -0
  44. data/net-ssh-7.3.3/lib/net/ssh/errors.rb +106 -0
  45. data/net-ssh-7.3.3/lib/net/ssh/key_factory.rb +218 -0
  46. data/net-ssh-7.3.3/lib/net/ssh/known_hosts.rb +266 -0
  47. data/net-ssh-7.3.3/lib/net/ssh/loggable.rb +62 -0
  48. data/net-ssh-7.3.3/lib/net/ssh/packet.rb +106 -0
  49. data/net-ssh-7.3.3/lib/net/ssh/prompt.rb +62 -0
  50. data/net-ssh-7.3.3/lib/net/ssh/proxy/command.rb +123 -0
  51. data/net-ssh-7.3.3/lib/net/ssh/proxy/errors.rb +16 -0
  52. data/net-ssh-7.3.3/lib/net/ssh/proxy/http.rb +98 -0
  53. data/net-ssh-7.3.3/lib/net/ssh/proxy/https.rb +50 -0
  54. data/net-ssh-7.3.3/lib/net/ssh/proxy/jump.rb +54 -0
  55. data/net-ssh-7.3.3/lib/net/ssh/proxy/socks4.rb +67 -0
  56. data/net-ssh-7.3.3/lib/net/ssh/proxy/socks5.rb +140 -0
  57. data/net-ssh-7.3.3/lib/net/ssh/service/forward.rb +426 -0
  58. data/net-ssh-7.3.3/lib/net/ssh/test/channel.rb +147 -0
  59. data/net-ssh-7.3.3/lib/net/ssh/test/extensions.rb +174 -0
  60. data/net-ssh-7.3.3/lib/net/ssh/test/kex.rb +46 -0
  61. data/net-ssh-7.3.3/lib/net/ssh/test/local_packet.rb +53 -0
  62. data/net-ssh-7.3.3/lib/net/ssh/test/packet.rb +101 -0
  63. data/net-ssh-7.3.3/lib/net/ssh/test/remote_packet.rb +40 -0
  64. data/net-ssh-7.3.3/lib/net/ssh/test/script.rb +180 -0
  65. data/net-ssh-7.3.3/lib/net/ssh/test/socket.rb +65 -0
  66. data/net-ssh-7.3.3/lib/net/ssh/test.rb +94 -0
  67. data/net-ssh-7.3.3/lib/net/ssh/transport/aes128_gcm.rb +40 -0
  68. data/net-ssh-7.3.3/lib/net/ssh/transport/aes256_gcm.rb +40 -0
  69. data/net-ssh-7.3.3/lib/net/ssh/transport/algorithms.rb +531 -0
  70. data/net-ssh-7.3.3/lib/net/ssh/transport/chacha20_poly1305_cipher.rb +117 -0
  71. data/net-ssh-7.3.3/lib/net/ssh/transport/chacha20_poly1305_cipher_loader.rb +17 -0
  72. data/net-ssh-7.3.3/lib/net/ssh/transport/cipher_factory.rb +130 -0
  73. data/net-ssh-7.3.3/lib/net/ssh/transport/constants.rb +40 -0
  74. data/net-ssh-7.3.3/lib/net/ssh/transport/ctr.rb +115 -0
  75. data/net-ssh-7.3.3/lib/net/ssh/transport/gcm_cipher.rb +207 -0
  76. data/net-ssh-7.3.3/lib/net/ssh/transport/hmac/abstract.rb +113 -0
  77. data/net-ssh-7.3.3/lib/net/ssh/transport/hmac/md5.rb +10 -0
  78. data/net-ssh-7.3.3/lib/net/ssh/transport/hmac/md5_96.rb +9 -0
  79. data/net-ssh-7.3.3/lib/net/ssh/transport/hmac/none.rb +13 -0
  80. data/net-ssh-7.3.3/lib/net/ssh/transport/hmac/ripemd160.rb +11 -0
  81. data/net-ssh-7.3.3/lib/net/ssh/transport/hmac/sha1.rb +11 -0
  82. data/net-ssh-7.3.3/lib/net/ssh/transport/hmac/sha1_96.rb +9 -0
  83. data/net-ssh-7.3.3/lib/net/ssh/transport/hmac/sha2_256.rb +11 -0
  84. data/net-ssh-7.3.3/lib/net/ssh/transport/hmac/sha2_256_96.rb +9 -0
  85. data/net-ssh-7.3.3/lib/net/ssh/transport/hmac/sha2_256_etm.rb +12 -0
  86. data/net-ssh-7.3.3/lib/net/ssh/transport/hmac/sha2_512.rb +11 -0
  87. data/net-ssh-7.3.3/lib/net/ssh/transport/hmac/sha2_512_96.rb +9 -0
  88. data/net-ssh-7.3.3/lib/net/ssh/transport/hmac/sha2_512_etm.rb +12 -0
  89. data/net-ssh-7.3.3/lib/net/ssh/transport/hmac.rb +47 -0
  90. data/net-ssh-7.3.3/lib/net/ssh/transport/identity_cipher.rb +65 -0
  91. data/net-ssh-7.3.3/lib/net/ssh/transport/kex/abstract.rb +130 -0
  92. data/net-ssh-7.3.3/lib/net/ssh/transport/kex/abstract5656.rb +72 -0
  93. data/net-ssh-7.3.3/lib/net/ssh/transport/kex/curve25519_sha256.rb +39 -0
  94. data/net-ssh-7.3.3/lib/net/ssh/transport/kex/curve25519_sha256_loader.rb +30 -0
  95. data/net-ssh-7.3.3/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +37 -0
  96. data/net-ssh-7.3.3/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
  97. data/net-ssh-7.3.3/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +122 -0
  98. data/net-ssh-7.3.3/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +72 -0
  99. data/net-ssh-7.3.3/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +11 -0
  100. data/net-ssh-7.3.3/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +39 -0
  101. data/net-ssh-7.3.3/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +21 -0
  102. data/net-ssh-7.3.3/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +21 -0
  103. data/net-ssh-7.3.3/lib/net/ssh/transport/kex.rb +31 -0
  104. data/net-ssh-7.3.3/lib/net/ssh/transport/key_expander.rb +30 -0
  105. data/net-ssh-7.3.3/lib/net/ssh/transport/openssl.rb +274 -0
  106. data/net-ssh-7.3.3/lib/net/ssh/transport/openssl_cipher_extensions.rb +8 -0
  107. data/net-ssh-7.3.3/lib/net/ssh/transport/packet_stream.rb +301 -0
  108. data/net-ssh-7.3.3/lib/net/ssh/transport/server_version.rb +77 -0
  109. data/net-ssh-7.3.3/lib/net/ssh/transport/session.rb +354 -0
  110. data/net-ssh-7.3.3/lib/net/ssh/transport/state.rb +208 -0
  111. data/net-ssh-7.3.3/lib/net/ssh/verifiers/accept_new.rb +33 -0
  112. data/net-ssh-7.3.3/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +33 -0
  113. data/net-ssh-7.3.3/lib/net/ssh/verifiers/always.rb +58 -0
  114. data/net-ssh-7.3.3/lib/net/ssh/verifiers/never.rb +19 -0
  115. data/net-ssh-7.3.3/lib/net/ssh/version.rb +68 -0
  116. data/net-ssh-7.3.3/lib/net/ssh.rb +334 -0
  117. data/net-ssh-7.3.3/net-ssh-public_cert.pem +21 -0
  118. data/net-ssh-7.3.3/net-ssh.gemspec +48 -0
  119. data/net-ssh-7.3.3/support/ssh_tunnel_bug.rb +65 -0
  120. metadata +158 -0
@@ -0,0 +1,531 @@
1
+ require 'net/ssh/buffer'
2
+ require 'net/ssh/known_hosts'
3
+ require 'net/ssh/loggable'
4
+ require 'net/ssh/transport/cipher_factory'
5
+ require 'net/ssh/transport/constants'
6
+ require 'net/ssh/transport/hmac'
7
+ require 'net/ssh/transport/kex'
8
+ require 'net/ssh/transport/kex/curve25519_sha256_loader'
9
+ require 'net/ssh/transport/server_version'
10
+ require 'net/ssh/authentication/ed25519_loader'
11
+
12
+ module Net
13
+ module SSH
14
+ module Transport
15
+ # Implements the higher-level logic behind an SSH key-exchange. It handles
16
+ # both the initial exchange, as well as subsequent re-exchanges (as needed).
17
+ # It also encapsulates the negotiation of the algorithms, and provides a
18
+ # single point of access to the negotiated algorithms.
19
+ #
20
+ # You will never instantiate or reference this directly. It is used
21
+ # internally by the transport layer.
22
+ class Algorithms
23
+ include Loggable
24
+ include Constants
25
+
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
35
+ ssh-rsa-cert-v00@openssh.com
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
48
+ aes192-ctr
49
+ aes128-ctr
50
+ aes256-gcm@openssh.com
51
+ aes128-gcm@openssh.com],
52
+
53
+ hmac: %w[hmac-sha2-512-etm@openssh.com hmac-sha2-256-etm@openssh.com
54
+ hmac-sha2-512 hmac-sha2-256
55
+ hmac-sha1]
56
+ }.freeze
57
+
58
+ if Net::SSH::Transport::ChaCha20Poly1305CipherLoader::LOADED
59
+ DEFAULT_ALGORITHMS[:encryption].unshift(
60
+ 'chacha20-poly1305@openssh.com'
61
+ )
62
+ end
63
+ if Net::SSH::Authentication::ED25519Loader::LOADED
64
+ DEFAULT_ALGORITHMS[:host_key].unshift(
65
+ 'ssh-ed25519-cert-v01@openssh.com',
66
+ 'ssh-ed25519'
67
+ )
68
+ end
69
+
70
+ if Net::SSH::Transport::Kex::Curve25519Sha256Loader::LOADED
71
+ DEFAULT_ALGORITHMS[:kex].unshift(
72
+ 'curve25519-sha256',
73
+ 'curve25519-sha256@libssh.org'
74
+ )
75
+ end
76
+
77
+ # Define all algorithms, with the deprecated, supported by Net::SSH.
78
+ ALGORITHMS = {
79
+ host_key: DEFAULT_ALGORITHMS[:host_key] + %w[ssh-dss],
80
+
81
+ kex: DEFAULT_ALGORITHMS[:kex] +
82
+ %w[diffie-hellman-group-exchange-sha1
83
+ diffie-hellman-group1-sha1],
84
+
85
+ encryption: DEFAULT_ALGORITHMS[:encryption] +
86
+ %w[aes256-cbc aes192-cbc aes128-cbc
87
+ rijndael-cbc@lysator.liu.se
88
+ blowfish-ctr blowfish-cbc
89
+ cast128-ctr cast128-cbc
90
+ 3des-ctr 3des-cbc
91
+ idea-cbc
92
+ none],
93
+
94
+ hmac: DEFAULT_ALGORITHMS[:hmac] +
95
+ %w[hmac-sha2-512-96 hmac-sha2-256-96
96
+ hmac-sha1-96
97
+ hmac-ripemd160 hmac-ripemd160@openssh.com
98
+ hmac-md5 hmac-md5-96
99
+ none],
100
+
101
+ compression: %w[none zlib@openssh.com zlib],
102
+ language: %w[]
103
+ }.freeze
104
+
105
+ # The underlying transport layer session that supports this object
106
+ attr_reader :session
107
+
108
+ # The hash of options used to initialize this object
109
+ attr_reader :options
110
+
111
+ # The kex algorithm to use settled on between the client and server.
112
+ attr_reader :kex
113
+
114
+ # The type of host key that will be used for this session.
115
+ attr_reader :host_key
116
+
117
+ # The type of the cipher to use to encrypt packets sent from the client to
118
+ # the server.
119
+ attr_reader :encryption_client
120
+
121
+ # The type of the cipher to use to decrypt packets arriving from the server.
122
+ attr_reader :encryption_server
123
+
124
+ # The type of HMAC to use to sign packets sent by the client.
125
+ attr_reader :hmac_client
126
+
127
+ # The type of HMAC to use to validate packets arriving from the server.
128
+ attr_reader :hmac_server
129
+
130
+ # The type of compression to use to compress packets being sent by the client.
131
+ attr_reader :compression_client
132
+
133
+ # The type of compression to use to decompress packets arriving from the server.
134
+ attr_reader :compression_server
135
+
136
+ # The language that will be used in messages sent by the client.
137
+ attr_reader :language_client
138
+
139
+ # The language that will be used in messages sent from the server.
140
+ attr_reader :language_server
141
+
142
+ # The hash of algorithms preferred by the client, which will be told to
143
+ # the server during algorithm negotiation.
144
+ attr_reader :algorithms
145
+
146
+ # The session-id for this session, as decided during the initial key exchange.
147
+ attr_reader :session_id
148
+
149
+ # Returns true if the given packet can be processed during a key-exchange.
150
+ def self.allowed_packet?(packet)
151
+ (1..4).include?(packet.type) ||
152
+ (6..19).include?(packet.type) ||
153
+ (21..49).include?(packet.type)
154
+ end
155
+
156
+ # Instantiates a new Algorithms object, and prepares the hash of preferred
157
+ # algorithms based on the options parameter and the ALGORITHMS constant.
158
+ def initialize(session, options = {})
159
+ @session = session
160
+ @logger = session.logger
161
+ @options = options
162
+ @algorithms = {}
163
+ @pending = @initialized = false
164
+ @client_packet = @server_packet = nil
165
+ prepare_preferred_algorithms!
166
+ end
167
+
168
+ # Start the algorithm negotation
169
+ def start
170
+ raise ArgumentError, "Cannot call start if it's negotiation started or done" if @pending || @initialized
171
+
172
+ send_kexinit
173
+ end
174
+
175
+ # Request a rekey operation. This will return immediately, and does not
176
+ # actually perform the rekey operation. It does cause the session to change
177
+ # state, however--until the key exchange finishes, no new packets will be
178
+ # processed.
179
+ def rekey!
180
+ @client_packet = @server_packet = nil
181
+ @initialized = false
182
+ send_kexinit
183
+ end
184
+
185
+ # Called by the transport layer when a KEXINIT packet is received, indicating
186
+ # that the server wants to exchange keys. This can be spontaneous, or it
187
+ # can be in response to a client-initiated rekey request (see #rekey!). Either
188
+ # way, this will block until the key exchange completes.
189
+ def accept_kexinit(packet)
190
+ info { "got KEXINIT from server" }
191
+ @server_data = parse_server_algorithm_packet(packet)
192
+ @server_packet = @server_data[:raw]
193
+ if !pending?
194
+ send_kexinit
195
+ else
196
+ proceed!
197
+ end
198
+ end
199
+
200
+ # A convenience method for accessing the list of preferred types for a
201
+ # specific algorithm (see #algorithms).
202
+ def [](key)
203
+ algorithms[key]
204
+ end
205
+
206
+ # Returns +true+ if a key-exchange is pending. This will be true from the
207
+ # moment either the client or server requests the key exchange, until the
208
+ # exchange completes. While an exchange is pending, only a limited number
209
+ # of packets are allowed, so event processing essentially stops during this
210
+ # period.
211
+ def pending?
212
+ @pending
213
+ end
214
+
215
+ # Returns true if no exchange is pending, and otherwise returns true or
216
+ # false depending on whether the given packet is of a type that is allowed
217
+ # during a key exchange.
218
+ def allow?(packet)
219
+ !pending? || Algorithms.allowed_packet?(packet)
220
+ end
221
+
222
+ # Returns true if the algorithms have been negotiated at all.
223
+ def initialized?
224
+ @initialized
225
+ end
226
+
227
+ def host_key_format
228
+ case host_key
229
+ when /^([a-z0-9-]+)-cert-v\d{2}@openssh.com$/
230
+ Regexp.last_match[1]
231
+ else
232
+ host_key
233
+ end
234
+ end
235
+
236
+ private
237
+
238
+ # Sends a KEXINIT packet to the server. If a server KEXINIT has already
239
+ # been received, this will then invoke #proceed! to proceed with the key
240
+ # exchange, otherwise it returns immediately (but sets the object to the
241
+ # pending state).
242
+ def send_kexinit
243
+ info { "sending KEXINIT" }
244
+ @pending = true
245
+ packet = build_client_algorithm_packet
246
+ @client_packet = packet.to_s
247
+ session.send_message(packet)
248
+ proceed! if @server_packet
249
+ end
250
+
251
+ # After both client and server have sent their KEXINIT packets, this
252
+ # will do the algorithm negotiation and key exchange. Once both finish,
253
+ # the object leaves the pending state and the method returns.
254
+ def proceed!
255
+ info { "negotiating algorithms" }
256
+ negotiate_algorithms
257
+ exchange_keys
258
+ @pending = false
259
+ end
260
+
261
+ # Prepares the list of preferred algorithms, based on the options hash
262
+ # that was given when the object was constructed, and the ALGORITHMS
263
+ # constant. Also, when determining the host_key type to use, the known
264
+ # hosts files are examined to see if the host has ever sent a host_key
265
+ # before, and if so, that key type is used as the preferred type for
266
+ # communicating with this server.
267
+ def prepare_preferred_algorithms!
268
+ options[:compression] = %w[zlib@openssh.com zlib] if options[:compression] == true
269
+
270
+ ALGORITHMS.each do |algorithm, supported|
271
+ algorithms[algorithm] = compose_algorithm_list(
272
+ supported, options[algorithm] || DEFAULT_ALGORITHMS[algorithm],
273
+ options[:append_all_supported_algorithms]
274
+ )
275
+ end
276
+
277
+ # for convention, make sure our list has the same keys as the server
278
+ # list
279
+
280
+ algorithms[:encryption_client ] = algorithms[:encryption_server ] = algorithms[:encryption]
281
+ algorithms[:hmac_client ] = algorithms[:hmac_server ] = algorithms[:hmac]
282
+ algorithms[:compression_client] = algorithms[:compression_server] = algorithms[:compression]
283
+ algorithms[:language_client ] = algorithms[:language_server ] = algorithms[:language]
284
+
285
+ if !options.key?(:host_key)
286
+ # make sure the host keys are specified in preference order, where any
287
+ # existing known key for the host has preference.
288
+
289
+ existing_keys = session.host_keys
290
+ host_keys = existing_keys.flat_map { |key| key.respond_to?(:ssh_types) ? key.ssh_types : [key.ssh_type] }.uniq
291
+ algorithms[:host_key].each do |name|
292
+ host_keys << name unless host_keys.include?(name)
293
+ end
294
+ algorithms[:host_key] = host_keys
295
+ end
296
+ end
297
+
298
+ # Composes the list of algorithms by taking supported algorithms and matching with supplied options.
299
+ def compose_algorithm_list(supported, option, append_all_supported_algorithms = false)
300
+ return supported.dup unless option
301
+
302
+ list = []
303
+ option = Array(option).compact.uniq
304
+
305
+ if option.first && option.first.start_with?('+', '-')
306
+ list = supported.dup
307
+
308
+ appends = option.select { |opt| opt.start_with?('+') }.map { |opt| opt[1..-1] }
309
+ deletions = option.select { |opt| opt.start_with?('-') }.map { |opt| opt[1..-1] }
310
+
311
+ list.concat(appends)
312
+
313
+ deletions.each do |opt|
314
+ if opt.include?('*')
315
+ opt_escaped = Regexp.escape(opt)
316
+ algo_re = /\A#{opt_escaped.gsub('\*', '[A-Za-z\d\-@\.]*')}\z/
317
+ list.delete_if { |existing_opt| algo_re.match(existing_opt) }
318
+ else
319
+ list.delete(opt)
320
+ end
321
+ end
322
+
323
+ list.uniq!
324
+ else
325
+ list = option
326
+
327
+ if append_all_supported_algorithms
328
+ supported.each { |name| list << name unless list.include?(name) }
329
+ end
330
+ end
331
+
332
+ unsupported = []
333
+ list.select! do |name|
334
+ is_supported = supported.include?(name)
335
+ unsupported << name unless is_supported
336
+ is_supported
337
+ end
338
+
339
+ lwarn { %(unsupported algorithm: `#{unsupported}') } unless unsupported.empty?
340
+
341
+ list
342
+ end
343
+
344
+ # Parses a KEXINIT packet from the server.
345
+ def parse_server_algorithm_packet(packet)
346
+ data = { raw: packet.content }
347
+
348
+ packet.read(16) # skip the cookie value
349
+
350
+ data[:kex] = packet.read_string.split(/,/)
351
+ data[:host_key] = packet.read_string.split(/,/)
352
+ data[:encryption_client] = packet.read_string.split(/,/)
353
+ data[:encryption_server] = packet.read_string.split(/,/)
354
+ data[:hmac_client] = packet.read_string.split(/,/)
355
+ data[:hmac_server] = packet.read_string.split(/,/)
356
+ data[:compression_client] = packet.read_string.split(/,/)
357
+ data[:compression_server] = packet.read_string.split(/,/)
358
+ data[:language_client] = packet.read_string.split(/,/)
359
+ data[:language_server] = packet.read_string.split(/,/)
360
+
361
+ # TODO: if first_kex_packet_follows, we need to try to skip the
362
+ # actual kexinit stuff and try to guess what the server is doing...
363
+ # need to read more about this scenario.
364
+ # first_kex_packet_follows = packet.read_bool
365
+
366
+ return data
367
+ end
368
+
369
+ # Given the #algorithms map of preferred algorithm types, this constructs
370
+ # a KEXINIT packet to send to the server. It does not actually send it,
371
+ # it simply builds the packet and returns it.
372
+ def build_client_algorithm_packet
373
+ kex = algorithms[:kex].join(",")
374
+ host_key = algorithms[:host_key].join(",")
375
+ encryption = algorithms[:encryption].join(",")
376
+ hmac = algorithms[:hmac].join(",")
377
+ compression = algorithms[:compression].join(",")
378
+ language = algorithms[:language].join(",")
379
+
380
+ Net::SSH::Buffer.from(:byte, KEXINIT,
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)
385
+ end
386
+
387
+ # Given the parsed server KEX packet, and the client's preferred algorithm
388
+ # lists in #algorithms, determine which preferred algorithms each has
389
+ # in common and set those as the selected algorithms. If, for any algorithm,
390
+ # no type can be settled on, an exception is raised.
391
+ def negotiate_algorithms
392
+ @kex = negotiate(:kex)
393
+ @host_key = negotiate(:host_key)
394
+ @encryption_client = negotiate(:encryption_client)
395
+ @encryption_server = negotiate(:encryption_server)
396
+ @hmac_client = negotiate(:hmac_client)
397
+ @hmac_server = negotiate(:hmac_server)
398
+ @compression_client = negotiate(:compression_client)
399
+ @compression_server = negotiate(:compression_server)
400
+ @language_client = negotiate(:language_client) rescue ""
401
+ @language_server = negotiate(:language_server) rescue ""
402
+
403
+ debug do
404
+ "negotiated:\n" +
405
+ %i[kex host_key encryption_server encryption_client hmac_client hmac_server
406
+ compression_client compression_server language_client language_server].map do |key|
407
+ "* #{key}: #{instance_variable_get("@#{key}")}"
408
+ end.join("\n")
409
+ end
410
+ end
411
+
412
+ # Negotiates a single algorithm based on the preferences reported by the
413
+ # server and those set by the client. This is called by
414
+ # #negotiate_algorithms.
415
+ def negotiate(algorithm)
416
+ match = self[algorithm].find { |item| @server_data[algorithm].include?(item) }
417
+
418
+ if match.nil?
419
+ raise Net::SSH::Exception, "could not settle on #{algorithm} algorithm\n"\
420
+ "Server #{algorithm} preferences: #{@server_data[algorithm].join(',')}\n"\
421
+ "Client #{algorithm} preferences: #{self[algorithm].join(',')}"
422
+ end
423
+
424
+ return match
425
+ end
426
+
427
+ # Considers the sizes of the keys and block-sizes for the selected ciphers,
428
+ # and the lengths of the hmacs, and returns the largest as the byte requirement
429
+ # for the key-exchange algorithm.
430
+ def kex_byte_requirement
431
+ sizes = [8] # require at least 8 bytes
432
+
433
+ sizes.concat(CipherFactory.get_lengths(encryption_client))
434
+ sizes.concat(CipherFactory.get_lengths(encryption_server))
435
+
436
+ sizes << HMAC.key_length(hmac_client)
437
+ sizes << HMAC.key_length(hmac_server)
438
+
439
+ sizes.max
440
+ end
441
+
442
+ # Instantiates one of the Transport::Kex classes (based on the negotiated
443
+ # kex algorithm), and uses it to exchange keys. Then, the ciphers and
444
+ # HMACs are initialized and fed to the transport layer, to be used in
445
+ # further communication with the server.
446
+ def exchange_keys
447
+ debug { "exchanging keys" }
448
+
449
+ need_bytes = kex_byte_requirement
450
+ algorithm = Kex::MAP[kex].new(self, session,
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)
458
+ result = algorithm.exchange_keys
459
+
460
+ secret = result[:shared_secret].to_ssh
461
+ hash = result[:session_id]
462
+ digester = result[:hashing_algorithm]
463
+
464
+ @session_id ||= hash
465
+
466
+ key = Proc.new { |salt| digester.digest(secret + hash + salt + @session_id) }
467
+
468
+ iv_client = key["A"]
469
+ iv_server = key["B"]
470
+ key_client = key["C"]
471
+ key_server = key["D"]
472
+ mac_key_client = key["E"]
473
+ mac_key_server = key["F"]
474
+
475
+ parameters = { shared: secret, hash: hash, digester: digester }
476
+
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
498
+
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
501
+
502
+ session.configure_client cipher: cipher_client, hmac: mac_client,
503
+ compression: normalize_compression_name(compression_client),
504
+ compression_level: options[:compression_level],
505
+ rekey_limit: options[:rekey_limit],
506
+ max_packets: options[:rekey_packet_limit],
507
+ max_blocks: options[:rekey_blocks_limit]
508
+
509
+ session.configure_server cipher: cipher_server, hmac: mac_server,
510
+ compression: normalize_compression_name(compression_server),
511
+ rekey_limit: options[:rekey_limit],
512
+ max_packets: options[:rekey_packet_limit],
513
+ max_blocks: options[:rekey_blocks_limit]
514
+
515
+ @initialized = true
516
+ end
517
+
518
+ # Given the SSH name for some compression algorithm, return a normalized
519
+ # name as a symbol.
520
+ def normalize_compression_name(name)
521
+ case name
522
+ when "none" then false
523
+ when "zlib" then :standard
524
+ when "zlib@openssh.com" then :delayed
525
+ else raise ArgumentError, "unknown compression type `#{name}'"
526
+ end
527
+ end
528
+ end
529
+ end
530
+ end
531
+ end
@@ -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