benburkert-gpgme 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -0
- data/COPYING +340 -0
- data/COPYING.LESSER +510 -0
- data/Gemfile +6 -0
- data/History.txt +15 -0
- data/Manifest.txt +18 -0
- data/README.rdoc +162 -0
- data/Rakefile +37 -0
- data/THANKS +15 -0
- data/benburkert-gpgme.gemspec +30 -0
- data/examples/edit.rb +77 -0
- data/examples/genkey.rb +55 -0
- data/examples/keylist.rb +6 -0
- data/examples/roundtrip.rb +39 -0
- data/examples/sign.rb +29 -0
- data/examples/verify.rb +6 -0
- data/ext/gpgme/extconf.rb +26 -0
- data/ext/gpgme/gpgme_n.c +2622 -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 +177 -0
- data/lib/gpgme/engine.rb +76 -0
- data/lib/gpgme/error.rb +66 -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 +108 -0
- data/test/crypto_test.rb +242 -0
- data/test/ctx_test.rb +426 -0
- data/test/data_test.rb +116 -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 +201 -0
- data/test/signature_test.rb +48 -0
- data/test/sub_key_test.rb +45 -0
- data/test/support/resources.rb +516 -0
- data/test/test_helper.rb +79 -0
- metadata +196 -0
data/lib/gpgme/compat.rb
ADDED
@@ -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
|
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
|