klacointe-openpgp 0.0.1.3

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