orthrus-ssh 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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-----
|