hrr_rb_ssh 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +27 -0
- data/.rspec +3 -0
- data/.travis.yml +22 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/LICENSE +201 -0
- data/README.md +47 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/demo/server.rb +134 -0
- data/hrr_rb_ssh.gemspec +27 -0
- data/lib/hrr_rb_ssh/authentication/authenticator.rb +16 -0
- data/lib/hrr_rb_ssh/authentication/method/none/context.rb +28 -0
- data/lib/hrr_rb_ssh/authentication/method/none.rb +38 -0
- data/lib/hrr_rb_ssh/authentication/method/password/context.rb +29 -0
- data/lib/hrr_rb_ssh/authentication/method/password.rb +37 -0
- data/lib/hrr_rb_ssh/authentication/method.rb +21 -0
- data/lib/hrr_rb_ssh/authentication.rb +107 -0
- data/lib/hrr_rb_ssh/closed_authentication_error.rb +7 -0
- data/lib/hrr_rb_ssh/closed_connection_error.rb +7 -0
- data/lib/hrr_rb_ssh/closed_transport_error.rb +7 -0
- data/lib/hrr_rb_ssh/compat.rb +65 -0
- data/lib/hrr_rb_ssh/connection/channel/proc_chain/chain_context.rb +22 -0
- data/lib/hrr_rb_ssh/connection/channel/proc_chain.rb +25 -0
- data/lib/hrr_rb_ssh/connection/channel/session/env/context.rb +43 -0
- data/lib/hrr_rb_ssh/connection/channel/session/env.rb +31 -0
- data/lib/hrr_rb_ssh/connection/channel/session/exec/context.rb +41 -0
- data/lib/hrr_rb_ssh/connection/channel/session/exec.rb +31 -0
- data/lib/hrr_rb_ssh/connection/channel/session/pty_req/context.rb +50 -0
- data/lib/hrr_rb_ssh/connection/channel/session/pty_req.rb +31 -0
- data/lib/hrr_rb_ssh/connection/channel/session/shell/context.rb +37 -0
- data/lib/hrr_rb_ssh/connection/channel/session/shell.rb +31 -0
- data/lib/hrr_rb_ssh/connection/channel/session/subsystem/context.rb +40 -0
- data/lib/hrr_rb_ssh/connection/channel/session/subsystem.rb +31 -0
- data/lib/hrr_rb_ssh/connection/channel/session.rb +31 -0
- data/lib/hrr_rb_ssh/connection/channel.rb +278 -0
- data/lib/hrr_rb_ssh/connection/request_handler.rb +18 -0
- data/lib/hrr_rb_ssh/connection.rb +170 -0
- data/lib/hrr_rb_ssh/logger.rb +52 -0
- data/lib/hrr_rb_ssh/message/001_ssh_msg_disconnect.rb +44 -0
- data/lib/hrr_rb_ssh/message/002_ssh_msg_ignore.rb +24 -0
- data/lib/hrr_rb_ssh/message/003_ssh_msg_unimplemented.rb +24 -0
- data/lib/hrr_rb_ssh/message/004_ssh_msg_debug.rb +26 -0
- data/lib/hrr_rb_ssh/message/005_ssh_msg_service_request.rb +24 -0
- data/lib/hrr_rb_ssh/message/006_ssh_msg_service_accept.rb +24 -0
- data/lib/hrr_rb_ssh/message/020_ssh_msg_kexinit.rb +51 -0
- data/lib/hrr_rb_ssh/message/021_ssh_msg_newkeys.rb +23 -0
- data/lib/hrr_rb_ssh/message/030_ssh_msg_kexdh_init.rb +24 -0
- data/lib/hrr_rb_ssh/message/031_ssh_msg_kexdh_reply.rb +26 -0
- data/lib/hrr_rb_ssh/message/050_ssh_msg_userauth_request.rb +58 -0
- data/lib/hrr_rb_ssh/message/051_ssh_msg_userauth_failure.rb +25 -0
- data/lib/hrr_rb_ssh/message/052_ssh_msg_userauth_success.rb +23 -0
- data/lib/hrr_rb_ssh/message/060_ssh_msg_userauth_pk_ok.rb +25 -0
- data/lib/hrr_rb_ssh/message/080_ssh_msg_global_request.rb +47 -0
- data/lib/hrr_rb_ssh/message/081_ssh_msg_request_success.rb +36 -0
- data/lib/hrr_rb_ssh/message/082_ssh_msg_request_failure.rb +23 -0
- data/lib/hrr_rb_ssh/message/090_ssh_msg_channel_open.rb +67 -0
- data/lib/hrr_rb_ssh/message/091_ssh_msg_channel_open_confirmation.rb +67 -0
- data/lib/hrr_rb_ssh/message/092_ssh_msg_channel_open_failure.rb +34 -0
- data/lib/hrr_rb_ssh/message/093_ssh_msg_channel_window_adjust.rb +25 -0
- data/lib/hrr_rb_ssh/message/094_ssh_msg_channel_data.rb +25 -0
- data/lib/hrr_rb_ssh/message/095_ssh_msg_channel_extended_data.rb +30 -0
- data/lib/hrr_rb_ssh/message/096_ssh_msg_channel_eof.rb +24 -0
- data/lib/hrr_rb_ssh/message/097_ssh_msg_channel_close.rb +24 -0
- data/lib/hrr_rb_ssh/message/098_ssh_msg_channel_request.rb +139 -0
- data/lib/hrr_rb_ssh/message/099_ssh_msg_channel_success.rb +24 -0
- data/lib/hrr_rb_ssh/message/100_ssh_msg_channel_failure.rb +24 -0
- data/lib/hrr_rb_ssh/message/codable.rb +67 -0
- data/lib/hrr_rb_ssh/message.rb +36 -0
- data/lib/hrr_rb_ssh/transport/compression_algorithm/none.rb +33 -0
- data/lib/hrr_rb_ssh/transport/compression_algorithm/zlib.rb +38 -0
- data/lib/hrr_rb_ssh/transport/compression_algorithm.rb +22 -0
- data/lib/hrr_rb_ssh/transport/constant.rb +11 -0
- data/lib/hrr_rb_ssh/transport/data_type.rb +163 -0
- data/lib/hrr_rb_ssh/transport/encryption_algorithm/aes_128_cbc.rb +73 -0
- data/lib/hrr_rb_ssh/transport/encryption_algorithm/none.rb +49 -0
- data/lib/hrr_rb_ssh/transport/encryption_algorithm.rb +22 -0
- data/lib/hrr_rb_ssh/transport/kex_algorithm/diffie_hellman.rb +129 -0
- data/lib/hrr_rb_ssh/transport/kex_algorithm/diffie_hellman_group14_sha1.rb +42 -0
- data/lib/hrr_rb_ssh/transport/kex_algorithm/diffie_hellman_group1_sha1.rb +34 -0
- data/lib/hrr_rb_ssh/transport/kex_algorithm.rb +22 -0
- data/lib/hrr_rb_ssh/transport/mac_algorithm/hmac_sha1.rb +45 -0
- data/lib/hrr_rb_ssh/transport/mac_algorithm/none.rb +40 -0
- data/lib/hrr_rb_ssh/transport/mac_algorithm.rb +22 -0
- data/lib/hrr_rb_ssh/transport/mode.rb +11 -0
- data/lib/hrr_rb_ssh/transport/receiver.rb +75 -0
- data/lib/hrr_rb_ssh/transport/sender.rb +57 -0
- data/lib/hrr_rb_ssh/transport/sequence_number.rb +22 -0
- data/lib/hrr_rb_ssh/transport/server_host_key_algorithm/ssh_rsa.rb +108 -0
- data/lib/hrr_rb_ssh/transport/server_host_key_algorithm.rb +21 -0
- data/lib/hrr_rb_ssh/transport.rb +459 -0
- data/lib/hrr_rb_ssh/version.rb +6 -0
- data/lib/hrr_rb_ssh.rb +13 -0
- metadata +193 -0
@@ -0,0 +1,73 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
require 'openssl'
|
5
|
+
|
6
|
+
require 'hrr_rb_ssh/logger'
|
7
|
+
|
8
|
+
module HrrRbSsh
|
9
|
+
class Transport
|
10
|
+
class EncryptionAlgorithm
|
11
|
+
name_list = [
|
12
|
+
'aes128-cbc'
|
13
|
+
]
|
14
|
+
|
15
|
+
class Aes128Cbc
|
16
|
+
CIPHER_NAME = "AES-128-CBC"
|
17
|
+
|
18
|
+
BLOCK_SIZE = OpenSSL::Cipher.new(CIPHER_NAME).block_size
|
19
|
+
IV_LENGTH = OpenSSL::Cipher.new(CIPHER_NAME).iv_len
|
20
|
+
KEY_LENGTH = OpenSSL::Cipher.new(CIPHER_NAME).key_len
|
21
|
+
|
22
|
+
def initialize iv, key
|
23
|
+
@logger = HrrRbSsh::Logger.new self.class.name
|
24
|
+
|
25
|
+
@encryptor = OpenSSL::Cipher.new(CIPHER_NAME)
|
26
|
+
@encryptor.encrypt
|
27
|
+
@encryptor.padding = 0
|
28
|
+
@encryptor.iv = iv
|
29
|
+
@encryptor.key = key
|
30
|
+
|
31
|
+
@decryptor = OpenSSL::Cipher.new(CIPHER_NAME)
|
32
|
+
@decryptor.decrypt
|
33
|
+
@decryptor.padding = 0
|
34
|
+
@decryptor.iv = iv
|
35
|
+
@decryptor.key = key
|
36
|
+
end
|
37
|
+
|
38
|
+
def block_size
|
39
|
+
BLOCK_SIZE
|
40
|
+
end
|
41
|
+
|
42
|
+
def iv_length
|
43
|
+
IV_LENGTH
|
44
|
+
end
|
45
|
+
|
46
|
+
def key_length
|
47
|
+
KEY_LENGTH
|
48
|
+
end
|
49
|
+
|
50
|
+
def encrypt data
|
51
|
+
if data.empty?
|
52
|
+
data
|
53
|
+
else
|
54
|
+
@encryptor.update(data) + @encryptor.final
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def decrypt data
|
59
|
+
if data.empty?
|
60
|
+
data
|
61
|
+
else
|
62
|
+
@decryptor.update(data) + @decryptor.final
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
@@list ||= Hash.new
|
68
|
+
name_list.each do |name|
|
69
|
+
@@list[name] = Aes128Cbc
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
require 'hrr_rb_ssh/logger'
|
5
|
+
|
6
|
+
module HrrRbSsh
|
7
|
+
class Transport
|
8
|
+
class EncryptionAlgorithm
|
9
|
+
name_list = [
|
10
|
+
'none'
|
11
|
+
]
|
12
|
+
|
13
|
+
class None
|
14
|
+
BLOCK_SIZE = 0
|
15
|
+
IV_LENGTH = 0
|
16
|
+
KEY_LENGTH = 0
|
17
|
+
|
18
|
+
def initialize iv=nil, key=nil
|
19
|
+
@logger = HrrRbSsh::Logger.new self.class.name
|
20
|
+
end
|
21
|
+
|
22
|
+
def block_size
|
23
|
+
BLOCK_SIZE
|
24
|
+
end
|
25
|
+
|
26
|
+
def iv_length
|
27
|
+
IV_LENGTH
|
28
|
+
end
|
29
|
+
|
30
|
+
def key_length
|
31
|
+
KEY_LENGTH
|
32
|
+
end
|
33
|
+
|
34
|
+
def encrypt data
|
35
|
+
data
|
36
|
+
end
|
37
|
+
|
38
|
+
def decrypt data
|
39
|
+
data
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
@@list ||= Hash.new
|
44
|
+
name_list.each do |name|
|
45
|
+
@@list[name] = None
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
require 'hrr_rb_ssh/logger'
|
5
|
+
require 'hrr_rb_ssh/transport/encryption_algorithm/none'
|
6
|
+
require 'hrr_rb_ssh/transport/encryption_algorithm/aes_128_cbc'
|
7
|
+
|
8
|
+
module HrrRbSsh
|
9
|
+
class Transport
|
10
|
+
class EncryptionAlgorithm
|
11
|
+
@@list ||= Hash.new
|
12
|
+
|
13
|
+
def self.[] key
|
14
|
+
@@list[key]
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.name_list
|
18
|
+
@@list.keys
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
require 'hrr_rb_ssh/logger'
|
5
|
+
require 'hrr_rb_ssh/transport/data_type'
|
6
|
+
|
7
|
+
module HrrRbSsh
|
8
|
+
class Transport
|
9
|
+
class KexAlgorithm
|
10
|
+
class DiffieHellman
|
11
|
+
H0_DEFINITION = [
|
12
|
+
['string', 'V_C'],
|
13
|
+
['string', 'V_S'],
|
14
|
+
['string', 'I_C'],
|
15
|
+
['string', 'I_S'],
|
16
|
+
['string', 'K_S'],
|
17
|
+
['mpint', 'e'],
|
18
|
+
['mpint', 'f'],
|
19
|
+
['mpint', 'k'],
|
20
|
+
]
|
21
|
+
|
22
|
+
def initialize
|
23
|
+
@logger = HrrRbSsh::Logger.new self.class.name
|
24
|
+
|
25
|
+
@dh = OpenSSL::PKey::DH.new
|
26
|
+
if @dh.respond_to?(:set_pqg)
|
27
|
+
@dh.set_pqg OpenSSL::BN.new(self.class::P, 16), nil, OpenSSL::BN.new(self.class::G)
|
28
|
+
else
|
29
|
+
@dh.p = OpenSSL::BN.new(self.class::P, 16)
|
30
|
+
@dh.g = OpenSSL::BN.new(self.class::G)
|
31
|
+
end
|
32
|
+
@dh.generate_key!
|
33
|
+
end
|
34
|
+
|
35
|
+
def encode definition, payload
|
36
|
+
definition.map{ |data_type, field_name|
|
37
|
+
field_value = if payload[field_name].instance_of? ::Proc then payload[field_name].call else payload[field_name] end
|
38
|
+
HrrRbSsh::Transport::DataType[data_type].encode(field_value)
|
39
|
+
}.join
|
40
|
+
end
|
41
|
+
|
42
|
+
def set_e e
|
43
|
+
@e = e
|
44
|
+
end
|
45
|
+
|
46
|
+
def shared_secret
|
47
|
+
k = OpenSSL::BN.new(@dh.compute_key(OpenSSL::BN.new(@e)), 2).to_i
|
48
|
+
end
|
49
|
+
|
50
|
+
def pub_key
|
51
|
+
f = @dh.pub_key.to_i
|
52
|
+
end
|
53
|
+
|
54
|
+
def hash transport
|
55
|
+
e = @e
|
56
|
+
k = shared_secret
|
57
|
+
f = pub_key
|
58
|
+
|
59
|
+
h0_payload = {
|
60
|
+
'V_C' => transport.v_c,
|
61
|
+
'V_S' => transport.v_s,
|
62
|
+
'I_C' => transport.i_c,
|
63
|
+
'I_S' => transport.i_s,
|
64
|
+
'K_S' => transport.server_host_key_algorithm.server_public_host_key,
|
65
|
+
'e' => e,
|
66
|
+
'f' => f,
|
67
|
+
'k' => k,
|
68
|
+
}
|
69
|
+
h0 = encode H0_DEFINITION, h0_payload
|
70
|
+
|
71
|
+
h = OpenSSL::Digest.digest self.class::DIGEST, h0
|
72
|
+
|
73
|
+
h
|
74
|
+
end
|
75
|
+
|
76
|
+
def sign transport
|
77
|
+
h = hash transport
|
78
|
+
s = transport.server_host_key_algorithm.sign self.class::DIGEST, h
|
79
|
+
|
80
|
+
s
|
81
|
+
end
|
82
|
+
|
83
|
+
def build_key(_k, h, _x, session_id, key_length)
|
84
|
+
k = HrrRbSsh::Transport::DataType::Mpint.encode _k
|
85
|
+
x = HrrRbSsh::Transport::DataType::Byte.encode _x
|
86
|
+
|
87
|
+
key = OpenSSL::Digest.digest(self.class::DIGEST, k + h + x + session_id)
|
88
|
+
|
89
|
+
while key.length < key_length
|
90
|
+
key = key + OpenSSL::Digest.digest(self.class::DIGEST, k + h + key )
|
91
|
+
end
|
92
|
+
|
93
|
+
key[0, key_length]
|
94
|
+
end
|
95
|
+
|
96
|
+
def iv_c_to_s transport, encryption_algorithm_c_to_s_name
|
97
|
+
key_length = HrrRbSsh::Transport::EncryptionAlgorithm[encryption_algorithm_c_to_s_name]::IV_LENGTH
|
98
|
+
build_key(shared_secret, hash(transport), 'A'.ord, transport.session_id, key_length)
|
99
|
+
end
|
100
|
+
|
101
|
+
def iv_s_to_c transport, encryption_algorithm_s_to_c_name
|
102
|
+
key_length = HrrRbSsh::Transport::EncryptionAlgorithm[encryption_algorithm_s_to_c_name]::IV_LENGTH
|
103
|
+
build_key(shared_secret, hash(transport), 'B'.ord, transport.session_id, key_length)
|
104
|
+
end
|
105
|
+
|
106
|
+
def key_c_to_s transport, encryption_algorithm_c_to_s_name
|
107
|
+
key_length = HrrRbSsh::Transport::EncryptionAlgorithm[encryption_algorithm_c_to_s_name]::KEY_LENGTH
|
108
|
+
build_key(shared_secret, hash(transport), 'C'.ord, transport.session_id, key_length)
|
109
|
+
end
|
110
|
+
|
111
|
+
def key_s_to_c transport, encryption_algorithm_s_to_c_name
|
112
|
+
key_length = HrrRbSsh::Transport::EncryptionAlgorithm[encryption_algorithm_s_to_c_name]::KEY_LENGTH
|
113
|
+
build_key(shared_secret, hash(transport), 'D'.ord, transport.session_id, key_length)
|
114
|
+
end
|
115
|
+
|
116
|
+
def mac_c_to_s transport, mac_algorithm_c_to_s_name
|
117
|
+
key_length = HrrRbSsh::Transport::MacAlgorithm[mac_algorithm_c_to_s_name]::KEY_LENGTH
|
118
|
+
build_key(shared_secret, hash(transport), 'E'.ord, transport.session_id, key_length)
|
119
|
+
end
|
120
|
+
|
121
|
+
def mac_s_to_c transport, mac_algorithm_s_to_c_name
|
122
|
+
key_length = HrrRbSsh::Transport::MacAlgorithm[mac_algorithm_s_to_c_name]::KEY_LENGTH
|
123
|
+
build_key(shared_secret, hash(transport), 'F'.ord, transport.session_id, key_length)
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
require 'hrr_rb_ssh/transport/kex_algorithm/diffie_hellman'
|
5
|
+
|
6
|
+
module HrrRbSsh
|
7
|
+
class Transport
|
8
|
+
class KexAlgorithm
|
9
|
+
name_list = [
|
10
|
+
'diffie-hellman-group14-sha1'
|
11
|
+
]
|
12
|
+
|
13
|
+
class DiffieHellmanGroup14Sha1 < DiffieHellman
|
14
|
+
P = \
|
15
|
+
"FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" \
|
16
|
+
"C4C6628B" "80DC1CD1" "29024E08" "8A67CC74" \
|
17
|
+
"020BBEA6" "3B139B22" "514A0879" "8E3404DD" \
|
18
|
+
"EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" \
|
19
|
+
"4FE1356D" "6D51C245" "E485B576" "625E7EC6" \
|
20
|
+
"F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED" \
|
21
|
+
"EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" \
|
22
|
+
"49286651" "ECE45B3D" "C2007CB8" "A163BF05" \
|
23
|
+
"98DA4836" "1C55D39A" "69163FA8" "FD24CF5F" \
|
24
|
+
"83655D23" "DCA3AD96" "1C62F356" "208552BB" \
|
25
|
+
"9ED52907" "7096966D" "670C354E" "4ABC9804" \
|
26
|
+
"F1746C08" "CA18217C" "32905E46" "2E36CE3B" \
|
27
|
+
"E39E772C" "180E8603" "9B2783A2" "EC07A28F" \
|
28
|
+
"B5C55DF0" "6F4C52C9" "DE2BCBF6" "95581718" \
|
29
|
+
"3995497C" "EA956AE5" "15D22618" "98FA0510" \
|
30
|
+
"15728E5A" "8AACAA68" "FFFFFFFF" "FFFFFFFF"
|
31
|
+
G = 2
|
32
|
+
|
33
|
+
DIGEST = 'sha1'
|
34
|
+
end
|
35
|
+
|
36
|
+
@@list ||= Hash.new
|
37
|
+
name_list.each do |name|
|
38
|
+
@@list[name] = DiffieHellmanGroup14Sha1
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
require 'hrr_rb_ssh/transport/kex_algorithm/diffie_hellman'
|
5
|
+
|
6
|
+
module HrrRbSsh
|
7
|
+
class Transport
|
8
|
+
class KexAlgorithm
|
9
|
+
name_list = [
|
10
|
+
'diffie-hellman-group1-sha1'
|
11
|
+
]
|
12
|
+
|
13
|
+
class DiffieHellmanGroup1Sha1 < DiffieHellman
|
14
|
+
P = \
|
15
|
+
"FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" \
|
16
|
+
"C4C6628B" "80DC1CD1" "29024E08" "8A67CC74" \
|
17
|
+
"020BBEA6" "3B139B22" "514A0879" "8E3404DD" \
|
18
|
+
"EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" \
|
19
|
+
"4FE1356D" "6D51C245" "E485B576" "625E7EC6" \
|
20
|
+
"F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED" \
|
21
|
+
"EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" \
|
22
|
+
"49286651" "ECE65381" "FFFFFFFF" "FFFFFFFF"
|
23
|
+
G = 2
|
24
|
+
|
25
|
+
DIGEST = 'sha1'
|
26
|
+
end
|
27
|
+
|
28
|
+
@@list ||= Hash.new
|
29
|
+
name_list.each do |name|
|
30
|
+
@@list[name] = DiffieHellmanGroup1Sha1
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
require 'hrr_rb_ssh/logger'
|
5
|
+
require 'hrr_rb_ssh/transport/kex_algorithm/diffie_hellman_group1_sha1'
|
6
|
+
require 'hrr_rb_ssh/transport/kex_algorithm/diffie_hellman_group14_sha1'
|
7
|
+
|
8
|
+
module HrrRbSsh
|
9
|
+
class Transport
|
10
|
+
class KexAlgorithm
|
11
|
+
@@list ||= Hash.new
|
12
|
+
|
13
|
+
def self.[] key
|
14
|
+
@@list[key]
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.name_list
|
18
|
+
@@list.keys
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
require 'hrr_rb_ssh/logger'
|
5
|
+
|
6
|
+
module HrrRbSsh
|
7
|
+
class Transport
|
8
|
+
class MacAlgorithm
|
9
|
+
name_list = [
|
10
|
+
'hmac-sha1'
|
11
|
+
]
|
12
|
+
|
13
|
+
class HmacSha1
|
14
|
+
DIGEST = 'sha1'
|
15
|
+
|
16
|
+
DIGEST_LENGTH = 20
|
17
|
+
KEY_LENGTH = 20
|
18
|
+
|
19
|
+
def initialize key
|
20
|
+
@logger = HrrRbSsh::Logger.new self.class.name
|
21
|
+
|
22
|
+
@key = key
|
23
|
+
end
|
24
|
+
|
25
|
+
def compute sequence_number, unencrypted_packet
|
26
|
+
data = HrrRbSsh::Transport::DataType::Uint32.encode(sequence_number) + unencrypted_packet
|
27
|
+
OpenSSL::HMAC.digest DIGEST, @key, data
|
28
|
+
end
|
29
|
+
|
30
|
+
def digest_length
|
31
|
+
DIGEST_LENGTH
|
32
|
+
end
|
33
|
+
|
34
|
+
def key_length
|
35
|
+
KEY_LENGTH
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
@@list ||= Hash.new
|
40
|
+
name_list.each do |name|
|
41
|
+
@@list[name] = HmacSha1
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
require 'hrr_rb_ssh/logger'
|
5
|
+
|
6
|
+
module HrrRbSsh
|
7
|
+
class Transport
|
8
|
+
class MacAlgorithm
|
9
|
+
name_list = [
|
10
|
+
'none'
|
11
|
+
]
|
12
|
+
|
13
|
+
class None
|
14
|
+
DIGEST_LENGTH = 0
|
15
|
+
KEY_LENGTH = 0
|
16
|
+
|
17
|
+
def initialize key=nil
|
18
|
+
@logger = HrrRbSsh::Logger.new self.class.name
|
19
|
+
end
|
20
|
+
|
21
|
+
def compute sequence_number, unencrypted_packet
|
22
|
+
String.new
|
23
|
+
end
|
24
|
+
|
25
|
+
def digest_length
|
26
|
+
DIGEST_LENGTH
|
27
|
+
end
|
28
|
+
|
29
|
+
def key_length
|
30
|
+
KEY_LENGTH
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
@@list ||= Hash.new
|
35
|
+
name_list.each do |name|
|
36
|
+
@@list[name] = None
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
require 'hrr_rb_ssh/logger'
|
5
|
+
require 'hrr_rb_ssh/transport/mac_algorithm/none'
|
6
|
+
require 'hrr_rb_ssh/transport/mac_algorithm/hmac_sha1'
|
7
|
+
|
8
|
+
module HrrRbSsh
|
9
|
+
class Transport
|
10
|
+
class MacAlgorithm
|
11
|
+
@@list ||= Hash.new
|
12
|
+
|
13
|
+
def self.[] key
|
14
|
+
@@list[key]
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.name_list
|
18
|
+
@@list.keys
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
require 'hrr_rb_ssh/logger'
|
5
|
+
#require 'hrr_rb_ssh/transport/packet'
|
6
|
+
|
7
|
+
module HrrRbSsh
|
8
|
+
class Transport
|
9
|
+
class Receiver
|
10
|
+
def initialize
|
11
|
+
@logger = HrrRbSsh::Logger.new self.class.name
|
12
|
+
end
|
13
|
+
|
14
|
+
def depacketize transport, packet
|
15
|
+
packet_length_field_length = 4
|
16
|
+
padding_length_field_length = 1
|
17
|
+
|
18
|
+
packet_length = packet[0,4].unpack("N")[0]
|
19
|
+
padding_length = packet[4,1].unpack("C")[0]
|
20
|
+
deflated_payload_length = packet_length - padding_length_field_length - padding_length
|
21
|
+
deflated_payload = packet[packet_length_field_length + padding_length_field_length, deflated_payload_length]
|
22
|
+
payload = transport.incoming_compression_algorithm.inflate deflated_payload
|
23
|
+
|
24
|
+
payload
|
25
|
+
end
|
26
|
+
|
27
|
+
def receive_packet transport
|
28
|
+
packet_length_field_length = 4
|
29
|
+
minimum_block_size = 8
|
30
|
+
|
31
|
+
block_size = [transport.incoming_encryption_algorithm.block_size, minimum_block_size].max
|
32
|
+
initial_encrypted_packet = transport.io.read block_size
|
33
|
+
if (initial_encrypted_packet == nil) || (initial_encrypted_packet.length != block_size)
|
34
|
+
@logger.warn("IO is EOF")
|
35
|
+
raise EOFError
|
36
|
+
end
|
37
|
+
initial_unencrypted_packet = transport.incoming_encryption_algorithm.decrypt initial_encrypted_packet
|
38
|
+
packet_length = initial_unencrypted_packet[0,4].unpack("N")[0]
|
39
|
+
last_packet_length = packet_length_field_length + packet_length - block_size
|
40
|
+
last_encrypted_packet = transport.io.read last_packet_length
|
41
|
+
if (last_encrypted_packet == nil) || (last_encrypted_packet.length != last_packet_length)
|
42
|
+
@logger.warn("IO is EOF")
|
43
|
+
raise EOFError
|
44
|
+
end
|
45
|
+
last_unencrypted_packet = transport.incoming_encryption_algorithm.decrypt last_encrypted_packet
|
46
|
+
encrypted_packet = initial_encrypted_packet + last_encrypted_packet
|
47
|
+
unencrypted_packet = initial_unencrypted_packet + last_unencrypted_packet
|
48
|
+
|
49
|
+
unencrypted_packet
|
50
|
+
end
|
51
|
+
|
52
|
+
def receive_mac transport
|
53
|
+
mac_length = transport.incoming_mac_algorithm.digest_length
|
54
|
+
mac = transport.io.read mac_length
|
55
|
+
if (mac == nil) || (mac.length != mac_length)
|
56
|
+
@logger.warn("IO is EOF")
|
57
|
+
raise EOFError
|
58
|
+
end
|
59
|
+
mac
|
60
|
+
end
|
61
|
+
|
62
|
+
def receive transport
|
63
|
+
unencrypted_packet = receive_packet transport
|
64
|
+
payload = depacketize transport, unencrypted_packet
|
65
|
+
mac = receive_mac transport
|
66
|
+
|
67
|
+
raise if mac != transport.incoming_mac_algorithm.compute( transport.incoming_sequence_number.sequence_number, unencrypted_packet )
|
68
|
+
|
69
|
+
transport.incoming_sequence_number.increment
|
70
|
+
|
71
|
+
payload
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
require 'hrr_rb_ssh/logger'
|
5
|
+
|
6
|
+
module HrrRbSsh
|
7
|
+
class Transport
|
8
|
+
class Sender
|
9
|
+
def initialize
|
10
|
+
@logger = HrrRbSsh::Logger.new self.class.name
|
11
|
+
end
|
12
|
+
|
13
|
+
def packetize transport, payload
|
14
|
+
packet_length_field_length = 4
|
15
|
+
padding_length_field_length = 1
|
16
|
+
minimum_padding_length = 4
|
17
|
+
minimum_block_size = 8
|
18
|
+
|
19
|
+
block_size = [transport.outgoing_encryption_algorithm.block_size, minimum_block_size].max
|
20
|
+
deflated_payload = transport.outgoing_compression_algorithm.deflate payload
|
21
|
+
tmp_total_length = packet_length_field_length + padding_length_field_length + deflated_payload.length + minimum_padding_length
|
22
|
+
total_length = tmp_total_length + (block_size - (tmp_total_length % block_size))
|
23
|
+
packet_length = total_length - packet_length_field_length
|
24
|
+
padding_length = packet_length - padding_length_field_length - deflated_payload.length
|
25
|
+
padding = OpenSSL::Random.random_bytes( padding_length )
|
26
|
+
packet = [packet_length, padding_length].pack("NC") + deflated_payload + padding
|
27
|
+
|
28
|
+
packet
|
29
|
+
end
|
30
|
+
|
31
|
+
def encrypt transport, packet
|
32
|
+
encrypted_packet = transport.outgoing_encryption_algorithm.encrypt packet
|
33
|
+
|
34
|
+
encrypted_packet
|
35
|
+
end
|
36
|
+
|
37
|
+
def send_packet transport, packet
|
38
|
+
encrypted_packet = encrypt transport, packet
|
39
|
+
transport.io.write encrypted_packet
|
40
|
+
end
|
41
|
+
|
42
|
+
def send_mac transport, packet
|
43
|
+
mac = transport.outgoing_mac_algorithm.compute transport.outgoing_sequence_number.sequence_number, packet
|
44
|
+
transport.io.write mac
|
45
|
+
end
|
46
|
+
|
47
|
+
def send transport, payload
|
48
|
+
packet = packetize transport, payload
|
49
|
+
|
50
|
+
send_packet transport, packet
|
51
|
+
send_mac transport, packet
|
52
|
+
|
53
|
+
transport.outgoing_sequence_number.increment
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
require 'hrr_rb_ssh/logger'
|
5
|
+
|
6
|
+
module HrrRbSsh
|
7
|
+
class Transport
|
8
|
+
class SequenceNumber
|
9
|
+
attr_reader :sequence_number
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@sequence_number = 0
|
13
|
+
|
14
|
+
@logger = HrrRbSsh::Logger.new self.class.name
|
15
|
+
end
|
16
|
+
|
17
|
+
def increment
|
18
|
+
@sequence_number = (@sequence_number + 1) % 0x1_0000_0000
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|