orthrus-ssh 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.autotest +23 -0
- data/.gemtest +0 -0
- data/History.txt +6 -0
- data/Manifest.txt +31 -0
- data/README.txt +61 -0
- data/Rakefile +12 -0
- data/bin/orthrus +16 -0
- data/lib/orthrus.rb +2 -0
- data/lib/orthrus/key.rb +12 -0
- data/lib/orthrus/key_holder.rb +15 -0
- data/lib/orthrus/ssh.rb +50 -0
- data/lib/orthrus/ssh/agent.rb +176 -0
- data/lib/orthrus/ssh/buffer.rb +343 -0
- data/lib/orthrus/ssh/dsa.rb +88 -0
- data/lib/orthrus/ssh/http_agent.rb +83 -0
- data/lib/orthrus/ssh/key.rb +50 -0
- data/lib/orthrus/ssh/public_key_set.rb +30 -0
- data/lib/orthrus/ssh/rack_app.rb +62 -0
- data/lib/orthrus/ssh/rsa.rb +51 -0
- data/lib/orthrus/ssh/utils.rb +26 -0
- data/test/data/authorized_keys +2 -0
- data/test/data/id_dsa +12 -0
- data/test/data/id_dsa.pub +1 -0
- data/test/data/id_rsa +27 -0
- data/test/data/id_rsa.pub +1 -0
- data/test/sessions.rb +28 -0
- data/test/test_orthrus_ssh_agent.rb +31 -0
- data/test/test_orthrus_ssh_dsa.rb +46 -0
- data/test/test_orthrus_ssh_http_agent.rb +71 -0
- data/test/test_orthrus_ssh_public_key_set.rb +29 -0
- data/test/test_orthrus_ssh_rackapp.rb +84 -0
- data/test/test_orthrus_ssh_rsa.rb +46 -0
- metadata +149 -0
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'orthrus/ssh/key'
|
2
|
+
|
3
|
+
require 'orthrus/ssh/buffer'
|
4
|
+
|
5
|
+
module Orthrus::SSH
|
6
|
+
module DSA
|
7
|
+
def initialize(k)
|
8
|
+
super k, OpenSSL::Digest::DSS1
|
9
|
+
end
|
10
|
+
|
11
|
+
def public_identity(base64=true)
|
12
|
+
b = Buffer.from :string, "ssh-dss",
|
13
|
+
:bignum, @key.p,
|
14
|
+
:bignum, @key.q,
|
15
|
+
:bignum, @key.g,
|
16
|
+
:bignum, @key.pub_key
|
17
|
+
|
18
|
+
d = b.to_s
|
19
|
+
|
20
|
+
return d unless base64
|
21
|
+
|
22
|
+
[d].pack("m").gsub("\n","")
|
23
|
+
end
|
24
|
+
|
25
|
+
def type
|
26
|
+
"ssh-dss"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class DSAPrivateKey < PrivateKey
|
31
|
+
include DSA
|
32
|
+
|
33
|
+
def sign(data)
|
34
|
+
sig = super data
|
35
|
+
|
36
|
+
a1sig = OpenSSL::ASN1.decode sig
|
37
|
+
|
38
|
+
sig_r = a1sig.value[0].value.to_s(2)
|
39
|
+
sig_s = a1sig.value[1].value.to_s(2)
|
40
|
+
|
41
|
+
if sig_r.length > 20 || sig_s.length > 20
|
42
|
+
raise OpenSSL::PKey::DSAError, "bad sig size"
|
43
|
+
end
|
44
|
+
|
45
|
+
sig_r = "\0" * ( 20 - sig_r.length ) + sig_r if sig_r.length < 20
|
46
|
+
sig_s = "\0" * ( 20 - sig_s.length ) + sig_s if sig_s.length < 20
|
47
|
+
return sig_r + sig_s
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class DSAPublicKey < PublicKey
|
52
|
+
def self.parse(data)
|
53
|
+
raw = data.unpack("m").first
|
54
|
+
|
55
|
+
b = Buffer.new raw
|
56
|
+
|
57
|
+
type = b.read_string
|
58
|
+
unless type == "ssh-dss"
|
59
|
+
raise "Unvalid key data"
|
60
|
+
end
|
61
|
+
|
62
|
+
k = OpenSSL::PKey::DSA.new
|
63
|
+
k.p = b.read_bignum
|
64
|
+
k.q = b.read_bignum
|
65
|
+
k.g = b.read_bignum
|
66
|
+
k.pub_key = b.read_bignum
|
67
|
+
|
68
|
+
new k
|
69
|
+
end
|
70
|
+
|
71
|
+
include DSA
|
72
|
+
|
73
|
+
# Adapted from net-ssh
|
74
|
+
# Verifies the given signature matches the given data.
|
75
|
+
def verify(sig, data)
|
76
|
+
sig_r = sig[0,20].unpack("H*")[0].to_i(16)
|
77
|
+
sig_s = sig[20,20].unpack("H*")[0].to_i(16)
|
78
|
+
|
79
|
+
a1sig = OpenSSL::ASN1::Sequence([
|
80
|
+
OpenSSL::ASN1::Integer(sig_r),
|
81
|
+
OpenSSL::ASN1::Integer(sig_s)
|
82
|
+
])
|
83
|
+
|
84
|
+
super a1sig.to_der, data
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'orthrus/ssh'
|
2
|
+
require 'orthrus/ssh/agent'
|
3
|
+
|
4
|
+
require 'uri'
|
5
|
+
|
6
|
+
require 'net/http'
|
7
|
+
|
8
|
+
module Orthrus::SSH
|
9
|
+
class HTTPAgent
|
10
|
+
def initialize(url)
|
11
|
+
@url = url
|
12
|
+
@keys = []
|
13
|
+
@access_token = nil
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_reader :access_token
|
17
|
+
|
18
|
+
def add_key(key)
|
19
|
+
@keys << Orthrus::SSH.load_private(key)
|
20
|
+
end
|
21
|
+
|
22
|
+
def check(user, k)
|
23
|
+
id = Rack::Utils.escape(k.public_identity)
|
24
|
+
user = Rack::Utils.escape(user)
|
25
|
+
|
26
|
+
url = @url + "?state=find&user=#{user}&id=#{id}"
|
27
|
+
response = Net::HTTP.get_response url
|
28
|
+
params = Rack::Utils.parse_query response.body
|
29
|
+
|
30
|
+
return nil unless params["code"] == "check"
|
31
|
+
|
32
|
+
[params['session_id'], params['nonce']]
|
33
|
+
end
|
34
|
+
|
35
|
+
def negotiate(k, sid, sig)
|
36
|
+
sig = Rack::Utils.escape sig
|
37
|
+
|
38
|
+
url = @url + "?state=signed&sig=#{sig}&session_id=#{sid}"
|
39
|
+
|
40
|
+
response = Net::HTTP.get_response url
|
41
|
+
params = Rack::Utils.parse_query response.body
|
42
|
+
|
43
|
+
if params['code'] == "verified"
|
44
|
+
return params['access_token']
|
45
|
+
end
|
46
|
+
|
47
|
+
return nil
|
48
|
+
end
|
49
|
+
|
50
|
+
def start(user)
|
51
|
+
@keys.each do |k|
|
52
|
+
sid, data = check(user, k)
|
53
|
+
next unless sid
|
54
|
+
|
55
|
+
sig = k.hexsign(data)
|
56
|
+
|
57
|
+
token = negotiate(k, sid, sig)
|
58
|
+
if token
|
59
|
+
@access_token = token
|
60
|
+
return
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
if Agent.available?
|
65
|
+
agent = Agent.connect
|
66
|
+
agent.identities.each do |k|
|
67
|
+
sid, data = check(user, k)
|
68
|
+
next unless sid
|
69
|
+
|
70
|
+
type, sig = agent.hexsign k, data
|
71
|
+
|
72
|
+
token = negotiate(k, sid, sig)
|
73
|
+
if token
|
74
|
+
@access_token = token
|
75
|
+
return
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
raise "Unable to find key to authenticate with"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Orthrus::SSH
|
2
|
+
class Key
|
3
|
+
def initialize(k, digest)
|
4
|
+
@key = k
|
5
|
+
@digest = digest
|
6
|
+
@comment = nil
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_reader :key
|
10
|
+
attr_accessor :comment
|
11
|
+
|
12
|
+
def rsa?
|
13
|
+
@key.kind_of? OpenSSL::PKey::RSA
|
14
|
+
end
|
15
|
+
|
16
|
+
def dsa?
|
17
|
+
@key.kind_of? OpenSSL::PKey::DSA
|
18
|
+
end
|
19
|
+
|
20
|
+
def fingerprint
|
21
|
+
blob = public_identity(false)
|
22
|
+
OpenSSL::Digest::MD5.hexdigest(blob).scan(/../).join(":")
|
23
|
+
end
|
24
|
+
|
25
|
+
def inspect
|
26
|
+
"#<#{self.class} #{fingerprint}>"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class PrivateKey < Key
|
31
|
+
def sign(data)
|
32
|
+
@key.sign @digest.new, data
|
33
|
+
end
|
34
|
+
|
35
|
+
def hexsign(data)
|
36
|
+
[sign(data)].pack("m").gsub("\n","")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class PublicKey < Key
|
41
|
+
def verify(sign, data)
|
42
|
+
@key.verify @digest.new, sign, data
|
43
|
+
end
|
44
|
+
|
45
|
+
def hexverify(sign, data)
|
46
|
+
verify sign.unpack("m").first, data
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'orthrus/ssh'
|
2
|
+
|
3
|
+
module Orthrus::SSH
|
4
|
+
class PublicKeySet
|
5
|
+
def self.load_file(path)
|
6
|
+
keys = {}
|
7
|
+
|
8
|
+
File.readlines(path).each do |x|
|
9
|
+
type, dig, comment = x.split(" ", 3)
|
10
|
+
|
11
|
+
keys[dig] = Orthrus::SSH.parse_public x
|
12
|
+
end
|
13
|
+
|
14
|
+
new keys
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(keys)
|
18
|
+
@keys = keys
|
19
|
+
end
|
20
|
+
|
21
|
+
def find(dig)
|
22
|
+
@keys[dig]
|
23
|
+
end
|
24
|
+
|
25
|
+
def num_keys
|
26
|
+
@keys.size
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'orthrus/ssh'
|
2
|
+
require 'rack'
|
3
|
+
|
4
|
+
module Orthrus::SSH
|
5
|
+
class RackApp
|
6
|
+
def initialize(sessions)
|
7
|
+
@sessions = sessions
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_reader :sessions
|
11
|
+
|
12
|
+
def call(env)
|
13
|
+
req = Rack::Request.new(env)
|
14
|
+
|
15
|
+
case req.params['state']
|
16
|
+
when 'find'
|
17
|
+
find req
|
18
|
+
when 'signed'
|
19
|
+
verify req
|
20
|
+
else
|
21
|
+
[500, {}, ["unknown state"]]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def form(body)
|
26
|
+
[200,
|
27
|
+
{ "Content-Type" => "application/x-www-form-urlencoded" },
|
28
|
+
[body]
|
29
|
+
]
|
30
|
+
end
|
31
|
+
|
32
|
+
def find(req)
|
33
|
+
user = req.params['user']
|
34
|
+
id = req.params["id"]
|
35
|
+
|
36
|
+
unless pub = @sessions.find_key(user, id)
|
37
|
+
return form("code=unknown")
|
38
|
+
end
|
39
|
+
|
40
|
+
session, nonce = @sessions.new_session(user, pub)
|
41
|
+
|
42
|
+
nonce = Rack::Utils.escape Utils.sha1_hash(nonce)
|
43
|
+
|
44
|
+
form "code=check&session_id=#{session}&nonce=#{nonce}"
|
45
|
+
end
|
46
|
+
|
47
|
+
def verify(req)
|
48
|
+
id = req.params["session_id"].to_i
|
49
|
+
nonce, pub = @sessions.find_session(id)
|
50
|
+
|
51
|
+
nonce = Utils.sha1_hash(nonce)
|
52
|
+
|
53
|
+
sig = req.params['sig']
|
54
|
+
|
55
|
+
if pub.hexverify(sig, nonce)
|
56
|
+
form "code=verified&access_token=1"
|
57
|
+
else
|
58
|
+
form "code=fail"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'orthrus/ssh/key'
|
2
|
+
|
3
|
+
module Orthrus::SSH
|
4
|
+
|
5
|
+
module RSA
|
6
|
+
def initialize(k)
|
7
|
+
super k, OpenSSL::Digest::SHA1
|
8
|
+
end
|
9
|
+
|
10
|
+
def public_identity(base64=true)
|
11
|
+
b = Buffer.from :string, "ssh-rsa",
|
12
|
+
:bignum, @key.e,
|
13
|
+
:bignum, @key.n
|
14
|
+
|
15
|
+
d = b.to_s
|
16
|
+
|
17
|
+
return d unless base64
|
18
|
+
|
19
|
+
[d].pack("m").gsub("\n","")
|
20
|
+
end
|
21
|
+
|
22
|
+
def type
|
23
|
+
"ssh-rsa"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class RSAPrivateKey < PrivateKey
|
28
|
+
include RSA
|
29
|
+
end
|
30
|
+
|
31
|
+
class RSAPublicKey < PublicKey
|
32
|
+
def self.parse(data)
|
33
|
+
raw = data.unpack("m").first
|
34
|
+
|
35
|
+
b = Buffer.new raw
|
36
|
+
|
37
|
+
type = b.read_string
|
38
|
+
unless type == "ssh-rsa"
|
39
|
+
raise "Unvalid key data"
|
40
|
+
end
|
41
|
+
|
42
|
+
k = OpenSSL::PKey::RSA.new
|
43
|
+
k.e = b.read_bignum
|
44
|
+
k.n = b.read_bignum
|
45
|
+
|
46
|
+
new k
|
47
|
+
end
|
48
|
+
|
49
|
+
include RSA
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Orthrus::SSH
|
2
|
+
module Utils
|
3
|
+
def self.write_bignum(bn)
|
4
|
+
# Cribbed from net-ssh
|
5
|
+
if bn.zero?
|
6
|
+
return [0].pack("N")
|
7
|
+
else
|
8
|
+
buf = bn.to_s(2)
|
9
|
+
if buf[0][7] == 1
|
10
|
+
return [buf.length+1, 0, buf].pack("NCA*")
|
11
|
+
else
|
12
|
+
return [buf.length, buf].pack("NA*")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.write_string(str)
|
18
|
+
[str.size].pack("N") + str
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.sha1_hash(data)
|
22
|
+
OpenSSL::Digest::SHA1.hexdigest data
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,2 @@
|
|
1
|
+
ssh-dss AAAAB3NzaC1kc3MAAACBAK8JRdWMWVcnFxRn8Pwhu6a7W8HQGPd93GY4JbKTTZjDrJEjKMnNUaFVZpu13MQwow8kaolqS+6tUaNDTFY+bymYcVWdQKWFAC/8MrOeJZq1GugNBxk9RC/VZBvW4nDTPgXhRftSxB7KBk0Tvk70fbwffaVGW7A+GBJKXYHdA/PdAAAAFQCjif6zl1zEITOq8us9WfvvBiQCkQAAAIEAqwFVbyhPWEVp5Ierq1syOJv4Hjqnbo/69mU/mFpnhIhreJ+uNIaFlEdwJY+WaQ7mUpWKCjhRMcDICQ+Lgq3zjaZhSe6F+SBHWI2ISDgRs73W2z42oECRrQoNJ9WZSF+6l+cHEHsD6Qv+B4cYtr7JJj7IGtMZzDO+zhQaUWTNeUoAAACADRsQHiTTr+50iRiiC26dq+W8GxksI4A5nESv3LpbqMI/SNzglK5OlLkKw403Ox7O1Hb+uZmmOZQmk1OTPjS3QPT+LC/lkUANpP7T7Bkh9RwUUVJF3qvhHDH94BDO3clZKdV558gSHi+T9P31h1gcw5rAVh+yK2ZyZGV/jP0r0z0= evan@aero.local
|
2
|
+
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDDgYlt6gUVZUZE4xgW2TRvi8HjVgrWZ5e6Av76/H3PzvZpsgHSZyDiU1rgVsgwfb1NmJiwflNpILLprSmp3RRqdOEKzEPgxdscQY1sJtTQcmdlWeIvN6KvmImPwV9krqtN8vji7Zqr0N3mcDmdK1MbQ56Cjx5l6/y9rYGLmIZvoLOLDVe3olOHjpapHQLHrQL3c/2Il5y+9aXR1c/gKFeEwwhRL6hcSIufBnanXqVGa5QNrfzw4si8oAIWDNfXDGRdFkxrnGxHOguj8hFeYXNtz6OHu2UPbvum9sUNHXdDHBYSTPqUJfdLvo49ZMqShcEgNrlBe8rx7ooPdDas40mH evan@aero.local
|
data/test/data/id_dsa
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
-----BEGIN DSA PRIVATE KEY-----
|
2
|
+
MIIBuwIBAAKBgQCvCUXVjFlXJxcUZ/D8Ibumu1vB0Bj3fdxmOCWyk02Yw6yRIyjJ
|
3
|
+
zVGhVWabtdzEMKMPJGqJakvurVGjQ0xWPm8pmHFVnUClhQAv/DKzniWatRroDQcZ
|
4
|
+
PUQv1WQb1uJw0z4F4UX7UsQeygZNE75O9H28H32lRluwPhgSSl2B3QPz3QIVAKOJ
|
5
|
+
/rOXXMQhM6ry6z1Z++8GJAKRAoGBAKsBVW8oT1hFaeSHq6tbMjib+B46p26P+vZl
|
6
|
+
P5haZ4SIa3ifrjSGhZRHcCWPlmkO5lKVigo4UTHAyAkPi4Kt842mYUnuhfkgR1iN
|
7
|
+
iEg4EbO91ts+NqBAka0KDSfVmUhfupfnBxB7A+kL/geHGLa+ySY+yBrTGcwzvs4U
|
8
|
+
GlFkzXlKAoGADRsQHiTTr+50iRiiC26dq+W8GxksI4A5nESv3LpbqMI/SNzglK5O
|
9
|
+
lLkKw403Ox7O1Hb+uZmmOZQmk1OTPjS3QPT+LC/lkUANpP7T7Bkh9RwUUVJF3qvh
|
10
|
+
HDH94BDO3clZKdV558gSHi+T9P31h1gcw5rAVh+yK2ZyZGV/jP0r0z0CFEY8QELo
|
11
|
+
OZ+AwfX3cTZZTQMaNgAm
|
12
|
+
-----END DSA PRIVATE KEY-----
|
@@ -0,0 +1 @@
|
|
1
|
+
ssh-dss AAAAB3NzaC1kc3MAAACBAK8JRdWMWVcnFxRn8Pwhu6a7W8HQGPd93GY4JbKTTZjDrJEjKMnNUaFVZpu13MQwow8kaolqS+6tUaNDTFY+bymYcVWdQKWFAC/8MrOeJZq1GugNBxk9RC/VZBvW4nDTPgXhRftSxB7KBk0Tvk70fbwffaVGW7A+GBJKXYHdA/PdAAAAFQCjif6zl1zEITOq8us9WfvvBiQCkQAAAIEAqwFVbyhPWEVp5Ierq1syOJv4Hjqnbo/69mU/mFpnhIhreJ+uNIaFlEdwJY+WaQ7mUpWKCjhRMcDICQ+Lgq3zjaZhSe6F+SBHWI2ISDgRs73W2z42oECRrQoNJ9WZSF+6l+cHEHsD6Qv+B4cYtr7JJj7IGtMZzDO+zhQaUWTNeUoAAACADRsQHiTTr+50iRiiC26dq+W8GxksI4A5nESv3LpbqMI/SNzglK5OlLkKw403Ox7O1Hb+uZmmOZQmk1OTPjS3QPT+LC/lkUANpP7T7Bkh9RwUUVJF3qvhHDH94BDO3clZKdV558gSHi+T9P31h1gcw5rAVh+yK2ZyZGV/jP0r0z0= evan@aero.local
|
data/test/data/id_rsa
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
-----BEGIN RSA PRIVATE KEY-----
|
2
|
+
MIIEogIBAAKCAQEAw4GJbeoFFWVGROMYFtk0b4vB41YK1meXugL++vx9z872abIB
|
3
|
+
0mcg4lNa4FbIMH29TZiYsH5TaSCy6a0pqd0UanThCsxD4MXbHEGNbCbU0HJnZVni
|
4
|
+
Lzeir5iJj8FfZK6rTfL44u2aq9Dd5nA5nStTG0Oego8eZev8va2Bi5iGb6Cziw1X
|
5
|
+
t6JTh46WqR0Cx60C93P9iJecvvWl0dXP4ChXhMMIUS+oXEiLnwZ2p16lRmuUDa38
|
6
|
+
8OLIvKACFgzX1wxkXRZMa5xsRzoLo/IRXmFzbc+jh7tlD277pvbFDR13QxwWEkz6
|
7
|
+
lCX3S76OPWTKkoXBIDa5QXvK8e6KD3Q2rONJhwIDAQABAoIBAH0yRr+MTRUWdZlH
|
8
|
+
k/WNwnZsGQ1r3CTQ0ejcYkx3xFl/P20QAPqr7/L/TgK7kBb9bmxye9UKEIAR4ICj
|
9
|
+
0zpjyN8jWbmAdTdLfLTrhZTsiPuzR2Mv3BhAmH26QN0+B8iB0lFodtlbLuE4L+GR
|
10
|
+
nFN5mw6qjqcs31qFdKRCp+KtGeoA8B2OvPLH6tBoLo4UPtB9OgZR9nhi6ZSkUuNP
|
11
|
+
xzFU+QgtfBumGOfspwa8Cy+zatwI0Xw4O4FY5bIcp7n+E43pzMLVnkrBxQKouugR
|
12
|
+
ldgW2PYm5yX/ffuKdjruSbXRb1Li+Ikx7rK76GfbBSzr33qH1PDqoOdPS4JPuAzj
|
13
|
+
wh4YLoECgYEA6q6GJBFui3xFmN+CXVDGeNGXutxxVksMtbHw3P3xwmerfs3+KQD6
|
14
|
+
UIb2r22dfu/dILAIkgsx6lsUpvpj0vyyav7mNVRv06qbcGs/zxTquTZXd7NA8+Gm
|
15
|
+
ZPv2WKugdsVKHO22D40pFdBM13GPnYo2FGSIsvTC2oZHScJxpnySrKMCgYEA1UP9
|
16
|
+
O0CrpYqI7Ktt3iPeX/a+tTCIcmxoWvKwq29dEg6Ck4JmLDcQETQms7tflbNyjX3L
|
17
|
+
VgzmBEeRo8cz0YpvSHFmcgy7F0Rnk2ijb85ppJF0rJS0yBJOlHzoYsqIlbFWihl/
|
18
|
+
QEy0sBMXQjcvLvIDpiQDzWNdLf7DS9aNKKAyec0CgYA+3rRW80iPG6K1eqM9Boe1
|
19
|
+
FEk2qRm/yWlFP79MJMfgkc9SsDK3n2hvrEhn5NC9kdrGiAIzxcYAh5f3x7p4anQN
|
20
|
+
z+2yOcWfieQMcN7uRic/qPwzuBTdgQUHpqxvQsNBLkdViqUsc1+fVWdQjD6yMLWe
|
21
|
+
LvSkJIgS7MgqTWoO9O6CSwKBgDhB3yMqRB0/Fi+YaTsYKykVZelWDChjAIQ9UO1o
|
22
|
+
SxzgRwGyfFFdlRd0smDnJKfQ1n8Ml/7zGBo45upVOg4kfoaVo3iicxgIK2pvR+3O
|
23
|
+
fX+z/xsnfyjn62KwMH0fADi8tx9m6nKDyYZJAvGsrP2tSdkh1v7vHz1q3wm6ZzI4
|
24
|
+
UBhhAoGAGno46WOio1hGOQoT5GFvyMPBsZAWvFdWSd14gOUzbX4cf+hRsBW4KqZy
|
25
|
+
v3jMQ1YgYXf0yvXODKycuFP9uz9HcznwwahT23T0jYtDWkGeMqdoncpenarsfVjF
|
26
|
+
PUQgoSpveFwz5UtsP3WhZKCl3/et7FDN1hbXqmWF1i6YbnjIJo8=
|
27
|
+
-----END RSA PRIVATE KEY-----
|