netpgp 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: baa8e73adf9e05b9b6fb5be2b2a9447ce72149f3
4
+ data.tar.gz: 66db535e3a79f188424cfd237381dbad0fe81e71
5
+ SHA512:
6
+ metadata.gz: a17b99842d2b900e2babd24fa8c5f0e80059935b4b627f0c7971f03ad36bd791833f35b243d454fe851509845bc3e1cb6a9421735436233267db7718250bbb7b
7
+ data.tar.gz: dfb73d76203ac990bbb3605783b83eb7c47333d02e64712813965fe335092d53ecef24aee35dbf2839060fca5b09bdd6d7f71c0c2eaa20556636be7ab98d5dfd
@@ -0,0 +1,3 @@
1
+ require_relative 'netpgp/lowlevel'
2
+ require_relative 'netpgp/highlevel'
3
+
@@ -0,0 +1,5 @@
1
+ require_relative 'highlevel/constants'
2
+ require_relative 'highlevel/publickey'
3
+ require_relative 'highlevel/secretkey'
4
+ require_relative 'highlevel/keyring'
5
+
@@ -0,0 +1,96 @@
1
+ require 'rubygems'
2
+
3
+ module NetPGP
4
+
5
+ class PublicKeyAlgorithm
6
+ NONE = 0
7
+ RSA = 1
8
+ RSA_ENCRYPT_ONLY = 2
9
+ RSA_SIGN_ONLY = 3
10
+ ELGAMAL = 16
11
+ DSA = 17
12
+ ECDH = 18
13
+ ECDSA = 19
14
+ FORMERLY_ELGAMAL = 20
15
+
16
+ def self.from_native(alg)
17
+ raise if alg.class != Symbol
18
+ LibNetPGP::PGP_PUBKEY_ALG_T[alg]
19
+ end
20
+
21
+ def self.to_native(alg)
22
+ # avoid a warning on newer versions of ruby
23
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.4.0')
24
+ raise if alg.class != Integer
25
+ else
26
+ raise if alg.class != Fixnum
27
+ end
28
+ LibNetPGP::PGP_PUBKEY_ALG_T[alg]
29
+ end
30
+
31
+ end
32
+
33
+ class HashAlgorithm
34
+ MD5 = 1
35
+ SHA1 = 2
36
+ RIPEMD = 3
37
+ SHA256 = 8
38
+ SHA384 = 9
39
+ SHA512 = 10
40
+ SHA224 = 11
41
+
42
+ # see pgp_str_to_hash_alg
43
+ STRING_MAPPING = {
44
+ MD5 => 'md5',
45
+ SHA1 => 'sha1',
46
+ SHA256 => 'sha256',
47
+ SHA384 => 'sha384',
48
+ SHA512 => 'sha512'
49
+ }
50
+
51
+ def self.to_s(alg)
52
+ STRING_MAPPING[alg]
53
+ end
54
+
55
+ end
56
+
57
+ class SymmetricKeyAlgorithm
58
+ PLAINTEXT = 0
59
+ IDEA = 1
60
+ TRIPLEDES = 2
61
+ CAST5 = 3
62
+ BLOWFISH = 4
63
+ AES128 = 7
64
+ AES192 = 8
65
+ AES256 = 9
66
+ TWOFISH256 = 10
67
+
68
+ # see pgp_str_to_cipher
69
+ STRING_MAPPING = {
70
+ IDEA => 'idea',
71
+ TRIPLEDES => 'tripledes',
72
+ CAST5 => 'cast5',
73
+ AES128 => 'aes128',
74
+ AES256 => 'aes256'
75
+ }
76
+
77
+ def self.to_s(alg)
78
+ STRING_MAPPING[alg]
79
+ end
80
+
81
+ end
82
+
83
+ class StringToKeyUsage
84
+ NONE = 0
85
+ ENCRYPTED_AND_HASHED = 254
86
+ ENCRYPTED = 255
87
+ end
88
+
89
+ class StringToKeySpecifier
90
+ SIMPLE = 0
91
+ SALTED = 1
92
+ ITERATED_AND_SALTED = 3
93
+ end
94
+
95
+ end
96
+
@@ -0,0 +1,259 @@
1
+ require 'English'
2
+ require 'forwardable'
3
+
4
+ module NetPGP
5
+
6
+ class Keyring
7
+ extend Forwardable
8
+ delegate [:size, :each, :select, :[], :push, :clear] => :@keys
9
+
10
+ attr_reader :keys
11
+
12
+ def initialize
13
+ @keys = []
14
+ end
15
+
16
+ def self.load(data, armored=true, &passphrase_provider)
17
+ kr = Keyring.new
18
+ kr.add(data, armored, &passphrase_provider)
19
+ kr
20
+ end
21
+
22
+ def add(data, armored=true, &passphrase_provider)
23
+ keys = NetPGP::load_keys(data, armored, &passphrase_provider)
24
+ @keys.push(*keys)
25
+ keys.size
26
+ end
27
+
28
+ def verify(data, armored=true)
29
+ NetPGP::verify(@keys, data, armored)
30
+ end
31
+
32
+ def export(key, armored=true)
33
+ raise if key.parent
34
+ is_public = key.is_a?(PublicKey)
35
+ if is_public
36
+ seckey = secret_keys.find {|sk| sk.key_id == key.key_id}
37
+ else
38
+ seckey = key
39
+ end
40
+ return nil if not seckey
41
+ output_ptr = FFI::MemoryPointer.new(:pointer)
42
+ mem_ptr = FFI::MemoryPointer.new(:pointer)
43
+ output = nil
44
+ mem = nil
45
+ decrypted_seckey = nil
46
+ begin
47
+ LibNetPGP::pgp_setup_memory_write(output_ptr, mem_ptr, 4096)
48
+ output = LibNetPGP::PGPOutput.new(output_ptr.read_pointer)
49
+ mem = LibNetPGP::PGPMemory.new(mem_ptr.read_pointer)
50
+ native_ptr = LibC::calloc(1, LibNetPGP::PGPKey.size)
51
+ native = LibNetPGP::PGPKey.new(native_ptr)
52
+ native_auto = FFI::AutoPointer.new(native_ptr, LibNetPGP::PGPKey.method(:release))
53
+ key.to_native_key(native)
54
+ decrypted_seckey = seckey.decrypted_seckey
55
+ return nil if not decrypted_seckey
56
+ # this is necessary for signatures
57
+ seckey = SecretKey.from_native(decrypted_seckey)
58
+ seckey.to_native(native[:key][:seckey])
59
+ native[:type] = :PGP_PTAG_CT_SECRET_KEY
60
+ if is_public
61
+ LibNetPGP::dynarray_clear(native, 'uid', :string)
62
+ key.userids.each {|userid|
63
+ LibNetPGP::pgp_add_selfsigned_userid(native, userid)
64
+ }
65
+ end
66
+ # PGPKeyring is a ManagedStruct
67
+ subkeysring_ptr = LibC::calloc(1, LibNetPGP::PGPKeyring.size)
68
+ subkeysring = LibNetPGP::PGPKeyring.new(subkeysring_ptr)
69
+ NetPGP::keys_to_native_keyring(key.subkeys, subkeysring)
70
+ # add a binding signature to each subkey
71
+ (0..LibNetPGP::dynarray_count(subkeysring, 'key') - 1).each {|n|
72
+ subkey = LibNetPGP::dynarray_get_item(subkeysring, 'key', LibNetPGP::PGPKey, n)
73
+ LibNetPGP::dynarray_clear(subkey, 'packet', LibNetPGP::PGPSubPacket)
74
+ NetPGP::add_subkey_signature(native, subkey)
75
+ }
76
+ if is_public
77
+ ret = LibNetPGP::pgp_write_xfer_pubkey(output, native, subkeysring, armored ? 1 : 0)
78
+ else
79
+ decrypted_key_ptr = LibC::calloc(1, LibNetPGP::PGPKey.size)
80
+ decrypted_key = LibNetPGP::PGPKey.new(decrypted_key_ptr)
81
+ decrypted_key_auto = FFI::AutoPointer.new(decrypted_key_ptr, LibNetPGP::PGPKey.method(:release))
82
+ seckey.to_native_key(decrypted_key)
83
+ key.userids.each {|userid|
84
+ LibNetPGP::pgp_add_selfsigned_userid(decrypted_key, userid)
85
+ }
86
+ decrypted_key[:key][:seckey][:s2k_usage] = :PGP_S2KU_ENCRYPTED_AND_HASHED
87
+ decrypted_key[:key][:seckey][:alg] = :PGP_SA_CAST5
88
+ decrypted_key[:key][:seckey][:s2k_specifier] = :PGP_S2KS_SALTED
89
+ (0..LibNetPGP::dynarray_count(subkeysring, 'key') - 1).each {|n|
90
+ subkey = LibNetPGP::dynarray_get_item(subkeysring, 'key', LibNetPGP::PGPKey, n)
91
+ subkey[:key][:seckey][:s2k_usage] = :PGP_S2KU_ENCRYPTED_AND_HASHED
92
+ subkey[:key][:seckey][:alg] = :PGP_SA_CAST5
93
+ subkey[:key][:seckey][:s2k_specifier] = :PGP_S2KS_SALTED
94
+ }
95
+ ret = LibNetPGP::pgp_write_xfer_seckey(output, decrypted_key, key.passphrase, key.passphrase.size, subkeysring, armored ? 1 : 0)
96
+ end
97
+ return nil if ret != 1
98
+ data = mem[:buf].read_bytes(mem[:length])
99
+ data
100
+ ensure
101
+ LibNetPGP::pgp_teardown_memory_write(output, mem) if mem
102
+ LibNetPGP::pgp_seckey_free(decrypted_seckey) if decrypted_seckey
103
+ end
104
+ end
105
+
106
+ def public_keys
107
+ self.select {|key|
108
+ key.is_a?(PublicKey)
109
+ }
110
+ end
111
+
112
+ def secret_keys
113
+ self.select {|key|
114
+ key.is_a?(SecretKey)
115
+ }
116
+ end
117
+
118
+ def to_native(native)
119
+ keys_to_native_keyring(@keys, native)
120
+ end
121
+
122
+ end
123
+
124
+ PARSE_KEYRING = Proc.new do |state, passphrase_provider, pkt, data|
125
+ next :PGP_RELEASE_MEMORY if state[:errors].any?
126
+
127
+ begin
128
+ lastkey = state[:keys].last
129
+ case pkt[:tag]
130
+ when :PGP_PTAG_CT_PUBLIC_KEY
131
+ key = PublicKey::from_native(pkt[:u][:pubkey])
132
+ state[:keys].push(key)
133
+ when :PGP_PTAG_CT_PUBLIC_SUBKEY
134
+ key = PublicKey::from_native(pkt[:u][:pubkey])
135
+ lastkey.add_subkey(key)
136
+ state[:keys].push(key)
137
+ when :PGP_PTAG_CT_ENCRYPTED_SECRET_KEY
138
+ key = SecretKey::from_native(pkt[:u][:seckey], true)
139
+ state[:keys].push(key)
140
+ when :PGP_PTAG_CT_ENCRYPTED_SECRET_SUBKEY
141
+ key = SecretKey::from_native(pkt[:u][:seckey], true)
142
+ lastkey.add_subkey(key)
143
+ state[:keys].push(key)
144
+ when :PGP_PTAG_CT_SECRET_KEY
145
+ key = SecretKey::from_native(pkt[:u][:seckey])
146
+ if state[:passphrase]
147
+ key.passphrase = state[:passphrase]
148
+ state[:passphrase] = nil
149
+ end
150
+ state[:keys].push(key)
151
+ when :PGP_PTAG_CT_SECRET_SUBKEY
152
+ key = SecretKey::from_native(pkt[:u][:seckey])
153
+ lastkey.add_subkey(key)
154
+ state[:keys].push(key)
155
+ when :PGP_GET_PASSPHRASE
156
+ seckey_ptr = pkt[:u][:skey_passphrase][:seckey]
157
+ seckey = LibNetPGP::PGPSecKey.new(seckey_ptr)
158
+ key = SecretKey::from_native(seckey)
159
+ passphrase = passphrase_provider.call(key)
160
+ if passphrase and passphrase != ''
161
+ passphrase_mem = LibC::calloc(1, passphrase.bytesize + 1)
162
+ passphrase_mem.write_bytes(passphrase)
163
+ pkt[:u][:skey_passphrase][:passphrase].write_pointer(passphrase_mem)
164
+ state[:passphrase] = passphrase
165
+ next :PGP_KEEP_MEMORY
166
+ end
167
+ when :PGP_PARSER_PACKET_END
168
+ if lastkey.is_a? NetPGP::SecretKey
169
+ raw_packet = pkt[:u][:packet]
170
+ bytes = raw_packet[:raw].read_bytes(raw_packet[:length])
171
+ lastkey.raw_subpackets.push(bytes)
172
+ end
173
+ when :PGP_PTAG_CT_USER_ID
174
+ lastkey.userids.push(pkt[:u][:userid].force_encoding('utf-8'))
175
+ when :PGP_PTAG_SS_KEY_EXPIRY
176
+ lastkey.expiration_time = lastkey.creation_time + pkt[:u][:ss_time]
177
+ else
178
+ # For debugging
179
+ #puts "Unhandled tag: #{pkt[:tag]}"
180
+ end # case
181
+ rescue
182
+ state[:errors].push($ERROR_INFO)
183
+ end
184
+ next :PGP_RELEASE_MEMORY
185
+ end
186
+
187
+ DEFAULT_PASSPHRASE_PROVIDER = Proc.new do |seckey|
188
+ nil
189
+ end
190
+
191
+ def self.load_keys(data, armored=true, &passphrase_provider)
192
+ # Just for readability
193
+ print_errors = 0
194
+ stream_mem = LibC::calloc(1, LibNetPGP::PGPStream.size)
195
+ # This will free the above memory (PGPStream is a ManagedStruct)
196
+ stream = LibNetPGP::PGPStream.new(stream_mem)
197
+ stream[:readinfo][:accumulate] = 1
198
+ LibNetPGP::pgp_parse_options(stream, :PGP_PTAG_SS_ALL, :PGP_PARSE_PARSED)
199
+
200
+ # This memory will be GC'd
201
+ mem = FFI::MemoryPointer.new(:uint8, data.bytesize)
202
+ mem.write_bytes(data)
203
+
204
+ LibNetPGP::pgp_reader_set_memory(stream, mem, mem.size)
205
+ state = {keys: [], errors: []}
206
+ provider = block_given? ? passphrase_provider : DEFAULT_PASSPHRASE_PROVIDER
207
+ callback = NetPGP::PARSE_KEYRING.curry[state][provider]
208
+ LibNetPGP::pgp_set_callback(stream, callback, nil)
209
+ LibNetPGP::pgp_reader_push_dearmour(stream) if armored
210
+ if LibNetPGP::pgp_parse(stream, print_errors) != 1
211
+ state[:errors].push('pgp_parse failed')
212
+ end
213
+ LibNetPGP::pgp_reader_pop_dearmour(stream) if armored
214
+
215
+ errors = stream_errors(stream)
216
+ state[:errors].push(errors) if errors.any?
217
+
218
+ raise state[:errors].join("\n") if state[:errors].any?
219
+ state[:keys]
220
+ end
221
+
222
+ def self.keys_to_native_keyring(keys, native)
223
+ raise if not native[:keys].null?
224
+
225
+ for key in keys
226
+ native_key = LibNetPGP::PGPKey.new
227
+ key.to_native_key(native_key)
228
+ LibNetPGP::dynarray_append_item(native, 'key', LibNetPGP::PGPKey, native_key)
229
+ end
230
+ end
231
+
232
+ def self.verify(keys, data, armored=true)
233
+ native_keyring_ptr = LibC::calloc(1, LibNetPGP::PGPKeyring.size)
234
+ native_keyring = LibNetPGP::PGPKeyring.new(native_keyring_ptr)
235
+ NetPGP::keys_to_native_keyring(keys, native_keyring)
236
+
237
+ pgpio = LibNetPGP::PGPIO.new
238
+ pgpio[:outs] = LibC::fdopen($stdout.to_i, 'w')
239
+ pgpio[:errs] = LibC::fdopen($stderr.to_i, 'w')
240
+ pgpio[:res] = pgpio[:errs]
241
+
242
+ data_buf = FFI::MemoryPointer.new(:uint8, data.bytesize)
243
+ data_buf.write_bytes(data)
244
+
245
+ # pgp_validate_mem frees this
246
+ mem_ptr = LibC::calloc(1, LibNetPGP::PGPMemory.size)
247
+ mem = LibNetPGP::PGPMemory.new(mem_ptr)
248
+ LibNetPGP::pgp_memory_add(mem, data_buf, data_buf.size)
249
+
250
+ # ManagedStruct, this frees itself
251
+ result_ptr = LibC::calloc(1, LibNetPGP::PGPValidation.size)
252
+ result = LibNetPGP::PGPValidation.new(result_ptr)
253
+
254
+ ret = LibNetPGP::pgp_validate_mem(pgpio, result, mem, nil, armored ? 1 : 0, native_keyring)
255
+ ret == 1
256
+ end
257
+
258
+ end # module NetPGP
259
+
@@ -0,0 +1,150 @@
1
+ module NetPGP
2
+
3
+ require_relative 'utils'
4
+
5
+ class PublicKey
6
+ attr_accessor :version,
7
+ :creation_time,
8
+ :expiration_time,
9
+ :public_key_algorithm,
10
+ :mpi,
11
+ :userids,
12
+ :parent,
13
+ :subkeys
14
+
15
+ def initialize
16
+ @version = nil
17
+ @creation_time = nil
18
+ @expiration_time = 0
19
+ @public_key_algorithm = nil
20
+ @mpi = {}
21
+ @userids = []
22
+ @parent = nil
23
+ @subkeys = []
24
+ end
25
+
26
+ def fingerprint
27
+ fp = LibNetPGP::PGPFingerprint.new
28
+ native_pubkey_ptr = LibC::calloc(1, LibNetPGP::PGPPubKey.size)
29
+ native_pubkey = LibNetPGP::PGPPubKey.new(native_pubkey_ptr)
30
+ native_pubkey_auto = FFI::AutoPointer.new(native_pubkey_ptr, LibNetPGP::PGPPubKey.method(:release))
31
+ to_native(native_pubkey)
32
+ hash = @version == 3 ? :PGP_HASH_MD5 : :PGP_HASH_SHA1
33
+ ret = LibNetPGP::pgp_fingerprint(fp, native_pubkey, hash)
34
+ raise 'pgp_fingerprint failed' if ret != 1
35
+ fp[:fingerprint].to_s[0, fp[:length]]
36
+ end
37
+
38
+ def fingerprint_hex
39
+ fingerprint.bytes.collect {|byte| '%02X' % byte}.join
40
+ end
41
+
42
+ def key_id
43
+ keyid_ptr = FFI::MemoryPointer.new(:uint8, LibNetPGP::PGP_KEY_ID_SIZE)
44
+ native_pubkey = LibNetPGP::PGPPubKey.new
45
+ to_native(native_pubkey)
46
+ ret = LibNetPGP::pgp_keyid(keyid_ptr, LibNetPGP::PGP_KEY_ID_SIZE, native_pubkey, :PGP_HASH_SHA1)
47
+ raise 'pgp_keyid failed' if ret != 1
48
+ keyid_ptr.read_bytes(LibNetPGP::PGP_KEY_ID_SIZE)
49
+ end
50
+
51
+ def key_id_hex
52
+ key_id.bytes.collect {|byte| '%02X' % byte}.join
53
+ end
54
+
55
+ def key_length
56
+ case @public_key_algorithm
57
+ when PublicKeyAlgorithm::RSA,
58
+ PublicKeyAlgorithm::RSA_ENCRYPT_ONLY,
59
+ PublicKeyAlgorithm::RSA_SIGN_ONLY
60
+ return NetPGP::bignum_byte_count(@mpi[:n]) * 8
61
+ when PublicKeyAlgorithm::DSA
62
+ case NetPGP::bignum_byte_count(@mpi[:q])
63
+ when 20
64
+ 1024
65
+ when 28
66
+ 2048
67
+ when 32
68
+ 3072
69
+ end
70
+ when PublicKeyAlgorithm::ELGAMAL
71
+ NetPGP::bignum_byte_count(@mpi[:y]) * 8
72
+ end
73
+ 0
74
+ end
75
+
76
+ def encrypt(data, armored=true, sk_algorithm=SymmetricKeyAlgorithm::CAST5)
77
+ cipher = SymmetricKeyAlgorithm::to_s(sk_algorithm)
78
+ memory = nil
79
+
80
+ begin
81
+ pubkey_ptr = LibC::calloc(1, LibNetPGP::PGPKey.size)
82
+ pubkey = LibNetPGP::PGPKey.new(pubkey_ptr)
83
+ pubkey_auto = FFI::AutoPointer.new(pubkey_ptr, LibNetPGP::PGPKey.method(:release))
84
+
85
+ to_native_key(pubkey)
86
+ data_buf = FFI::MemoryPointer.new(:uint8, data.bytesize)
87
+ data_buf.write_bytes(data)
88
+ pgpio = LibNetPGP::PGPIO.new
89
+ pgpio[:outs] = LibC::fdopen($stdout.to_i, 'w')
90
+ pgpio[:errs] = LibC::fdopen($stderr.to_i, 'w')
91
+ pgpio[:res] = pgpio[:errs]
92
+ memory_ptr = LibNetPGP::pgp_encrypt_buf(pgpio, data_buf, data_buf.size, pubkey, armored ? 1 : 0, cipher)
93
+ return nil if memory_ptr.null?
94
+ memory = LibNetPGP::PGPMemory.new(memory_ptr)
95
+ memory[:buf].read_bytes(memory[:length])
96
+ ensure
97
+ LibNetPGP::pgp_memory_free(memory) if memory
98
+ end
99
+ end
100
+
101
+ def verify(data, armored=true)
102
+ NetPGP::verify([self], data, armored)
103
+ end
104
+
105
+ def add_subkey(subkey)
106
+ raise if subkey.subkeys.any?
107
+ subkey.parent = self
108
+ subkey.userids = @userids
109
+ @subkeys.push(subkey)
110
+ end
111
+
112
+ def self.from_native(native)
113
+ pubkey = PublicKey.new
114
+ pubkey.version = LibNetPGP::enum_value(native[:version])
115
+ pubkey.creation_time = Time.at(native[:birthtime])
116
+ if pubkey.version == 3
117
+ pubkey.expiration_time = Time.at(native[:birthtime]) + (native[:days_valid] * 86400)
118
+ end
119
+ pubkey.public_key_algorithm = PublicKeyAlgorithm::from_native(native[:alg])
120
+ pubkey.mpi = NetPGP::mpis_from_native(native[:alg], native)
121
+ pubkey
122
+ end
123
+
124
+ def to_native(native)
125
+ native[:version] = @version
126
+ native[:birthtime] = @creation_time.to_i
127
+ if @version == 3 and @expiration_time
128
+ native[:days_valid] = ((@expiration_time.to_i - @creation_time.to_i) / 86400).to_i
129
+ else
130
+ native[:duration] = (@expiration_time.to_i - @creation_time.to_i).to_i
131
+ end
132
+ native[:alg] = @public_key_algorithm
133
+ NetPGP::mpis_to_native(native[:alg], @mpi, native)
134
+ end
135
+
136
+ def to_native_key(native_key)
137
+ native_key[:type] = :PGP_PTAG_CT_PUBLIC_KEY
138
+ native_key[:sigid] = key_id
139
+ to_native(native_key[:key][:pubkey])
140
+ if not @parent
141
+ @userids.each {|userid|
142
+ LibNetPGP::dynarray_append_item(native_key, 'uid', :string, userid)
143
+ }
144
+ end
145
+ end
146
+
147
+ end
148
+
149
+ end # module NetPGP
150
+