rnp 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +12 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +5 -0
  5. data/CODE_OF_CONDUCT.md +74 -0
  6. data/Gemfile +4 -0
  7. data/Gemfile.lock +26 -0
  8. data/README.adoc +208 -0
  9. data/Rakefile +6 -0
  10. data/Use_Cases.adoc +119 -0
  11. data/bin/console +14 -0
  12. data/bin/setup +8 -0
  13. data/example-usage.rb +766 -0
  14. data/examples/highlevel/decrypt_mem.rb +44 -0
  15. data/examples/highlevel/encrypt_mem.rb +46 -0
  16. data/examples/lowlevel/decrypt_file.rb +76 -0
  17. data/examples/lowlevel/decrypt_mem.rb +80 -0
  18. data/examples/lowlevel/encrypt_file.rb +68 -0
  19. data/examples/lowlevel/encrypt_mem.rb +75 -0
  20. data/examples/lowlevel/load_pubkey.rb +118 -0
  21. data/examples/lowlevel/print_keyring_file.rb +68 -0
  22. data/examples/lowlevel/print_keyring_mem.rb +96 -0
  23. data/examples/lowlevel/sign_file.rb +104 -0
  24. data/examples/lowlevel/sign_mem.rb +96 -0
  25. data/examples/lowlevel/verify_file.rb +55 -0
  26. data/examples/lowlevel/verify_mem.rb +61 -0
  27. data/lib/rnp/highlevel/constants.rb +96 -0
  28. data/lib/rnp/highlevel/keyring.rb +259 -0
  29. data/lib/rnp/highlevel/publickey.rb +150 -0
  30. data/lib/rnp/highlevel/secretkey.rb +318 -0
  31. data/lib/rnp/highlevel/utils.rb +119 -0
  32. data/lib/rnp/highlevel.rb +5 -0
  33. data/lib/rnp/lowlevel/constants.rb +11 -0
  34. data/lib/rnp/lowlevel/dynarray.rb +129 -0
  35. data/lib/rnp/lowlevel/enums.rb +243 -0
  36. data/lib/rnp/lowlevel/libc.rb +28 -0
  37. data/lib/rnp/lowlevel/libopenssl.rb +15 -0
  38. data/lib/rnp/lowlevel/librnp.rb +213 -0
  39. data/lib/rnp/lowlevel/structs.rb +541 -0
  40. data/lib/rnp/lowlevel/utils.rb +25 -0
  41. data/lib/rnp/lowlevel.rb +6 -0
  42. data/lib/rnp/version.rb +3 -0
  43. data/lib/rnp.rb +5 -0
  44. data/rnp/lib/rnp.rb +5 -0
  45. data/rnp/spec/rnp_spec.rb +11 -0
  46. data/rnp.gemspec +35 -0
  47. metadata +82 -9
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env ruby
2
+ require 'optparse'
3
+ require 'io/console'
4
+
5
+ require_relative '../../lib/rnp'
6
+
7
+ options = {armored: false, keys_armored: false}
8
+ parser = OptionParser.new do |opts|
9
+ opts.banner = "Usage: #{$0} [options] <seckey> <passphrase>"
10
+ opts.on('-k', '--keys-armored', 'Keys are ASCII armored') do
11
+ options[:keys_armored] = true
12
+ end
13
+ opts.on('-a', '--armored', 'Input is ASCII armored') do
14
+ options[:armored] = true
15
+ end
16
+ opts.on('-h', '--help', 'Print this help') do
17
+ puts opts
18
+ exit
19
+ end
20
+ end
21
+ parser.parse!
22
+
23
+ if ARGV.length != 2
24
+ parser.display
25
+ exit
26
+ end
27
+
28
+ seckey_filename = ARGV.shift
29
+ passphrase = ARGV.shift + "\n"
30
+
31
+ secring = RNP::load_keyring(File.binread(seckey_filename), options[:keys_armored])
32
+
33
+ $stdin.binmode
34
+ data = $stdin.read
35
+
36
+ seckey = secring[0]
37
+ decrypted_data = seckey.decrypt(data, passphrase, options[:armored])
38
+ if decrypted_data
39
+ $stderr.puts 'Decryption succeeded'
40
+ $stdout.puts decrypted_data
41
+ else
42
+ $stderr.puts 'Decryption failed!'
43
+ end
44
+
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env ruby
2
+ require 'optparse'
3
+
4
+ require_relative '../../lib/rnp'
5
+
6
+ options = {armored: false, keys_armored: false}
7
+ parser = OptionParser.new do |opts|
8
+ opts.banner = "Usage: #{$0} [options] <pubkey>"
9
+ opts.on('-k', '--keys-armored', 'Seckey is ASCII armored') do
10
+ options[:keys_armored] = true
11
+ end
12
+ opts.on('-a', '--armored', 'Output will be ASCII armored') do
13
+ options[:armored] = true
14
+ end
15
+ opts.on('-h', '--help', 'Print this help') do
16
+ puts opts
17
+ exit
18
+ end
19
+ end
20
+ parser.parse!
21
+
22
+ if ARGV.length != 1
23
+ parser.display
24
+ exit
25
+ end
26
+
27
+ pubkey_filename = ARGV.shift
28
+
29
+ keyring = RNP::load_keyring(File.binread(pubkey_filename), options[:keys_armored])
30
+
31
+ pubkey = keyring[0]
32
+
33
+ $stdin.binmode
34
+ data = $stdin.read
35
+
36
+ encrypted_data = pubkey.encrypt(data, options[:armored])
37
+
38
+ $stdout.binmode
39
+ $stdout.puts encrypted_data
40
+
41
+ if encrypted_data != nil
42
+ $stderr.puts 'Encryption succeeded'
43
+ else
44
+ $stderr.puts 'Encryption failed!'
45
+ end
46
+
@@ -0,0 +1,76 @@
1
+ #!/usr/bin/env ruby
2
+ require 'optparse'
3
+ require 'io/console'
4
+
5
+ require_relative '../../lib/rnp'
6
+
7
+ options = {armored: false, keys_armored: false}
8
+ parser = OptionParser.new do |opts|
9
+ opts.banner = "Usage: #{$0} [options] <pubkey> <seckey> <input-file> <output-file>"
10
+ opts.on('-k', '--keys-armored', 'Keys are ASCII armored') do
11
+ options[:keys_armored] = true
12
+ end
13
+ opts.on('-a', '--armored', 'Input file is ASCII armored') do
14
+ options[:armored] = true
15
+ end
16
+ opts.on('-h', '--help', 'Print this help') do
17
+ puts opts
18
+ exit
19
+ end
20
+ end
21
+ parser.parse!
22
+
23
+ if ARGV.length != 4
24
+ parser.display
25
+ exit
26
+ end
27
+
28
+ pubkey_filename = ARGV.shift
29
+ seckey_filename = ARGV.shift
30
+ input_filename = ARGV.shift
31
+ output_filename = ARGV.shift
32
+
33
+ # Load pubkey/keyring
34
+ pubkeyring_mem = LibC::calloc(1, LibRNP::PGPKeyring.size)
35
+ pubkeyring = LibRNP::PGPKeyring.new(pubkeyring_mem)
36
+ if 1 != LibRNP::pgp_keyring_fileread(pubkeyring, options[:keys_armored] ? 1 : 0, pubkey_filename)
37
+ puts 'Errors encountered while loading public keyring.'
38
+ exit 1
39
+ end
40
+ # Load seckey/keyring
41
+ seckeyring_mem = LibC::calloc(1, LibRNP::PGPKeyring.size)
42
+ seckeyring = LibRNP::PGPKeyring.new(seckeyring_mem)
43
+ if 1 != LibRNP::pgp_keyring_fileread(seckeyring, options[:keys_armored] ? 1 : 0, seckey_filename)
44
+ puts 'Errors encountered while loading secret keyring.'
45
+ exit 1
46
+ end
47
+
48
+ pgpio = LibRNP::PGPIO.new
49
+ stdout_fp = LibC::fdopen($stdout.to_i, 'w')
50
+ stderr_fp = LibC::fdopen($stderr.to_i, 'w')
51
+ pgpio[:outs] = stdout_fp
52
+ pgpio[:errs] = stderr_fp
53
+ pgpio[:res] = stdout_fp
54
+
55
+ rd, wr = IO.pipe
56
+ print 'Enter passphrase: '
57
+ passphrase = $stdin.noecho(&:gets)
58
+ puts ''
59
+ wr.write passphrase
60
+ wr.close
61
+ passfp = LibC::fdopen(rd.to_i, 'r')
62
+
63
+ armored = options[:armored] ? 1 : 0
64
+ overwrite = 1
65
+ sshkeys = 0
66
+ numtries = 1
67
+
68
+ ret = LibRNP::pgp_decrypt_file(pgpio, input_filename, output_filename, seckeyring, pubkeyring, armored, overwrite, sshkeys, passfp, numtries, nil)
69
+ rd.close
70
+ LibC::fclose(passfp)
71
+ if ret == 1
72
+ puts 'Success'
73
+ else
74
+ puts 'Failed!'
75
+ end
76
+
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env ruby
2
+ require 'optparse'
3
+ require 'io/console'
4
+
5
+ require_relative '../../lib/rnp'
6
+
7
+ options = {armored: false, keys_armored: false}
8
+ parser = OptionParser.new do |opts|
9
+ opts.banner = "Usage: #{$0} [options] <pubkey> <seckey> <passphrase>"
10
+ opts.on('-k', '--keys-armored', 'Keys are ASCII armored') do
11
+ options[:keys_armored] = true
12
+ end
13
+ opts.on('-a', '--armored', 'Input is ASCII armored') do
14
+ options[:armored] = true
15
+ end
16
+ opts.on('-h', '--help', 'Print this help') do
17
+ puts opts
18
+ exit
19
+ end
20
+ end
21
+ parser.parse!
22
+
23
+ if ARGV.length != 3
24
+ parser.display
25
+ exit
26
+ end
27
+
28
+ pubkey_filename = ARGV.shift
29
+ seckey_filename = ARGV.shift
30
+ passphrase = ARGV.shift + "\n"
31
+
32
+ # Load pubkey/keyring
33
+ pubkeyring_mem = LibC::calloc(1, LibRNP::PGPKeyring.size)
34
+ pubkeyring = LibRNP::PGPKeyring.new(pubkeyring_mem)
35
+ if 1 != LibRNP::pgp_keyring_fileread(pubkeyring, options[:keys_armored] ? 1 : 0, pubkey_filename)
36
+ puts 'Errors encountered while loading public keyring.'
37
+ exit 1
38
+ end
39
+ # Load seckey/keyring
40
+ seckeyring_mem = LibC::calloc(1, LibRNP::PGPKeyring.size)
41
+ seckeyring = LibRNP::PGPKeyring.new(seckeyring_mem)
42
+ if 1 != LibRNP::pgp_keyring_fileread(seckeyring, options[:keys_armored] ? 1 : 0, seckey_filename)
43
+ puts 'Errors encountered while loading secret keyring.'
44
+ exit 1
45
+ end
46
+
47
+ pgpio = LibRNP::PGPIO.new
48
+ stderr_fp = LibC::fdopen($stderr.to_i, 'w')
49
+ # send all to stderr
50
+ pgpio[:outs] = stderr_fp
51
+ pgpio[:errs] = stderr_fp
52
+ pgpio[:res] = stderr_fp
53
+
54
+ rd, wr = IO.pipe
55
+ wr.write passphrase
56
+ wr.close
57
+ passfp = LibC::fdopen(rd.to_i, 'r')
58
+
59
+ armored = options[:armored] ? 1 : 0
60
+ sshkeys = 0
61
+ numtries = 1
62
+
63
+ $stdin.binmode
64
+ data = $stdin.read
65
+ data_buf = FFI::MemoryPointer.new(:uint8, data.bytesize)
66
+ data_buf.put_bytes(0, data)
67
+ memory_ptr = LibRNP::pgp_decrypt_buf(pgpio, data_buf, data_buf.size, seckeyring, pubkeyring, armored, sshkeys, passfp, numtries, nil)
68
+ rd.close
69
+ LibC::fclose(passfp)
70
+
71
+ memory = LibRNP::PGPMemory.new(memory_ptr)
72
+ if not memory.null?
73
+ $stdout.binmode
74
+ $stdout.puts memory[:buf].read_bytes(memory[:length])
75
+ LibRNP::pgp_memory_free(memory)
76
+ $stderr.puts 'Success'
77
+ else
78
+ $stderr.puts 'Failed!'
79
+ end
80
+
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env ruby
2
+ require 'optparse'
3
+
4
+ require_relative '../../lib/rnp'
5
+
6
+ options = {armored: false, keys_armored: false}
7
+ parser = OptionParser.new do |opts|
8
+ opts.banner = "Usage: #{$0} [options] <pubkey> <input-file> <output-file>"
9
+ opts.on('-k', '--keys-armored', 'Seckey is ASCII armored') do
10
+ options[:keys_armored] = true
11
+ end
12
+ opts.on('-a', '--armored', 'Output file will be ASCII armored') do
13
+ options[:armored] = true
14
+ end
15
+ opts.on('-h', '--help', 'Print this help') do
16
+ puts opts
17
+ exit
18
+ end
19
+ end
20
+ parser.parse!
21
+
22
+ if ARGV.length != 3
23
+ parser.display
24
+ exit
25
+ end
26
+
27
+ pubkey_filename = ARGV.shift
28
+ input_filename = ARGV.shift
29
+ output_filename = ARGV.shift
30
+
31
+ # Load keys/keyring
32
+ keyring_mem = LibC::calloc(1, LibRNP::PGPKeyring.size)
33
+ keyring = LibRNP::PGPKeyring.new(keyring_mem)
34
+ if 1 != LibRNP::pgp_keyring_fileread(keyring, options[:keys_armored] ? 1 : 0, pubkey_filename)
35
+ puts 'Errors encountered while loading keyring.'
36
+ exit 1
37
+ end
38
+ # Find first pubkey
39
+ keycount = LibRNP::dynarray_count(keyring, 'key')
40
+ pubkey = nil
41
+ (0..keycount - 1).each {|keyn|
42
+ key = LibRNP::dynarray_get_item(keyring, 'key', LibRNP::PGPKey, keyn)
43
+ pubkey = key if LibRNP::pgp_is_key_secret(key) == 0
44
+ break if pubkey != nil
45
+ }
46
+ if pubkey == nil
47
+ puts 'No pubkey found'
48
+ exit 1
49
+ end
50
+
51
+ pgpio = LibRNP::PGPIO.new
52
+ stdout_fp = LibC::fdopen($stdout.to_i, 'w')
53
+ stderr_fp = LibC::fdopen($stderr.to_i, 'w')
54
+ pgpio[:outs] = stdout_fp
55
+ pgpio[:errs] = stderr_fp
56
+ pgpio[:res] = stdout_fp
57
+
58
+ armored = options[:armored] ? 1 : 0
59
+ overwrite = 1
60
+ # see pgp_str_to_cipher
61
+ cipher = 'cast5'
62
+ ret = LibRNP::pgp_encrypt_file(pgpio, input_filename, output_filename, pubkey, armored, overwrite, cipher)
63
+ if ret == 1
64
+ puts 'Success'
65
+ else
66
+ puts 'Failed!'
67
+ end
68
+
@@ -0,0 +1,75 @@
1
+ #!/usr/bin/env ruby
2
+ require 'optparse'
3
+
4
+ require_relative '../../lib/rnp'
5
+
6
+ options = {armored: false, keys_armored: false}
7
+ parser = OptionParser.new do |opts|
8
+ opts.banner = "Usage: #{$0} [options] <pubkey>"
9
+ opts.on('-k', '--keys-armored', 'Seckey is ASCII armored') do
10
+ options[:keys_armored] = true
11
+ end
12
+ opts.on('-a', '--armored', 'Output will be ASCII armored') do
13
+ options[:armored] = true
14
+ end
15
+ opts.on('-h', '--help', 'Print this help') do
16
+ puts opts
17
+ exit
18
+ end
19
+ end
20
+ parser.parse!
21
+
22
+ if ARGV.length != 1
23
+ parser.display
24
+ exit
25
+ end
26
+
27
+ pubkey_filename = ARGV.shift
28
+
29
+ # Load keys/keyring
30
+ keyring_mem = LibC::calloc(1, LibRNP::PGPKeyring.size)
31
+ keyring = LibRNP::PGPKeyring.new(keyring_mem)
32
+ if 1 != LibRNP::pgp_keyring_fileread(keyring, options[:keys_armored] ? 1 : 0, pubkey_filename)
33
+ puts 'Errors encountered while loading keyring.'
34
+ exit 1
35
+ end
36
+ # Find first pubkey
37
+ keycount = LibRNP::dynarray_count(keyring, 'key')
38
+ pubkey = nil
39
+ (0..keycount - 1).each {|keyn|
40
+ key = LibRNP::dynarray_get_item(keyring, 'key', LibRNP::PGPKey, keyn)
41
+ pubkey = key if LibRNP::pgp_is_key_secret(key) == 0
42
+ break if pubkey != nil
43
+ }
44
+ if pubkey == nil
45
+ puts 'No pubkey found'
46
+ exit 1
47
+ end
48
+
49
+ pgpio = LibRNP::PGPIO.new
50
+ stdout_fp = LibC::fdopen($stdout.to_i, 'w')
51
+ stderr_fp = LibC::fdopen($stderr.to_i, 'w')
52
+ pgpio[:outs] = stdout_fp
53
+ pgpio[:errs] = stderr_fp
54
+ pgpio[:res] = stdout_fp
55
+
56
+ armored = options[:armored] ? 1 : 0
57
+ # see pgp_str_to_cipher
58
+ cipher = 'cast5'
59
+ $stdin.binmode
60
+ data = $stdin.read
61
+ data_buf = FFI::MemoryPointer.new(:uint8, data.bytesize)
62
+ data_buf.put_bytes(0, data)
63
+ memory_ptr = LibRNP::pgp_encrypt_buf(pgpio, data_buf, data_buf.size, pubkey, armored, cipher)
64
+
65
+ memory = LibRNP::PGPMemory.new(memory_ptr)
66
+ $stdout.binmode
67
+ $stdout.puts memory[:buf].read_bytes(memory[:length])
68
+ LibRNP::pgp_memory_free(memory)
69
+
70
+ if not memory.null?
71
+ $stderr.puts 'Success'
72
+ else
73
+ $stderr.puts 'Failed!'
74
+ end
75
+
@@ -0,0 +1,118 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative '../../lib/rnp'
3
+
4
+ def bignum_byte_count(bn)
5
+ bn.to_s(16).length / 2
6
+ end
7
+
8
+ class PublicKey
9
+ attr_accessor :version,
10
+ :creation_time,
11
+ :expiration_time,
12
+ :public_key_algorithm,
13
+ :mpi,
14
+ :userids
15
+
16
+ def initialize
17
+ @version = nil
18
+ @creation_time = nil
19
+ @expiration_time = nil
20
+ @public_key_algorithm = nil
21
+ @mpi = {}
22
+
23
+ @userids = []
24
+ end
25
+
26
+ def bitcount
27
+ case @public_key_algorithm
28
+ when :PGP_PKA_RSA, :PGP_PKA_RSA_ENCRYPT_ONLY, :PGP_PKA_RSA_SIGN_ONLY
29
+ return RNP::bignum_byte_count(@n) * 8
30
+ when :PGP_PKA_DSA
31
+ case RNP::bignum_byte_count(@q)
32
+ when 20
33
+ 1024
34
+ when 28
35
+ 2048
36
+ when 32
37
+ 3072
38
+ end
39
+ when :PGP_PKA_ELGAMAL
40
+ RNP::bignum_byte_count(@y) * 8
41
+ end
42
+ 0
43
+ end
44
+
45
+ end
46
+
47
+ PARSE_PUBLIC_KEY = Proc.new do |results, pkt, data|
48
+ case pkt[:tag]
49
+ when :PGP_PARSER_PTAG
50
+
51
+ when :PGP_PARSER_PACKET_END
52
+ when :PGP_PTAG_CT_PUBLIC_KEY, :PGP_PTAG_CT_PUBLIC_SUBKEY
53
+ pk = pkt[:u][:pubkey]
54
+ pubkey = PublicKey.new
55
+ case pk[:alg]
56
+ when :PGP_PKA_RSA, :PGP_PKA_RSA_ENCRYPT_ONLY, :PGP_PKA_RSA_SIGN_ONLY
57
+ rsa = pk[:key][:rsa]
58
+ pubkey.mpi[:n] = LibRNP::bn2hex(rsa[:n]).hex
59
+ pubkey.mpi[:e] = LibRNP::bn2hex(rsa[:e]).hex
60
+ when :PGP_PKA_DSA
61
+ dsa = pk[:key][:dsa]
62
+ pubkey.mpi[:p] = LibRNP::bn2hex(dsa[:p]).hex
63
+ pubkey.mpi[:q] = LibRNP::bn2hex(dsa[:q]).hex
64
+ pubkey.mpi[:g] = LibRNP::bn2hex(dsa[:g]).hex
65
+ pubkey.mpi[:y] = LibRNP::bn2hex(dsa[:y]).hex
66
+ when :PGP_PKA_ELGAMAL
67
+ elg = pk[:key][:elgamal]
68
+ pubkey.mpi[:p] = LibRNP::bn2hex(rsa[:p]).hex
69
+ pubkey.mpi[:g] = LibRNP::bn2hex(rsa[:g]).hex
70
+ pubkey.mpi[:y] = LibRNP::bn2hex(rsa[:y]).hex
71
+ else
72
+ next :PGP_RELEASE_MEMORY
73
+ end
74
+ pubkey.version = pk[:version]
75
+ pubkey.creation_time = Time.at(pk[:birthtime])
76
+ pubkey.public_key_algorithm = pk[:alg]
77
+ results.push(pubkey)
78
+ when :PGP_PTAG_SS_KEY_EXPIRY
79
+ pubkey = results.last
80
+ pubkey.expiration_time = Time.at(results.last.creation_time.to_i + pkt[:u][:ss_time])
81
+ when :PGP_PTAG_CT_USER_ID
82
+ pubkey = results.last
83
+ pubkey.userids.push(pkt[:u][:userid].force_encoding('utf-8'))
84
+ end
85
+ next :PGP_RELEASE_MEMORY
86
+ end
87
+
88
+ def load_pubkey(data, armored=false, print_errors=true)
89
+ stream_mem = LibC::calloc(1, LibRNP::PGPStream.size)
90
+ # This will free the above memory (PGPStream is a ManagedStruct)
91
+ stream = LibRNP::PGPStream.new(stream_mem)
92
+ stream[:readinfo][:accumulate] = 1
93
+ LibRNP::pgp_parse_options(stream, :PGP_PTAG_SS_ALL, :PGP_PARSE_PARSED)
94
+
95
+ # This memory will be GC'd
96
+ mem = FFI::MemoryPointer.new(:uint8, data.bytesize)
97
+ mem.put_bytes(0, data)
98
+
99
+ LibRNP::pgp_reader_set_memory(stream, mem, mem.size)
100
+ results = []
101
+ callback = PARSE_PUBLIC_KEY.curry[results]
102
+ LibRNP::pgp_set_callback(stream, callback, nil)
103
+ LibRNP::pgp_reader_push_dearmour(stream) if armored
104
+ LibRNP::pgp_parse(stream, print_errors ? 1 : 0)
105
+ LibRNP::pgp_reader_pop_dearmour(stream) if armored
106
+ results[0]
107
+ end
108
+
109
+ def usage
110
+ puts "Usage: #{$0} <file>"
111
+ exit 1
112
+ end
113
+
114
+ usage if ARGV.length != 1
115
+ armored = ARGV[0].downcase.end_with?('.asc')
116
+ pubkey = load_pubkey(File.binread(ARGV[0]), armored)
117
+ puts pubkey.inspect
118
+
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative '../../lib/rnp'
3
+
4
+ def usage
5
+ puts "Usage: #{$0} <file>"
6
+ exit 1
7
+ end
8
+
9
+ def print_pubkey(pubkey, indent=0)
10
+ puts "#{' ' * indent}Version: #{pubkey[:version]}"
11
+ puts "#{' ' * indent}Creation Time: #{Time.at(pubkey[:birthtime])}"
12
+ puts "#{' ' * indent}Algorithm: #{pubkey[:alg]}"
13
+ case pubkey[:alg]
14
+ when :PGP_PKA_RSA
15
+ n = LibRNP::bn2hex(pubkey[:key][:rsa][:n])
16
+ e = LibRNP::bn2hex(pubkey[:key][:rsa][:e])
17
+ puts "#{' ' * indent}n: 0x#{n}"
18
+ puts "#{' ' * indent}e: 0x#{e}"
19
+ end
20
+ end
21
+
22
+ def print_seckey(seckey, indent=0)
23
+ puts "#{' ' * (indent+2)}[Public Key]"
24
+ print_pubkey(seckey[:pubkey], indent + 2)
25
+ puts "#{' ' * indent}string-to-key usage: #{seckey[:s2k_usage]}"
26
+ puts "#{' ' * indent}string-to-key specifier: #{seckey[:s2k_specifier]}"
27
+ puts "#{' ' * indent}Symmetric algorithm: #{seckey[:alg]}"
28
+ puts "#{' ' * indent}Hash algorithm: #{seckey[:hash_alg]}"
29
+ end
30
+
31
+ usage if ARGV.length != 1
32
+ armored = ARGV[0].downcase.end_with?('.asc') ? 1 : 0
33
+
34
+ keyring_mem = LibC::calloc(1, LibRNP::PGPKeyring.size)
35
+ keyring = LibRNP::PGPKeyring.new(keyring_mem)
36
+ if 1 != LibRNP::pgp_keyring_fileread(keyring, armored, ARGV[0])
37
+ puts 'Failed to load keyring'
38
+ exit 1
39
+ end
40
+ keycount = LibRNP::dynarray_count(keyring, 'key')
41
+ puts "Loaded #{keycount} key(s)"
42
+
43
+ (0..keycount - 1).each {|keyn|
44
+ key = LibRNP::dynarray_get_item(keyring, 'key', LibRNP::PGPKey, keyn)
45
+ puts "[Key ##{keyn}]"
46
+ uidcount = LibRNP::dynarray_count(key, 'uid')
47
+ print "User ids: "
48
+ puts LibRNP::dynarray_get_item(key, 'uid', :string, 0)
49
+ (1..uidcount - 1).each {|uidn|
50
+ print ' '
51
+ puts LibRNP::dynarray_get_item(key, 'uid', :string, uidn)
52
+ }
53
+ puts "Subpackets: #{LibRNP::dynarray_count(key, 'packet')}"
54
+ puts "Subsigs: #{LibRNP::dynarray_count(key, 'subsig')}"
55
+ puts "Revocations: #{LibRNP::dynarray_count(key, 'revoke')}"
56
+ case key[:type]
57
+ when :PGP_PTAG_CT_PUBLIC_KEY
58
+ puts ' [Public Key]'
59
+ pubkey = key[:key][:pubkey]
60
+ print_pubkey(pubkey, 2)
61
+ when :PGP_PTAG_CT_SECRET_KEY
62
+ puts ' [Secret Key]'
63
+ seckey = key[:key][:seckey]
64
+ print_seckey(seckey, 2)
65
+ end
66
+ puts ''
67
+ }
68
+
@@ -0,0 +1,96 @@
1
+ #!/usr/bin/env ruby
2
+ require 'optparse'
3
+
4
+ require_relative '../../lib/rnp'
5
+
6
+ options = {armored: false}
7
+ parser = OptionParser.new do |opts|
8
+ opts.banner = "Usage: #{$0} [options]"
9
+ opts.on('-a', '--armored', 'Input file is ASCII armored') do
10
+ options[:armored] = true
11
+ end
12
+ opts.on('-h', '--help', 'Print this help') do
13
+ puts opts
14
+ exit
15
+ end
16
+ end
17
+
18
+ def print_pubkey(pubkey, indent=0)
19
+ puts "#{' ' * indent}Version: #{pubkey[:version]}"
20
+ puts "#{' ' * indent}Creation Time: #{Time.at(pubkey[:birthtime])}"
21
+ puts "#{' ' * indent}Algorithm: #{pubkey[:alg]}"
22
+ case pubkey[:alg]
23
+ when :PGP_PKA_RSA
24
+ n = LibRNP::bn2hex(pubkey[:key][:rsa][:n])
25
+ e = LibRNP::bn2hex(pubkey[:key][:rsa][:e])
26
+ puts "#{' ' * indent}n: 0x#{n}"
27
+ puts "#{' ' * indent}e: 0x#{e}"
28
+ end
29
+ end
30
+
31
+ def print_seckey(seckey, indent=0)
32
+ puts "#{' ' * (indent+2)}[Public Key]"
33
+ print_pubkey(seckey[:pubkey], indent + 2)
34
+ puts "#{' ' * indent}string-to-key usage: #{seckey[:s2k_usage]}"
35
+ puts "#{' ' * indent}string-to-key specifier: #{seckey[:s2k_specifier]}"
36
+ puts "#{' ' * indent}Symmetric algorithm: #{seckey[:alg]}"
37
+ puts "#{' ' * indent}Hash algorithm: #{seckey[:hash_alg]}"
38
+ end
39
+
40
+ parser.parse!
41
+ armored = options[:armored] ? 1 : 0
42
+
43
+ pgpio = LibRNP::PGPIO.new
44
+ stdout_fp = LibC::fdopen($stdout.to_i, 'w')
45
+ stderr_fp = LibC::fdopen($stderr.to_i, 'w')
46
+ pgpio[:outs] = stdout_fp
47
+ pgpio[:errs] = stderr_fp
48
+ pgpio[:res] = stdout_fp
49
+
50
+ mem_ptr = LibC::calloc(1, LibRNP::PGPMemory.size)
51
+ mem = LibRNP::PGPMemory.new(mem_ptr)
52
+
53
+ $stdin.binmode
54
+ data = $stdin.read
55
+ data_buf = FFI::MemoryPointer.new(:uint8, data.bytesize)
56
+ data_buf.put_bytes(0, data)
57
+ LibRNP::pgp_memory_add(mem, data_buf, data_buf.size)
58
+
59
+ keyring_mem = LibC::calloc(1, LibRNP::PGPKeyring.size)
60
+ keyring = LibRNP::PGPKeyring.new(keyring_mem)
61
+ if 1 != LibRNP::pgp_keyring_read_from_mem(pgpio, keyring, armored, mem)
62
+ puts 'Failed to load keyring'
63
+ exit 1
64
+ end
65
+ keycount = LibRNP::dynarray_count(keyring, 'key')
66
+ puts "Loaded #{keycount} key(s)"
67
+
68
+ (0..keycount - 1).each {|keyn|
69
+ key = LibRNP::dynarray_get_item(keyring, 'key', LibRNP::PGPKey, keyn)
70
+ puts "[Key ##{keyn}]"
71
+ uidcount = LibRNP::dynarray_count(key, 'uid')
72
+ print "User ids: "
73
+ puts LibRNP::dynarray_get_item(key, 'uid', :string, 0)
74
+ (1..uidcount - 1).each {|uidn|
75
+ print ' '
76
+ puts LibRNP::dynarray_get_item(key, 'uid', :string, uidn)
77
+ }
78
+ puts "Subpackets: #{LibRNP::dynarray_count(key, 'packet')}"
79
+ puts "Subsigs: #{LibRNP::dynarray_count(key, 'subsig')}"
80
+ puts "Revocations: #{LibRNP::dynarray_count(key, 'revoke')}"
81
+ printf "Key Flags: 0x%02X\n", key[:key_flags]
82
+ case key[:type]
83
+ when :PGP_PTAG_CT_PUBLIC_KEY
84
+ puts ' [Public Key]'
85
+ pubkey = key[:key][:pubkey]
86
+ print_pubkey(pubkey, 2)
87
+ when :PGP_PTAG_CT_SECRET_KEY
88
+ puts ' [Secret Key]'
89
+ seckey = key[:key][:seckey]
90
+ print_seckey(seckey, 2)
91
+ end
92
+ puts ''
93
+ }
94
+
95
+ LibRNP::pgp_memory_free(mem)
96
+