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.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data/.dockerignore +6 -0
- data/.github/FUNDING.yml +1 -0
- data/.github/config/rubocop_linter_action.yml +4 -0
- data/.github/workflows/ci-with-docker.yml +44 -0
- data/.github/workflows/ci.yml +94 -0
- data/.github/workflows/rubocop.yml +16 -0
- data/.gitignore +15 -0
- data/.rubocop.yml +22 -0
- data/.rubocop_todo.yml +1081 -0
- data/CHANGES.txt +387 -0
- data/DEVELOPMENT.md +23 -0
- data/Dockerfile +29 -0
- data/Dockerfile.openssl3 +17 -0
- data/Gemfile +13 -0
- data/Gemfile.noed25519 +12 -0
- data/Gemfile.norbnacl +12 -0
- data/ISSUE_TEMPLATE.md +30 -0
- data/Manifest +4 -5
- data/README.md +303 -0
- data/Rakefile +174 -40
- data/SECURITY.md +4 -0
- data/THANKS.txt +25 -0
- data/appveyor.yml +58 -0
- data/docker-compose.yml +25 -0
- data/lib/net/ssh/authentication/agent.rb +279 -18
- data/lib/net/ssh/authentication/certificate.rb +183 -0
- data/lib/net/ssh/authentication/constants.rb +17 -15
- data/lib/net/ssh/authentication/ed25519.rb +184 -0
- data/lib/net/ssh/authentication/ed25519_loader.rb +31 -0
- data/lib/net/ssh/authentication/key_manager.rb +125 -54
- data/lib/net/ssh/authentication/methods/abstract.rb +67 -48
- data/lib/net/ssh/authentication/methods/hostbased.rb +34 -37
- data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +19 -12
- data/lib/net/ssh/authentication/methods/none.rb +16 -19
- data/lib/net/ssh/authentication/methods/password.rb +56 -19
- data/lib/net/ssh/authentication/methods/publickey.rb +96 -55
- data/lib/net/ssh/authentication/pageant.rb +483 -246
- data/lib/net/ssh/authentication/pub_key_fingerprint.rb +43 -0
- data/lib/net/ssh/authentication/session.rb +138 -120
- data/lib/net/ssh/buffer.rb +399 -300
- data/lib/net/ssh/buffered_io.rb +154 -150
- data/lib/net/ssh/config.rb +361 -166
- data/lib/net/ssh/connection/channel.rb +640 -596
- data/lib/net/ssh/connection/constants.rb +29 -29
- data/lib/net/ssh/connection/event_loop.rb +123 -0
- data/lib/net/ssh/connection/keepalive.rb +59 -0
- data/lib/net/ssh/connection/session.rb +628 -548
- data/lib/net/ssh/connection/term.rb +125 -123
- data/lib/net/ssh/errors.rb +101 -95
- data/lib/net/ssh/key_factory.rb +198 -100
- data/lib/net/ssh/known_hosts.rb +221 -98
- data/lib/net/ssh/loggable.rb +50 -49
- data/lib/net/ssh/packet.rb +83 -79
- data/lib/net/ssh/prompt.rb +50 -81
- data/lib/net/ssh/proxy/command.rb +108 -60
- data/lib/net/ssh/proxy/errors.rb +12 -10
- data/lib/net/ssh/proxy/http.rb +82 -78
- data/lib/net/ssh/proxy/https.rb +50 -0
- data/lib/net/ssh/proxy/jump.rb +54 -0
- data/lib/net/ssh/proxy/socks4.rb +5 -8
- data/lib/net/ssh/proxy/socks5.rb +18 -20
- data/lib/net/ssh/service/forward.rb +383 -255
- data/lib/net/ssh/test/channel.rb +145 -136
- data/lib/net/ssh/test/extensions.rb +131 -110
- data/lib/net/ssh/test/kex.rb +34 -32
- data/lib/net/ssh/test/local_packet.rb +46 -44
- data/lib/net/ssh/test/packet.rb +89 -70
- data/lib/net/ssh/test/remote_packet.rb +32 -30
- data/lib/net/ssh/test/script.rb +156 -142
- data/lib/net/ssh/test/socket.rb +49 -48
- data/lib/net/ssh/test.rb +82 -77
- data/lib/net/ssh/transport/aes128_gcm.rb +40 -0
- data/lib/net/ssh/transport/aes256_gcm.rb +40 -0
- data/lib/net/ssh/transport/algorithms.rb +472 -348
- data/lib/net/ssh/transport/chacha20_poly1305_cipher.rb +117 -0
- data/lib/net/ssh/transport/chacha20_poly1305_cipher_loader.rb +17 -0
- data/lib/net/ssh/transport/cipher_factory.rb +124 -100
- data/lib/net/ssh/transport/constants.rb +32 -24
- data/lib/net/ssh/transport/ctr.rb +42 -22
- data/lib/net/ssh/transport/gcm_cipher.rb +207 -0
- data/lib/net/ssh/transport/hmac/abstract.rb +97 -63
- data/lib/net/ssh/transport/hmac/md5.rb +0 -2
- data/lib/net/ssh/transport/hmac/md5_96.rb +0 -2
- data/lib/net/ssh/transport/hmac/none.rb +0 -2
- data/lib/net/ssh/transport/hmac/ripemd160.rb +0 -2
- data/lib/net/ssh/transport/hmac/sha1.rb +0 -2
- data/lib/net/ssh/transport/hmac/sha1_96.rb +0 -2
- data/lib/net/ssh/transport/hmac/sha2_256.rb +7 -11
- data/lib/net/ssh/transport/hmac/sha2_256_96.rb +4 -8
- data/lib/net/ssh/transport/hmac/sha2_256_etm.rb +12 -0
- data/lib/net/ssh/transport/hmac/sha2_512.rb +6 -9
- data/lib/net/ssh/transport/hmac/sha2_512_96.rb +4 -8
- data/lib/net/ssh/transport/hmac/sha2_512_etm.rb +12 -0
- data/lib/net/ssh/transport/hmac.rb +14 -12
- data/lib/net/ssh/transport/identity_cipher.rb +54 -44
- data/lib/net/ssh/transport/kex/abstract.rb +130 -0
- data/lib/net/ssh/transport/kex/abstract5656.rb +72 -0
- data/lib/net/ssh/transport/kex/curve25519_sha256.rb +39 -0
- data/lib/net/ssh/transport/kex/curve25519_sha256_loader.rb +30 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +33 -40
- data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +119 -213
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +53 -61
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +5 -9
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +36 -90
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +18 -10
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +18 -10
- data/lib/net/ssh/transport/kex.rb +15 -12
- data/lib/net/ssh/transport/key_expander.rb +24 -20
- data/lib/net/ssh/transport/openssl.rb +161 -124
- data/lib/net/ssh/transport/openssl_cipher_extensions.rb +8 -0
- data/lib/net/ssh/transport/packet_stream.rb +246 -183
- data/lib/net/ssh/transport/server_version.rb +57 -51
- data/lib/net/ssh/transport/session.rb +307 -235
- data/lib/net/ssh/transport/state.rb +178 -176
- data/lib/net/ssh/verifiers/accept_new.rb +33 -0
- data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +33 -0
- data/lib/net/ssh/verifiers/always.rb +58 -0
- data/lib/net/ssh/verifiers/never.rb +19 -0
- data/lib/net/ssh/version.rb +57 -51
- data/lib/net/ssh.rb +140 -40
- data/net-ssh-public_cert.pem +21 -0
- data/net-ssh.gemspec +39 -184
- data/support/ssh_tunnel_bug.rb +5 -5
- data.tar.gz.sig +0 -0
- metadata +205 -99
- metadata.gz.sig +0 -0
- data/README.rdoc +0 -219
- data/Rudyfile +0 -96
- data/gem-public_cert.pem +0 -20
- data/lib/net/ssh/authentication/agent/java_pageant.rb +0 -85
- data/lib/net/ssh/authentication/agent/socket.rb +0 -170
- data/lib/net/ssh/ruby_compat.rb +0 -51
- data/lib/net/ssh/verifiers/lenient.rb +0 -30
- data/lib/net/ssh/verifiers/null.rb +0 -12
- data/lib/net/ssh/verifiers/secure.rb +0 -54
- data/lib/net/ssh/verifiers/strict.rb +0 -24
- data/setup.rb +0 -1585
- data/support/arcfour_check.rb +0 -20
- data/test/README.txt +0 -47
- data/test/authentication/methods/common.rb +0 -28
- data/test/authentication/methods/test_abstract.rb +0 -51
- data/test/authentication/methods/test_hostbased.rb +0 -114
- data/test/authentication/methods/test_keyboard_interactive.rb +0 -100
- data/test/authentication/methods/test_none.rb +0 -41
- data/test/authentication/methods/test_password.rb +0 -52
- data/test/authentication/methods/test_publickey.rb +0 -148
- data/test/authentication/test_agent.rb +0 -205
- data/test/authentication/test_key_manager.rb +0 -218
- data/test/authentication/test_session.rb +0 -108
- data/test/common.rb +0 -108
- data/test/configs/eqsign +0 -3
- data/test/configs/exact_match +0 -8
- data/test/configs/host_plus +0 -10
- data/test/configs/multihost +0 -4
- data/test/configs/nohost +0 -19
- data/test/configs/numeric_host +0 -4
- data/test/configs/send_env +0 -2
- data/test/configs/substitutes +0 -8
- data/test/configs/wild_cards +0 -14
- data/test/connection/test_channel.rb +0 -467
- data/test/connection/test_session.rb +0 -526
- data/test/known_hosts/github +0 -1
- data/test/manual/test_forward.rb +0 -223
- data/test/start/test_options.rb +0 -36
- data/test/start/test_transport.rb +0 -28
- data/test/test_all.rb +0 -11
- data/test/test_buffer.rb +0 -433
- data/test/test_buffered_io.rb +0 -63
- data/test/test_config.rb +0 -151
- data/test/test_key_factory.rb +0 -173
- data/test/test_known_hosts.rb +0 -13
- data/test/transport/hmac/test_md5.rb +0 -41
- data/test/transport/hmac/test_md5_96.rb +0 -27
- data/test/transport/hmac/test_none.rb +0 -34
- data/test/transport/hmac/test_ripemd160.rb +0 -36
- data/test/transport/hmac/test_sha1.rb +0 -36
- data/test/transport/hmac/test_sha1_96.rb +0 -27
- data/test/transport/hmac/test_sha2_256.rb +0 -37
- data/test/transport/hmac/test_sha2_256_96.rb +0 -27
- data/test/transport/hmac/test_sha2_512.rb +0 -37
- data/test/transport/hmac/test_sha2_512_96.rb +0 -27
- data/test/transport/kex/test_diffie_hellman_group14_sha1.rb +0 -13
- data/test/transport/kex/test_diffie_hellman_group1_sha1.rb +0 -146
- data/test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb +0 -92
- data/test/transport/kex/test_diffie_hellman_group_exchange_sha256.rb +0 -34
- data/test/transport/kex/test_ecdh_sha2_nistp256.rb +0 -161
- data/test/transport/kex/test_ecdh_sha2_nistp384.rb +0 -38
- data/test/transport/kex/test_ecdh_sha2_nistp521.rb +0 -38
- data/test/transport/test_algorithms.rb +0 -330
- data/test/transport/test_cipher_factory.rb +0 -443
- data/test/transport/test_hmac.rb +0 -34
- data/test/transport/test_identity_cipher.rb +0 -40
- data/test/transport/test_packet_stream.rb +0 -1755
- data/test/transport/test_server_version.rb +0 -78
- data/test/transport/test_session.rb +0 -319
- 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
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
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
|
2
|
-
module
|
1
|
+
module Net
|
2
|
+
module SSH
|
3
|
+
module Transport
|
4
|
+
module Constants
|
5
|
+
#--
|
6
|
+
# Transport layer generic messages
|
7
|
+
#++
|
3
8
|
|
4
|
-
|
5
|
-
|
6
|
-
|
9
|
+
DISCONNECT = 1
|
10
|
+
IGNORE = 2
|
11
|
+
UNIMPLEMENTED = 3
|
12
|
+
DEBUG = 4
|
13
|
+
SERVICE_REQUEST = 5
|
14
|
+
SERVICE_ACCEPT = 6
|
7
15
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
DEBUG = 4
|
12
|
-
SERVICE_REQUEST = 5
|
13
|
-
SERVICE_ACCEPT = 6
|
16
|
+
#--
|
17
|
+
# Algorithm negotiation messages
|
18
|
+
#++
|
14
19
|
|
15
|
-
|
16
|
-
|
17
|
-
#++
|
20
|
+
KEXINIT = 20
|
21
|
+
NEWKEYS = 21
|
18
22
|
|
19
|
-
|
20
|
-
|
23
|
+
#--
|
24
|
+
# Key exchange method specific messages
|
25
|
+
#++
|
21
26
|
|
22
|
-
|
23
|
-
|
24
|
-
#++
|
27
|
+
KEXDH_INIT = 30
|
28
|
+
KEXDH_REPLY = 31
|
25
29
|
|
26
|
-
|
27
|
-
|
30
|
+
KEXECDH_INIT = 30
|
31
|
+
KEXECDH_REPLY = 31
|
28
32
|
|
29
|
-
|
30
|
-
|
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
|
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
|
-
|
18
|
-
|
19
|
-
|
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
|
-
|
56
|
-
|
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
|
-
|
66
|
-
|
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
|
-
|
111
|
+
singleton_class.send(:private, :increment_counter!)
|
112
|
+
}
|
93
113
|
end
|
94
114
|
end
|
95
115
|
end
|