mskeyblob 0.0.1

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f1dc47d417a33062f972534222dd4cb1babb597a
4
+ data.tar.gz: 4f2a6903983f95e014a373f1a72e20355b65eeca
5
+ SHA512:
6
+ metadata.gz: 6630ebb682df863903b3fb435e7d4b338588cc176233087d197c8fc4fcf34ddfc2d3b117e34d9adbde804133ce1b60f4ae353bbb1dcf6cd49cb2fbcc62fd361f
7
+ data.tar.gz: 084f66bf311ffc0041ee7fddd97872299ed7f2cc77d3d8bfd611b5ad8f2555169aff48808dbce8841307d5fa28cdb0e6ef58307bd18f9951983e294c935428e6
@@ -0,0 +1,23 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
23
+ .idea/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in mskeyblob.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Alexander Zimin
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,52 @@
1
+ # Microsoft RSA key blob
2
+
3
+ Exchange RSA keys between Microsoft CSP blob format (ExportCspBlob, ImportCspBlob of RSACryptoServiceProvider)
4
+ and ruby openssl key OpenSSL::PKey::RSA
5
+
6
+ ## Usage
7
+
8
+ Create key from blob created by ExportCspBlob
9
+
10
+ ```ruby
11
+ blob = File.binread 'msblob.bin'
12
+
13
+ key = OpenSSL::PKey::RSA.from_mskeyblob blob
14
+ ```
15
+
16
+ Create blob for ExportCspBlob
17
+
18
+ ```ruby
19
+ key = OpenSSL::PKey::RSA.new 2048
20
+
21
+ blob = key.to_mskeyblob
22
+ public_blob = key.to_mskeyblob(include_private: false)
23
+ ```
24
+
25
+ ## Installation
26
+
27
+ Add this line to your application's Gemfile:
28
+
29
+ gem 'mskeyblob'
30
+
31
+ And then execute:
32
+
33
+ $ bundle
34
+
35
+ Or install it yourself as:
36
+
37
+ $ gem install mskeyblob
38
+
39
+ ## Contributing
40
+
41
+ 1. Fork it ( https://github.com/Ziaw/mskeyblob/fork )
42
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
43
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
44
+ 4. Push to the branch (`git push origin my-new-feature`)
45
+ 5. Create a new Pull Request
46
+
47
+
48
+ ## Links
49
+
50
+ 1. [MSDN Enhanced Provider Key BLOBs](https://msdn.microsoft.com/en-us/library/windows/desktop/aa382021%28v=vs.85%29.aspx)
51
+
52
+ 2. [Ruby and OpenSSL](http://blog.flame.org/2009/02/28/ruby-and-openssl.html)
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rake/testtask'
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.libs << 'test'
7
+ end
8
+
9
+ desc "Run tests"
10
+ task :default => :test
@@ -0,0 +1,101 @@
1
+ require 'mskeyblob/version'
2
+
3
+ module OpenSSL
4
+ module PKey
5
+ class RSA
6
+ RSA1 = 0x31415352
7
+ RSA2 = 0x32415352
8
+
9
+ PUBLICKEYBLOB = 0x6
10
+ PRIVATEKEYBLOB = 0x7
11
+
12
+ CALG_RSA_KEYX = 0x0000a400
13
+
14
+ def self.from_mskeyblob(key)
15
+ b_type, b_version, reserved, alg_id, # PUBLICKEYSTRUC
16
+ magic, bit_len, public_exponent, # RSAPUBKEY
17
+ rest =
18
+ key.unpack('CCSL LLL a*')
19
+
20
+ # PUBLICKEYBLOB || PRIVATEKEYBLOB
21
+ raise OpenSSL::PKey::RSAError, "Neither PUB key nor PRIV key: invalid bType #{b_type}" unless [PUBLICKEYBLOB, 0x7].include? b_type
22
+ raise OpenSSL::PKey::RSAError, "Neither PUB key nor PRIV key: invalid bVersion #{b_version}" unless b_version == 2
23
+ raise OpenSSL::PKey::RSAError, "Neither PUB key nor PRIV key: invalid magic #{magic}" unless [RSA1, RSA2].include? magic
24
+
25
+ b8 = "a#{bit_len / 8}"
26
+ b16 = "a#{bit_len / 16}"
27
+
28
+ unpack_pattern = [b8, b16, b16, b16, b16, b16, b8].join('')
29
+
30
+ modulus, p1, p2, e1, e2, c, private_exponent = rest.unpack(unpack_pattern)
31
+
32
+ modulus, p1, p2, e1, e2, c, private_exponent = [modulus, p1, p2, e1, e2, c, private_exponent].map do |byte_array|
33
+ if byte_array.empty?
34
+ nil
35
+ else
36
+ OpenSSL::BN.new byte_array.reverse, 2
37
+ end
38
+ end
39
+
40
+ key = OpenSSL::PKey::RSA.new
41
+ key.n = modulus
42
+ key.e = public_exponent
43
+
44
+ if private_exponent
45
+ key.d = private_exponent
46
+ key.p = p1
47
+ key.q = p2
48
+ key.dmp1 = e1
49
+ key.dmq1 = e2
50
+ key.iqmp = c
51
+ end
52
+
53
+ key
54
+ end
55
+
56
+ def to_mskeyblob(include_private: :not_set)
57
+ if include_private == :not_set
58
+ include_private = private?
59
+ else
60
+ if include_private && !private?
61
+ raise OpenSSL::PKey::RSAError, 'Public key can not export private part'
62
+ end
63
+ end
64
+
65
+ b_type = include_private ? PRIVATEKEYBLOB : PUBLICKEYBLOB
66
+ b_version = 2
67
+ reserved = 0
68
+ alg_id = CALG_RSA_KEYX
69
+ magic = include_private ? RSA2 : RSA1
70
+
71
+
72
+ bit_len = n.num_bits # https://github.com/ruby/openssl/issues/5
73
+ public_exponent = e
74
+
75
+ b8 = "a#{bit_len / 8}"
76
+ b16 = "a#{bit_len / 16}"
77
+
78
+ header = [
79
+ b_type, b_version, reserved, alg_id, # PUBLICKEYSTRUC
80
+ magic, bit_len, public_exponent, # RSAPUBKEY
81
+ ].pack('CCSL LLL')
82
+
83
+ modulus, p1, p2, e1, e2, c, private_exponent = [n, p, q, dmp1, dmq1, iqmp, d].map do |bn|
84
+ if bn
85
+ bn.to_s(2).reverse
86
+ else
87
+ nil
88
+ end
89
+ end
90
+
91
+ if include_private
92
+ pack_pattern = [b8, b16, b16, b16, b16, b16, b8].join('')
93
+
94
+ header + [modulus, p1, p2, e1, e2, c, private_exponent].pack(pack_pattern)
95
+ else
96
+ header + [modulus].pack(b8)
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,3 @@
1
+ module Mskeyblob
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'mskeyblob/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "mskeyblob"
8
+ spec.version = Mskeyblob::VERSION
9
+ spec.authors = ["Alexander Zimin"]
10
+ spec.email = ["ziminav@gmail.com"]
11
+ spec.summary = %q{Using Microsoft crypto service provider RSA blob format.}
12
+ spec.description = %q{Exchange RSA keys between Microsoft CSP blob format (ExportCspBlob, ImportCspBlob) and ruby openssl key OpenSSL::PKey::RSA}
13
+ spec.homepage = "https://github.com/Ziaw/mskeyblob"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.6"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "pry"
24
+ spec.add_development_dependency "test-unit", '~> 3.0.1'
25
+ end
Binary file
Binary file
@@ -0,0 +1,27 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ MIIEpAIBAAKCAQEAt9o2CYu/0TfT8eoqV2DQqkirCCbmm1D+UE/YFFbQkn1j+zhI
3
+ IDkPDHzYeO+N8lsNPHxcC0chNAPnKj/GjVGTv54xK+1++zxnjXfvQR/nQ9TqYt0U
4
+ nq4vtPD2XtulHSe5JlTPFrIv5vAXV4kFzP4tQWZnnzedsi/zgyPFmy0ZmfDLZEPs
5
+ pGkuDk8/2xjyVin0GJZBzsekwj25AzUeZ9lGJaZ5Yth1XufaVSSfoy740jmmP9JM
6
+ YMIDNOAsQf41sngtOoJmw+fOYj52w1uHtsRemAC65xBvPX9FJlQsPNzBUM8PbgtI
7
+ 63qydCJeA4owBFEHpczJqM9IvvdpIlGfZJDZOwIDAQABAoIBAA2nao5LRIEiD3RZ
8
+ attCE5fPPXMltHMCJl5KN7whoGwosiVaTjJPxS2CaMST10ERqwomxY00M06SIE0J
9
+ Hyf9UCbnIDQTd3PqzgP5zW59kzwnPWBUlpnxn2sQNDPiRcEZuKHp+CvxgCY7XCMX
10
+ nYiBCKphPmkwL7Qn5IKvmZbcgsNluCqXxhT+jpe//LDg8dKHRlqZ/19VZvMjZP6P
11
+ +rJFV5YWQQjWHiG8YZNQsaAuFr4Unj3YpArGY1r68rwx3BpoeAohh7Ts+M8zgBxB
12
+ Ms8kRr+7kmjJJmltSIB30T2wehegx8ApXal7rtdzWXbRMiFoJ02jXKkNZf0+I1Kn
13
+ LJ2IgQkCgYEAxwv7nEgsi5KA25GoJCif5FbpUNsXJyVMoG+1f/wk35pUvPE50oaB
14
+ JitdQI3xPeA3BdolviXzYIHHMZfhpHzSsFFEjkVWVWXYgSM1e4v48wm99Pv9VPAu
15
+ 0RbJPjSJxt4OJ1Ao3gDRn01zani1SYZv3t9W1L4nhw+tYddc3XPh+yMCgYEA7HU/
16
+ zS1dhV9UTsObvZN6Ag18IdvZL6Tmo8J+4KvjkgLI9YiSBfAIxB28xHQUk7CoGS4X
17
+ 9xh/9epew7XV90czjlwBW8eZWY8F+rAUANdBvB3nocqXt264idleQUI460b0lwhA
18
+ hgedWtWReZqp7lu/F2la07tyM5goPXGou0aTtwkCgYBJfL8UYAEyNpCkgA5X6ze9
19
+ EelqFLljln3H7fZQnkLu2wfWCimS9F3SPchcAQvEEHfADV5J6bEFPGTShoSkOgF/
20
+ X0G0VR0ewk9AvkMMrgznjf036aEKLvLZ91OtR7BmX61SDmJINH0wF2Q5Nv+Xea7r
21
+ 1gE04k+tqbgVm3GJwTL5iQKBgQDPKEmlL8FnP4VVG/ottC6H7dh6sWktXILTpWoS
22
+ 24ScPuRgeC22Ff0YFBV0512/pl0e8kr8p/IzOAmd3IiAA1kft2tZRR0MYUkTv39G
23
+ 3U8xx+FO1XbltZLm8hCpi6LiPV+7kfc1dSZelgzFRMLrmGVp1VtFdEsw+HUIn7L7
24
+ n3F6QQKBgQCGXMPYtRpis4CqoL2JY76kEADeD4ii5eA8gLo9yCltLvK84bfXEuJr
25
+ EJvBCzAe9yrFY2y/LrVp0eUQISx+5vUHrQyGll+zthDSQ88vZHsJinHSWaGR3pIR
26
+ aQtm/MckNy1E+ROFqzLYaXcnn1l5pdhak7/Sjao6az2Q1fxzsqQH6w==
27
+ -----END RSA PRIVATE KEY-----
@@ -0,0 +1,9 @@
1
+ -----BEGIN PUBLIC KEY-----
2
+ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt9o2CYu/0TfT8eoqV2DQ
3
+ qkirCCbmm1D+UE/YFFbQkn1j+zhIIDkPDHzYeO+N8lsNPHxcC0chNAPnKj/GjVGT
4
+ v54xK+1++zxnjXfvQR/nQ9TqYt0Unq4vtPD2XtulHSe5JlTPFrIv5vAXV4kFzP4t
5
+ QWZnnzedsi/zgyPFmy0ZmfDLZEPspGkuDk8/2xjyVin0GJZBzsekwj25AzUeZ9lG
6
+ JaZ5Yth1XufaVSSfoy740jmmP9JMYMIDNOAsQf41sngtOoJmw+fOYj52w1uHtsRe
7
+ mAC65xBvPX9FJlQsPNzBUM8PbgtI63qydCJeA4owBFEHpczJqM9IvvdpIlGfZJDZ
8
+ OwIDAQAB
9
+ -----END PUBLIC KEY-----
@@ -0,0 +1,77 @@
1
+ require 'test/unit'
2
+ require 'mskeyblob'
3
+ require 'base64'
4
+
5
+ class TestActor < Test::Unit::TestCase
6
+ TEST_DATA = 'test'
7
+ ENCRYPTED_TEST_DATA = Base64.decode64 'RqcD37GZP0D3T24GEU+xEI9v8D/jKpwIFhD37EJ/MBMF82MqeyJ/RN689UExT2kzuOt8CqIA2S6c9xXVxw4aWTPJq8jJO431yFvSYQBNGyQ6jkPCE5s2TW8HI5vxWiaGkIdR6wJJP2KtDr5s0BsspjDmH2dNlQ6sPnkKJJEaxuS041PjwA8F+gEKbbwCmOc5hs4J8yQfBezn61VXYXzRDDSUtYhhscko9Nb44O9fXRcLh0KXr2nqZcn16pWalwHvx9zBt9EROlCRJmGPXBZPmXdtTgGNZZqaaca+3p5VjXN652sdT4EQX52sKLWBLSiwHD+u15NoAJ8BcQwBnW8Nng=='
8
+
9
+ def test_private_key_from_mskeyblob
10
+ base = File.dirname(__FILE__)
11
+ msblob = File.binread(File.join(base, 'fixtures', 'msblob'))
12
+
13
+ key = OpenSSL::PKey::RSA.from_mskeyblob msblob
14
+
15
+ assert_not_nil key
16
+ assert key.private?
17
+
18
+ pem = File.read(File.join(base, 'fixtures', 'pem'))
19
+ pem_key = OpenSSL::PKey::RSA.new pem
20
+
21
+ assert_equal key.n, pem_key.n
22
+ assert_equal key.e, pem_key.e
23
+ assert_equal key.d, pem_key.d
24
+ assert_equal key.p, pem_key.p
25
+ assert_equal key.q, pem_key.q
26
+ assert_equal key.dmp1, pem_key.dmp1
27
+ assert_equal key.dmq1, pem_key.dmq1
28
+ assert_equal key.iqmp, pem_key.iqmp
29
+
30
+ assert_equal key.private_decrypt(key.public_encrypt(TEST_DATA)), TEST_DATA
31
+ assert_equal key.public_decrypt(key.private_encrypt(TEST_DATA)), TEST_DATA
32
+
33
+ assert_equal key.private_decrypt(ENCRYPTED_TEST_DATA), TEST_DATA
34
+ end
35
+
36
+ def test_private_key_to_mskeyblob
37
+ base = File.dirname(__FILE__)
38
+ msblob = File.binread(File.join(base, 'fixtures', 'msblob'))
39
+ pem = File.read(File.join(base, 'fixtures', 'pem'))
40
+
41
+ pem_key = OpenSSL::PKey::RSA.new pem
42
+
43
+ assert_equal pem_key.to_mskeyblob, msblob
44
+
45
+ msblob = File.binread(File.join(base, 'fixtures', 'msblob.pub'))
46
+ assert_equal pem_key.to_mskeyblob(include_private: false), msblob
47
+ end
48
+
49
+ def test_public_key_from_mskeyblob
50
+ base = File.dirname(__FILE__)
51
+ msblob = File.binread(File.join(base, 'fixtures', 'msblob.pub'))
52
+
53
+ key = OpenSSL::PKey::RSA.from_mskeyblob msblob
54
+
55
+ assert_not_nil key
56
+ assert key.public?
57
+ assert !key.private?
58
+
59
+ pem = File.read(File.join(base, 'fixtures', 'pem'))
60
+ pem_key = OpenSSL::PKey::RSA.new pem
61
+
62
+ assert_equal key.n, pem_key.n
63
+ assert_equal key.e, pem_key.e
64
+
65
+ assert_equal key.public_decrypt(pem_key.private_encrypt(TEST_DATA)), TEST_DATA
66
+ end
67
+
68
+ def test_public_key_to_mskeyblob
69
+ base = File.dirname(__FILE__)
70
+ msblob = File.binread(File.join(base, 'fixtures', 'msblob.pub'))
71
+ pem = File.read(File.join(base, 'fixtures', 'pem.pub'))
72
+
73
+ pem_key = OpenSSL::PKey::RSA.new pem
74
+
75
+ assert_equal pem_key.to_mskeyblob, msblob
76
+ end
77
+ end
metadata ADDED
@@ -0,0 +1,119 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mskeyblob
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Alexander Zimin
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-05-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: pry
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: test-unit
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 3.0.1
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 3.0.1
69
+ description: Exchange RSA keys between Microsoft CSP blob format (ExportCspBlob, ImportCspBlob)
70
+ and ruby openssl key OpenSSL::PKey::RSA
71
+ email:
72
+ - ziminav@gmail.com
73
+ executables: []
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - ".gitignore"
78
+ - Gemfile
79
+ - LICENSE.txt
80
+ - README.md
81
+ - Rakefile
82
+ - lib/mskeyblob.rb
83
+ - lib/mskeyblob/version.rb
84
+ - mskeyblob.gemspec
85
+ - test/fixtures/msblob
86
+ - test/fixtures/msblob.pub
87
+ - test/fixtures/pem
88
+ - test/fixtures/pem.pub
89
+ - test/test_mskeyblob.rb
90
+ homepage: https://github.com/Ziaw/mskeyblob
91
+ licenses:
92
+ - MIT
93
+ metadata: {}
94
+ post_install_message:
95
+ rdoc_options: []
96
+ require_paths:
97
+ - lib
98
+ required_ruby_version: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ required_rubygems_version: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ version: '0'
108
+ requirements: []
109
+ rubyforge_project:
110
+ rubygems_version: 2.2.2
111
+ signing_key:
112
+ specification_version: 4
113
+ summary: Using Microsoft crypto service provider RSA blob format.
114
+ test_files:
115
+ - test/fixtures/msblob
116
+ - test/fixtures/msblob.pub
117
+ - test/fixtures/pem
118
+ - test/fixtures/pem.pub
119
+ - test/test_mskeyblob.rb