klacointe-openpgp 0.0.1.3
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.
- data/LICENSE +19 -0
- data/README +104 -0
- data/Rakefile +19 -0
- data/VERSION +1 -0
- data/bin/openpgp +3 -0
- data/lib/openpgp/algorithm.rb +57 -0
- data/lib/openpgp/armor.rb +120 -0
- data/lib/openpgp/buffer.rb +100 -0
- data/lib/openpgp/cipher/3des.rb +9 -0
- data/lib/openpgp/cipher/aes.rb +26 -0
- data/lib/openpgp/cipher/blowfish.rb +9 -0
- data/lib/openpgp/cipher/cast5.rb +9 -0
- data/lib/openpgp/cipher/idea.rb +9 -0
- data/lib/openpgp/cipher/twofish.rb +9 -0
- data/lib/openpgp/cipher.rb +117 -0
- data/lib/openpgp/client/gnupg.rb +583 -0
- data/lib/openpgp/digest/md5.rb +7 -0
- data/lib/openpgp/digest/rmd160.rb +7 -0
- data/lib/openpgp/digest/sha1.rb +7 -0
- data/lib/openpgp/digest/sha2.rb +19 -0
- data/lib/openpgp/digest.rb +60 -0
- data/lib/openpgp/engine/gnupg.rb +194 -0
- data/lib/openpgp/engine/openssl.rb +47 -0
- data/lib/openpgp/engine.rb +46 -0
- data/lib/openpgp/message.rb +106 -0
- data/lib/openpgp/packet.rb +507 -0
- data/lib/openpgp/random.rb +31 -0
- data/lib/openpgp/s2k.rb +186 -0
- data/lib/openpgp/util.rb +65 -0
- data/lib/openpgp/version.rb +14 -0
- data/lib/openpgp.rb +17 -0
- metadata +96 -0
@@ -0,0 +1,583 @@
|
|
1
|
+
module OpenPGP module Client
|
2
|
+
##
|
3
|
+
# GNU Privacy Guard (GnuPG) implementation.
|
4
|
+
#
|
5
|
+
# @see http://www.gnupg.org/
|
6
|
+
class GnuPG
|
7
|
+
VERSION = OpenPGP::VERSION
|
8
|
+
|
9
|
+
attr_accessor :options
|
10
|
+
|
11
|
+
def initialize(options = {})
|
12
|
+
@options = {
|
13
|
+
:homedir => ENV['GNUPGHOME'] || '~/.gnupg',
|
14
|
+
:version => false,
|
15
|
+
}
|
16
|
+
@options.merge!(options)
|
17
|
+
|
18
|
+
if options.has_key?(:options)
|
19
|
+
parse_options_file(options[:options])
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Commands not specific to the function
|
24
|
+
|
25
|
+
##
|
26
|
+
# Prints the program version and licensing information.
|
27
|
+
def version
|
28
|
+
puts "gpg.rb (GnuPG compatible) #{VERSION}"
|
29
|
+
puts
|
30
|
+
puts "Home: #{options[:homedir]}"
|
31
|
+
puts "Supported algorithms:"
|
32
|
+
puts "Pubkey: " # TODO
|
33
|
+
puts "Cipher: #{cipher_algorithms.keys.map(&:to_s).sort.join(', ')}"
|
34
|
+
puts "Hash: #{digest_algorithms.join(', ')}"
|
35
|
+
puts "Compression: #{compress_algorithms.keys.map(&:to_s).sort.join(', ')}"
|
36
|
+
end
|
37
|
+
|
38
|
+
##
|
39
|
+
# Prints a usage message summarizing the most useful command-line options.
|
40
|
+
def help() end
|
41
|
+
|
42
|
+
##
|
43
|
+
# Prints warranty information.
|
44
|
+
def warranty
|
45
|
+
raise NotImplementedError
|
46
|
+
end
|
47
|
+
|
48
|
+
##
|
49
|
+
# Prints a list of all available options and commands.
|
50
|
+
def dump_options
|
51
|
+
self.class.public_instance_methods(false).each do |command|
|
52
|
+
if command =~ /^[\w\d_]+$/
|
53
|
+
puts "--#{command.to_s.gsub('_', '-')}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
# TODO: list available options, too.
|
57
|
+
end
|
58
|
+
|
59
|
+
# Commands to select the type of operation
|
60
|
+
|
61
|
+
##
|
62
|
+
# Makes a signature.
|
63
|
+
def sign
|
64
|
+
raise NotImplementedError # TODO
|
65
|
+
end
|
66
|
+
|
67
|
+
##
|
68
|
+
# Makes a clear text signature.
|
69
|
+
def clearsign
|
70
|
+
raise NotImplementedError # TODO
|
71
|
+
end
|
72
|
+
|
73
|
+
##
|
74
|
+
# Makes a detached signature.
|
75
|
+
def detach_sign
|
76
|
+
raise NotImplementedError # TODO
|
77
|
+
end
|
78
|
+
|
79
|
+
##
|
80
|
+
# Encrypts data.
|
81
|
+
def encrypt
|
82
|
+
raise NotImplementedError # TODO
|
83
|
+
end
|
84
|
+
|
85
|
+
##
|
86
|
+
# Encrypts with a symmetric cipher using a passphrase.
|
87
|
+
def symmetric(file)
|
88
|
+
print OpenPGP.encrypt(File.read(file), {
|
89
|
+
:symmetric => true,
|
90
|
+
:passphrase => read_passphrase,
|
91
|
+
:cipher => cipher_algorithm,
|
92
|
+
:digest => digest_algorithm,
|
93
|
+
:compress => compress_algorithm,
|
94
|
+
})
|
95
|
+
end
|
96
|
+
|
97
|
+
##
|
98
|
+
# Stores only (make a simple RFC1991 literal data packet).
|
99
|
+
def store(file)
|
100
|
+
Message.write(stdout) do |msg|
|
101
|
+
msg << Packet::LiteralData.new({
|
102
|
+
:format => :b,
|
103
|
+
:filename => File.basename(file),
|
104
|
+
:timestamp => File.mtime(file),
|
105
|
+
:data => File.read(file),
|
106
|
+
})
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
##
|
111
|
+
# Decrypts data.
|
112
|
+
def decrypt(file)
|
113
|
+
raise NotImplementedError # TODO
|
114
|
+
end
|
115
|
+
|
116
|
+
##
|
117
|
+
# Verifies data.
|
118
|
+
def verify(file)
|
119
|
+
raise NotImplementedError # TODO
|
120
|
+
end
|
121
|
+
|
122
|
+
##
|
123
|
+
# Identical to --multifile --verify.
|
124
|
+
def verify_files(*files)
|
125
|
+
options[:multifile] = true
|
126
|
+
files.each { |file| verify(file) }
|
127
|
+
end
|
128
|
+
|
129
|
+
##
|
130
|
+
# Identical to --multifile --encrypt.
|
131
|
+
def encrypt_files(*files)
|
132
|
+
options[:multifile] = true
|
133
|
+
files.each { |file| encrypt(file) }
|
134
|
+
end
|
135
|
+
|
136
|
+
##
|
137
|
+
# Identical to --multifile --decrypt.
|
138
|
+
def decrypt_files(*files)
|
139
|
+
options[:multifile] = true
|
140
|
+
files.each { |file| decrypt(file) }
|
141
|
+
end
|
142
|
+
|
143
|
+
##
|
144
|
+
# Lists keys from the public keyrings.
|
145
|
+
def list_keys(*keys)
|
146
|
+
list_public_keys(*keys)
|
147
|
+
end
|
148
|
+
|
149
|
+
##
|
150
|
+
# Lists keys from the public keyrings.
|
151
|
+
def list_public_keys(*keys)
|
152
|
+
public_keyrings.each do |keyring_filename, keyring|
|
153
|
+
puts (keyring_filename = File.expand_path(keyring_filename))
|
154
|
+
print '-' * keyring_filename.size
|
155
|
+
|
156
|
+
keyring.each do |packet|
|
157
|
+
case packet
|
158
|
+
when Packet::PublicSubkey
|
159
|
+
print_key_listing(packet, :sub)
|
160
|
+
when Packet::PublicKey
|
161
|
+
print_key_listing(packet, :pub)
|
162
|
+
when Packet::UserID
|
163
|
+
print_uid_listing(packet)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
##
|
170
|
+
# Lists keys from the secret keyrings.
|
171
|
+
def list_secret_keys(*keys)
|
172
|
+
secret_keyrings.each do |keyring_filename, keyring|
|
173
|
+
puts (keyring_filename = File.expand_path(keyring_filename))
|
174
|
+
print '-' * keyring_filename.size
|
175
|
+
|
176
|
+
keyring.each do |packet|
|
177
|
+
case packet
|
178
|
+
when Packet::SecretSubkey
|
179
|
+
print_key_listing(packet, :ssb)
|
180
|
+
when Packet::SecretKey
|
181
|
+
print_key_listing(packet, :sec)
|
182
|
+
when Packet::UserID
|
183
|
+
print_uid_listing(packet)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
##
|
190
|
+
# Same as +list_keys+, but the signatures are listed too.
|
191
|
+
def list_sigs
|
192
|
+
raise NotImplementedError # TODO
|
193
|
+
end
|
194
|
+
|
195
|
+
##
|
196
|
+
# Same as +list_sigs+, but the signatures are verified.
|
197
|
+
def check_sigs
|
198
|
+
raise NotImplementedError # TODO
|
199
|
+
end
|
200
|
+
|
201
|
+
##
|
202
|
+
# Lists all keys (or the specified ones) along with their fingerprints.
|
203
|
+
def fingerprint(*keys)
|
204
|
+
options[:fingerprint] = true
|
205
|
+
list_keys(*keys)
|
206
|
+
end
|
207
|
+
|
208
|
+
##
|
209
|
+
# Lists only the sequence of packets.
|
210
|
+
def list_packets
|
211
|
+
raise NotImplementedError # TODO
|
212
|
+
end
|
213
|
+
|
214
|
+
##
|
215
|
+
# Presents a menu to work with a smartcard.
|
216
|
+
def card_edit
|
217
|
+
raise NotImplementedError # TODO
|
218
|
+
end
|
219
|
+
|
220
|
+
##
|
221
|
+
# Shows the content of the smart card.
|
222
|
+
def card_status
|
223
|
+
raise NotImplementedError # TODO
|
224
|
+
end
|
225
|
+
|
226
|
+
##
|
227
|
+
# Presents a menu to allow changing the PIN of a smartcard.
|
228
|
+
def change_pin
|
229
|
+
raise NotImplementedError # TODO
|
230
|
+
end
|
231
|
+
|
232
|
+
##
|
233
|
+
# Removes key from the public keyring.
|
234
|
+
def delete_key(name)
|
235
|
+
raise NotImplementedError # TODO
|
236
|
+
end
|
237
|
+
|
238
|
+
##
|
239
|
+
# Removes key from the secret and public keyring.
|
240
|
+
def delete_secret_key(name)
|
241
|
+
raise NotImplementedError # TODO
|
242
|
+
end
|
243
|
+
|
244
|
+
##
|
245
|
+
# Removes key from the secret and public keyring. If a secret key exists, it will be removed first.
|
246
|
+
def delete_secret_and_public_key(name)
|
247
|
+
raise NotImplementedError # TODO
|
248
|
+
end
|
249
|
+
|
250
|
+
##
|
251
|
+
# Exports keys from the public keyring.
|
252
|
+
def export(*keys)
|
253
|
+
raise NotImplementedError # TODO
|
254
|
+
end
|
255
|
+
|
256
|
+
##
|
257
|
+
# Sends keys to a keyserver.
|
258
|
+
def send_keys(*keys)
|
259
|
+
raise NotImplementedError # TODO
|
260
|
+
end
|
261
|
+
|
262
|
+
##
|
263
|
+
# Exports the secret keys.
|
264
|
+
def export_secret_keys
|
265
|
+
raise NotImplementedError # TODO
|
266
|
+
end
|
267
|
+
|
268
|
+
##
|
269
|
+
# Exports the secret subkeys.
|
270
|
+
def export_secret_subkeys
|
271
|
+
raise NotImplementedError # TODO
|
272
|
+
end
|
273
|
+
|
274
|
+
##
|
275
|
+
# Imports/merges keys, adding the given keys to the keyring.
|
276
|
+
def import(*keys)
|
277
|
+
raise NotImplementedError # TODO
|
278
|
+
end
|
279
|
+
|
280
|
+
##
|
281
|
+
# Alias for +import+.
|
282
|
+
def fast_import(*keys)
|
283
|
+
import(*keys)
|
284
|
+
end
|
285
|
+
|
286
|
+
##
|
287
|
+
# Imports the keys with the given key IDs from a keyserver.
|
288
|
+
def recv_keys(*keys)
|
289
|
+
raise NotImplementedError # TODO
|
290
|
+
end
|
291
|
+
|
292
|
+
##
|
293
|
+
# Requests updates from a keyserver for keys that already exist on the local keyring.
|
294
|
+
def refresh_keys(*keys)
|
295
|
+
raise NotImplementedError # TODO
|
296
|
+
end
|
297
|
+
|
298
|
+
##
|
299
|
+
# Searches the keyserver for the given names.
|
300
|
+
def search_keys(*names)
|
301
|
+
raise NotImplementedError # TODO
|
302
|
+
end
|
303
|
+
|
304
|
+
##
|
305
|
+
# Retrieves keys located at the specified URIs.
|
306
|
+
def fetch_keys(*uris)
|
307
|
+
require 'open-uri'
|
308
|
+
raise NotImplementedError # TODO
|
309
|
+
end
|
310
|
+
|
311
|
+
##
|
312
|
+
# Does trust database maintenance.
|
313
|
+
def update_trustdb
|
314
|
+
raise NotImplementedError # TODO
|
315
|
+
end
|
316
|
+
|
317
|
+
##
|
318
|
+
# Does trust database maintenance without user interaction.
|
319
|
+
def check_trustdb
|
320
|
+
raise NotImplementedError # TODO
|
321
|
+
end
|
322
|
+
|
323
|
+
##
|
324
|
+
# Sends the ownertrust values to stdout.
|
325
|
+
def export_ownertrust
|
326
|
+
raise NotImplementedError # TODO
|
327
|
+
end
|
328
|
+
|
329
|
+
##
|
330
|
+
# Updates the trustdb with the ownertrust values stored in +files+ or stdin.
|
331
|
+
def import_ownertrust(*files)
|
332
|
+
raise NotImplementedError # TODO
|
333
|
+
end
|
334
|
+
|
335
|
+
##
|
336
|
+
# Creates signature caches in the keyring.
|
337
|
+
def rebuild_keydb_caches
|
338
|
+
raise NotImplementedError # TODO
|
339
|
+
end
|
340
|
+
|
341
|
+
##
|
342
|
+
# Prints message digest of algorithm +algo+ for all given files or stdin.
|
343
|
+
def print_md(algo, *files)
|
344
|
+
unless digest_algorithms.include?(algorithm = algo.to_s.upcase.to_sym)
|
345
|
+
abort "gpg: invalid hash algorithm `#{algo}'"
|
346
|
+
else
|
347
|
+
digest = Digest.for(algorithm)
|
348
|
+
end
|
349
|
+
|
350
|
+
files.each do |file|
|
351
|
+
puts (prefix = "#{file}: ") << format_fingerprint(digest.file(file).hexdigest, prefix.size)
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
##
|
356
|
+
# Prints message digests of all available algorithms for all given files or stdin.
|
357
|
+
def print_mds(*files)
|
358
|
+
files.each do |file|
|
359
|
+
digest_algorithms.each do |algorithm|
|
360
|
+
algorithm = :RMD160 if algorithm == :RIPEMD160
|
361
|
+
digest = Digest.for(algorithm)
|
362
|
+
|
363
|
+
puts (prefix = "#{file}: #{algorithm.to_s.rjust(6)} = ") << format_fingerprint(digest.file(file).hexdigest, prefix.size)
|
364
|
+
end
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
##
|
369
|
+
# Emits +count+ random bytes of the given quality level.
|
370
|
+
def gen_random(level = 0, count = nil)
|
371
|
+
wrong_args "--gen-random 0|1|2 [count]" unless (0..2).include?(level)
|
372
|
+
|
373
|
+
require 'openssl'
|
374
|
+
count = count.to_i if count
|
375
|
+
endless = count.nil?
|
376
|
+
while endless || count > 0
|
377
|
+
n = !endless && count < 99 ? count : 99
|
378
|
+
p = Random.bytes(n)
|
379
|
+
print options[:armor] ? [p].pack('m').delete("\n") : p
|
380
|
+
count -= n unless endless
|
381
|
+
end
|
382
|
+
puts if options[:armor]
|
383
|
+
end
|
384
|
+
|
385
|
+
##
|
386
|
+
# Generates a prime number.
|
387
|
+
def gen_prime(mode, bits, qbits = nil)
|
388
|
+
case mode.to_i
|
389
|
+
when 1..4
|
390
|
+
raise NotImplementedError # TODO
|
391
|
+
else
|
392
|
+
wrong_args "--gen-prime mode bits [qbits]"
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
396
|
+
##
|
397
|
+
# Packs an arbitrary input into an OpenPGP ASCII armor.
|
398
|
+
def enarmor(file)
|
399
|
+
text = OpenPGP.enarmor(File.read(file), :armored_file, :comment => 'Use "gpg --dearmor" for unpacking', :line_length => 64)
|
400
|
+
puts text # FIXME
|
401
|
+
end
|
402
|
+
|
403
|
+
##
|
404
|
+
# Unpacks an arbitrary input from an OpenPGP ASCII armor.
|
405
|
+
def dearmor(file)
|
406
|
+
data = OpenPGP.dearmor(File.read(file))
|
407
|
+
puts data # FIXME
|
408
|
+
end
|
409
|
+
|
410
|
+
# Commands for key management
|
411
|
+
|
412
|
+
##
|
413
|
+
# Generates a new key pair.
|
414
|
+
def gen_key
|
415
|
+
raise NotImplementedError # TODO
|
416
|
+
end
|
417
|
+
|
418
|
+
##
|
419
|
+
# Generates a revocation certificate for the complete key.
|
420
|
+
def gen_revoke(name)
|
421
|
+
raise NotImplementedError # TODO
|
422
|
+
end
|
423
|
+
|
424
|
+
##
|
425
|
+
# Generates a designated revocation certificate for a key.
|
426
|
+
def desig_revoke(name)
|
427
|
+
raise NotImplementedError # TODO
|
428
|
+
end
|
429
|
+
|
430
|
+
##
|
431
|
+
# Present a menu which enables you to do most of the key management related tasks.
|
432
|
+
def edit_key(key)
|
433
|
+
raise NotImplementedError # TODO
|
434
|
+
end
|
435
|
+
|
436
|
+
##
|
437
|
+
# Signs a public key with your secret key.
|
438
|
+
def sign_key(name)
|
439
|
+
raise NotImplementedError # TODO
|
440
|
+
end
|
441
|
+
|
442
|
+
##
|
443
|
+
# Signs a public key with your secret key but marks it as non-exportable.
|
444
|
+
def lsign_key(name)
|
445
|
+
raise NotImplementedError # TODO
|
446
|
+
end
|
447
|
+
|
448
|
+
protected
|
449
|
+
|
450
|
+
def stdin() $stdin end
|
451
|
+
def stdout() $stdout end
|
452
|
+
def stderr() $stdout end
|
453
|
+
|
454
|
+
def read_passphrase
|
455
|
+
if options[:passphrase]
|
456
|
+
options[:passphrase]
|
457
|
+
else
|
458
|
+
# TODO
|
459
|
+
end
|
460
|
+
end
|
461
|
+
|
462
|
+
def public_keyrings
|
463
|
+
{public_keyring_file => keyring(public_keyring_file)} # FIXME
|
464
|
+
end
|
465
|
+
|
466
|
+
def secret_keyrings
|
467
|
+
{secret_keyring_file => keyring(secret_keyring_file)} # FIXME
|
468
|
+
end
|
469
|
+
|
470
|
+
def keyring(file)
|
471
|
+
OpenPGP::Message.parse(File.read(File.expand_path(file)))
|
472
|
+
end
|
473
|
+
|
474
|
+
def public_keyring_file
|
475
|
+
File.join(options[:homedir], 'pubring.gpg')
|
476
|
+
end
|
477
|
+
|
478
|
+
def secret_keyring_file
|
479
|
+
File.join(options[:homedir], 'secring.gpg')
|
480
|
+
end
|
481
|
+
|
482
|
+
def trustdb_file
|
483
|
+
File.join(options[:homedir], 'trustdb.gpg')
|
484
|
+
end
|
485
|
+
|
486
|
+
def print_key_listing(packet, type)
|
487
|
+
puts unless (is_sub_key = [:sub, :ssb].include?(type))
|
488
|
+
puts "#{type} #{format_keyspec(packet)} #{Time.at(packet.timestamp).strftime('%Y-%m-%d')}"
|
489
|
+
if options[:fingerprint] && !is_sub_key
|
490
|
+
puts " Key fingerprint = #{format_fingerprint(packet.fingerprint)}"
|
491
|
+
end
|
492
|
+
end
|
493
|
+
|
494
|
+
def print_uid_listing(packet)
|
495
|
+
puts "uid" + (' ' * 18) + packet.to_s
|
496
|
+
end
|
497
|
+
|
498
|
+
def format_keyspec(key)
|
499
|
+
"____?/#{key.key_id}" # TODO
|
500
|
+
end
|
501
|
+
|
502
|
+
def format_fingerprint(input, column = 0)
|
503
|
+
group_size = case input.size
|
504
|
+
when 32 then 2 # MD5
|
505
|
+
when 40 then 4 # SHA1, RIPEMD160
|
506
|
+
else 8 # SHA2*
|
507
|
+
end
|
508
|
+
|
509
|
+
lines, line, pos = [], '', 0
|
510
|
+
input.upcase!
|
511
|
+
input.each_byte do |c|
|
512
|
+
line << c
|
513
|
+
if (pos += 1) % group_size == 0
|
514
|
+
if (line.size + column) >= (80 - group_size)
|
515
|
+
lines << line
|
516
|
+
line, pos = '', 0
|
517
|
+
else
|
518
|
+
line << ' '
|
519
|
+
end
|
520
|
+
end
|
521
|
+
end
|
522
|
+
lines << line.strip unless line.empty?
|
523
|
+
|
524
|
+
output = lines.join($/ + (' ' * column))
|
525
|
+
output = output.insert(output.size / 2, ' ') if group_size < 8
|
526
|
+
return output
|
527
|
+
end
|
528
|
+
|
529
|
+
def parse_options_file(file)
|
530
|
+
# TODO
|
531
|
+
end
|
532
|
+
|
533
|
+
def cipher_algorithm
|
534
|
+
unless options[:cipher_algo]
|
535
|
+
Cipher::CAST5 # this is the default cipher
|
536
|
+
else
|
537
|
+
algorithm = options[:cipher_algo].to_s.upcase.to_sym
|
538
|
+
unless cipher_algorithms.has_key?(algorithm)
|
539
|
+
abort "gpg: selected cipher algorithm is invalid"
|
540
|
+
end
|
541
|
+
cipher_algorithms[algorithm]
|
542
|
+
end
|
543
|
+
end
|
544
|
+
|
545
|
+
def digest_algorithm
|
546
|
+
options[:digest_algo]
|
547
|
+
end
|
548
|
+
|
549
|
+
def compress_algorithm
|
550
|
+
options[:compress_algo]
|
551
|
+
end
|
552
|
+
|
553
|
+
def cipher_algorithms
|
554
|
+
{
|
555
|
+
:"3DES" => Cipher::TripleDES,
|
556
|
+
:CAST5 => Cipher::CAST5,
|
557
|
+
:BLOWFISH => Cipher::Blowfish,
|
558
|
+
:AES => Cipher::AES128,
|
559
|
+
:AES192 => Cipher::AES192,
|
560
|
+
:AES256 => Cipher::AES256,
|
561
|
+
#:TWOFISH => Cipher::Twofish, # N/A
|
562
|
+
}
|
563
|
+
end
|
564
|
+
|
565
|
+
def digest_algorithms
|
566
|
+
[:MD5, :SHA1, :RIPEMD160, :SHA256, :SHA384, :SHA512]
|
567
|
+
end
|
568
|
+
|
569
|
+
def compress_algorithms
|
570
|
+
{
|
571
|
+
:none => nil,
|
572
|
+
:ZIP => nil, # TODO
|
573
|
+
:ZLIB => nil, # TODO
|
574
|
+
:BZIP2 => nil, # TODO
|
575
|
+
}
|
576
|
+
end
|
577
|
+
|
578
|
+
def wrong_args(usage)
|
579
|
+
abort "usage: gpg.rb [options] #{usage}"
|
580
|
+
end
|
581
|
+
end
|
582
|
+
|
583
|
+
end end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module OpenPGP
|
2
|
+
class Digest
|
3
|
+
class SHA224 < Digest
|
4
|
+
IDENTIFIER = 11
|
5
|
+
end
|
6
|
+
|
7
|
+
class SHA256 < Digest
|
8
|
+
IDENTIFIER = 8
|
9
|
+
end
|
10
|
+
|
11
|
+
class SHA384 < Digest
|
12
|
+
IDENTIFIER = 9
|
13
|
+
end
|
14
|
+
|
15
|
+
class SHA512 < Digest
|
16
|
+
IDENTIFIER = 10
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module OpenPGP
|
2
|
+
##
|
3
|
+
# OpenPGP message digest algorithm.
|
4
|
+
#
|
5
|
+
# @see http://tools.ietf.org/html/rfc4880#section-9.4
|
6
|
+
class Digest
|
7
|
+
autoload :MD5, 'openpgp/digest/md5'
|
8
|
+
autoload :SHA1, 'openpgp/digest/sha1'
|
9
|
+
autoload :RIPEMD160, 'openpgp/digest/rmd160'
|
10
|
+
autoload :SHA256, 'openpgp/digest/sha2'
|
11
|
+
autoload :SHA384, 'openpgp/digest/sha2'
|
12
|
+
autoload :SHA512, 'openpgp/digest/sha2'
|
13
|
+
autoload :SHA224, 'openpgp/digest/sha2'
|
14
|
+
|
15
|
+
DEFAULT = SHA1
|
16
|
+
|
17
|
+
def self.for(identifier)
|
18
|
+
case identifier
|
19
|
+
when Symbol then const_get(identifier.to_s.upcase)
|
20
|
+
when String then const_get(identifier.upcase.to_sym)
|
21
|
+
when 1 then const_get(:MD5)
|
22
|
+
when 2 then const_get(:SHA1)
|
23
|
+
when 3 then const_get(:RIPEMD160)
|
24
|
+
when 8 then const_get(:SHA256)
|
25
|
+
when 9 then const_get(:SHA384)
|
26
|
+
when 10 then const_get(:SHA512)
|
27
|
+
when 11 then const_get(:SHA224)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.to_i() identifier end
|
32
|
+
|
33
|
+
def self.identifier
|
34
|
+
const_get(:IDENTIFIER)
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.algorithm
|
38
|
+
name.split('::').last.to_sym unless self == Digest
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.hexsize
|
42
|
+
size * 2
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.size
|
46
|
+
require 'digest' unless defined?(::Digest)
|
47
|
+
::Digest.const_get(algorithm).new.digest_length
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.hexdigest(data)
|
51
|
+
require 'digest' unless defined?(::Digest)
|
52
|
+
::Digest.const_get(algorithm).hexdigest(data).upcase
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.digest(data)
|
56
|
+
require 'digest' unless defined?(::Digest)
|
57
|
+
::Digest.const_get(algorithm).digest(data)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|