benburkert-gpgme 0.1.0

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