hrr_rb_ssh 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|