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.
Files changed (65) hide show
  1. data/examples/edit.rb +77 -0
  2. data/examples/genkey.rb +55 -0
  3. data/examples/keylist.rb +7 -0
  4. data/examples/roundtrip.rb +42 -0
  5. data/examples/sign.rb +31 -0
  6. data/examples/verify.rb +8 -0
  7. data/ext/gpgme/Makefile.in +55 -0
  8. data/ext/gpgme/extconf.rb +8 -0
  9. data/ext/gpgme/extract_enums.rb +88 -0
  10. data/ext/gpgme/gpgme-1.3.1.tar.bz2 +0 -0
  11. data/ext/gpgme/libassuan-2.0.2.tar.bz2 +0 -0
  12. data/ext/gpgme/libgpg-error-1.10.tar.bz2 +0 -0
  13. data/ext/gpgme/libgpgme_gem.so +0 -0
  14. data/lib/gpgme/compat.rb +48 -0
  15. data/lib/gpgme/constants.rb +187 -0
  16. data/lib/gpgme/crypto.rb +357 -0
  17. data/lib/gpgme/ctx.rb +462 -0
  18. data/lib/gpgme/data.rb +189 -0
  19. data/lib/gpgme/engine.rb +76 -0
  20. data/lib/gpgme/error.rb +66 -0
  21. data/lib/gpgme/ffi/ctx.rb +36 -0
  22. data/lib/gpgme/ffi/data.rb +24 -0
  23. data/lib/gpgme/ffi/decrypt_result.rb +14 -0
  24. data/lib/gpgme/ffi/encrypt_result.rb +22 -0
  25. data/lib/gpgme/ffi/engine_info.rb +17 -0
  26. data/lib/gpgme/ffi/enums.rb +687 -0
  27. data/lib/gpgme/ffi/functions.rb +364 -0
  28. data/lib/gpgme/ffi/import_result.rb +35 -0
  29. data/lib/gpgme/ffi/import_status.rb +15 -0
  30. data/lib/gpgme/ffi/invalid_key.rb +14 -0
  31. data/lib/gpgme/ffi/key.rb +60 -0
  32. data/lib/gpgme/ffi/key_sig.rb +20 -0
  33. data/lib/gpgme/ffi/library.rb +279 -0
  34. data/lib/gpgme/ffi/meta.rb +57 -0
  35. data/lib/gpgme/ffi/new_signature.rb +18 -0
  36. data/lib/gpgme/ffi/sig_notation.rb +12 -0
  37. data/lib/gpgme/ffi/sign_result.rb +33 -0
  38. data/lib/gpgme/ffi/signature.rb +35 -0
  39. data/lib/gpgme/ffi/sub_key.rb +27 -0
  40. data/lib/gpgme/ffi/trust_item.rb +31 -0
  41. data/lib/gpgme/ffi/user_id.rb +30 -0
  42. data/lib/gpgme/ffi/verify_result.rb +22 -0
  43. data/lib/gpgme/ffi.rb +22 -0
  44. data/lib/gpgme/io_callbacks.rb +21 -0
  45. data/lib/gpgme/key.rb +242 -0
  46. data/lib/gpgme/key_common.rb +43 -0
  47. data/lib/gpgme/key_sig.rb +35 -0
  48. data/lib/gpgme/misc.rb +66 -0
  49. data/lib/gpgme/signature.rb +85 -0
  50. data/lib/gpgme/sub_key.rb +58 -0
  51. data/lib/gpgme/user_id.rb +20 -0
  52. data/lib/gpgme/version.rb +3 -0
  53. data/lib/gpgme.rb +106 -0
  54. data/test/crypto_test.rb +246 -0
  55. data/test/ctx_test.rb +432 -0
  56. data/test/data_test.rb +129 -0
  57. data/test/files/testkey_pub.gpg +52 -0
  58. data/test/files/testkey_sec.gpg +54 -0
  59. data/test/gpgme_test.rb +12 -0
  60. data/test/key_test.rb +209 -0
  61. data/test/signature_test.rb +52 -0
  62. data/test/sub_key_test.rb +48 -0
  63. data/test/support/resources.rb +516 -0
  64. data/test/test_helper.rb +84 -0
  65. metadata +203 -0
@@ -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