gpgme-ffi 3.0.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/examples/edit.rb +77 -0
- data/examples/genkey.rb +55 -0
- data/examples/keylist.rb +7 -0
- data/examples/roundtrip.rb +42 -0
- data/examples/sign.rb +31 -0
- data/examples/verify.rb +8 -0
- data/ext/gpgme/Makefile.in +55 -0
- data/ext/gpgme/extconf.rb +8 -0
- data/ext/gpgme/extract_enums.rb +88 -0
- data/ext/gpgme/gpgme-1.3.1.tar.bz2 +0 -0
- data/ext/gpgme/libassuan-2.0.2.tar.bz2 +0 -0
- data/ext/gpgme/libgpg-error-1.10.tar.bz2 +0 -0
- data/ext/gpgme/libgpgme_gem.so +0 -0
- data/lib/gpgme/compat.rb +48 -0
- data/lib/gpgme/constants.rb +187 -0
- data/lib/gpgme/crypto.rb +357 -0
- data/lib/gpgme/ctx.rb +462 -0
- data/lib/gpgme/data.rb +189 -0
- data/lib/gpgme/engine.rb +76 -0
- data/lib/gpgme/error.rb +66 -0
- data/lib/gpgme/ffi/ctx.rb +36 -0
- data/lib/gpgme/ffi/data.rb +24 -0
- data/lib/gpgme/ffi/decrypt_result.rb +14 -0
- data/lib/gpgme/ffi/encrypt_result.rb +22 -0
- data/lib/gpgme/ffi/engine_info.rb +17 -0
- data/lib/gpgme/ffi/enums.rb +687 -0
- data/lib/gpgme/ffi/functions.rb +364 -0
- data/lib/gpgme/ffi/import_result.rb +35 -0
- data/lib/gpgme/ffi/import_status.rb +15 -0
- data/lib/gpgme/ffi/invalid_key.rb +14 -0
- data/lib/gpgme/ffi/key.rb +60 -0
- data/lib/gpgme/ffi/key_sig.rb +20 -0
- data/lib/gpgme/ffi/library.rb +279 -0
- data/lib/gpgme/ffi/meta.rb +57 -0
- data/lib/gpgme/ffi/new_signature.rb +18 -0
- data/lib/gpgme/ffi/sig_notation.rb +12 -0
- data/lib/gpgme/ffi/sign_result.rb +33 -0
- data/lib/gpgme/ffi/signature.rb +35 -0
- data/lib/gpgme/ffi/sub_key.rb +27 -0
- data/lib/gpgme/ffi/trust_item.rb +31 -0
- data/lib/gpgme/ffi/user_id.rb +30 -0
- data/lib/gpgme/ffi/verify_result.rb +22 -0
- data/lib/gpgme/ffi.rb +22 -0
- data/lib/gpgme/io_callbacks.rb +21 -0
- data/lib/gpgme/key.rb +242 -0
- data/lib/gpgme/key_common.rb +43 -0
- data/lib/gpgme/key_sig.rb +35 -0
- data/lib/gpgme/misc.rb +66 -0
- data/lib/gpgme/signature.rb +85 -0
- data/lib/gpgme/sub_key.rb +58 -0
- data/lib/gpgme/user_id.rb +20 -0
- data/lib/gpgme/version.rb +3 -0
- data/lib/gpgme.rb +106 -0
- data/test/crypto_test.rb +246 -0
- data/test/ctx_test.rb +432 -0
- data/test/data_test.rb +129 -0
- data/test/files/testkey_pub.gpg +52 -0
- data/test/files/testkey_sec.gpg +54 -0
- data/test/gpgme_test.rb +12 -0
- data/test/key_test.rb +209 -0
- data/test/signature_test.rb +52 -0
- data/test/sub_key_test.rb +48 -0
- data/test/support/resources.rb +516 -0
- data/test/test_helper.rb +84 -0
- metadata +203 -0
data/lib/gpgme/crypto.rb
ADDED
@@ -0,0 +1,357 @@
|
|
1
|
+
module GPGME
|
2
|
+
|
3
|
+
##
|
4
|
+
# Different, independent methods providing the simplest possible API to
|
5
|
+
# execute crypto operations via GPG. All methods accept as options the same
|
6
|
+
# common options as {GPGME::Ctx.new}. Read the documentation for that class to
|
7
|
+
# know how to customize things further (like output stuff in ASCII armored
|
8
|
+
# format, for example).
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# crypto = GPGME::Crypto.new :armor => true
|
12
|
+
# encrypted = crypto.encrypt 'Plain text'
|
13
|
+
#
|
14
|
+
class Crypto
|
15
|
+
|
16
|
+
attr_reader :default_options
|
17
|
+
|
18
|
+
def initialize(options = {})
|
19
|
+
@default_options = options
|
20
|
+
end
|
21
|
+
|
22
|
+
##
|
23
|
+
# Encrypts an element
|
24
|
+
#
|
25
|
+
# crypto.encrypt something, options
|
26
|
+
#
|
27
|
+
# Will return a {GPGME::Data} element which can then be read.
|
28
|
+
#
|
29
|
+
# Must have some key imported, look for {GPGME::Key.import} to know how
|
30
|
+
# to import one, or the gpg documentation to know how to create one
|
31
|
+
#
|
32
|
+
# @param plain
|
33
|
+
# Must be something that can be converted into a {GPGME::Data} object, or
|
34
|
+
# a {GPGME::Data} object itself.
|
35
|
+
#
|
36
|
+
# @param [Hash] options
|
37
|
+
# The optional parameters are as follows:
|
38
|
+
# * +:recipients+ for which recipient do you want to encrypt this file. It
|
39
|
+
# will pick the first one available if none specified. Can be an array of
|
40
|
+
# identifiers or just one (a string).
|
41
|
+
# * +:symmetric+ if set to true, will ignore +:recipients+, and will perform
|
42
|
+
# a symmetric encryption. Must provide a password via the +:password+
|
43
|
+
# option.
|
44
|
+
# * +:always_trust+ if set to true specifies all the recipients to be
|
45
|
+
# trusted, thus not requiring confirmation.
|
46
|
+
# * +:sign+ if set to true, performs a combined sign and encrypt operation.
|
47
|
+
# * +:signers+ if +:sign+ specified to true, a list of additional possible
|
48
|
+
# signers. Must be an array of sign identifiers.
|
49
|
+
# * +:output+ if specified, it will write the output into it. It will be
|
50
|
+
# converted to a {GPGME::Data} object, so it could be a file for example.
|
51
|
+
# * Any other option accepted by {GPGME::Ctx.new}
|
52
|
+
#
|
53
|
+
# @return [GPGME::Data] a {GPGME::Data} object that can be read.
|
54
|
+
#
|
55
|
+
# @example returns a {GPGME::Data} that can be later encrypted
|
56
|
+
# encrypted = crypto.encrypt "Hello world!"
|
57
|
+
# encrypted.read # => Encrypted stuff
|
58
|
+
#
|
59
|
+
# @example to be decrypted by someone@example.com.
|
60
|
+
# crypto.encrypt "Hello", :recipients => "someone@example.com"
|
61
|
+
#
|
62
|
+
# @example If I didn't trust any of my keys by default
|
63
|
+
# crypto.encrypt "Hello" # => GPGME::Error::General
|
64
|
+
# crypto.encrypt "Hello", :always_trust => true # => Will work fine
|
65
|
+
#
|
66
|
+
# @example encrypted string that can be decrypted and/or *verified*
|
67
|
+
# crypto.encrypt "Hello", :sign => true
|
68
|
+
#
|
69
|
+
# @example multiple signers
|
70
|
+
# crypto.encrypt "Hello", :sign => true, :signers => "extra@example.com"
|
71
|
+
#
|
72
|
+
# @example writing to a file instead
|
73
|
+
# file = File.open("signed.sec","w+")
|
74
|
+
# crypto.encrypt "Hello", :output => file # output written to signed.sec
|
75
|
+
#
|
76
|
+
# @raise [GPGME::Error::General] when trying to encrypt with a key that is
|
77
|
+
# not trusted, and +:always_trust+ wasn't specified
|
78
|
+
#
|
79
|
+
def encrypt(plain, options = {})
|
80
|
+
options = @default_options.merge options
|
81
|
+
|
82
|
+
plain_data = Data.new(plain)
|
83
|
+
cipher_data = Data.new(options[:output])
|
84
|
+
keys = Key.find(:public, options[:recipients])
|
85
|
+
keys = nil if options[:symmetric]
|
86
|
+
|
87
|
+
flags = 0
|
88
|
+
flags |= GPGME::ENCRYPT_ALWAYS_TRUST if options[:always_trust]
|
89
|
+
|
90
|
+
GPGME::Ctx.new(options) do |ctx|
|
91
|
+
begin
|
92
|
+
if options[:sign]
|
93
|
+
if options[:signers]
|
94
|
+
signers = Key.find(:public, options[:signers], :sign)
|
95
|
+
ctx.add_signer(*signers)
|
96
|
+
end
|
97
|
+
ctx.encrypt_sign(keys, plain_data, cipher_data, flags)
|
98
|
+
else
|
99
|
+
ctx.encrypt(keys, plain_data, cipher_data, flags)
|
100
|
+
end
|
101
|
+
rescue GPGME::Error::UnusablePublicKey => exc
|
102
|
+
exc.keys = ctx.encrypt_result.invalid_recipients
|
103
|
+
raise exc
|
104
|
+
rescue GPGME::Error::UnusableSecretKey => exc
|
105
|
+
exc.keys = ctx.sign_result.invalid_signers
|
106
|
+
raise exc
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
cipher_data.seek(0)
|
111
|
+
cipher_data
|
112
|
+
end
|
113
|
+
|
114
|
+
##
|
115
|
+
# Decrypts a previously encrypted element
|
116
|
+
#
|
117
|
+
# crypto.decrypt cipher, options, &block
|
118
|
+
#
|
119
|
+
# Must have the appropiate key to be able to decrypt, of course. Returns
|
120
|
+
# a {GPGME::Data} object which can then be read.
|
121
|
+
#
|
122
|
+
# @param cipher
|
123
|
+
# Must be something that can be converted into a {GPGME::Data} object,
|
124
|
+
# or a {GPGME::Data} object itself. It is the element that will be
|
125
|
+
# decrypted.
|
126
|
+
#
|
127
|
+
# @param [Hash] options
|
128
|
+
# The optional parameters:
|
129
|
+
# * +:output+ if specified, it will write the output into it. It will
|
130
|
+
# me converted to a {GPGME::Data} object, so it can also be a file,
|
131
|
+
# for example.
|
132
|
+
# * If the file was encrypted with symmentric encryption, must provide
|
133
|
+
# a :password option.
|
134
|
+
# * Any other option accepted by {GPGME::Ctx.new}
|
135
|
+
#
|
136
|
+
# @param &block
|
137
|
+
# In the block all the signatures are yielded, so one could verify them.
|
138
|
+
# See examples.
|
139
|
+
#
|
140
|
+
# @return [GPGME::Data] a {GPGME::Data} that can be read.
|
141
|
+
#
|
142
|
+
# @example Simple decrypt
|
143
|
+
# crypto.decrypt encrypted_data
|
144
|
+
#
|
145
|
+
# @example symmetric encryption, or passwored key
|
146
|
+
# crypto.decrypt encrypted_data, :password => "gpgme"
|
147
|
+
#
|
148
|
+
# @example Output to file
|
149
|
+
# file = File.open("decrypted.txt", "w+")
|
150
|
+
# crypto.decrypt encrypted_data, :output => file
|
151
|
+
#
|
152
|
+
# @example Verifying signatures
|
153
|
+
# crypto.decrypt encrypted_data do |signature|
|
154
|
+
# raise "Signature could not be verified" unless signature.valid?
|
155
|
+
# end
|
156
|
+
#
|
157
|
+
# @raise [GPGME::Error::UnsupportedAlgorithm] when the cipher was encrypted
|
158
|
+
# using an algorithm that's not supported currently.
|
159
|
+
#
|
160
|
+
# @raise [GPGME::Error::WrongKeyUsage] TODO Don't know when
|
161
|
+
#
|
162
|
+
# @raise [GPGME::Error::DecryptFailed] when the cipher was encrypted
|
163
|
+
# for a key that's not available currently.
|
164
|
+
def decrypt(cipher, options = {})
|
165
|
+
options = @default_options.merge options
|
166
|
+
|
167
|
+
plain_data = Data.new(options[:output])
|
168
|
+
cipher_data = Data.new(cipher)
|
169
|
+
|
170
|
+
GPGME::Ctx.new(options) do |ctx|
|
171
|
+
begin
|
172
|
+
ctx.decrypt_verify(cipher_data, plain_data)
|
173
|
+
rescue GPGME::Error::UnsupportedAlgorithm => exc
|
174
|
+
exc.algorithm = ctx.decrypt_result.unsupported_algorithm
|
175
|
+
raise exc
|
176
|
+
rescue GPGME::Error::WrongKeyUsage => exc
|
177
|
+
exc.key_usage = ctx.decrypt_result.wrong_key_usage
|
178
|
+
raise exc
|
179
|
+
end
|
180
|
+
|
181
|
+
verify_result = ctx.verify_result
|
182
|
+
if verify_result && block_given?
|
183
|
+
verify_result.signatures.each do |signature|
|
184
|
+
yield signature
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
end
|
189
|
+
|
190
|
+
plain_data.seek(0)
|
191
|
+
plain_data
|
192
|
+
end
|
193
|
+
|
194
|
+
##
|
195
|
+
# Creates a signature of a text
|
196
|
+
#
|
197
|
+
# crypto.sign text, options
|
198
|
+
#
|
199
|
+
# Must have the appropiate key to be able to decrypt, of course. Returns
|
200
|
+
# a {GPGME::Data} object which can then be read.
|
201
|
+
#
|
202
|
+
# @param text
|
203
|
+
# The object that will be signed. Must be something that can be converted
|
204
|
+
# to {GPGME::Data}.
|
205
|
+
#
|
206
|
+
# @param [Hash] options
|
207
|
+
# Optional parameters.
|
208
|
+
# * +:signer+ sign identifier to sign the text with. Will use the first
|
209
|
+
# key it finds if none specified.
|
210
|
+
# * +:output+ if specified, it will write the output into it. It will be
|
211
|
+
# converted to a {GPGME::Data} object, so it could be a file for example.
|
212
|
+
# * +:mode+ Desired type of signature. Options are:
|
213
|
+
# - +GPGME::SIG_MODE_NORMAL+ for a normal signature. The default one if
|
214
|
+
# not specified.
|
215
|
+
# - +GPGME::SIG_MODE_DETACH+ for a detached signature
|
216
|
+
# - +GPGME::SIG_MODE_CLEAR+ for a cleartext signature
|
217
|
+
# * Any other option accepted by {GPGME::Ctx.new}
|
218
|
+
#
|
219
|
+
# @return [GPGME::Data] a {GPGME::Data} that can be read.
|
220
|
+
#
|
221
|
+
# @example normal sign
|
222
|
+
# crypto.sign "Hi there"
|
223
|
+
#
|
224
|
+
# @example outputing to a file
|
225
|
+
# file = File.open("text.sign", "w+")
|
226
|
+
# crypto.sign "Hi there", :options => file
|
227
|
+
#
|
228
|
+
# @example doing a detached signature
|
229
|
+
# crypto.sign "Hi there", :mode => GPGME::SIG_MODE_DETACH
|
230
|
+
#
|
231
|
+
# @example specifying the signer
|
232
|
+
# crypto.sign "Hi there", :signer => "mrsimo@example.com"
|
233
|
+
#
|
234
|
+
# @raise [GPGME::Error::UnusableSecretKey] TODO don't know when
|
235
|
+
def sign(text, options = {})
|
236
|
+
options = @default_options.merge options
|
237
|
+
|
238
|
+
plain = Data.new(text)
|
239
|
+
output = Data.new(options[:output])
|
240
|
+
mode = options[:mode] || GPGME::SIG_MODE_NORMAL
|
241
|
+
|
242
|
+
GPGME::Ctx.new(options) do |ctx|
|
243
|
+
if options[:signer]
|
244
|
+
signers = Key.find(:secret, options[:signer], :sign)
|
245
|
+
ctx.add_signer(*signers)
|
246
|
+
end
|
247
|
+
|
248
|
+
begin
|
249
|
+
ctx.sign(plain, output, mode)
|
250
|
+
rescue GPGME::Error::UnusableSecretKey => exc
|
251
|
+
exc.keys = ctx.sign_result.invalid_signers
|
252
|
+
raise exc
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
output.seek(0)
|
257
|
+
output
|
258
|
+
end
|
259
|
+
|
260
|
+
# Verifies a previously signed element
|
261
|
+
#
|
262
|
+
# crypto.verify sig, options, &block
|
263
|
+
#
|
264
|
+
# Must have the proper keys available.
|
265
|
+
#
|
266
|
+
# @param sig
|
267
|
+
# The signature itself. Must be possible to convert into a {GPGME::Data}
|
268
|
+
# object, so can be a file.
|
269
|
+
#
|
270
|
+
# @param [Hash] options
|
271
|
+
# * +:signed_text+ if the sign is detached, then must be the plain text
|
272
|
+
# for which the signature was created.
|
273
|
+
# * +:output+ where to store the result of the signature. Will be
|
274
|
+
# converted to a {GPGME::Data} object.
|
275
|
+
# * Any other option accepted by {GPGME::Ctx.new}
|
276
|
+
#
|
277
|
+
# @param &block
|
278
|
+
# In the block all the signatures are yielded, so one could verify them.
|
279
|
+
# See examples.
|
280
|
+
#
|
281
|
+
# @return [GPGME::Data] unless the sign is detached, the {GPGME::Data}
|
282
|
+
# object with the plain text. If the sign is detached, will return nil.
|
283
|
+
#
|
284
|
+
# @example simple verification
|
285
|
+
# sign = crypto.sign("Hi there")
|
286
|
+
# data = crypto.verify(sign) { |signature| signature.valid? }
|
287
|
+
# data.read # => "Hi there"
|
288
|
+
#
|
289
|
+
# @example saving output to file
|
290
|
+
# sign = crypto.sign("Hi there")
|
291
|
+
# out = File.open("test.asc", "w+")
|
292
|
+
# crypto.verify(sign, :output => out) {|signature| signature.valid?}
|
293
|
+
# out.read # => "Hi there"
|
294
|
+
#
|
295
|
+
# @example verifying a detached signature
|
296
|
+
# sign = crypto.detach_sign("Hi there")
|
297
|
+
# # Will fail
|
298
|
+
# crypto.verify(sign) { |signature| signature.valid? }
|
299
|
+
# # Will succeed
|
300
|
+
# crypto.verify(sign, :signed_text => "hi there") do |signature|
|
301
|
+
# signature.valid?
|
302
|
+
# end
|
303
|
+
#
|
304
|
+
def verify(sig, options = {})
|
305
|
+
options = @default_options.merge options
|
306
|
+
|
307
|
+
sig = Data.new(sig)
|
308
|
+
signed_text = Data.new(options[:signed_text])
|
309
|
+
output = Data.new(options[:output]) unless options[:signed_text]
|
310
|
+
|
311
|
+
GPGME::Ctx.new(options) do |ctx|
|
312
|
+
ctx.verify(sig, signed_text, output)
|
313
|
+
ctx.verify_result.signatures.each do |signature|
|
314
|
+
yield signature
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
if output
|
319
|
+
output.seek(0)
|
320
|
+
output
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
# Clearsigns an element
|
325
|
+
#
|
326
|
+
# crypto.clearsign text, options
|
327
|
+
#
|
328
|
+
# Same functionality of {.sign} only doing clearsigns by default.
|
329
|
+
#
|
330
|
+
def clearsign(text, options = {})
|
331
|
+
sign text, options.merge(:mode => GPGME::SIG_MODE_CLEAR)
|
332
|
+
end
|
333
|
+
|
334
|
+
# Creates a detached signature of an element
|
335
|
+
#
|
336
|
+
# crypto.detach_sign text, options
|
337
|
+
#
|
338
|
+
# Same functionality of {.sign} only doing detached signs by default.
|
339
|
+
#
|
340
|
+
def detach_sign(text, options = {})
|
341
|
+
sign text, options.merge(:mode => GPGME::SIG_MODE_DETACH)
|
342
|
+
end
|
343
|
+
|
344
|
+
##
|
345
|
+
# Allows calling of methods directly in the module without the need to
|
346
|
+
# create a new instance.
|
347
|
+
def self.method_missing(method, *args, &block)
|
348
|
+
if GPGME::Crypto.instance_methods(false).include?(method)
|
349
|
+
crypto = GPGME::Crypto.new
|
350
|
+
crypto.send method, *args, &block
|
351
|
+
else
|
352
|
+
super
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
end # module Crypto
|
357
|
+
end # module GPGME
|