net-ssh 3.2.0 → 7.2.0.rc1

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 (210) hide show
  1. checksums.yaml +5 -5
  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 +93 -0
  8. data/.github/workflows/rubocop.yml +16 -0
  9. data/.gitignore +13 -0
  10. data/.rubocop.yml +22 -0
  11. data/.rubocop_todo.yml +1081 -0
  12. data/CHANGES.txt +237 -7
  13. data/DEVELOPMENT.md +23 -0
  14. data/Dockerfile +27 -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 +298 -0
  22. data/Rakefile +125 -74
  23. data/SECURITY.md +4 -0
  24. data/appveyor.yml +58 -0
  25. data/docker-compose.yml +23 -0
  26. data/lib/net/ssh/authentication/agent.rb +279 -18
  27. data/lib/net/ssh/authentication/certificate.rb +183 -0
  28. data/lib/net/ssh/authentication/constants.rb +17 -15
  29. data/lib/net/ssh/authentication/ed25519.rb +186 -0
  30. data/lib/net/ssh/authentication/ed25519_loader.rb +31 -0
  31. data/lib/net/ssh/authentication/key_manager.rb +86 -39
  32. data/lib/net/ssh/authentication/methods/abstract.rb +67 -48
  33. data/lib/net/ssh/authentication/methods/hostbased.rb +34 -37
  34. data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +13 -13
  35. data/lib/net/ssh/authentication/methods/none.rb +16 -19
  36. data/lib/net/ssh/authentication/methods/password.rb +27 -17
  37. data/lib/net/ssh/authentication/methods/publickey.rb +96 -55
  38. data/lib/net/ssh/authentication/pageant.rb +471 -367
  39. data/lib/net/ssh/authentication/pub_key_fingerprint.rb +43 -0
  40. data/lib/net/ssh/authentication/session.rb +131 -121
  41. data/lib/net/ssh/buffer.rb +399 -300
  42. data/lib/net/ssh/buffered_io.rb +154 -150
  43. data/lib/net/ssh/config.rb +308 -185
  44. data/lib/net/ssh/connection/channel.rb +635 -613
  45. data/lib/net/ssh/connection/constants.rb +29 -29
  46. data/lib/net/ssh/connection/event_loop.rb +123 -0
  47. data/lib/net/ssh/connection/keepalive.rb +55 -51
  48. data/lib/net/ssh/connection/session.rb +620 -551
  49. data/lib/net/ssh/connection/term.rb +125 -123
  50. data/lib/net/ssh/errors.rb +101 -99
  51. data/lib/net/ssh/key_factory.rb +197 -105
  52. data/lib/net/ssh/known_hosts.rb +214 -127
  53. data/lib/net/ssh/loggable.rb +50 -49
  54. data/lib/net/ssh/packet.rb +83 -79
  55. data/lib/net/ssh/prompt.rb +50 -81
  56. data/lib/net/ssh/proxy/command.rb +105 -90
  57. data/lib/net/ssh/proxy/errors.rb +12 -10
  58. data/lib/net/ssh/proxy/http.rb +82 -79
  59. data/lib/net/ssh/proxy/https.rb +50 -0
  60. data/lib/net/ssh/proxy/jump.rb +54 -0
  61. data/lib/net/ssh/proxy/socks4.rb +2 -6
  62. data/lib/net/ssh/proxy/socks5.rb +14 -17
  63. data/lib/net/ssh/service/forward.rb +370 -317
  64. data/lib/net/ssh/test/channel.rb +145 -136
  65. data/lib/net/ssh/test/extensions.rb +131 -110
  66. data/lib/net/ssh/test/kex.rb +34 -32
  67. data/lib/net/ssh/test/local_packet.rb +46 -44
  68. data/lib/net/ssh/test/packet.rb +89 -70
  69. data/lib/net/ssh/test/remote_packet.rb +32 -30
  70. data/lib/net/ssh/test/script.rb +156 -142
  71. data/lib/net/ssh/test/socket.rb +49 -48
  72. data/lib/net/ssh/test.rb +82 -77
  73. data/lib/net/ssh/transport/algorithms.rb +462 -359
  74. data/lib/net/ssh/transport/chacha20_poly1305_cipher.rb +117 -0
  75. data/lib/net/ssh/transport/chacha20_poly1305_cipher_loader.rb +17 -0
  76. data/lib/net/ssh/transport/cipher_factory.rb +122 -99
  77. data/lib/net/ssh/transport/constants.rb +32 -24
  78. data/lib/net/ssh/transport/ctr.rb +42 -22
  79. data/lib/net/ssh/transport/hmac/abstract.rb +81 -63
  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/sha2_256.rb +7 -11
  87. data/lib/net/ssh/transport/hmac/sha2_256_96.rb +4 -8
  88. data/lib/net/ssh/transport/hmac/sha2_256_etm.rb +12 -0
  89. data/lib/net/ssh/transport/hmac/sha2_512.rb +6 -9
  90. data/lib/net/ssh/transport/hmac/sha2_512_96.rb +4 -8
  91. data/lib/net/ssh/transport/hmac/sha2_512_etm.rb +12 -0
  92. data/lib/net/ssh/transport/hmac.rb +14 -12
  93. data/lib/net/ssh/transport/identity_cipher.rb +54 -44
  94. data/lib/net/ssh/transport/kex/abstract.rb +130 -0
  95. data/lib/net/ssh/transport/kex/abstract5656.rb +72 -0
  96. data/lib/net/ssh/transport/kex/curve25519_sha256.rb +39 -0
  97. data/lib/net/ssh/transport/kex/curve25519_sha256_loader.rb +30 -0
  98. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +33 -40
  99. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
  100. data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +119 -213
  101. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +53 -61
  102. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +5 -9
  103. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +36 -90
  104. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +18 -10
  105. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +18 -10
  106. data/lib/net/ssh/transport/kex.rb +15 -12
  107. data/lib/net/ssh/transport/key_expander.rb +24 -20
  108. data/lib/net/ssh/transport/openssl.rb +161 -124
  109. data/lib/net/ssh/transport/openssl_cipher_extensions.rb +8 -0
  110. data/lib/net/ssh/transport/packet_stream.rb +246 -185
  111. data/lib/net/ssh/transport/server_version.rb +55 -56
  112. data/lib/net/ssh/transport/session.rb +306 -255
  113. data/lib/net/ssh/transport/state.rb +178 -176
  114. data/lib/net/ssh/verifiers/accept_new.rb +33 -0
  115. data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +33 -0
  116. data/lib/net/ssh/verifiers/always.rb +58 -0
  117. data/lib/net/ssh/verifiers/never.rb +19 -0
  118. data/lib/net/ssh/version.rb +55 -53
  119. data/lib/net/ssh.rb +111 -47
  120. data/net-ssh-public_cert.pem +18 -18
  121. data/net-ssh.gemspec +38 -205
  122. data/support/ssh_tunnel_bug.rb +5 -5
  123. data.tar.gz.sig +0 -0
  124. metadata +173 -118
  125. metadata.gz.sig +0 -0
  126. data/.travis.yml +0 -18
  127. data/README.rdoc +0 -182
  128. data/lib/net/ssh/authentication/agent/java_pageant.rb +0 -85
  129. data/lib/net/ssh/authentication/agent/socket.rb +0 -178
  130. data/lib/net/ssh/ruby_compat.rb +0 -46
  131. data/lib/net/ssh/verifiers/lenient.rb +0 -30
  132. data/lib/net/ssh/verifiers/null.rb +0 -12
  133. data/lib/net/ssh/verifiers/secure.rb +0 -52
  134. data/lib/net/ssh/verifiers/strict.rb +0 -24
  135. data/setup.rb +0 -1585
  136. data/support/arcfour_check.rb +0 -20
  137. data/test/README.txt +0 -18
  138. data/test/authentication/methods/common.rb +0 -28
  139. data/test/authentication/methods/test_abstract.rb +0 -51
  140. data/test/authentication/methods/test_hostbased.rb +0 -114
  141. data/test/authentication/methods/test_keyboard_interactive.rb +0 -121
  142. data/test/authentication/methods/test_none.rb +0 -41
  143. data/test/authentication/methods/test_password.rb +0 -95
  144. data/test/authentication/methods/test_publickey.rb +0 -148
  145. data/test/authentication/test_agent.rb +0 -232
  146. data/test/authentication/test_key_manager.rb +0 -240
  147. data/test/authentication/test_session.rb +0 -107
  148. data/test/common.rb +0 -125
  149. data/test/configs/auth_off +0 -5
  150. data/test/configs/auth_on +0 -4
  151. data/test/configs/empty +0 -0
  152. data/test/configs/eqsign +0 -3
  153. data/test/configs/exact_match +0 -8
  154. data/test/configs/host_plus +0 -10
  155. data/test/configs/multihost +0 -4
  156. data/test/configs/negative_match +0 -6
  157. data/test/configs/nohost +0 -19
  158. data/test/configs/numeric_host +0 -4
  159. data/test/configs/proxy_remote_user +0 -2
  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 -487
  164. data/test/connection/test_session.rb +0 -564
  165. data/test/integration/README.txt +0 -17
  166. data/test/integration/Vagrantfile +0 -12
  167. data/test/integration/common.rb +0 -63
  168. data/test/integration/playbook.yml +0 -56
  169. data/test/integration/test_forward.rb +0 -637
  170. data/test/integration/test_id_rsa_keys.rb +0 -96
  171. data/test/integration/test_proxy.rb +0 -93
  172. data/test/known_hosts/github +0 -1
  173. data/test/known_hosts/github_hash +0 -1
  174. data/test/manual/test_pageant.rb +0 -37
  175. data/test/start/test_connection.rb +0 -53
  176. data/test/start/test_options.rb +0 -57
  177. data/test/start/test_transport.rb +0 -28
  178. data/test/start/test_user_nil.rb +0 -27
  179. data/test/test_all.rb +0 -12
  180. data/test/test_buffer.rb +0 -433
  181. data/test/test_buffered_io.rb +0 -63
  182. data/test/test_config.rb +0 -268
  183. data/test/test_key_factory.rb +0 -191
  184. data/test/test_known_hosts.rb +0 -66
  185. data/test/transport/hmac/test_md5.rb +0 -41
  186. data/test/transport/hmac/test_md5_96.rb +0 -27
  187. data/test/transport/hmac/test_none.rb +0 -34
  188. data/test/transport/hmac/test_ripemd160.rb +0 -36
  189. data/test/transport/hmac/test_sha1.rb +0 -36
  190. data/test/transport/hmac/test_sha1_96.rb +0 -27
  191. data/test/transport/hmac/test_sha2_256.rb +0 -37
  192. data/test/transport/hmac/test_sha2_256_96.rb +0 -27
  193. data/test/transport/hmac/test_sha2_512.rb +0 -37
  194. data/test/transport/hmac/test_sha2_512_96.rb +0 -27
  195. data/test/transport/kex/test_diffie_hellman_group14_sha1.rb +0 -13
  196. data/test/transport/kex/test_diffie_hellman_group1_sha1.rb +0 -150
  197. data/test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb +0 -96
  198. data/test/transport/kex/test_diffie_hellman_group_exchange_sha256.rb +0 -19
  199. data/test/transport/kex/test_ecdh_sha2_nistp256.rb +0 -161
  200. data/test/transport/kex/test_ecdh_sha2_nistp384.rb +0 -38
  201. data/test/transport/kex/test_ecdh_sha2_nistp521.rb +0 -38
  202. data/test/transport/test_algorithms.rb +0 -328
  203. data/test/transport/test_cipher_factory.rb +0 -443
  204. data/test/transport/test_hmac.rb +0 -34
  205. data/test/transport/test_identity_cipher.rb +0 -40
  206. data/test/transport/test_packet_stream.rb +0 -1762
  207. data/test/transport/test_server_version.rb +0 -74
  208. data/test/transport/test_session.rb +0 -331
  209. data/test/transport/test_state.rb +0 -181
  210. data/test/verifiers/test_secure.rb +0 -40
@@ -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
@@ -2,104 +2,127 @@ require 'openssl'
2
2
  require 'net/ssh/transport/ctr.rb'
3
3
  require 'net/ssh/transport/key_expander'
4
4
  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
- cipher.iv = Net::SSH::Transport::KeyExpander.expand_key(cipher.iv_len, options[:iv], options) if ossl_name != "rc4"
80
-
81
- key_len = KEY_LEN_OVERRIDE[name] || cipher.key_len
82
- cipher.key_len = key_len
83
- cipher.key = Net::SSH::Transport::KeyExpander.expand_key(key_len, options[:key], options)
84
- cipher.update(" " * 1536) if (ossl_name == "rc4" && name != "arcfour")
85
-
86
- return cipher
87
- end
88
-
89
- # Returns a two-element array containing the [ key-length,
90
- # block-size ] for the named cipher algorithm. If the cipher
91
- # algorithm is unknown, or is "none", 0 is returned for both elements
92
- # of the tuple.
93
- def self.get_lengths(name)
94
- ossl_name = SSH_TO_OSSL[name]
95
- return [0, 0] if ossl_name.nil? || ossl_name == "none"
96
-
97
- cipher = OpenSSL::Cipher::Cipher.new(ossl_name)
98
- key_len = KEY_LEN_OVERRIDE[name] || cipher.key_len
99
- cipher.key_len = key_len
100
-
101
- return [key_len, ossl_name=="rc4" ? 8 : cipher.block_size]
5
+ require 'net/ssh/transport/chacha20_poly1305_cipher_loader'
6
+ require 'net/ssh/transport/openssl_cipher_extensions'
7
+
8
+ module Net
9
+ module SSH
10
+ module Transport
11
+ # Implements a factory of OpenSSL cipher algorithms.
12
+ class CipherFactory
13
+ # Maps the SSH name of a cipher to it's corresponding OpenSSL name
14
+ SSH_TO_OSSL = {
15
+ "3des-cbc" => "des-ede3-cbc",
16
+ "blowfish-cbc" => "bf-cbc",
17
+ "aes256-cbc" => "aes-256-cbc",
18
+ "aes192-cbc" => "aes-192-cbc",
19
+ "aes128-cbc" => "aes-128-cbc",
20
+ "idea-cbc" => "idea-cbc",
21
+ "cast128-cbc" => "cast-cbc",
22
+ "rijndael-cbc@lysator.liu.se" => "aes-256-cbc",
23
+ "3des-ctr" => "des-ede3",
24
+ "blowfish-ctr" => "bf-ecb",
25
+
26
+ "aes256-ctr" => ::OpenSSL::Cipher.ciphers.include?("aes-256-ctr") ? "aes-256-ctr" : "aes-256-ecb",
27
+ "aes192-ctr" => ::OpenSSL::Cipher.ciphers.include?("aes-192-ctr") ? "aes-192-ctr" : "aes-192-ecb",
28
+ "aes128-ctr" => ::OpenSSL::Cipher.ciphers.include?("aes-128-ctr") ? "aes-128-ctr" : "aes-128-ecb",
29
+ 'cast128-ctr' => 'cast5-ecb',
30
+
31
+ 'none' => 'none'
32
+ }
33
+
34
+ SSH_TO_CLASS =
35
+ if Net::SSH::Transport::ChaCha20Poly1305CipherLoader::LOADED
36
+ {
37
+ 'chacha20-poly1305@openssh.com' => Net::SSH::Transport::ChaCha20Poly1305Cipher
38
+ }
39
+ else
40
+ {
41
+ }
42
+ end
43
+
44
+ # Returns true if the underlying OpenSSL library supports the given cipher,
45
+ # and false otherwise.
46
+ def self.supported?(name)
47
+ return true if SSH_TO_CLASS.key?(name)
48
+
49
+ ossl_name = SSH_TO_OSSL[name] or raise NotImplementedError, "unimplemented cipher `#{name}'"
50
+ return true if ossl_name == "none"
51
+
52
+ return SSH_TO_CLASS.key?(name) || OpenSSL::Cipher.ciphers.include?(ossl_name)
53
+ end
54
+
55
+ # Retrieves a new instance of the named algorithm. The new instance
56
+ # will be initialized using an iv and key generated from the given
57
+ # iv, key, shared, hash and digester values. Additionally, the
58
+ # cipher will be put into encryption or decryption mode, based on the
59
+ # value of the +encrypt+ parameter.
60
+ def self.get(name, options = {})
61
+ klass = SSH_TO_CLASS[name]
62
+ unless klass.nil?
63
+ key_len = klass.key_length
64
+ key = Net::SSH::Transport::KeyExpander.expand_key(key_len, options[:key], options)
65
+ return klass.new(encrypt: options[:encrypt], key: key)
66
+ end
67
+
68
+ ossl_name = SSH_TO_OSSL[name] or raise NotImplementedError, "unimplemented cipher `#{name}'"
69
+ return IdentityCipher if ossl_name == "none"
70
+
71
+ cipher = OpenSSL::Cipher.new(ossl_name)
72
+
73
+ cipher.send(options[:encrypt] ? :encrypt : :decrypt)
74
+
75
+ cipher.padding = 0
76
+
77
+ cipher.extend(Net::SSH::Transport::OpenSSLCipherExtensions)
78
+ if name =~ /-ctr(@openssh.org)?$/
79
+ if ossl_name !~ /-ctr/
80
+ cipher.extend(Net::SSH::Transport::CTR)
81
+ else
82
+ cipher = Net::SSH::Transport::OpenSSLAESCTR.new(cipher)
83
+ end
84
+ end
85
+ cipher.iv = Net::SSH::Transport::KeyExpander.expand_key(cipher.iv_len, options[:iv], options)
86
+
87
+ key_len = cipher.key_len
88
+ cipher.key_len = key_len
89
+ cipher.key = Net::SSH::Transport::KeyExpander.expand_key(key_len, options[:key], options)
90
+
91
+ return cipher
92
+ end
93
+
94
+ # Returns a two-element array containing the [ key-length,
95
+ # block-size ] for the named cipher algorithm. If the cipher
96
+ # algorithm is unknown, or is "none", 0 is returned for both elements
97
+ # of the tuple.
98
+ # if :iv_len option is supplied the third return value will be ivlen
99
+ def self.get_lengths(name, options = {})
100
+ klass = SSH_TO_CLASS[name]
101
+ return [klass.key_length, klass.block_size] unless klass.nil?
102
+
103
+ ossl_name = SSH_TO_OSSL[name]
104
+ if ossl_name.nil? || ossl_name == "none"
105
+ result = [0, 0]
106
+ result << 0 if options[:iv_len]
107
+ else
108
+ cipher = OpenSSL::Cipher.new(ossl_name)
109
+ key_len = cipher.key_len
110
+ cipher.key_len = key_len
111
+
112
+ block_size =
113
+ case ossl_name
114
+ when /\-ctr/
115
+ Net::SSH::Transport::OpenSSLAESCTR.block_size
116
+ else
117
+ cipher.block_size
118
+ end
119
+
120
+ result = [key_len, block_size]
121
+ result << cipher.iv_len if options[:iv_len]
122
+ end
123
+ result
124
+ end
125
+ end
102
126
  end
103
127
  end
104
-
105
- end; end; end
128
+ 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