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.
@@ -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,7 @@
1
+ module OpenPGP
2
+ class Digest
3
+ class MD5 < Digest
4
+ IDENTIFIER = 1
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module OpenPGP
2
+ class Digest
3
+ class RIPEMD160 < Digest
4
+ IDENTIFIER = 3
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module OpenPGP
2
+ class Digest
3
+ class SHA1 < Digest
4
+ IDENTIFIER = 2
5
+ end
6
+ end
7
+ 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