sonixlabs-net-ssh 2.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 (123) hide show
  1. data/CHANGELOG.rdoc +262 -0
  2. data/Manifest +121 -0
  3. data/README.rdoc +184 -0
  4. data/Rakefile +86 -0
  5. data/Rudyfile +96 -0
  6. data/THANKS.rdoc +19 -0
  7. data/lib/net/ssh.rb +223 -0
  8. data/lib/net/ssh/authentication/agent.rb +179 -0
  9. data/lib/net/ssh/authentication/constants.rb +18 -0
  10. data/lib/net/ssh/authentication/key_manager.rb +253 -0
  11. data/lib/net/ssh/authentication/methods/abstract.rb +60 -0
  12. data/lib/net/ssh/authentication/methods/hostbased.rb +75 -0
  13. data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +70 -0
  14. data/lib/net/ssh/authentication/methods/password.rb +43 -0
  15. data/lib/net/ssh/authentication/methods/publickey.rb +96 -0
  16. data/lib/net/ssh/authentication/pageant.rb +264 -0
  17. data/lib/net/ssh/authentication/session.rb +146 -0
  18. data/lib/net/ssh/buffer.rb +340 -0
  19. data/lib/net/ssh/buffered_io.rb +198 -0
  20. data/lib/net/ssh/config.rb +207 -0
  21. data/lib/net/ssh/connection/channel.rb +630 -0
  22. data/lib/net/ssh/connection/constants.rb +33 -0
  23. data/lib/net/ssh/connection/session.rb +597 -0
  24. data/lib/net/ssh/connection/term.rb +178 -0
  25. data/lib/net/ssh/errors.rb +88 -0
  26. data/lib/net/ssh/key_factory.rb +102 -0
  27. data/lib/net/ssh/known_hosts.rb +129 -0
  28. data/lib/net/ssh/loggable.rb +61 -0
  29. data/lib/net/ssh/packet.rb +102 -0
  30. data/lib/net/ssh/prompt.rb +93 -0
  31. data/lib/net/ssh/proxy/command.rb +75 -0
  32. data/lib/net/ssh/proxy/errors.rb +14 -0
  33. data/lib/net/ssh/proxy/http.rb +94 -0
  34. data/lib/net/ssh/proxy/socks4.rb +70 -0
  35. data/lib/net/ssh/proxy/socks5.rb +142 -0
  36. data/lib/net/ssh/ruby_compat.rb +43 -0
  37. data/lib/net/ssh/service/forward.rb +298 -0
  38. data/lib/net/ssh/test.rb +89 -0
  39. data/lib/net/ssh/test/channel.rb +129 -0
  40. data/lib/net/ssh/test/extensions.rb +152 -0
  41. data/lib/net/ssh/test/kex.rb +44 -0
  42. data/lib/net/ssh/test/local_packet.rb +51 -0
  43. data/lib/net/ssh/test/packet.rb +81 -0
  44. data/lib/net/ssh/test/remote_packet.rb +38 -0
  45. data/lib/net/ssh/test/script.rb +157 -0
  46. data/lib/net/ssh/test/socket.rb +64 -0
  47. data/lib/net/ssh/transport/algorithms.rb +386 -0
  48. data/lib/net/ssh/transport/cipher_factory.rb +79 -0
  49. data/lib/net/ssh/transport/constants.rb +30 -0
  50. data/lib/net/ssh/transport/hmac.rb +42 -0
  51. data/lib/net/ssh/transport/hmac/abstract.rb +79 -0
  52. data/lib/net/ssh/transport/hmac/md5.rb +12 -0
  53. data/lib/net/ssh/transport/hmac/md5_96.rb +11 -0
  54. data/lib/net/ssh/transport/hmac/none.rb +15 -0
  55. data/lib/net/ssh/transport/hmac/sha1.rb +13 -0
  56. data/lib/net/ssh/transport/hmac/sha1_96.rb +11 -0
  57. data/lib/net/ssh/transport/hmac/sha2_256.rb +15 -0
  58. data/lib/net/ssh/transport/hmac/sha2_256_96.rb +13 -0
  59. data/lib/net/ssh/transport/hmac/sha2_512.rb +14 -0
  60. data/lib/net/ssh/transport/hmac/sha2_512_96.rb +13 -0
  61. data/lib/net/ssh/transport/identity_cipher.rb +55 -0
  62. data/lib/net/ssh/transport/kex.rb +17 -0
  63. data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +208 -0
  64. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +80 -0
  65. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +15 -0
  66. data/lib/net/ssh/transport/key_expander.rb +26 -0
  67. data/lib/net/ssh/transport/openssl.rb +127 -0
  68. data/lib/net/ssh/transport/packet_stream.rb +235 -0
  69. data/lib/net/ssh/transport/server_version.rb +71 -0
  70. data/lib/net/ssh/transport/session.rb +278 -0
  71. data/lib/net/ssh/transport/state.rb +206 -0
  72. data/lib/net/ssh/verifiers/lenient.rb +30 -0
  73. data/lib/net/ssh/verifiers/null.rb +12 -0
  74. data/lib/net/ssh/verifiers/strict.rb +53 -0
  75. data/lib/net/ssh/version.rb +62 -0
  76. data/lib/sonixlabs-net-ssh.rb +1 -0
  77. data/net-ssh.gemspec +145 -0
  78. data/setup.rb +1585 -0
  79. data/support/arcfour_check.rb +20 -0
  80. data/support/ssh_tunnel_bug.rb +65 -0
  81. data/test/authentication/methods/common.rb +28 -0
  82. data/test/authentication/methods/test_abstract.rb +51 -0
  83. data/test/authentication/methods/test_hostbased.rb +114 -0
  84. data/test/authentication/methods/test_keyboard_interactive.rb +100 -0
  85. data/test/authentication/methods/test_password.rb +52 -0
  86. data/test/authentication/methods/test_publickey.rb +148 -0
  87. data/test/authentication/test_agent.rb +205 -0
  88. data/test/authentication/test_key_manager.rb +171 -0
  89. data/test/authentication/test_session.rb +106 -0
  90. data/test/common.rb +107 -0
  91. data/test/configs/eqsign +3 -0
  92. data/test/configs/exact_match +8 -0
  93. data/test/configs/host_plus +10 -0
  94. data/test/configs/multihost +4 -0
  95. data/test/configs/wild_cards +14 -0
  96. data/test/connection/test_channel.rb +467 -0
  97. data/test/connection/test_session.rb +488 -0
  98. data/test/test_all.rb +9 -0
  99. data/test/test_buffer.rb +336 -0
  100. data/test/test_buffered_io.rb +63 -0
  101. data/test/test_config.rb +120 -0
  102. data/test/test_key_factory.rb +79 -0
  103. data/test/transport/hmac/test_md5.rb +39 -0
  104. data/test/transport/hmac/test_md5_96.rb +25 -0
  105. data/test/transport/hmac/test_none.rb +34 -0
  106. data/test/transport/hmac/test_sha1.rb +34 -0
  107. data/test/transport/hmac/test_sha1_96.rb +25 -0
  108. data/test/transport/hmac/test_sha2_256.rb +35 -0
  109. data/test/transport/hmac/test_sha2_256_96.rb +25 -0
  110. data/test/transport/hmac/test_sha2_512.rb +35 -0
  111. data/test/transport/hmac/test_sha2_512_96.rb +25 -0
  112. data/test/transport/kex/test_diffie_hellman_group1_sha1.rb +146 -0
  113. data/test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb +92 -0
  114. data/test/transport/kex/test_diffie_hellman_group_exchange_sha256.rb +33 -0
  115. data/test/transport/test_algorithms.rb +308 -0
  116. data/test/transport/test_cipher_factory.rb +213 -0
  117. data/test/transport/test_hmac.rb +34 -0
  118. data/test/transport/test_identity_cipher.rb +40 -0
  119. data/test/transport/test_packet_stream.rb +736 -0
  120. data/test/transport/test_server_version.rb +78 -0
  121. data/test/transport/test_session.rb +315 -0
  122. data/test/transport/test_state.rb +179 -0
  123. metadata +178 -0
@@ -0,0 +1,92 @@
1
+ require 'common'
2
+ require 'transport/kex/test_diffie_hellman_group1_sha1'
3
+ require 'net/ssh/transport/kex/diffie_hellman_group_exchange_sha1'
4
+
5
+ module Transport; module Kex
6
+
7
+ class TestDiffieHellmanGroupExchangeSHA1 < TestDiffieHellmanGroup1SHA1
8
+ KEXDH_GEX_GROUP = 31
9
+ KEXDH_GEX_INIT = 32
10
+ KEXDH_GEX_REPLY = 33
11
+ KEXDH_GEX_REQUEST = 34
12
+
13
+ def test_exchange_with_fewer_than_minimum_bits_uses_minimum_bits
14
+ dh_options :need_bytes => 20
15
+ assert_equal 1024, need_bits
16
+ assert_nothing_raised { exchange! }
17
+ end
18
+
19
+ def test_exchange_with_fewer_than_maximum_bits_uses_need_bits
20
+ dh_options :need_bytes => 500
21
+ need_bits(8001)
22
+ assert_nothing_raised { exchange! }
23
+ end
24
+
25
+ def test_exchange_with_more_than_maximum_bits_uses_maximum_bits
26
+ dh_options :need_bytes => 2000
27
+ need_bits(8192)
28
+ assert_nothing_raised { exchange! }
29
+ end
30
+
31
+ def test_that_p_and_g_are_provided_by_the_server
32
+ assert_nothing_raised { exchange! :p => default_p+2, :g => 3 }
33
+ assert_equal default_p+2, dh.dh.p
34
+ assert_equal 3, dh.dh.g
35
+ end
36
+
37
+ private
38
+
39
+ def need_bits(bits=1024)
40
+ @need_bits ||= bits
41
+ end
42
+
43
+ def default_p
44
+ 142326151570335518660743995281621698377057354949884468943021767573608899048361360422513557553514790045512299468953431585300812548859419857171094366358158903433167915517332113861059747425408670144201099811846875730766487278261498262568348338476437200556998366087779709990807518291581860338635288400119315130179
45
+ end
46
+
47
+ def exchange!(options={})
48
+ connection.expect do |t, buffer|
49
+ assert_equal KEXDH_GEX_REQUEST, buffer.type
50
+ assert_equal 1024, buffer.read_long
51
+ assert_equal need_bits, buffer.read_long
52
+ assert_equal 8192, buffer.read_long
53
+ t.return(KEXDH_GEX_GROUP, :bignum, bn(options[:p] || default_p), :bignum, bn(options[:g] || 2))
54
+ t.expect do |t2, buffer2|
55
+ assert_equal KEXDH_GEX_INIT, buffer2.type
56
+ assert_equal dh.dh.pub_key, buffer2.read_bignum
57
+ t2.return(KEXDH_GEX_REPLY, :string, b(:key, server_key), :bignum, server_dh_pubkey, :string, b(:string, options[:key_type] || "ssh-rsa", :string, signature))
58
+ t2.expect do |t3, buffer3|
59
+ assert_equal NEWKEYS, buffer3.type
60
+ t3.return(NEWKEYS)
61
+ end
62
+ end
63
+ end
64
+
65
+ dh.exchange_keys
66
+ end
67
+
68
+ def subject
69
+ Net::SSH::Transport::Kex::DiffieHellmanGroupExchangeSHA1
70
+ end
71
+
72
+ def session_id
73
+ @session_id ||= begin
74
+ buffer = Net::SSH::Buffer.from(:string, packet_data[:client_version_string],
75
+ :string, packet_data[:server_version_string],
76
+ :string, packet_data[:client_algorithm_packet],
77
+ :string, packet_data[:server_algorithm_packet],
78
+ :string, Net::SSH::Buffer.from(:key, server_key),
79
+ :long, 1024,
80
+ :long, need_bits, # need bits, figure this part out,
81
+ :long, 8192,
82
+ :bignum, dh.dh.p,
83
+ :bignum, dh.dh.g,
84
+ :bignum, dh.dh.pub_key,
85
+ :bignum, server_dh_pubkey,
86
+ :bignum, shared_secret)
87
+ OpenSSL::Digest::SHA1.digest(buffer.to_s)
88
+ end
89
+ end
90
+ end
91
+
92
+ end; end
@@ -0,0 +1,33 @@
1
+ require 'common'
2
+ require 'net/ssh/transport/kex/diffie_hellman_group_exchange_sha1'
3
+
4
+ module Transport; module Kex
5
+
6
+ class TestDiffieHellmanGroupExchangeSHA256 < TestDiffieHellmanGroupExchangeSHA1
7
+ private
8
+
9
+ def subject
10
+ Net::SSH::Transport::Kex::DiffieHellmanGroupExchangeSHA256
11
+ end
12
+
13
+ def session_id
14
+ @session_id ||= begin
15
+ buffer = Net::SSH::Buffer.from(:string, packet_data[:client_version_string],
16
+ :string, packet_data[:server_version_string],
17
+ :string, packet_data[:client_algorithm_packet],
18
+ :string, packet_data[:server_algorithm_packet],
19
+ :string, Net::SSH::Buffer.from(:key, server_key),
20
+ :long, 1024,
21
+ :long, 1024,
22
+ :long, 8192,
23
+ :bignum, dh.dh.p,
24
+ :bignum, dh.dh.g,
25
+ :bignum, dh.dh.pub_key,
26
+ :bignum, server_dh_pubkey,
27
+ :bignum, shared_secret)
28
+ OpenSSL::Digest::SHA256.digest(buffer.to_s)
29
+ end
30
+ end
31
+ end
32
+
33
+ end; end
@@ -0,0 +1,308 @@
1
+ require 'common'
2
+ require 'net/ssh/transport/algorithms'
3
+
4
+ module Transport
5
+
6
+ class TestAlgorithms < Test::Unit::TestCase
7
+ include Net::SSH::Transport::Constants
8
+
9
+ def test_allowed_packets
10
+ (0..255).each do |type|
11
+ packet = stub("packet", :type => type)
12
+ case type
13
+ when 1..4, 6..19, 21..49 then assert(Net::SSH::Transport::Algorithms.allowed_packet?(packet), "#{type} should be allowed during key exchange")
14
+ else assert(!Net::SSH::Transport::Algorithms.allowed_packet?(packet), "#{type} should not be allowed during key exchange")
15
+ end
16
+ end
17
+ end
18
+
19
+ def test_constructor_should_build_default_list_of_preferred_algorithms
20
+ assert_equal %w(ssh-rsa ssh-dss), algorithms[:host_key]
21
+ assert_equal %w(diffie-hellman-group-exchange-sha1 diffie-hellman-group1-sha1 diffie-hellman-group-exchange-sha256), algorithms[:kex]
22
+ assert_equal %w(aes128-cbc 3des-cbc blowfish-cbc cast128-cbc aes192-cbc aes256-cbc rijndael-cbc@lysator.liu.se idea-cbc none arcfour128 arcfour256), algorithms[:encryption]
23
+ if defined?(OpenSSL::Digest::SHA256)
24
+ assert_equal %w(hmac-sha1 hmac-md5 hmac-sha1-96 hmac-md5-96 hmac-sha2-256 hmac-sha2-512 hmac-sha2-256-96 hmac-sha2-512-96 none), algorithms[:hmac]
25
+ else
26
+ assert_equal %w(hmac-sha1 hmac-md5 hmac-sha1-96 hmac-md5-96 none), algorithms[:hmac]
27
+ end
28
+ assert_equal %w(none zlib@openssh.com zlib), algorithms[:compression]
29
+ assert_equal %w(), algorithms[:language]
30
+ end
31
+
32
+ def test_constructor_should_set_client_and_server_prefs_identically
33
+ %w(encryption hmac compression language).each do |key|
34
+ assert_equal algorithms[key.to_sym], algorithms[:"#{key}_client"], key
35
+ assert_equal algorithms[key.to_sym], algorithms[:"#{key}_server"], key
36
+ end
37
+ end
38
+
39
+ def test_constructor_with_preferred_host_key_type_should_put_preferred_host_key_type_first
40
+ assert_equal %w(ssh-dss ssh-rsa), algorithms(:host_key => "ssh-dss")[:host_key]
41
+ end
42
+
43
+ def test_constructor_with_known_hosts_reporting_known_host_key_should_use_that_host_key_type
44
+ Net::SSH::KnownHosts.expects(:search_for).with("net.ssh.test,127.0.0.1", {}).returns([stub("key", :ssh_type => "ssh-dss")])
45
+ assert_equal %w(ssh-dss ssh-rsa), algorithms[:host_key]
46
+ end
47
+
48
+ def test_constructor_with_unrecognized_host_key_type_should_raise_exception
49
+ assert_raises(NotImplementedError) { algorithms(:host_key => "bogus") }
50
+ end
51
+
52
+ def test_constructor_with_preferred_kex_should_put_preferred_kex_first
53
+ assert_equal %w(diffie-hellman-group1-sha1 diffie-hellman-group-exchange-sha1 diffie-hellman-group-exchange-sha256), algorithms(:kex => "diffie-hellman-group1-sha1")[:kex]
54
+ end
55
+
56
+ def test_constructor_with_unrecognized_kex_should_raise_exception
57
+ assert_raises(NotImplementedError) { algorithms(:kex => "bogus") }
58
+ end
59
+
60
+ def test_constructor_with_preferred_encryption_should_put_preferred_encryption_first
61
+ assert_equal %w(aes256-cbc aes128-cbc 3des-cbc blowfish-cbc cast128-cbc aes192-cbc rijndael-cbc@lysator.liu.se idea-cbc none arcfour128 arcfour256), algorithms(:encryption => "aes256-cbc")[:encryption]
62
+ end
63
+
64
+ def test_constructor_with_multiple_preferred_encryption_should_put_all_preferred_encryption_first
65
+ assert_equal %w(aes256-cbc 3des-cbc idea-cbc aes128-cbc blowfish-cbc cast128-cbc aes192-cbc rijndael-cbc@lysator.liu.se none arcfour128 arcfour256), algorithms(:encryption => %w(aes256-cbc 3des-cbc idea-cbc))[:encryption]
66
+ end
67
+
68
+ def test_constructor_with_unrecognized_encryption_should_raise_exception
69
+ assert_raises(NotImplementedError) { algorithms(:encryption => "bogus") }
70
+ end
71
+
72
+ def test_constructor_with_preferred_hmac_should_put_preferred_hmac_first
73
+ assert_equal %w(hmac-md5-96 hmac-sha1 hmac-md5 hmac-sha1-96 hmac-sha2-256 hmac-sha2-512 hmac-sha2-256-96 hmac-sha2-512-96 none), algorithms(:hmac => "hmac-md5-96")[:hmac]
74
+ end
75
+
76
+ def test_constructor_with_multiple_preferred_hmac_should_put_all_preferred_hmac_first
77
+ assert_equal %w(hmac-md5-96 hmac-sha1-96 hmac-sha1 hmac-md5 hmac-sha2-256 hmac-sha2-512 hmac-sha2-256-96 hmac-sha2-512-96 none), algorithms(:hmac => %w(hmac-md5-96 hmac-sha1-96))[:hmac]
78
+ end
79
+
80
+ def test_constructor_with_unrecognized_hmac_should_raise_exception
81
+ assert_raises(NotImplementedError) { algorithms(:hmac => "bogus") }
82
+ end
83
+
84
+ def test_constructor_with_preferred_compression_should_put_preferred_compression_first
85
+ assert_equal %w(zlib none zlib@openssh.com), algorithms(:compression => "zlib")[:compression]
86
+ end
87
+
88
+ def test_constructor_with_multiple_preferred_compression_should_put_all_preferred_compression_first
89
+ assert_equal %w(zlib@openssh.com zlib none), algorithms(:compression => %w(zlib@openssh.com zlib))[:compression]
90
+ end
91
+
92
+ def test_constructor_with_general_preferred_compression_should_put_none_last
93
+ assert_equal %w(zlib@openssh.com zlib none), algorithms(:compression => true)[:compression]
94
+ end
95
+
96
+ def test_constructor_with_unrecognized_compression_should_raise_exception
97
+ assert_raises(NotImplementedError) { algorithms(:compression => "bogus") }
98
+ end
99
+
100
+ def test_initial_state_should_be_neither_pending_nor_initialized
101
+ assert !algorithms.pending?
102
+ assert !algorithms.initialized?
103
+ end
104
+
105
+ def test_key_exchange_when_initiated_by_server
106
+ transport.expect do |t, buffer|
107
+ assert_kexinit(buffer)
108
+ install_mock_key_exchange(buffer)
109
+ end
110
+
111
+ install_mock_algorithm_lookups
112
+ algorithms.accept_kexinit(kexinit)
113
+
114
+ assert_exchange_results
115
+ end
116
+
117
+ def test_key_exchange_when_initiated_by_client
118
+ state = nil
119
+ transport.expect do |t, buffer|
120
+ assert_kexinit(buffer)
121
+ state = :sent_kexinit
122
+ install_mock_key_exchange(buffer)
123
+ end
124
+
125
+ algorithms.rekey!
126
+ assert_equal state, :sent_kexinit
127
+ assert algorithms.pending?
128
+
129
+ install_mock_algorithm_lookups
130
+ algorithms.accept_kexinit(kexinit)
131
+
132
+ assert_exchange_results
133
+ end
134
+
135
+ def test_key_exchange_when_server_does_not_support_preferred_kex_should_fallback_to_secondary
136
+ kexinit :kex => "diffie-hellman-group1-sha1"
137
+ transport.expect do |t,buffer|
138
+ assert_kexinit(buffer)
139
+ install_mock_key_exchange(buffer, :kex => Net::SSH::Transport::Kex::DiffieHellmanGroup1SHA1)
140
+ end
141
+ algorithms.accept_kexinit(kexinit)
142
+ end
143
+
144
+ def test_key_exchange_when_server_does_not_support_any_preferred_kex_should_raise_error
145
+ kexinit :kex => "something-obscure"
146
+ transport.expect { |t,buffer| assert_kexinit(buffer) }
147
+ assert_raises(Net::SSH::Exception) { algorithms.accept_kexinit(kexinit) }
148
+ end
149
+
150
+ def test_allow_when_not_pending_should_be_true_for_all_packets
151
+ (0..255).each do |type|
152
+ packet = stub("packet", :type => type)
153
+ assert algorithms.allow?(packet), type.to_s
154
+ end
155
+ end
156
+
157
+ def test_allow_when_pending_should_be_true_only_for_packets_valid_during_key_exchange
158
+ transport.expect!
159
+ algorithms.rekey!
160
+ assert algorithms.pending?
161
+
162
+ (0..255).each do |type|
163
+ packet = stub("packet", :type => type)
164
+ case type
165
+ when 1..4, 6..19, 21..49 then assert(algorithms.allow?(packet), "#{type} should be allowed during key exchange")
166
+ else assert(!algorithms.allow?(packet), "#{type} should not be allowed during key exchange")
167
+ end
168
+ end
169
+ end
170
+
171
+ def test_exchange_with_zlib_compression_enabled_sets_compression_to_standard
172
+ algorithms :compression => "zlib"
173
+
174
+ transport.expect do |t, buffer|
175
+ assert_kexinit(buffer, :compression_client => "zlib,none,zlib@openssh.com", :compression_server => "zlib,none,zlib@openssh.com")
176
+ install_mock_key_exchange(buffer)
177
+ end
178
+
179
+ install_mock_algorithm_lookups
180
+ algorithms.accept_kexinit(kexinit)
181
+
182
+ assert_equal :standard, transport.client_options[:compression]
183
+ assert_equal :standard, transport.server_options[:compression]
184
+ end
185
+
186
+ def test_exchange_with_zlib_at_openssh_dot_com_compression_enabled_sets_compression_to_delayed
187
+ algorithms :compression => "zlib@openssh.com"
188
+
189
+ transport.expect do |t, buffer|
190
+ assert_kexinit(buffer, :compression_client => "zlib@openssh.com,none,zlib", :compression_server => "zlib@openssh.com,none,zlib")
191
+ install_mock_key_exchange(buffer)
192
+ end
193
+
194
+ install_mock_algorithm_lookups
195
+ algorithms.accept_kexinit(kexinit)
196
+
197
+ assert_equal :delayed, transport.client_options[:compression]
198
+ assert_equal :delayed, transport.server_options[:compression]
199
+ end
200
+
201
+ private
202
+
203
+ def install_mock_key_exchange(buffer, options={})
204
+ kex = options[:kex] || Net::SSH::Transport::Kex::DiffieHellmanGroupExchangeSHA1
205
+
206
+ Net::SSH::Transport::Kex::MAP.each do |name, klass|
207
+ next if klass == kex
208
+ klass.expects(:new).never
209
+ end
210
+
211
+ kex.expects(:new).
212
+ with(algorithms, transport,
213
+ :client_version_string => Net::SSH::Transport::ServerVersion::PROTO_VERSION,
214
+ :server_version_string => transport.server_version.version,
215
+ :server_algorithm_packet => kexinit.to_s,
216
+ :client_algorithm_packet => buffer.to_s,
217
+ :need_bytes => 20,
218
+ :logger => nil).
219
+ returns(stub("kex", :exchange_keys => { :shared_secret => shared_secret, :session_id => session_id, :hashing_algorithm => hashing_algorithm }))
220
+ end
221
+
222
+ def install_mock_algorithm_lookups(options={})
223
+ params = { :shared => shared_secret.to_ssh, :hash => session_id, :digester => hashing_algorithm }
224
+ Net::SSH::Transport::CipherFactory.expects(:get).
225
+ with(options[:client_cipher] || "aes128-cbc", params.merge(:iv => key("A"), :key => key("C"), :encrypt => true)).
226
+ returns(:client_cipher)
227
+
228
+ Net::SSH::Transport::CipherFactory.expects(:get).
229
+ with(options[:server_cipher] || "aes128-cbc", params.merge(:iv => key("B"), :key => key("D"), :decrypt => true)).
230
+ returns(:server_cipher)
231
+
232
+ Net::SSH::Transport::HMAC.expects(:get).with(options[:client_hmac] || "hmac-sha1", key("E"), params).returns(:client_hmac)
233
+ Net::SSH::Transport::HMAC.expects(:get).with(options[:server_hmac] || "hmac-sha1", key("F"), params).returns(:server_hmac)
234
+ end
235
+
236
+ def shared_secret
237
+ @shared_secret ||= OpenSSL::BN.new("1234567890", 10)
238
+ end
239
+
240
+ def session_id
241
+ @session_id ||= "this is the session id"
242
+ end
243
+
244
+ def hashing_algorithm
245
+ OpenSSL::Digest::SHA1
246
+ end
247
+
248
+ def key(salt)
249
+ hashing_algorithm.digest(shared_secret.to_ssh + session_id + salt + session_id)
250
+ end
251
+
252
+ def cipher(type, options={})
253
+ Net::SSH::Transport::CipherFactory.get(type, options)
254
+ end
255
+
256
+ def kexinit(options={})
257
+ @kexinit ||= P(:byte, KEXINIT,
258
+ :long, rand(0xFFFFFFFF), :long, rand(0xFFFFFFFF), :long, rand(0xFFFFFFFF), :long, rand(0xFFFFFFFF),
259
+ :string, options[:kex] || "diffie-hellman-group-exchange-sha1,diffie-hellman-group1-sha1,diffie-hellman-group-exchange-sha256",
260
+ :string, options[:host_key] || "ssh-rsa,ssh-dss",
261
+ :string, options[:encryption_client] || "aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc,aes256-cbc,rijndael-cbc@lysator.liu.se,idea-cbc",
262
+ :string, options[:encryption_server] || "aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc,aes256-cbc,rijndael-cbc@lysator.liu.se,idea-cbc",
263
+ :string, options[:hmac_client] || "hmac-sha1,hmac-md5,hmac-sha1-96,hmac-md5-96",
264
+ :string, options[:hmac_server] || "hmac-sha1,hmac-md5,hmac-sha1-96,hmac-md5-96",
265
+ :string, options[:compmression_client] || "none,zlib@openssh.com,zlib",
266
+ :string, options[:compmression_server] || "none,zlib@openssh.com,zlib",
267
+ :string, options[:language_client] || "",
268
+ :string, options[:langauge_server] || "",
269
+ :bool, options[:first_kex_follows])
270
+ end
271
+
272
+ def assert_kexinit(buffer, options={})
273
+ assert_equal KEXINIT, buffer.type
274
+ assert_equal 16, buffer.read(16).length
275
+ assert_equal options[:kex] || "diffie-hellman-group-exchange-sha1,diffie-hellman-group1-sha1,diffie-hellman-group-exchange-sha256", buffer.read_string
276
+ assert_equal options[:host_key] || "ssh-rsa,ssh-dss", buffer.read_string
277
+ assert_equal options[:encryption_client] || "aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc,aes256-cbc,rijndael-cbc@lysator.liu.se,idea-cbc,none,arcfour128,arcfour256", buffer.read_string
278
+ assert_equal options[:encryption_server] || "aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc,aes256-cbc,rijndael-cbc@lysator.liu.se,idea-cbc,none,arcfour128,arcfour256", buffer.read_string
279
+ assert_equal options[:hmac_client] || "hmac-sha1,hmac-md5,hmac-sha1-96,hmac-md5-96,hmac-sha2-256,hmac-sha2-512,hmac-sha2-256-96,hmac-sha2-512-96,none", buffer.read_string
280
+ assert_equal options[:hmac_server] || "hmac-sha1,hmac-md5,hmac-sha1-96,hmac-md5-96,hmac-sha2-256,hmac-sha2-512,hmac-sha2-256-96,hmac-sha2-512-96,none", buffer.read_string
281
+ assert_equal options[:compression_client] || "none,zlib@openssh.com,zlib", buffer.read_string
282
+ assert_equal options[:compression_server] || "none,zlib@openssh.com,zlib", buffer.read_string
283
+ assert_equal options[:language_client] || "", buffer.read_string
284
+ assert_equal options[:language_server] || "", buffer.read_string
285
+ assert_equal options[:first_kex_follows] || false, buffer.read_bool
286
+ end
287
+
288
+ def assert_exchange_results
289
+ assert algorithms.initialized?
290
+ assert !algorithms.pending?
291
+ assert !transport.client_options[:compression]
292
+ assert !transport.server_options[:compression]
293
+ assert_equal :client_cipher, transport.client_options[:cipher]
294
+ assert_equal :server_cipher, transport.server_options[:cipher]
295
+ assert_equal :client_hmac, transport.client_options[:hmac]
296
+ assert_equal :server_hmac, transport.server_options[:hmac]
297
+ end
298
+
299
+ def algorithms(options={})
300
+ @algorithms ||= Net::SSH::Transport::Algorithms.new(transport, options)
301
+ end
302
+
303
+ def transport
304
+ @transport ||= MockTransport.new
305
+ end
306
+ end
307
+
308
+ end
@@ -0,0 +1,213 @@
1
+ require 'common'
2
+ require 'net/ssh/transport/cipher_factory'
3
+
4
+ module Transport
5
+
6
+ class TestCipherFactory < Test::Unit::TestCase
7
+ def self.if_supported?(name)
8
+ yield if Net::SSH::Transport::CipherFactory.supported?(name)
9
+ end
10
+
11
+ def test_lengths_for_none
12
+ assert_equal [0,0], factory.get_lengths("none")
13
+ assert_equal [0,0], factory.get_lengths("bogus")
14
+ end
15
+
16
+ def test_lengths_for_blowfish_cbc
17
+ assert_equal [16,8], factory.get_lengths("blowfish-cbc")
18
+ end
19
+
20
+ if_supported?("idea-cbc") do
21
+ def test_lengths_for_idea_cbc
22
+ assert_equal [16,8], factory.get_lengths("idea-cbc")
23
+ end
24
+ end
25
+
26
+ def test_lengths_for_rijndael_cbc
27
+ assert_equal [32,16], factory.get_lengths("rijndael-cbc@lysator.liu.se")
28
+ end
29
+
30
+ def test_lengths_for_cast128_cbc
31
+ assert_equal [16,8], factory.get_lengths("cast128-cbc")
32
+ end
33
+
34
+ def test_lengths_for_3des_cbc
35
+ assert_equal [24,8], factory.get_lengths("3des-cbc")
36
+ end
37
+
38
+ def test_lengths_for_aes192_cbc
39
+ assert_equal [24,16], factory.get_lengths("aes192-cbc")
40
+ end
41
+
42
+ def test_lengths_for_aes128_cbc
43
+ assert_equal [16,16], factory.get_lengths("aes128-cbc")
44
+ end
45
+
46
+ def test_lengths_for_aes256_cbc
47
+ assert_equal [32,16], factory.get_lengths("aes256-cbc")
48
+ end
49
+
50
+ def test_lengths_for_arcfour128
51
+ assert_equal [16,8], factory.get_lengths("arcfour128")
52
+ end
53
+
54
+ def test_lengths_for_arcfour256
55
+ assert_equal [32,8], factory.get_lengths("arcfour256")
56
+ end
57
+
58
+ def test_lengths_for_arcfour512
59
+ assert_equal [64,8], factory.get_lengths("arcfour512")
60
+ end
61
+
62
+ BLOWFISH = "\210\021\200\315\240_\026$\352\204g\233\244\242x\332e\370\001\327\224Nv@9_\323\037\252kb\037\036\237\375]\343/y\037\237\312Q\f7]\347Y\005\275%\377\0010$G\272\250B\265Nd\375\342\372\025r6}+Y\213y\n\237\267\\\374^\346BdJ$\353\220Ik\023<\236&H\277=\225"
63
+
64
+ def test_blowfish_cbc_for_encryption
65
+ assert_equal BLOWFISH, encrypt("blowfish-cbc")
66
+ end
67
+
68
+ def test_blowfish_cbc_for_decryption
69
+ assert_equal TEXT, decrypt("blowfish-cbc", BLOWFISH)
70
+ end
71
+
72
+ if_supported?("idea-cbc") do
73
+ IDEA = "W\234\017G\231\b\357\370H\b\256U]\343M\031k\233]~\023C\363\263\177\262-\261\341$\022\376mv\217\322\b\2763\270H\306\035\343z\313\312\3531\351\t\201\302U\022\360\300\354ul7$z\320O]\360g\024\305\005`V\005\335A\351\312\270c\320D\232\eQH1\340\265\2118\031g*\303v"
74
+
75
+ def test_idea_cbc_for_encryption
76
+ assert_equal IDEA, encrypt("idea-cbc")
77
+ end
78
+
79
+ def test_idea_cbc_for_decryption
80
+ assert_equal TEXT, decrypt("idea-cbc", IDEA)
81
+ end
82
+ end
83
+
84
+ RIJNDAEL = "$\253\271\255\005Z\354\336&\312\324\221\233\307Mj\315\360\310Fk\241EfN\037\231\213\361{'\310\204\347I\343\271\005\240`\325;\034\346uM>#\241\231C`\374\261\vo\226;Z\302:\b\250\366T\330\\#V\330\340\226\363\374!\bm\266\232\207!\232\347\340\t\307\370\356z\236\343=v\210\206y"
85
+
86
+ def test_rijndael_cbc_for_encryption
87
+ assert_equal RIJNDAEL, encrypt("rijndael-cbc@lysator.liu.se")
88
+ end
89
+
90
+ def test_rijndael_cbc_for_decryption
91
+ assert_equal TEXT, decrypt("rijndael-cbc@lysator.liu.se", RIJNDAEL)
92
+ end
93
+
94
+ CAST128 = "qW\302\331\333P\223t[9 ~(sg\322\271\227\272\022I\223\373p\255>k\326\314\260\2003\236C_W\211\227\373\205>\351\334\322\227\223\e\236\202Ii\032!P\214\035:\017\360h7D\371v\210\264\317\236a\262w1\2772\023\036\331\227\240:\f/X\351\324I\t[x\350\323E\2301\016m"
95
+
96
+ def test_cast128_cbc_for_encryption
97
+ assert_equal CAST128, encrypt("cast128-cbc")
98
+ end
99
+
100
+ def test_cast128_cbc_for_decryption
101
+ assert_equal TEXT, decrypt("cast128-cbc", CAST128)
102
+ end
103
+
104
+ TRIPLE_DES = "\322\252\216D\303Q\375gg\367A{\177\313\3436\272\353%\223K?\257\206|\r&\353/%\340\336 \203E8rY\206\234\004\274\267\031\233T/{\"\227/B!i?[qGaw\306T\206\223\213n \212\032\244%]@\355\250\334\312\265E\251\017\361\270\357\230\274KP&^\031r+r%\370"
105
+
106
+ def test_3des_cbc_for_encryption
107
+ assert_equal TRIPLE_DES, encrypt("3des-cbc")
108
+ end
109
+
110
+ def test_3des_cbc_for_decryption
111
+ assert_equal TEXT, decrypt("3des-cbc", TRIPLE_DES)
112
+ end
113
+
114
+ AES128 = "k\026\350B\366-k\224\313\3277}B\035\004\200\035\r\233\024$\205\261\231Q\2214r\245\250\360\315\237\266hg\262C&+\321\346Pf\267v\376I\215P\327\345-\232&HK\375\326_\030<\a\276\212\303g\342C\242O\233\260\006\001a&V\345`\\T\e\236.\207\223l\233ri^\v\252\363\245"
115
+
116
+ def test_aes128_cbc_for_encryption
117
+ assert_equal AES128, encrypt("aes128-cbc")
118
+ end
119
+
120
+ def test_aes128_cbc_for_decryption
121
+ assert_equal TEXT, decrypt("aes128-cbc", AES128)
122
+ end
123
+
124
+ AES192 = "\256\017)x\270\213\336\303L\003f\235'jQ\3231k9\225\267\242\364C4\370\224\201\302~\217I\202\374\2167='\272\037\225\223\177Y\r\212\376(\275\n\3553\377\177\252C\254\236\016MA\274Z@H\331<\rL\317\205\323[\305X8\376\237=\374\352bH9\244\0231\353\204\352p\226\326~J\242"
125
+
126
+ def test_aes192_cbc_for_encryption
127
+ assert_equal AES192, encrypt("aes192-cbc")
128
+ end
129
+
130
+ def test_aes192_cbc_for_decryption
131
+ assert_equal TEXT, decrypt("aes192-cbc", AES192)
132
+ end
133
+
134
+ AES256 = "$\253\271\255\005Z\354\336&\312\324\221\233\307Mj\315\360\310Fk\241EfN\037\231\213\361{'\310\204\347I\343\271\005\240`\325;\034\346uM>#\241\231C`\374\261\vo\226;Z\302:\b\250\366T\330\\#V\330\340\226\363\374!\bm\266\232\207!\232\347\340\t\307\370\356z\236\343=v\210\206y"
135
+
136
+ def test_aes256_cbc_for_encryption
137
+ assert_equal AES256, encrypt("aes256-cbc")
138
+ end
139
+
140
+ def test_aes256_cbc_for_decryption
141
+ assert_equal TEXT, decrypt("aes256-cbc", AES256)
142
+ end
143
+
144
+ ARCFOUR128 = "\n\x90\xED*\xD4\xBE\xCBg5\xA5\a\xEC]\x97\xB7L\x06)6\x12FL\x90@\xF4Sqxqh\r\x11\x1Aq \xC8\xE6v\xC6\x12\xD9<A\xDAZ\xFE\x7F\x88\x19f.\x06\xA7\xFE:\xFF\x93\x9B\x8D\xA0\\\x9E\xCA\x03\x15\xE1\xE2\f\xC0\b\xA2C\xE1\xBD\xB6\x13D\xD1\xB4'g\x89\xDC\xEB\f\x19Z)U"
145
+
146
+ def test_arcfour128_for_encryption
147
+ assert_equal ARCFOUR128, encrypt("arcfour128")
148
+ end
149
+
150
+ def test_arcfour128_for_decryption
151
+ assert_equal TEXT, decrypt("arcfour128", ARCFOUR128)
152
+ end
153
+
154
+ ARCFOUR256 = "|g\xCCw\xF5\xC1y\xEB\xF0\v\xF7\x83\x14\x03\xC8\xAB\xE8\xC2\xFCY\xDC,\xB8\xD4dVa\x8B\x18%\xA4S\x00\xE0at\x86\xE8\xA6W\xAB\xD2\x9D\xA8\xDE[g\aZy.\xFB\xFC\x82c\x04h\f\xBFYq\xB7U\x80\x0EG\x91\x88\xDF\xA3\xA2\xFA(\xEC\xDB\xA4\xE7\xFE)\x12u\xAF\x0EZ\xA0\xBA\x97\n\xFC"
155
+
156
+ def test_arcfour256_for_encryption
157
+ assert_equal ARCFOUR256, encrypt("arcfour256")
158
+ end
159
+
160
+ def test_arcfour256_for_decryption
161
+ assert_equal TEXT, decrypt("arcfour256", ARCFOUR256)
162
+ end
163
+
164
+ ARCFOUR512 = "|8\"v\xE7\xE3\b\xA8\x19\x9Aa\xB6Vv\x00\x11\x8A$C\xB6xE\xEF\xF1j\x90\xA8\xFA\x10\xE4\xA1b8\xF6\x04\xF2+\xC0\xD1(8\xEBT]\xB0\xF3/\xD9\xE0@\x83\a\x93\x9D\xCA\x04RXS\xB7A\x0Fj\x94\bE\xEB\x84j\xB4\xDF\nU\xF7\x83o\n\xE8\xF9\x01{jH\xEE\xCDQym\x9E"
165
+
166
+ def test_arcfour512_for_encryption
167
+ assert_equal ARCFOUR512, encrypt("arcfour512")
168
+ end
169
+
170
+ def test_arcfour512_for_decryption
171
+ assert_equal TEXT, decrypt("arcfour512", ARCFOUR512)
172
+ end
173
+
174
+ def test_none_for_encryption
175
+ assert_equal TEXT, encrypt("none").strip
176
+ end
177
+
178
+ def test_none_for_decryption
179
+ assert_equal TEXT, decrypt("none", TEXT)
180
+ end
181
+
182
+ private
183
+
184
+ TEXT = "But soft! What light through yonder window breaks? It is the east, and Juliet is the sun!"
185
+
186
+ OPTIONS = { :iv => "ABC",
187
+ :key => "abc",
188
+ :digester => OpenSSL::Digest::MD5,
189
+ :shared => "1234567890123456780",
190
+ :hash => '!@#$%#$^%$&^&%#$@$'
191
+ }
192
+
193
+ def factory
194
+ Net::SSH::Transport::CipherFactory
195
+ end
196
+
197
+ def encrypt(type)
198
+ cipher = factory.get(type, OPTIONS.merge(:encrypt => true))
199
+ padding = TEXT.length % cipher.block_size
200
+ result = cipher.update(TEXT.dup)
201
+ result << cipher.update(" " * (cipher.block_size - padding)) if padding > 0
202
+ result << cipher.final
203
+ end
204
+
205
+ def decrypt(type, data)
206
+ cipher = factory.get(type, OPTIONS.merge(:decrypt => true))
207
+ result = cipher.update(data.dup)
208
+ result << cipher.final
209
+ result.strip
210
+ end
211
+ end
212
+
213
+ end