benburkert-gpgme 0.1.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.
@@ -0,0 +1,48 @@
1
+ require 'gpgme'
2
+
3
+ # TODO: Find why is this needed. I guess the name compat means it's just
4
+ # backwards compatibility. Consider removing?
5
+ module GPGME
6
+ GpgmeError = Error
7
+ GpgmeData = Data
8
+ GpgmeEngineInfo = EngineInfo
9
+ GpgmeCtx = Ctx
10
+ GpgmeKey = Key
11
+ GpgmeSubKey = SubKey
12
+ GpgmeUserID = UserID
13
+ GpgmeKeySig = KeySig
14
+ GpgmeVerifyResult = VerifyResult
15
+ GpgmeSignature = Signature
16
+ GpgmeDecryptResult = DecryptResult
17
+ GpgmeSignResult = SignResult
18
+ GpgmeEncryptResult = EncryptResult
19
+ GpgmeInvalidKey = InvalidKey
20
+ GpgmeNewSignature = NewSignature
21
+ GpgmeImportStatus = ImportStatus
22
+ GpgmeImportResult = ImportResult
23
+
24
+ class Ctx
25
+ # Set the data pointer to the beginning.
26
+ def rewind
27
+ seek(0)
28
+ end
29
+ end
30
+
31
+ def gpgme_data_rewind(dh)
32
+ begin
33
+ GPGME::gpgme_data_seek(dh, 0, IO::SEEK_SET)
34
+ rescue SystemCallError => e
35
+ return e.errno
36
+ end
37
+ end
38
+ module_function :gpgme_data_rewind
39
+
40
+ def gpgme_op_import_ext(ctx, keydata, nr)
41
+ err = GPGME::gpgme_op_import(ctx, keydata)
42
+ if GPGME::gpgme_err_code(err) == GPGME::GPG_ERR_NO_ERROR
43
+ result = GPGME::gpgme_op_import_result(ctx)
44
+ nr.push(result.considered)
45
+ end
46
+ end
47
+ module_function :gpgme_op_import_ext
48
+ end
@@ -0,0 +1,187 @@
1
+ module GPGME
2
+
3
+ ATTR_ALGO = GPGME_ATTR_ALGO
4
+ ATTR_CAN_CERTIFY = GPGME_ATTR_CAN_CERTIFY
5
+ ATTR_CAN_ENCRYPT = GPGME_ATTR_CAN_ENCRYPT
6
+ ATTR_CAN_SIGN = GPGME_ATTR_CAN_SIGN
7
+ ATTR_CHAINID = GPGME_ATTR_CHAINID
8
+ ATTR_COMMENT = GPGME_ATTR_COMMENT
9
+ ATTR_CREATED = GPGME_ATTR_CREATED
10
+ ATTR_EMAIL = GPGME_ATTR_EMAIL
11
+ ATTR_ERRTOK = GPGME_ATTR_ERRTOK
12
+ ATTR_EXPIRE = GPGME_ATTR_EXPIRE
13
+ ATTR_FPR = GPGME_ATTR_FPR
14
+ ATTR_ISSUER = GPGME_ATTR_ISSUER
15
+ ATTR_IS_SECRET = GPGME_ATTR_IS_SECRET
16
+ ATTR_KEYID = GPGME_ATTR_KEYID
17
+ ATTR_KEY_CAPS = GPGME_ATTR_KEY_CAPS
18
+ ATTR_KEY_DISABLED = GPGME_ATTR_KEY_DISABLED
19
+ ATTR_KEY_EXPIRED = GPGME_ATTR_KEY_EXPIRED
20
+ ATTR_KEY_INVALID = GPGME_ATTR_KEY_INVALID
21
+ ATTR_KEY_REVOKED = GPGME_ATTR_KEY_REVOKED
22
+ ATTR_LEN = GPGME_ATTR_LEN
23
+ ATTR_LEVEL = GPGME_ATTR_LEVEL
24
+ ATTR_NAME = GPGME_ATTR_NAME
25
+ ATTR_OTRUST = GPGME_ATTR_OTRUST
26
+ ATTR_SERIAL = GPGME_ATTR_SERIAL
27
+ ATTR_SIG_STATUS = GPGME_ATTR_SIG_STATUS
28
+ ATTR_SIG_SUMMARY = GPGME_ATTR_SIG_SUMMARY
29
+ ATTR_TYPE = GPGME_ATTR_TYPE
30
+ ATTR_UID_INVALID = GPGME_ATTR_UID_INVALID
31
+ ATTR_UID_REVOKED = GPGME_ATTR_UID_REVOKED
32
+ ATTR_USERID = GPGME_ATTR_USERID
33
+ ATTR_VALIDITY = GPGME_ATTR_VALIDITY
34
+ DATA_ENCODING_ARMOR = GPGME_DATA_ENCODING_ARMOR
35
+ DATA_ENCODING_BASE64 = GPGME_DATA_ENCODING_BASE64
36
+ DATA_ENCODING_BINARY = GPGME_DATA_ENCODING_BINARY
37
+ DATA_ENCODING_NONE = GPGME_DATA_ENCODING_NONE
38
+ ENCRYPT_ALWAYS_TRUST = GPGME_ENCRYPT_ALWAYS_TRUST
39
+ IMPORT_NEW = GPGME_IMPORT_NEW
40
+ IMPORT_SECRET = GPGME_IMPORT_SECRET
41
+ IMPORT_SIG = GPGME_IMPORT_SIG
42
+ IMPORT_SUBKEY = GPGME_IMPORT_SUBKEY
43
+ IMPORT_UID = GPGME_IMPORT_UID
44
+ KEYLIST_MODE_EXTERN = GPGME_KEYLIST_MODE_EXTERN
45
+ KEYLIST_MODE_LOCAL = GPGME_KEYLIST_MODE_LOCAL
46
+ KEYLIST_MODE_SIGS = GPGME_KEYLIST_MODE_SIGS
47
+ KEYLIST_MODE_VALIDATE = GPGME_KEYLIST_MODE_VALIDATE
48
+ MD_CRC24_RFC2440 = GPGME_MD_CRC24_RFC2440
49
+ MD_CRC32 = GPGME_MD_CRC32
50
+ MD_CRC32_RFC1510 = GPGME_MD_CRC32_RFC1510
51
+ MD_HAVAL = GPGME_MD_HAVAL
52
+ MD_MD2 = GPGME_MD_MD2
53
+ MD_MD4 = GPGME_MD_MD4
54
+ MD_MD5 = GPGME_MD_MD5
55
+ MD_RMD160 = GPGME_MD_RMD160
56
+ MD_SHA1 = GPGME_MD_SHA1
57
+ MD_SHA256 = GPGME_MD_SHA256
58
+ MD_SHA384 = GPGME_MD_SHA384
59
+ MD_SHA512 = GPGME_MD_SHA512
60
+ MD_TIGER = GPGME_MD_TIGER
61
+ PK_DSA = GPGME_PK_DSA
62
+ PK_ELG = GPGME_PK_ELG
63
+ PK_ELG_E = GPGME_PK_ELG_E
64
+ PK_RSA = GPGME_PK_RSA
65
+ PROTOCOL_CMS = GPGME_PROTOCOL_CMS
66
+ PROTOCOL_OpenPGP = GPGME_PROTOCOL_OpenPGP
67
+ SIGSUM_BAD_POLICY = GPGME_SIGSUM_BAD_POLICY
68
+ SIGSUM_CRL_MISSING = GPGME_SIGSUM_CRL_MISSING
69
+ SIGSUM_CRL_TOO_OLD = GPGME_SIGSUM_CRL_TOO_OLD
70
+ SIGSUM_GREEN = GPGME_SIGSUM_GREEN
71
+ SIGSUM_KEY_EXPIRED = GPGME_SIGSUM_KEY_EXPIRED
72
+ SIGSUM_KEY_MISSING = GPGME_SIGSUM_KEY_MISSING
73
+ SIGSUM_KEY_REVOKED = GPGME_SIGSUM_KEY_REVOKED
74
+ SIGSUM_RED = GPGME_SIGSUM_RED
75
+ SIGSUM_SIG_EXPIRED = GPGME_SIGSUM_SIG_EXPIRED
76
+ SIGSUM_SYS_ERROR = GPGME_SIGSUM_SYS_ERROR
77
+ SIGSUM_VALID = GPGME_SIGSUM_VALID
78
+ SIG_MODE_CLEAR = GPGME_SIG_MODE_CLEAR
79
+ SIG_MODE_DETACH = GPGME_SIG_MODE_DETACH
80
+ SIG_MODE_NORMAL = GPGME_SIG_MODE_NORMAL
81
+ SIG_STAT_BAD = GPGME_SIG_STAT_BAD
82
+ SIG_STAT_DIFF = GPGME_SIG_STAT_DIFF
83
+ SIG_STAT_ERROR = GPGME_SIG_STAT_ERROR
84
+ SIG_STAT_GOOD = GPGME_SIG_STAT_GOOD
85
+ SIG_STAT_GOOD_EXP = GPGME_SIG_STAT_GOOD_EXP
86
+ SIG_STAT_GOOD_EXPKEY = GPGME_SIG_STAT_GOOD_EXPKEY
87
+ SIG_STAT_NOKEY = GPGME_SIG_STAT_NOKEY
88
+ SIG_STAT_NONE = GPGME_SIG_STAT_NONE
89
+ SIG_STAT_NOSIG = GPGME_SIG_STAT_NOSIG
90
+ STATUS_ABORT = GPGME_STATUS_ABORT
91
+ STATUS_ALREADY_SIGNED = GPGME_STATUS_ALREADY_SIGNED
92
+ STATUS_BADARMOR = GPGME_STATUS_BADARMOR
93
+ STATUS_BADMDC = GPGME_STATUS_BADMDC
94
+ STATUS_BADSIG = GPGME_STATUS_BADSIG
95
+ STATUS_BAD_PASSPHRASE = GPGME_STATUS_BAD_PASSPHRASE
96
+ STATUS_BEGIN_DECRYPTION = GPGME_STATUS_BEGIN_DECRYPTION
97
+ STATUS_BEGIN_ENCRYPTION = GPGME_STATUS_BEGIN_ENCRYPTION
98
+ STATUS_BEGIN_STREAM = GPGME_STATUS_BEGIN_STREAM
99
+ STATUS_DECRYPTION_FAILED = GPGME_STATUS_DECRYPTION_FAILED
100
+ STATUS_DECRYPTION_OKAY = GPGME_STATUS_DECRYPTION_OKAY
101
+ STATUS_DELETE_PROBLEM = GPGME_STATUS_DELETE_PROBLEM
102
+ STATUS_ENC_TO = GPGME_STATUS_ENC_TO
103
+ STATUS_END_DECRYPTION = GPGME_STATUS_END_DECRYPTION
104
+ STATUS_END_ENCRYPTION = GPGME_STATUS_END_ENCRYPTION
105
+ STATUS_END_STREAM = GPGME_STATUS_END_STREAM
106
+ STATUS_ENTER = GPGME_STATUS_ENTER
107
+ STATUS_EOF = GPGME_STATUS_EOF
108
+ STATUS_ERRMDC = GPGME_STATUS_ERRMDC
109
+ STATUS_ERROR = GPGME_STATUS_ERROR
110
+ STATUS_ERRSIG = GPGME_STATUS_ERRSIG
111
+ STATUS_EXPKEYSIG = GPGME_STATUS_EXPKEYSIG
112
+ STATUS_EXPSIG = GPGME_STATUS_EXPSIG
113
+ STATUS_FILE_DONE = GPGME_STATUS_FILE_DONE
114
+ STATUS_FILE_ERROR = GPGME_STATUS_FILE_ERROR
115
+ STATUS_FILE_START = GPGME_STATUS_FILE_START
116
+ STATUS_GET_BOOL = GPGME_STATUS_GET_BOOL
117
+ STATUS_GET_HIDDEN = GPGME_STATUS_GET_HIDDEN
118
+ STATUS_GET_LINE = GPGME_STATUS_GET_LINE
119
+ STATUS_GOODMDC = GPGME_STATUS_GOODMDC
120
+ STATUS_GOODSIG = GPGME_STATUS_GOODSIG
121
+ STATUS_GOOD_PASSPHRASE = GPGME_STATUS_GOOD_PASSPHRASE
122
+ STATUS_GOT_IT = GPGME_STATUS_GOT_IT
123
+ STATUS_IMPORTED = GPGME_STATUS_IMPORTED
124
+ STATUS_IMPORT_RES = GPGME_STATUS_IMPORT_RES
125
+ STATUS_INV_RECP = GPGME_STATUS_INV_RECP
126
+ STATUS_KEYEXPIRED = GPGME_STATUS_KEYEXPIRED
127
+ STATUS_KEYREVOKED = GPGME_STATUS_KEYREVOKED
128
+ STATUS_KEY_CREATED = GPGME_STATUS_KEY_CREATED
129
+ STATUS_LEAVE = GPGME_STATUS_LEAVE
130
+ STATUS_MISSING_PASSPHRASE = GPGME_STATUS_MISSING_PASSPHRASE
131
+ STATUS_NEED_PASSPHRASE = GPGME_STATUS_NEED_PASSPHRASE
132
+ STATUS_NEED_PASSPHRASE_SYM = GPGME_STATUS_NEED_PASSPHRASE_SYM
133
+ STATUS_NODATA = GPGME_STATUS_NODATA
134
+ STATUS_NOTATION_DATA = GPGME_STATUS_NOTATION_DATA
135
+ STATUS_NOTATION_NAME = GPGME_STATUS_NOTATION_NAME
136
+ STATUS_NO_PUBKEY = GPGME_STATUS_NO_PUBKEY
137
+ STATUS_NO_RECP = GPGME_STATUS_NO_RECP
138
+ STATUS_NO_SECKEY = GPGME_STATUS_NO_SECKEY
139
+ STATUS_POLICY_URL = GPGME_STATUS_POLICY_URL
140
+ STATUS_PROGRESS = GPGME_STATUS_PROGRESS
141
+ STATUS_RSA_OR_IDEA = GPGME_STATUS_RSA_OR_IDEA
142
+ STATUS_SESSION_KEY = GPGME_STATUS_SESSION_KEY
143
+ STATUS_SHM_GET = GPGME_STATUS_SHM_GET
144
+ STATUS_SHM_GET_BOOL = GPGME_STATUS_SHM_GET_BOOL
145
+ STATUS_SHM_GET_HIDDEN = GPGME_STATUS_SHM_GET_HIDDEN
146
+ STATUS_SHM_INFO = GPGME_STATUS_SHM_INFO
147
+ STATUS_SIGEXPIRED = GPGME_STATUS_SIGEXPIRED
148
+ STATUS_SIG_CREATED = GPGME_STATUS_SIG_CREATED
149
+ STATUS_SIG_ID = GPGME_STATUS_SIG_ID
150
+ STATUS_TRUNCATED = GPGME_STATUS_TRUNCATED
151
+ STATUS_TRUST_FULLY = GPGME_STATUS_TRUST_FULLY
152
+ STATUS_TRUST_MARGINAL = GPGME_STATUS_TRUST_MARGINAL
153
+ STATUS_TRUST_NEVER = GPGME_STATUS_TRUST_NEVER
154
+ STATUS_TRUST_ULTIMATE = GPGME_STATUS_TRUST_ULTIMATE
155
+ STATUS_TRUST_UNDEFINED = GPGME_STATUS_TRUST_UNDEFINED
156
+ STATUS_UNEXPECTED = GPGME_STATUS_UNEXPECTED
157
+ STATUS_USERID_HINT = GPGME_STATUS_USERID_HINT
158
+ STATUS_VALIDSIG = GPGME_STATUS_VALIDSIG
159
+ VALIDITY_FULL = GPGME_VALIDITY_FULL
160
+ VALIDITY_MARGINAL = GPGME_VALIDITY_MARGINAL
161
+ VALIDITY_NEVER = GPGME_VALIDITY_NEVER
162
+ VALIDITY_ULTIMATE = GPGME_VALIDITY_ULTIMATE
163
+ VALIDITY_UNDEFINED = GPGME_VALIDITY_UNDEFINED
164
+ VALIDITY_UNKNOWN = GPGME_VALIDITY_UNKNOWN
165
+
166
+ PROTOCOL_NAMES = {
167
+ PROTOCOL_OpenPGP => :OpenPGP,
168
+ PROTOCOL_CMS => :CMS
169
+ }
170
+
171
+ KEYLIST_MODE_NAMES = {
172
+ KEYLIST_MODE_LOCAL => :local,
173
+ KEYLIST_MODE_EXTERN => :extern,
174
+ KEYLIST_MODE_SIGS => :sigs,
175
+ KEYLIST_MODE_VALIDATE => :validate
176
+ }
177
+
178
+ VALIDITY_NAMES = {
179
+ VALIDITY_UNKNOWN => :unknown,
180
+ VALIDITY_UNDEFINED => :undefined,
181
+ VALIDITY_NEVER => :never,
182
+ VALIDITY_MARGINAL => :marginal,
183
+ VALIDITY_FULL => :full,
184
+ VALIDITY_ULTIMATE => :ultimate
185
+ }
186
+
187
+ end
@@ -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