hrr_rb_ssh 0.2.1 → 0.2.2
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 +4 -4
- data/README.md +6 -2
- data/demo/server.rb +1 -1
- data/hrr_rb_ssh.gemspec +1 -0
- data/lib/hrr_rb_ssh.rb +6 -4
- data/lib/hrr_rb_ssh/algorithm/publickey.rb +4 -14
- data/lib/hrr_rb_ssh/algorithm/publickey/ssh_ed25519.rb +61 -0
- data/lib/hrr_rb_ssh/algorithm/publickey/ssh_ed25519/openssh_private_key.rb +29 -0
- data/lib/hrr_rb_ssh/algorithm/publickey/ssh_ed25519/openssh_private_key_content.rb +26 -0
- data/lib/hrr_rb_ssh/algorithm/publickey/ssh_ed25519/pkey.rb +158 -0
- data/lib/hrr_rb_ssh/algorithm/publickey/ssh_ed25519/public_key_blob.rb +23 -0
- data/lib/hrr_rb_ssh/algorithm/publickey/ssh_ed25519/signature.rb +23 -0
- data/lib/hrr_rb_ssh/authentication/method/publickey/algorithm.rb +1 -0
- data/lib/hrr_rb_ssh/authentication/method/publickey/algorithm/ssh_ed25519.rb +21 -0
- data/lib/hrr_rb_ssh/codable.rb +2 -1
- data/lib/hrr_rb_ssh/connection/channel/channel_type.rb +3 -14
- data/lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type.rb +3 -14
- data/lib/hrr_rb_ssh/connection/request_handler/reference_pty_req_request_handler.rb +5 -11
- data/lib/hrr_rb_ssh/data_type.rb +10 -144
- data/lib/hrr_rb_ssh/data_type/boolean.rb +37 -0
- data/lib/hrr_rb_ssh/data_type/byte.rb +31 -0
- data/lib/hrr_rb_ssh/data_type/mpint.rb +56 -0
- data/lib/hrr_rb_ssh/data_type/name_list.rb +38 -0
- data/lib/hrr_rb_ssh/data_type/string.rb +34 -0
- data/lib/hrr_rb_ssh/data_type/uint32.rb +31 -0
- data/lib/hrr_rb_ssh/data_type/uint64.rb +31 -0
- data/lib/hrr_rb_ssh/subclass_without_preference_listable.rb +25 -0
- data/lib/hrr_rb_ssh/transport/server_host_key_algorithm.rb +1 -0
- data/lib/hrr_rb_ssh/transport/server_host_key_algorithm/ssh_ed25519.rb +20 -0
- data/lib/hrr_rb_ssh/version.rb +1 -1
- metadata +32 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0c8f4e84817663132562929cf774d32295eb62df8820d7c08aa621672ae6a002
|
4
|
+
data.tar.gz: 783f325e4514b69f5bc2c9936ad012d07d263e1c93aa813393afb773ee72c4c9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b08a544e2085ea9399564ae5a0ce654ba81adbcf5eaa28b17dbea438d29dadeafb89a450d7cf3151115cce29d1e32a3dada2c14e96efe1f47516fad75076c551
|
7
|
+
data.tar.gz: 204b40938e402920729b2e96261faf2be13851b9ee4e2b0de996db9bba17363b169bfb107bc951917008c9950fc314a53807c1ea639d8512378ecc9711540e21
|
data/README.md
CHANGED
@@ -7,6 +7,8 @@
|
|
7
7
|
|
8
8
|
hrr_rb_ssh is a pure Ruby SSH 2.0 server implementation.
|
9
9
|
|
10
|
+
With hrr_rb_ssh, it is possible to write an SSH server easily, and also possible to write an original server side application on secure connection provided by SSH protocol.
|
11
|
+
|
10
12
|
## Table of Contents
|
11
13
|
|
12
14
|
- [Installation](#installation)
|
@@ -299,9 +301,9 @@ p HrrRbSsh::Transport::EncryptionAlgorithm.list_preferred
|
|
299
301
|
# => ["aes128-ctr", "aes192-ctr", "aes256-ctr", "aes128-cbc", "3des-cbc", "blowfish-cbc", "cast128-cbc", "aes192-cbc", "aes256-cbc", "arcfour"]
|
300
302
|
|
301
303
|
p HrrRbSsh::Transport::ServerHostKeyAlgorithm.list_supported
|
302
|
-
# => ["ssh-dss", "ssh-rsa", "ecdsa-sha2-nistp256", "ecdsa-sha2-nistp384", "ecdsa-sha2-nistp521"]
|
304
|
+
# => ["ssh-dss", "ssh-rsa", "ecdsa-sha2-nistp256", "ecdsa-sha2-nistp384", "ecdsa-sha2-nistp521", "ssh-ed25519"]
|
303
305
|
p HrrRbSsh::Transport::ServerHostKeyAlgorithm.list_preferred
|
304
|
-
# => ["ecdsa-sha2-nistp521", "ecdsa-sha2-nistp384", "ecdsa-sha2-nistp256", "ssh-rsa", "ssh-dss"]
|
306
|
+
# => ["ssh-ed25519", "ecdsa-sha2-nistp521", "ecdsa-sha2-nistp384", "ecdsa-sha2-nistp256", "ssh-rsa", "ssh-dss"]
|
305
307
|
|
306
308
|
p HrrRbSsh::Transport::KexAlgorithm.list_supported
|
307
309
|
# => ["diffie-hellman-group1-sha1", "diffie-hellman-group14-sha1", "diffie-hellman-group-exchange-sha1", "diffie-hellman-group-exchange-sha256", "diffie-hellman-group14-sha256", "diffie-hellman-group15-sha512", "diffie-hellman-group16-sha512", "diffie-hellman-group17-sha512", "diffie-hellman-group18-sha512", "ecdh-sha2-nistp256", "ecdh-sha2-nistp384", "ecdh-sha2-nistp521"]
|
@@ -346,6 +348,7 @@ The following features are currently supported.
|
|
346
348
|
- ecdsa-sha2-nistp256
|
347
349
|
- ecdsa-sha2-nistp384
|
348
350
|
- ecdsa-sha2-nistp521
|
351
|
+
- ssh-ed25519
|
349
352
|
- Keyboard interactive (generic interactive / challenge response) authentication
|
350
353
|
|
351
354
|
### Transport layer
|
@@ -368,6 +371,7 @@ The following features are currently supported.
|
|
368
371
|
- ecdsa-sha2-nistp256
|
369
372
|
- ecdsa-sha2-nistp384
|
370
373
|
- ecdsa-sha2-nistp521
|
374
|
+
- ssh-ed25519
|
371
375
|
- Kex algorithm
|
372
376
|
- diffie-hellman-group1-sha1
|
373
377
|
- diffie-hellman-group14-sha1
|
data/demo/server.rb
CHANGED
@@ -18,7 +18,7 @@ def start_service io, logger=nil
|
|
18
18
|
HrrRbSsh::Logger.initialize logger if logger
|
19
19
|
|
20
20
|
tran_preferred_encryption_algorithms = %w(aes128-ctr aes192-ctr aes256-ctr aes128-cbc 3des-cbc blowfish-cbc cast128-cbc aes192-cbc aes256-cbc arcfour)
|
21
|
-
tran_preferred_server_host_key_algorithms = %w(ecdsa-sha2-nistp521 ecdsa-sha2-nistp384 ecdsa-sha2-nistp256 ssh-rsa ssh-dss)
|
21
|
+
tran_preferred_server_host_key_algorithms = %w(ssh-ed25519 ecdsa-sha2-nistp521 ecdsa-sha2-nistp384 ecdsa-sha2-nistp256 ssh-rsa ssh-dss)
|
22
22
|
tran_preferred_kex_algorithms = %w(ecdh-sha2-nistp521 ecdh-sha2-nistp384 ecdh-sha2-nistp256 diffie-hellman-group14-sha1 diffie-hellman-group1-sha1)
|
23
23
|
tran_preferred_mac_algorithms = %w(hmac-sha2-512 hmac-sha2-256 hmac-sha1 hmac-md5 hmac-sha1-96 hmac-md5-96)
|
24
24
|
tran_preferred_compression_algorithms = %w(none zlib)
|
data/hrr_rb_ssh.gemspec
CHANGED
@@ -20,6 +20,7 @@ Gem::Specification.new do |spec|
|
|
20
20
|
|
21
21
|
spec.required_ruby_version = '>= 2.0.0'
|
22
22
|
|
23
|
+
spec.add_dependency "ed25519", "~> 1.2"
|
23
24
|
spec.add_development_dependency "bundler", "~> 1.16"
|
24
25
|
spec.add_development_dependency "rake", "~> 10.0"
|
25
26
|
spec.add_development_dependency "rspec", "~> 3.0"
|
data/lib/hrr_rb_ssh.rb
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
# vim: et ts=2 sw=2
|
3
3
|
|
4
|
+
|
5
|
+
|
6
|
+
# HrrRbSsh is a pure Ruby SSH 2.0 implementation.
|
7
|
+
module HrrRbSsh
|
8
|
+
end
|
9
|
+
|
4
10
|
require "hrr_rb_ssh/version"
|
5
11
|
require "hrr_rb_ssh/compat"
|
6
12
|
require "hrr_rb_ssh/logger"
|
@@ -11,7 +17,3 @@ require "hrr_rb_ssh/transport"
|
|
11
17
|
require "hrr_rb_ssh/authentication"
|
12
18
|
require "hrr_rb_ssh/connection"
|
13
19
|
require "hrr_rb_ssh/server"
|
14
|
-
|
15
|
-
module HrrRbSsh
|
16
|
-
# Your code goes here...
|
17
|
-
end
|
@@ -1,25 +1,14 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
# vim: et ts=2 sw=2
|
3
3
|
|
4
|
+
require 'hrr_rb_ssh/subclass_without_preference_listable'
|
5
|
+
|
4
6
|
module HrrRbSsh
|
5
7
|
module Algorithm
|
6
8
|
class Publickey
|
7
9
|
@subclass_list = Array.new
|
8
10
|
class << self
|
9
|
-
|
10
|
-
@subclass_list.push klass if @subclass_list
|
11
|
-
end
|
12
|
-
|
13
|
-
def [] key
|
14
|
-
__subclass_list__(__method__).find{ |klass| klass::NAME == key }
|
15
|
-
end
|
16
|
-
|
17
|
-
def __subclass_list__ method_name
|
18
|
-
send(:method_missing, method_name) unless @subclass_list
|
19
|
-
@subclass_list
|
20
|
-
end
|
21
|
-
|
22
|
-
private :__subclass_list__
|
11
|
+
include SubclassWithoutPreferenceListable
|
23
12
|
end
|
24
13
|
end
|
25
14
|
end
|
@@ -30,3 +19,4 @@ require 'hrr_rb_ssh/algorithm/publickey/ssh_rsa'
|
|
30
19
|
require 'hrr_rb_ssh/algorithm/publickey/ecdsa_sha2_nistp256'
|
31
20
|
require 'hrr_rb_ssh/algorithm/publickey/ecdsa_sha2_nistp384'
|
32
21
|
require 'hrr_rb_ssh/algorithm/publickey/ecdsa_sha2_nistp521'
|
22
|
+
require 'hrr_rb_ssh/algorithm/publickey/ssh_ed25519'
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
require 'hrr_rb_ssh/logger'
|
5
|
+
|
6
|
+
module HrrRbSsh
|
7
|
+
module Algorithm
|
8
|
+
class Publickey
|
9
|
+
class SshEd25519 < Publickey
|
10
|
+
NAME = 'ssh-ed25519'
|
11
|
+
|
12
|
+
def initialize arg
|
13
|
+
begin
|
14
|
+
new_by_key_str arg
|
15
|
+
rescue PKey::Error
|
16
|
+
new_by_public_key_blob arg
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def new_by_key_str key_str
|
21
|
+
@publickey = PKey.new(key_str)
|
22
|
+
end
|
23
|
+
|
24
|
+
def new_by_public_key_blob public_key_blob
|
25
|
+
public_key_blob_h = PublicKeyBlob.decode(public_key_blob)
|
26
|
+
@publickey = PKey.new
|
27
|
+
@publickey.set_public_key(public_key_blob_h[:key])
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_pem
|
31
|
+
@publickey.public_key.to_pem
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_public_key_blob
|
35
|
+
public_key_blob_h = {
|
36
|
+
:'public key algorithm name' => self.class::NAME,
|
37
|
+
:'key' => @publickey.public_key.key_str,
|
38
|
+
}
|
39
|
+
PublicKeyBlob.encode(public_key_blob_h)
|
40
|
+
end
|
41
|
+
|
42
|
+
def sign signature_blob
|
43
|
+
signature_h = {
|
44
|
+
:'public key algorithm name' => self.class::NAME,
|
45
|
+
:'signature blob' => @publickey.sign(signature_blob),
|
46
|
+
}
|
47
|
+
Signature.encode signature_h
|
48
|
+
end
|
49
|
+
|
50
|
+
def verify signature, signature_blob
|
51
|
+
signature_h = Signature.decode signature
|
52
|
+
signature_h[:'public key algorithm name'] == self.class::NAME && @publickey.public_key.verify(signature_h[:'signature blob'], signature_blob)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
require 'hrr_rb_ssh/algorithm/publickey/ssh_ed25519/pkey'
|
60
|
+
require 'hrr_rb_ssh/algorithm/publickey/ssh_ed25519/public_key_blob'
|
61
|
+
require 'hrr_rb_ssh/algorithm/publickey/ssh_ed25519/signature'
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
require 'hrr_rb_ssh/data_type'
|
5
|
+
require 'hrr_rb_ssh/codable'
|
6
|
+
|
7
|
+
module HrrRbSsh
|
8
|
+
module Algorithm
|
9
|
+
class Publickey
|
10
|
+
class SshEd25519
|
11
|
+
module OpenSSHPrivateKey
|
12
|
+
class << self
|
13
|
+
include Codable
|
14
|
+
end
|
15
|
+
DEFINITION = [
|
16
|
+
[DataType::String, :'cipher'],
|
17
|
+
[DataType::String, :'kdfname'],
|
18
|
+
[DataType::Uint32, :'kdfopts'],
|
19
|
+
[DataType::Uint32, :'number of public keys'],
|
20
|
+
[DataType::Uint32, :'first public key length'],
|
21
|
+
[DataType::String, :'name'],
|
22
|
+
[DataType::String, :'public key'],
|
23
|
+
[DataType::String, :'content'],
|
24
|
+
]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
require 'hrr_rb_ssh/data_type'
|
5
|
+
require 'hrr_rb_ssh/codable'
|
6
|
+
|
7
|
+
module HrrRbSsh
|
8
|
+
module Algorithm
|
9
|
+
class Publickey
|
10
|
+
class SshEd25519
|
11
|
+
module OpenSSHPrivateKeyContent
|
12
|
+
class << self
|
13
|
+
include Codable
|
14
|
+
end
|
15
|
+
DEFINITION = [
|
16
|
+
[DataType::Uint64, :'unknown'],
|
17
|
+
[DataType::String, :'name'],
|
18
|
+
[DataType::String, :'public key'],
|
19
|
+
[DataType::String, :'key pair'],
|
20
|
+
[DataType::String, :'padding'],
|
21
|
+
]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,158 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
require 'stringio'
|
5
|
+
require 'base64'
|
6
|
+
require 'ed25519'
|
7
|
+
|
8
|
+
module HrrRbSsh
|
9
|
+
module Algorithm
|
10
|
+
class Publickey
|
11
|
+
class SshEd25519
|
12
|
+
class PKey
|
13
|
+
class Error < ::StandardError
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize arg=nil
|
17
|
+
case arg
|
18
|
+
when ::Ed25519::SigningKey, ::Ed25519::VerifyKey
|
19
|
+
@key = arg
|
20
|
+
when ::String
|
21
|
+
@key = load_key_str arg
|
22
|
+
when nil
|
23
|
+
# do nothing
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def load_key_str key_str
|
28
|
+
begin
|
29
|
+
load_openssh_key key_str
|
30
|
+
rescue
|
31
|
+
begin
|
32
|
+
load_openssl_key key_str
|
33
|
+
rescue
|
34
|
+
raise Error
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def load_openssh_key key_str
|
40
|
+
begin_marker = "-----BEGIN OPENSSH PRIVATE KEY-----\n"
|
41
|
+
end_marker = "-----END OPENSSH PRIVATE KEY-----\n"
|
42
|
+
magic = "openssh-key-v1"
|
43
|
+
|
44
|
+
raise Error unless key_str.start_with? begin_marker
|
45
|
+
raise Error unless key_str.end_with? end_marker
|
46
|
+
decoded_key_str = Base64.decode64(key_str[begin_marker.size...-end_marker.size])
|
47
|
+
raise Error unless decoded_key_str[0,14] == magic
|
48
|
+
|
49
|
+
private_key_h = OpenSSHPrivateKey.decode decoded_key_str[15..-1]
|
50
|
+
private_key_content_h = OpenSSHPrivateKeyContent.decode private_key_h[:'content']
|
51
|
+
key_pair = private_key_content_h[:'key pair']
|
52
|
+
|
53
|
+
::Ed25519::SigningKey.new(key_pair[0,32])
|
54
|
+
end
|
55
|
+
|
56
|
+
def load_openssl_key key_str
|
57
|
+
private_key_begin_marker = "-----BEGIN PRIVATE KEY-----\n"
|
58
|
+
public_key_begin_marker = "-----BEGIN PUBLIC KEY-----\n"
|
59
|
+
if key_str.start_with? private_key_begin_marker
|
60
|
+
begin_marker = "-----BEGIN PRIVATE KEY-----\n"
|
61
|
+
end_marker = "-----END PRIVATE KEY-----\n"
|
62
|
+
|
63
|
+
raise Error unless key_str.start_with? begin_marker
|
64
|
+
raise Error unless key_str.end_with? end_marker
|
65
|
+
|
66
|
+
decoded_key_str = Base64.decode64(key_str[begin_marker.size...-end_marker.size])
|
67
|
+
key_der = OpenSSL::ASN1.decode decoded_key_str
|
68
|
+
|
69
|
+
::Ed25519::SigningKey.new(key_der.value[2].value[2..-1])
|
70
|
+
elsif key_str.start_with? public_key_begin_marker
|
71
|
+
begin_marker = "-----BEGIN PUBLIC KEY-----\n"
|
72
|
+
end_marker = "-----END PUBLIC KEY-----\n"
|
73
|
+
|
74
|
+
raise Error unless key_str.start_with? begin_marker
|
75
|
+
raise Error unless key_str.end_with? end_marker
|
76
|
+
|
77
|
+
decoded_key_str = Base64.decode64(key_str[begin_marker.size...-end_marker.size])
|
78
|
+
key_der = OpenSSL::ASN1.decode decoded_key_str
|
79
|
+
|
80
|
+
::Ed25519::VerifyKey.new(key_der.value[1].value)
|
81
|
+
else
|
82
|
+
raise Error
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def set_public_key key_str
|
87
|
+
@key = ::Ed25519::VerifyKey.new(key_str)
|
88
|
+
end
|
89
|
+
|
90
|
+
def to_pem
|
91
|
+
ed25519_object_id = '1.3.101.112'
|
92
|
+
case @key
|
93
|
+
=begin
|
94
|
+
when ::Ed25519::SigningKey
|
95
|
+
begin_marker = "-----BEGIN PRIVATE KEY-----\n"
|
96
|
+
end_marker = "-----END PRIVATE KEY-----\n"
|
97
|
+
key_asn1 = OpenSSL::ASN1::Sequence.new(
|
98
|
+
[
|
99
|
+
OpenSSL::ASN1::Integer.new(OpenSSL::BN.new(0)),
|
100
|
+
OpenSSL::ASN1::Sequence.new(
|
101
|
+
[
|
102
|
+
OpenSSL::ASN1::ObjectId.new(ed25519_object_id),
|
103
|
+
]
|
104
|
+
),
|
105
|
+
OpenSSL::ASN1::OctetString.new(@key.to_bytes),
|
106
|
+
]
|
107
|
+
)
|
108
|
+
=end
|
109
|
+
when ::Ed25519::VerifyKey
|
110
|
+
begin_marker = "-----BEGIN PUBLIC KEY-----\n"
|
111
|
+
end_marker = "-----END PUBLIC KEY-----\n"
|
112
|
+
key_asn1 = OpenSSL::ASN1::Sequence.new(
|
113
|
+
[
|
114
|
+
OpenSSL::ASN1::Sequence.new(
|
115
|
+
[
|
116
|
+
OpenSSL::ASN1::ObjectId.new(ed25519_object_id),
|
117
|
+
]
|
118
|
+
),
|
119
|
+
OpenSSL::ASN1::BitString.new(@key.to_bytes),
|
120
|
+
]
|
121
|
+
)
|
122
|
+
end
|
123
|
+
pem_str = Base64.encode64(key_asn1.to_der)
|
124
|
+
begin_marker + pem_str + end_marker
|
125
|
+
end
|
126
|
+
|
127
|
+
def public_key
|
128
|
+
case @key
|
129
|
+
when ::Ed25519::SigningKey
|
130
|
+
self.class.new @key.verify_key
|
131
|
+
when ::Ed25519::VerifyKey
|
132
|
+
self
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def key_str
|
137
|
+
@key.to_bytes
|
138
|
+
end
|
139
|
+
|
140
|
+
def sign data
|
141
|
+
@key.sign data
|
142
|
+
end
|
143
|
+
|
144
|
+
def verify signature, data
|
145
|
+
begin
|
146
|
+
@key.verify signature, data
|
147
|
+
rescue ::Ed25519::VerifyError
|
148
|
+
false
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
require 'hrr_rb_ssh/algorithm/publickey/ssh_ed25519/openssh_private_key'
|
158
|
+
require 'hrr_rb_ssh/algorithm/publickey/ssh_ed25519/openssh_private_key_content'
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
require 'hrr_rb_ssh/data_type'
|
5
|
+
require 'hrr_rb_ssh/codable'
|
6
|
+
|
7
|
+
module HrrRbSsh
|
8
|
+
module Algorithm
|
9
|
+
class Publickey
|
10
|
+
class SshEd25519
|
11
|
+
module PublicKeyBlob
|
12
|
+
class << self
|
13
|
+
include Codable
|
14
|
+
end
|
15
|
+
DEFINITION = [
|
16
|
+
[DataType::String, :'public key algorithm name'],
|
17
|
+
[DataType::String, :'key'],
|
18
|
+
]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
require 'hrr_rb_ssh/data_type'
|
5
|
+
require 'hrr_rb_ssh/codable'
|
6
|
+
|
7
|
+
module HrrRbSsh
|
8
|
+
module Algorithm
|
9
|
+
class Publickey
|
10
|
+
class SshEd25519
|
11
|
+
module Signature
|
12
|
+
class << self
|
13
|
+
include Codable
|
14
|
+
end
|
15
|
+
DEFINITION = [
|
16
|
+
[DataType::String, :'public key algorithm name'],
|
17
|
+
[DataType::String, :'signature blob'],
|
18
|
+
]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -23,3 +23,4 @@ require 'hrr_rb_ssh/authentication/method/publickey/algorithm/ssh_rsa'
|
|
23
23
|
require 'hrr_rb_ssh/authentication/method/publickey/algorithm/ecdsa_sha2_nistp256'
|
24
24
|
require 'hrr_rb_ssh/authentication/method/publickey/algorithm/ecdsa_sha2_nistp384'
|
25
25
|
require 'hrr_rb_ssh/authentication/method/publickey/algorithm/ecdsa_sha2_nistp521'
|
26
|
+
require 'hrr_rb_ssh/authentication/method/publickey/algorithm/ssh_ed25519'
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
require 'hrr_rb_ssh/authentication/method/publickey/algorithm/functionable'
|
5
|
+
|
6
|
+
module HrrRbSsh
|
7
|
+
class Authentication
|
8
|
+
class Method
|
9
|
+
class Publickey
|
10
|
+
class Algorithm
|
11
|
+
class SshEd25519 < Algorithm
|
12
|
+
NAME = 'ssh-ed25519'
|
13
|
+
PREFERENCE = 60
|
14
|
+
|
15
|
+
include Functionable
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/hrr_rb_ssh/codable.rb
CHANGED
@@ -14,10 +14,11 @@ module HrrRbSsh
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def conditional_definition message
|
17
|
+
return [] unless self.const_defined? :CONDITIONAL_DEFINITION
|
17
18
|
message.inject([]){ |a, (k,v)|
|
18
19
|
field_name = k
|
19
20
|
field_value = if v.instance_of? ::Proc then v.call else v end
|
20
|
-
a + (
|
21
|
+
a + (self::CONDITIONAL_DEFINITION.fetch(field_name, {})[field_value] || [])
|
21
22
|
}
|
22
23
|
end
|
23
24
|
|
@@ -1,26 +1,15 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
# vim: et ts=2 sw=2
|
3
3
|
|
4
|
+
require 'hrr_rb_ssh/subclass_without_preference_listable'
|
5
|
+
|
4
6
|
module HrrRbSsh
|
5
7
|
class Connection
|
6
8
|
class Channel
|
7
9
|
class ChannelType
|
8
10
|
@subclass_list = Array.new
|
9
11
|
class << self
|
10
|
-
|
11
|
-
@subclass_list.push klass if @subclass_list
|
12
|
-
end
|
13
|
-
|
14
|
-
def [] key
|
15
|
-
__subclass_list__(__method__).find{ |klass| klass::NAME == key }
|
16
|
-
end
|
17
|
-
|
18
|
-
def __subclass_list__ method_name
|
19
|
-
send(:method_missing, method_name) unless @subclass_list
|
20
|
-
@subclass_list
|
21
|
-
end
|
22
|
-
|
23
|
-
private :__subclass_list__
|
12
|
+
include SubclassWithoutPreferenceListable
|
24
13
|
end
|
25
14
|
end
|
26
15
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
# vim: et ts=2 sw=2
|
3
3
|
|
4
|
+
require 'hrr_rb_ssh/subclass_without_preference_listable'
|
5
|
+
|
4
6
|
module HrrRbSsh
|
5
7
|
class Connection
|
6
8
|
class Channel
|
@@ -9,20 +11,7 @@ module HrrRbSsh
|
|
9
11
|
class RequestType
|
10
12
|
@subclass_list = Array.new
|
11
13
|
class << self
|
12
|
-
|
13
|
-
@subclass_list.push klass if @subclass_list
|
14
|
-
end
|
15
|
-
|
16
|
-
def [] key
|
17
|
-
__subclass_list__(__method__).find{ |klass| klass::NAME == key }
|
18
|
-
end
|
19
|
-
|
20
|
-
def __subclass_list__ method_name
|
21
|
-
send(:method_missing, method_name) unless @subclass_list
|
22
|
-
@subclass_list
|
23
|
-
end
|
24
|
-
|
25
|
-
private :__subclass_list__
|
14
|
+
include SubclassWithoutPreferenceListable
|
26
15
|
end
|
27
16
|
end
|
28
17
|
end
|
@@ -67,19 +67,13 @@ module HrrRbSsh
|
|
67
67
|
}
|
68
68
|
chain.call_next
|
69
69
|
ensure
|
70
|
+
context.logger.info { "closing pty-req request handler chain_proc" }
|
70
71
|
context.vars[:ptm].close rescue nil
|
71
72
|
context.vars[:pts].close rescue nil
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
end
|
77
|
-
begin
|
78
|
-
ptm_write_thread.exit
|
79
|
-
ptm_write_thread.join
|
80
|
-
rescue => e
|
81
|
-
context.logger.error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
|
82
|
-
end
|
73
|
+
ptm_read_thread.join
|
74
|
+
ptm_write_thread.exit
|
75
|
+
ptm_write_thread.join
|
76
|
+
context.logger.info { "pty-req request handler chain_proc closed" }
|
83
77
|
end
|
84
78
|
}
|
85
79
|
rescue => e
|
data/lib/hrr_rb_ssh/data_type.rb
CHANGED
@@ -1,150 +1,16 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
# vim: et ts=2 sw=2
|
3
3
|
|
4
|
-
require 'openssl'
|
5
|
-
|
6
4
|
module HrrRbSsh
|
7
|
-
|
8
|
-
|
9
|
-
def self.encode arg
|
10
|
-
case arg
|
11
|
-
when 0x00..0xff
|
12
|
-
[arg].pack("C")
|
13
|
-
else
|
14
|
-
raise ArgumentError, "must be in #{0x00}..#{0xff}, but got #{arg.inspect}"
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def self.decode io
|
19
|
-
io.read(1).unpack("C")[0]
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
class Boolean
|
24
|
-
def self.encode arg
|
25
|
-
case arg
|
26
|
-
when false
|
27
|
-
[0].pack("C")
|
28
|
-
when true
|
29
|
-
[1].pack("C")
|
30
|
-
else
|
31
|
-
raise ArgumentError, "must be #{true} or #{false}, but got #{arg.inspect}"
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def self.decode io
|
36
|
-
if 0 == io.read(1).unpack("C")[0]
|
37
|
-
false
|
38
|
-
else
|
39
|
-
true
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
class Uint32
|
45
|
-
def self.encode arg
|
46
|
-
case arg
|
47
|
-
when 0x0000_0000..0xffff_ffff
|
48
|
-
[arg].pack("N")
|
49
|
-
else
|
50
|
-
raise ArgumentError, "must be in #{0x0000_0000}..#{0xffff_ffff}, but got #{arg.inspect}"
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def self.decode io
|
55
|
-
io.read(4).unpack("N")[0]
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
class Uint64
|
60
|
-
def self.encode arg
|
61
|
-
case arg
|
62
|
-
when 0x0000_0000_0000_0000..0xffff_ffff_ffff_ffff
|
63
|
-
[arg >> 32].pack("N") + [arg & 0x0000_0000_ffff_ffff].pack("N")
|
64
|
-
else
|
65
|
-
raise ArgumentError, "must be in #{0x0000_0000_0000_0000}..#{0xffff_ffff_ffff_ffff}, but got #{arg.inspect}"
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def self.decode io
|
70
|
-
(io.read(4).unpack("N")[0] << 32) + (io.read(4).unpack("N")[0])
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
class String
|
75
|
-
def self.encode arg
|
76
|
-
unless arg.kind_of? ::String
|
77
|
-
raise ArgumentError, "must be a kind of String, but got #{arg.inspect}"
|
78
|
-
end
|
79
|
-
if arg.length > 0xffff_ffff
|
80
|
-
raise ArgumentError, "must be shorter than or equal to #{0xffff_ffff}, but got length #{arg.length}"
|
81
|
-
end
|
82
|
-
[arg.length, arg].pack("Na*")
|
83
|
-
end
|
84
|
-
|
85
|
-
def self.decode io
|
86
|
-
length = io.read(4).unpack("N")[0]
|
87
|
-
io.read(length).unpack("a*")[0]
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
class Mpint
|
92
|
-
def self.encode arg
|
93
|
-
unless arg.kind_of? ::Integer
|
94
|
-
raise ArgumentError, "must be a kind of Integer, but got #{arg.inspect}"
|
95
|
-
end
|
96
|
-
bn = ::OpenSSL::BN.new(arg)
|
97
|
-
if bn < 0
|
98
|
-
# get 2's complement
|
99
|
-
tc = bn.to_i & ((1 << (bn.num_bytes * 8)) - 1)
|
100
|
-
# get hex representation
|
101
|
-
hex_str = "%x" % tc
|
102
|
-
|
103
|
-
if tc[(bn.num_bytes * 8) - 1] == 1
|
104
|
-
[bn.num_bytes, hex_str].pack("NH*")
|
105
|
-
else
|
106
|
-
[bn.num_bytes + 1, "ff" + hex_str].pack("NH*")
|
107
|
-
end
|
108
|
-
else
|
109
|
-
bn.to_s(0)
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
def self.decode io
|
114
|
-
length = io.read(4).unpack("N")[0]
|
115
|
-
hex_str = io.read(length).unpack("H*")[0]
|
116
|
-
# get temporal integer value
|
117
|
-
value = hex_str.hex
|
118
|
-
if length == 0
|
119
|
-
0
|
120
|
-
elsif value[(length * 8) - 1] == 0
|
121
|
-
value
|
122
|
-
else
|
123
|
-
num_bytes = if hex_str.start_with?("ff") then length - 1 else length end
|
124
|
-
- (((~ value) & ((1 << (num_bytes * 8)) - 1)) + 1)
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
class NameList
|
130
|
-
def self.encode arg
|
131
|
-
unless arg.kind_of? Array
|
132
|
-
raise ArgumentError, "must be a kind of Array, but got #{arg.inspect}"
|
133
|
-
end
|
134
|
-
unless (arg.map(&:class) - [::String]).empty?
|
135
|
-
raise ArgumentError, "must be with all elements of String, but got #{arg.inspect}"
|
136
|
-
end
|
137
|
-
joined_arg = arg.join(',')
|
138
|
-
if joined_arg.length > 0xffff_ffff
|
139
|
-
raise ArgumentError, "must be shorter than or equal to #{0xffff_ffff}, but got length #{joined_arg.length}"
|
140
|
-
end
|
141
|
-
[joined_arg.length, joined_arg].pack("Na*")
|
142
|
-
end
|
143
|
-
|
144
|
-
def self.decode io
|
145
|
-
length = io.read(4).unpack("N")[0]
|
146
|
-
io.read(length).unpack("a*")[0].split(',')
|
147
|
-
end
|
148
|
-
end
|
5
|
+
# DataType is a parent class of classes that provide methods to convert value and binary string each other.
|
6
|
+
class DataType
|
149
7
|
end
|
150
8
|
end
|
9
|
+
|
10
|
+
require 'hrr_rb_ssh/data_type/byte'
|
11
|
+
require 'hrr_rb_ssh/data_type/boolean'
|
12
|
+
require 'hrr_rb_ssh/data_type/uint32'
|
13
|
+
require 'hrr_rb_ssh/data_type/uint64'
|
14
|
+
require 'hrr_rb_ssh/data_type/string'
|
15
|
+
require 'hrr_rb_ssh/data_type/mpint'
|
16
|
+
require 'hrr_rb_ssh/data_type/name_list'
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
module HrrRbSsh
|
5
|
+
class DataType
|
6
|
+
# Boolean provides methods to convert boolean value and 8-bit unsigned binary string each other.
|
7
|
+
class Boolean < DataType
|
8
|
+
# Convert boolean value into 8-bit unsigned binary string.
|
9
|
+
#
|
10
|
+
# @param [::Boolean] arg boolean value to be converted
|
11
|
+
# @raise [::ArgumentError] when arg is not true nor false
|
12
|
+
# @return [::String] converted 8-bit unsigned binary string
|
13
|
+
def self.encode arg
|
14
|
+
case arg
|
15
|
+
when false
|
16
|
+
[0].pack("C")
|
17
|
+
when true
|
18
|
+
[1].pack("C")
|
19
|
+
else
|
20
|
+
raise ArgumentError, "must be #{true} or #{false}, but got #{arg.inspect}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Convert 8-bit unsigned binary into boolean value.
|
25
|
+
#
|
26
|
+
# @param [::IO] io IO instance that has buffer to be read
|
27
|
+
# @return [::Boolean] converted boolean value
|
28
|
+
def self.decode io
|
29
|
+
if 0 == io.read(1).unpack("C")[0]
|
30
|
+
false
|
31
|
+
else
|
32
|
+
true
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
module HrrRbSsh
|
5
|
+
class DataType
|
6
|
+
# Byte provides methods to convert integer value and 8-bit unsigned binary string each other.
|
7
|
+
class Byte < DataType
|
8
|
+
# Convert integer value into 8-bit unsigned binary string.
|
9
|
+
#
|
10
|
+
# @param [::Integer] arg integer value to be converted
|
11
|
+
# @raise [::ArgumentError] when arg is not between 0x00 and 0xff
|
12
|
+
# @return [::String] converted 8-bit unsigned binary string
|
13
|
+
def self.encode arg
|
14
|
+
case arg
|
15
|
+
when 0x00..0xff
|
16
|
+
[arg].pack("C")
|
17
|
+
else
|
18
|
+
raise ArgumentError, "must be in #{0x00}..#{0xff}, but got #{arg.inspect}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Convert 8-bit unsigned binary into Integer value.
|
23
|
+
#
|
24
|
+
# @param [::IO] io IO instance that has buffer to be read
|
25
|
+
# @return [::Integer] converted integer value
|
26
|
+
def self.decode io
|
27
|
+
io.read(1).unpack("C")[0]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
require 'openssl'
|
5
|
+
|
6
|
+
module HrrRbSsh
|
7
|
+
class DataType
|
8
|
+
# Mpint provides methods to convert integer value and multiple precision integer in two's complement as binary string each other.
|
9
|
+
class Mpint < DataType
|
10
|
+
# Convert integer value into multiple precision integer in two's complement as binary string.
|
11
|
+
#
|
12
|
+
# @param [::Integer] arg integer value to be converted
|
13
|
+
# @raise [::ArgumentError] when arg is not an integer value
|
14
|
+
# @return [::String] converted multiple precision integer in two's complement as binary string
|
15
|
+
def self.encode arg
|
16
|
+
unless arg.kind_of? ::Integer
|
17
|
+
raise ArgumentError, "must be a kind of Integer, but got #{arg.inspect}"
|
18
|
+
end
|
19
|
+
bn = ::OpenSSL::BN.new(arg)
|
20
|
+
if bn < 0
|
21
|
+
# get 2's complement
|
22
|
+
tc = bn.to_i & ((1 << (bn.num_bytes * 8)) - 1)
|
23
|
+
# get hex representation
|
24
|
+
hex_str = "%x" % tc
|
25
|
+
|
26
|
+
if tc[(bn.num_bytes * 8) - 1] == 1
|
27
|
+
[bn.num_bytes, hex_str].pack("NH*")
|
28
|
+
else
|
29
|
+
[bn.num_bytes + 1, "ff" + hex_str].pack("NH*")
|
30
|
+
end
|
31
|
+
else
|
32
|
+
bn.to_s(0)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Convert multiple precision integer in two's complement as binary string into integer value.
|
37
|
+
#
|
38
|
+
# @param [::IO] io IO instance that has buffer to be read
|
39
|
+
# @return [::Integer] converted integer value
|
40
|
+
def self.decode io
|
41
|
+
length = io.read(4).unpack("N")[0]
|
42
|
+
hex_str = io.read(length).unpack("H*")[0]
|
43
|
+
# get temporal integer value
|
44
|
+
value = hex_str.hex
|
45
|
+
if length == 0
|
46
|
+
0
|
47
|
+
elsif value[(length * 8) - 1] == 0
|
48
|
+
value
|
49
|
+
else
|
50
|
+
num_bytes = if hex_str.start_with?("ff") then length - 1 else length end
|
51
|
+
- (((~ value) & ((1 << (num_bytes * 8)) - 1)) + 1)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
module HrrRbSsh
|
5
|
+
class DataType
|
6
|
+
# NameList provides methods to convert a comma-separated list of names and binary string each other.
|
7
|
+
class NameList < DataType
|
8
|
+
# Convert a comma-separated list of names into binary string.
|
9
|
+
#
|
10
|
+
# @param [::Array] arg an array that containes names to be converted
|
11
|
+
# @raise [::ArgumentError] when arg is not an array
|
12
|
+
# @raise [::ArgumentError] when arg array containes an instance of not string
|
13
|
+
# @return [::String] converted binary string
|
14
|
+
def self.encode arg
|
15
|
+
unless arg.kind_of? ::Array
|
16
|
+
raise ArgumentError, "must be a kind of Array, but got #{arg.inspect}"
|
17
|
+
end
|
18
|
+
unless arg.all?{ |e| e.kind_of? ::String }
|
19
|
+
raise ArgumentError, "must be with all elements of String, but got #{arg.inspect}"
|
20
|
+
end
|
21
|
+
joined_arg = arg.join(',')
|
22
|
+
if joined_arg.length > 0xffff_ffff
|
23
|
+
raise ArgumentError, "must be shorter than or equal to #{0xffff_ffff}, but got length #{joined_arg.length}"
|
24
|
+
end
|
25
|
+
[joined_arg.length, joined_arg].pack("Na*")
|
26
|
+
end
|
27
|
+
|
28
|
+
# Convert binary string into a comma-separated list of names.
|
29
|
+
#
|
30
|
+
# @param [::IO] io IO instance that has buffer to be read
|
31
|
+
# @return [::Array] converted a comma-separated list of names
|
32
|
+
def self.decode io
|
33
|
+
length = io.read(4).unpack("N")[0]
|
34
|
+
io.read(length).unpack("a*")[0].split(',')
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
module HrrRbSsh
|
5
|
+
class DataType
|
6
|
+
# String provides methods to convert Ruby's string value and binary string each other.
|
7
|
+
class String < DataType
|
8
|
+
# Convert Ruby's string value into binary string.
|
9
|
+
#
|
10
|
+
# @param [::String] arg Ruby's string value to be converted
|
11
|
+
# @raise [::ArgumentError] when arg is not string
|
12
|
+
# @raise [::ArgumentError] when length of arg is longer than 0xffff_ffff
|
13
|
+
# @return [::String] converted binary string
|
14
|
+
def self.encode arg
|
15
|
+
unless arg.kind_of? ::String
|
16
|
+
raise ArgumentError, "must be a kind of String, but got #{arg.inspect}"
|
17
|
+
end
|
18
|
+
if arg.length > 0xffff_ffff
|
19
|
+
raise ArgumentError, "must be shorter than or equal to #{0xffff_ffff}, but got length #{arg.length}"
|
20
|
+
end
|
21
|
+
[arg.length, arg].pack("Na*")
|
22
|
+
end
|
23
|
+
|
24
|
+
# Convert binary string into Ruby's string value.
|
25
|
+
#
|
26
|
+
# @param [::IO] io IO instance that has buffer to be read
|
27
|
+
# @return [::String] converted Ruby's string value
|
28
|
+
def self.decode io
|
29
|
+
length = io.read(4).unpack("N")[0]
|
30
|
+
io.read(length).unpack("a*")[0]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
module HrrRbSsh
|
5
|
+
class DataType
|
6
|
+
# Uint32 provides methods to convert integer value and 32-bit unsigned binary string each other.
|
7
|
+
class Uint32 < DataType
|
8
|
+
# Convert integer value into 32-bit unsigned binary string.
|
9
|
+
#
|
10
|
+
# @param [::Integer] arg integer value to be converted
|
11
|
+
# @raise [::ArgumentError] when arg is not between 0x0000_0000 and 0xffff_ffff
|
12
|
+
# @return [::String] converted 32-bit unsigned binary string
|
13
|
+
def self.encode arg
|
14
|
+
case arg
|
15
|
+
when 0x0000_0000..0xffff_ffff
|
16
|
+
[arg].pack("N")
|
17
|
+
else
|
18
|
+
raise ArgumentError, "must be in #{0x0000_0000}..#{0xffff_ffff}, but got #{arg.inspect}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Convert 32-bit unsigned binary into Integer value.
|
23
|
+
#
|
24
|
+
# @param [::IO] io IO instance that has buffer to be read
|
25
|
+
# @return [::Integer] converted integer value
|
26
|
+
def self.decode io
|
27
|
+
io.read(4).unpack("N")[0]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
module HrrRbSsh
|
5
|
+
class DataType
|
6
|
+
# Uint64 provides methods to convert integer value and 64-bit unsigned binary string each other.
|
7
|
+
class Uint64 < DataType
|
8
|
+
# Convert integer value into 64-bit unsigned binary string.
|
9
|
+
#
|
10
|
+
# @param [::Integer] arg integer value to be converted
|
11
|
+
# @raise [::ArgumentError] when arg is not between 0x0000_0000_0000_0000 and 0xffff_ffff_ffff_ffff
|
12
|
+
# @return [::String] converted 64-bit unsigned binary string
|
13
|
+
def self.encode arg
|
14
|
+
case arg
|
15
|
+
when 0x0000_0000_0000_0000..0xffff_ffff_ffff_ffff
|
16
|
+
[arg >> 32].pack("N") + [arg & 0x0000_0000_ffff_ffff].pack("N")
|
17
|
+
else
|
18
|
+
raise ArgumentError, "must be in #{0x0000_0000_0000_0000}..#{0xffff_ffff_ffff_ffff}, but got #{arg.inspect}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Convert 64-bit unsigned binary into Integer value.
|
23
|
+
#
|
24
|
+
# @param [::IO] io IO instance that has buffer to be read
|
25
|
+
# @return [::Integer] converted integer value
|
26
|
+
def self.decode io
|
27
|
+
(io.read(4).unpack("N")[0] << 32) + (io.read(4).unpack("N")[0])
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
module HrrRbSsh
|
5
|
+
module SubclassWithoutPreferenceListable
|
6
|
+
def inherited klass
|
7
|
+
@subclass_list.push klass if @subclass_list
|
8
|
+
end
|
9
|
+
|
10
|
+
def [] key
|
11
|
+
__subclass_list__(__method__).find{ |klass| klass::NAME == key }
|
12
|
+
end
|
13
|
+
|
14
|
+
def list_supported
|
15
|
+
__subclass_list__(__method__).map{ |klass| klass::NAME }
|
16
|
+
end
|
17
|
+
|
18
|
+
def __subclass_list__ method_name
|
19
|
+
send(:method_missing, method_name) unless @subclass_list
|
20
|
+
@subclass_list
|
21
|
+
end
|
22
|
+
|
23
|
+
private :__subclass_list__
|
24
|
+
end
|
25
|
+
end
|
@@ -19,3 +19,4 @@ require 'hrr_rb_ssh/transport/server_host_key_algorithm/ssh_rsa'
|
|
19
19
|
require 'hrr_rb_ssh/transport/server_host_key_algorithm/ecdsa_sha2_nistp256'
|
20
20
|
require 'hrr_rb_ssh/transport/server_host_key_algorithm/ecdsa_sha2_nistp384'
|
21
21
|
require 'hrr_rb_ssh/transport/server_host_key_algorithm/ecdsa_sha2_nistp521'
|
22
|
+
require 'hrr_rb_ssh/transport/server_host_key_algorithm/ssh_ed25519'
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
require 'ed25519'
|
5
|
+
require 'hrr_rb_ssh/openssl_secure_random'
|
6
|
+
require 'hrr_rb_ssh/transport/server_host_key_algorithm/functionable'
|
7
|
+
|
8
|
+
module HrrRbSsh
|
9
|
+
class Transport
|
10
|
+
class ServerHostKeyAlgorithm
|
11
|
+
class SshEd25519 < ServerHostKeyAlgorithm
|
12
|
+
NAME = 'ssh-ed25519'
|
13
|
+
PREFERENCE = 60
|
14
|
+
SECRET_KEY = ::Ed25519::SigningKey.generate
|
15
|
+
|
16
|
+
include Functionable
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/hrr_rb_ssh/version.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hrr_rb_ssh
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- hirura
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-08-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: ed25519
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.2'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.2'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: bundler
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -98,6 +112,12 @@ files:
|
|
98
112
|
- lib/hrr_rb_ssh/algorithm/publickey/ssh_dss.rb
|
99
113
|
- lib/hrr_rb_ssh/algorithm/publickey/ssh_dss/public_key_blob.rb
|
100
114
|
- lib/hrr_rb_ssh/algorithm/publickey/ssh_dss/signature.rb
|
115
|
+
- lib/hrr_rb_ssh/algorithm/publickey/ssh_ed25519.rb
|
116
|
+
- lib/hrr_rb_ssh/algorithm/publickey/ssh_ed25519/openssh_private_key.rb
|
117
|
+
- lib/hrr_rb_ssh/algorithm/publickey/ssh_ed25519/openssh_private_key_content.rb
|
118
|
+
- lib/hrr_rb_ssh/algorithm/publickey/ssh_ed25519/pkey.rb
|
119
|
+
- lib/hrr_rb_ssh/algorithm/publickey/ssh_ed25519/public_key_blob.rb
|
120
|
+
- lib/hrr_rb_ssh/algorithm/publickey/ssh_ed25519/signature.rb
|
101
121
|
- lib/hrr_rb_ssh/algorithm/publickey/ssh_rsa.rb
|
102
122
|
- lib/hrr_rb_ssh/algorithm/publickey/ssh_rsa/public_key_blob.rb
|
103
123
|
- lib/hrr_rb_ssh/algorithm/publickey/ssh_rsa/signature.rb
|
@@ -120,6 +140,7 @@ files:
|
|
120
140
|
- lib/hrr_rb_ssh/authentication/method/publickey/algorithm/functionable.rb
|
121
141
|
- lib/hrr_rb_ssh/authentication/method/publickey/algorithm/signature_blob.rb
|
122
142
|
- lib/hrr_rb_ssh/authentication/method/publickey/algorithm/ssh_dss.rb
|
143
|
+
- lib/hrr_rb_ssh/authentication/method/publickey/algorithm/ssh_ed25519.rb
|
123
144
|
- lib/hrr_rb_ssh/authentication/method/publickey/algorithm/ssh_rsa.rb
|
124
145
|
- lib/hrr_rb_ssh/authentication/method/publickey/context.rb
|
125
146
|
- lib/hrr_rb_ssh/codable.rb
|
@@ -161,6 +182,13 @@ files:
|
|
161
182
|
- lib/hrr_rb_ssh/connection/request_handler/reference_shell_request_handler.rb
|
162
183
|
- lib/hrr_rb_ssh/connection/request_handler/reference_window_change_request_handler.rb
|
163
184
|
- lib/hrr_rb_ssh/data_type.rb
|
185
|
+
- lib/hrr_rb_ssh/data_type/boolean.rb
|
186
|
+
- lib/hrr_rb_ssh/data_type/byte.rb
|
187
|
+
- lib/hrr_rb_ssh/data_type/mpint.rb
|
188
|
+
- lib/hrr_rb_ssh/data_type/name_list.rb
|
189
|
+
- lib/hrr_rb_ssh/data_type/string.rb
|
190
|
+
- lib/hrr_rb_ssh/data_type/uint32.rb
|
191
|
+
- lib/hrr_rb_ssh/data_type/uint64.rb
|
164
192
|
- lib/hrr_rb_ssh/error.rb
|
165
193
|
- lib/hrr_rb_ssh/error/closed_authentication.rb
|
166
194
|
- lib/hrr_rb_ssh/error/closed_connection.rb
|
@@ -208,6 +236,7 @@ files:
|
|
208
236
|
- lib/hrr_rb_ssh/openssl_secure_random.rb
|
209
237
|
- lib/hrr_rb_ssh/server.rb
|
210
238
|
- lib/hrr_rb_ssh/subclass_with_preference_listable.rb
|
239
|
+
- lib/hrr_rb_ssh/subclass_without_preference_listable.rb
|
211
240
|
- lib/hrr_rb_ssh/transport.rb
|
212
241
|
- lib/hrr_rb_ssh/transport/compression_algorithm.rb
|
213
242
|
- lib/hrr_rb_ssh/transport/compression_algorithm/functionable.rb
|
@@ -269,6 +298,7 @@ files:
|
|
269
298
|
- lib/hrr_rb_ssh/transport/server_host_key_algorithm/ecdsa_sha2_nistp521.rb
|
270
299
|
- lib/hrr_rb_ssh/transport/server_host_key_algorithm/functionable.rb
|
271
300
|
- lib/hrr_rb_ssh/transport/server_host_key_algorithm/ssh_dss.rb
|
301
|
+
- lib/hrr_rb_ssh/transport/server_host_key_algorithm/ssh_ed25519.rb
|
272
302
|
- lib/hrr_rb_ssh/transport/server_host_key_algorithm/ssh_rsa.rb
|
273
303
|
- lib/hrr_rb_ssh/version.rb
|
274
304
|
homepage: https://github.com/hirura/hrr_rb_ssh
|