gpgme-ffi 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|