bendiken-openpgp 0.0.1.1

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 ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2009 Arto Bendiken <http://ar.to/>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to
5
+ deal in the Software without restriction, including without limitation the
6
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7
+ sell copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19
+ IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,92 @@
1
+ = OpenPGP.rb
2
+
3
+ This is a pure-Ruby implementation of the OpenPGP Message Format (RFC 4880).
4
+
5
+
6
+ === About OpenPGP
7
+
8
+ OpenPGP is the most widely-used e-mail encryption standard in the world. It
9
+ is defined by the OpenPGP Working Group of the Internet Engineering Task
10
+ Force (IETF) Proposed Standard RFC 4880. The OpenPGP standard was originally
11
+ derived from PGP (Pretty Good Privacy), first created by Phil Zimmermann in
12
+ 1991.
13
+
14
+ * http://tools.ietf.org/html/rfc4880
15
+ * http://www.openpgp.org
16
+
17
+
18
+ == Features
19
+
20
+ * Encodes and decodes ASCII-armored OpenPGP messages.
21
+ * Parses OpenPGP messages into their constituent packets.
22
+ * Supports both old-format (PGP 2.6.x) and new-format (RFC 4880) packets.
23
+ * Includes a GnuPG wrapper for features that are not natively supported.
24
+
25
+
26
+ == Examples
27
+
28
+ require 'openpgp'
29
+
30
+
31
+ === Decoding an ASCII-armored message
32
+
33
+ require 'open-uri'
34
+ text = open('http://ar.to/pgp.txt').read
35
+
36
+ msg = OpenPGP::Message.parse(OpenPGP.dearmor(text))
37
+
38
+
39
+ === Generating a new keypair
40
+
41
+ gpg = OpenPGP::GnuPG.new(:homedir => '~/.gnupg')
42
+ key_id = gpg.gen_key({
43
+ :key_type => 'DSA',
44
+ :key_length => 1024,
45
+ :subkey_type => 'ELG-E',
46
+ :subkey_length => 1024,
47
+ :name => 'J. Random Hacker',
48
+ :comment => nil,
49
+ :email => 'jhacker@example.org',
50
+ :passphrase => 'secret passphrase',
51
+ })
52
+
53
+
54
+ == Documentation
55
+
56
+ * http://openpgp.rubyforge.org
57
+
58
+
59
+ == Download
60
+
61
+ To get a local working copy of the development repository, do:
62
+
63
+ % git clone git://github.com/bendiken/openpgp.git
64
+
65
+ Alternatively, you can download the latest development version as a tarball
66
+ as follows:
67
+
68
+ % wget http://github.com/bendiken/openpgp/tarball/master
69
+
70
+
71
+ == Installation
72
+
73
+ The recommended installation method is via RubyGems. To install the latest
74
+ official release from RubyForge, do:
75
+
76
+ % [sudo] gem install openpgp
77
+
78
+ To use the very latest bleeding-edge development version, install the gem
79
+ directly from GitHub as follows:
80
+
81
+ % [sudo] gem install bendiken-openpgp -s http://gems.github.com
82
+
83
+
84
+ == Authors
85
+
86
+ * Arto Bendiken (mailto:arto.bendiken@gmail.com) - http://ar.to
87
+
88
+
89
+ == License
90
+
91
+ All source code is available under the terms of the MIT license. For more
92
+ information, see the accompanying LICENSE file.
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ $:.unshift(File.expand_path(File.join(File.dirname(__FILE__), 'lib')))
3
+ require 'rubygems'
4
+ require 'rakefile' # http://github.com/bendiken/rakefile
5
+ require 'openpgp'
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1.1
data/bin/openpgp ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby -rubygems
2
+ $:.unshift(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')))
3
+ require 'openpgp'
@@ -0,0 +1,57 @@
1
+ module OpenPGP
2
+ module Algorithm
3
+ ##
4
+ # OpenPGP public-key algorithms.
5
+ #
6
+ # @see http://tools.ietf.org/html/rfc4880#section-9.1
7
+ module Asymmetric
8
+ RSA = 1
9
+ RSA_E = 2
10
+ RSA_S = 3
11
+ ELG_E = 16
12
+ DSA = 17
13
+ end
14
+
15
+ ##
16
+ # OpenPGP symmetric-key algorithms.
17
+ #
18
+ # @see http://tools.ietf.org/html/rfc4880#section-9.2
19
+ module Symmetric
20
+ NONE = 0
21
+ IDEA = 1
22
+ TRIPLEDES = 2
23
+ CAST5 = 3
24
+ BLOWFISH = 4
25
+ AES = 7
26
+ AES128 = 7
27
+ AES192 = 8
28
+ AES256 = 9
29
+ TWOFISH = 10
30
+ end
31
+
32
+ ##
33
+ # OpenPGP compression algorithms.
34
+ #
35
+ # @see http://tools.ietf.org/html/rfc4880#section-9.3
36
+ module Compression
37
+ NONE = 0
38
+ ZIP = 1
39
+ ZLIB = 2
40
+ BZIP2 = 3
41
+ end
42
+
43
+ ##
44
+ # OpenPGP hash algorithms.
45
+ #
46
+ # @see http://tools.ietf.org/html/rfc4880#section-9.4
47
+ module Hash
48
+ MD5 = 1
49
+ SHA1 = 2
50
+ RIPEMD160 = 3
51
+ SHA256 = 8
52
+ SHA384 = 9
53
+ SHA512 = 10
54
+ SHA224 = 11
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,114 @@
1
+ module OpenPGP
2
+ ##
3
+ # Alias for OpenPGP::Armor.encode().
4
+ def self.enarmor(data, marker = 'MESSAGE', headers = {})
5
+ Armor.encode(data, marker, headers)
6
+ end
7
+
8
+ ##
9
+ # Alias for OpenPGP::Armor.decode().
10
+ def self.dearmor(text, marker = nil)
11
+ Armor.decode(text, marker)
12
+ end
13
+
14
+ ##
15
+ # OpenPGP ASCII Armor utilities.
16
+ #
17
+ # @see http://tools.ietf.org/html/rfc4880#section-6.2
18
+ module Armor
19
+ ##
20
+ # @see http://tools.ietf.org/html/rfc4880#section-6.2
21
+ module Markers
22
+ MESSAGE = 'MESSAGE'
23
+ PUBLIC_KEY_BLOCK = 'PUBLIC KEY BLOCK'
24
+ PRIVATE_KEY_BLOCK = 'PRIVATE KEY BLOCK'
25
+ SIGNATURE = 'SIGNATURE'
26
+ end
27
+
28
+ ##
29
+ # @see http://tools.ietf.org/html/rfc4880#section-6.2
30
+ def self.header(marker)
31
+ "-----BEGIN PGP #{marker.to_s.upcase}-----"
32
+ end
33
+
34
+ ##
35
+ # @see http://tools.ietf.org/html/rfc4880#section-6.2
36
+ def self.footer(marker)
37
+ "-----END PGP #{marker.to_s.upcase}-----"
38
+ end
39
+
40
+ ##
41
+ # @see http://tools.ietf.org/html/rfc4880#section-6
42
+ # @see http://tools.ietf.org/html/rfc4880#section-6.2
43
+ # @see http://tools.ietf.org/html/rfc2045
44
+ def self.encode(data, marker = 'MESSAGE', headers = {})
45
+ require 'stringio'
46
+ require 'base64'
47
+
48
+ text = StringIO.new
49
+ text << self.header(marker) << "\n"
50
+ headers.each { |key, value| text << "#{key}: #{value}\n" }
51
+ text << "\n" << Base64.encode64(data)
52
+ text << "=" << Base64.encode64([self.crc24(data)].pack('N')[1, 3])
53
+ text << self.footer(marker) << "\n"
54
+ text.string
55
+ end
56
+
57
+ ##
58
+ # @see http://tools.ietf.org/html/rfc4880#section-6
59
+ # @see http://tools.ietf.org/html/rfc2045
60
+ def self.decode(text, marker = nil)
61
+ require 'stringio'
62
+ require 'base64'
63
+
64
+ data, crc, state = StringIO.new, nil, :begin
65
+ text.each_line do |line|
66
+ line.chomp!
67
+ case state
68
+ when :begin
69
+ case line
70
+ when /^-----BEGIN PGP ([^-]+)-----$/
71
+ state = :head if marker.nil? || marker.to_s.upcase == $1
72
+ end
73
+ when :head
74
+ state = :body if line =~ /^\s*$/
75
+ when :body
76
+ case line
77
+ when /^=(....)$/
78
+ crc = ("\0" << Base64.decode64($1)).unpack('N').first
79
+ state = :end
80
+ when /^-----END PGP ([^-]+)-----$/
81
+ state = :end
82
+ else
83
+ data << Base64.decode64(line)
84
+ end
85
+ when :end
86
+ break
87
+ end
88
+ end
89
+ data.string
90
+ end
91
+
92
+ ##
93
+ # @see http://tools.ietf.org/html/rfc4880#section-6.1
94
+ CRC24_INIT = 0x00b704ce
95
+ CRC24_POLY = 0x01864cfb
96
+
97
+ ##
98
+ # @see http://tools.ietf.org/html/rfc4880#section-6
99
+ # @see http://tools.ietf.org/html/rfc4880#section-6.1
100
+ def self.crc24(data)
101
+ crc = CRC24_INIT
102
+ data.each_byte do |octet|
103
+ crc ^= octet << 16
104
+ 8.times do
105
+ crc <<= 1
106
+ crc ^= CRC24_POLY if (crc & 0x01000000).nonzero?
107
+ end
108
+ end
109
+ crc &= 0x00ffffff
110
+ end
111
+ end
112
+
113
+ include Armor::Markers
114
+ end
@@ -0,0 +1,169 @@
1
+ module OpenPGP
2
+ ##
3
+ # GNU Privacy Guard (GnuPG) wrapper.
4
+ #
5
+ # @see http://www.gnupg.org/
6
+ class GnuPG
7
+ class Error < IOError; end
8
+
9
+ OPTIONS = {
10
+ :batch => true,
11
+ :quiet => true,
12
+ :no_verbose => true,
13
+ :no_tty => true,
14
+ :no_permission_warning => true,
15
+ :no_random_seed_file => true,
16
+ }
17
+
18
+ attr_accessor :where
19
+ attr_accessor :options
20
+
21
+ def initialize(options = {})
22
+ @where = '/usr/bin/env gpg' # FIXME
23
+ @options = OPTIONS.merge!(options)
24
+ end
25
+
26
+ ##
27
+ # Determines if GnuPG is available.
28
+ def available?
29
+ !!version
30
+ end
31
+
32
+ ##
33
+ # Returns the GnuPG version number.
34
+ def version
35
+ exec(:version).readline =~ /^gpg \(GnuPG\) (.*)$/ ? $1 : nil
36
+ end
37
+
38
+ ##
39
+ # Generates a new OpenPGP keypair and stores it GnuPG's keyring.
40
+ def gen_key(info = {})
41
+ stdin, stdout, stderr = exec3(:gen_key) do |stdin, stdout, stderr|
42
+ stdin.puts "Key-Type: #{info[:key_type]}" if info[:key_type]
43
+ stdin.puts "Key-Length: #{info[:key_length]}" if info[:key_length]
44
+ stdin.puts "Subkey-Type: #{info[:subkey_type]}" if info[:subkey_type]
45
+ stdin.puts "Subkey-Length: #{info[:subkey_length]}" if info[:subkey_length]
46
+ stdin.puts "Name-Real: #{info[:name]}" if info[:name]
47
+ stdin.puts "Name-Comment: #{info[:comment]}" if info[:comment]
48
+ stdin.puts "Name-Email: #{info[:email]}" if info[:email]
49
+ stdin.puts "Expire-Date: #{info[:expire_date]}" if info[:expire_date]
50
+ stdin.puts "Passphrase: #{info[:passphrase]}" if info[:passphrase]
51
+ stdin.puts "%commit"
52
+ end
53
+ stderr.each_line do |line|
54
+ if (line = line.chomp) =~ /^gpg: key ([0-9A-F]+) marked as ultimately trusted/
55
+ return $1.to_i(16) # the key ID
56
+ end
57
+ end
58
+ return nil
59
+ end
60
+
61
+ ##
62
+ # Exports a specified key from the GnuPG keyring.
63
+ def export(key_id = nil)
64
+ OpenPGP::Message.parse(exec([:export, *[key_id].flatten]).read)
65
+ end
66
+
67
+ ##
68
+ # Imports a specified keyfile into the GnuPG keyring.
69
+ def import()
70
+ # TODO
71
+ end
72
+
73
+ ##
74
+ # Returns an array of key IDs/titles of the keys in the public keyring.
75
+ def list_keys()
76
+ # TODO
77
+ end
78
+
79
+ ##
80
+ # Encrypts the given plaintext to the specified recipients.
81
+ def encrypt(plaintext, options = {})
82
+ # TODO
83
+ end
84
+
85
+ ##
86
+ # Decrypts the given ciphertext using the specified key ID.
87
+ def decrypt(ciphertext, options = {})
88
+ # TODO
89
+ end
90
+
91
+ ##
92
+ # Makes an OpenPGP signature.
93
+ def sign()
94
+ # TODO
95
+ end
96
+
97
+ ##
98
+ # Makes a clear text OpenPGP signature.
99
+ def clearsign()
100
+ # TODO
101
+ end
102
+
103
+ ##
104
+ # Makes a detached OpenPGP signature.
105
+ def detach_sign()
106
+ # TODO
107
+ end
108
+
109
+ ##
110
+ # Verifies an OpenPGP signature.
111
+ def verify()
112
+ # TODO
113
+ end
114
+
115
+ ##
116
+ # Executes a GnuPG command, yielding the standard input and returning
117
+ # the standard output.
118
+ def exec(command, options = {}, &block) #:yields: stdin
119
+ exec4(command, options) do |pid, stdin, stdout, stderr|
120
+ block.call(stdin) if block_given?
121
+ stdin.close_write
122
+ pid, status = Process.waitpid2(pid)
123
+ raise Error, stderr.read.chomp if status.exitstatus.nonzero?
124
+ stdout
125
+ end
126
+ end
127
+
128
+ ##
129
+ # Executes a GnuPG command, yielding and returning the standard input,
130
+ # output and error.
131
+ def exec3(command, options = {}, &block) #:yields: stdin, stdout, stderr
132
+ exec4(command, options) do |pid, stdin, stdout, stderr|
133
+ block.call(stdin, stdout, stderr) if block_given?
134
+ stdin.close_write
135
+ pid, status = Process.waitpid2(pid)
136
+ raise Error, stderr.read.chomp if status.exitstatus.nonzero?
137
+ [stdin, stdout, stderr]
138
+ end
139
+ end
140
+
141
+ ##
142
+ # Executes a GnuPG command, yielding the process identifier as well as
143
+ # the standard input, output and error.
144
+ def exec4(command, options = {}, &block) #:yields: pid, stdin, stdout, stderr
145
+ require 'rubygems'
146
+ require 'open4'
147
+ block.call(*Open4.popen4(cmdline(command, options)))
148
+ end
149
+
150
+ protected
151
+
152
+ ##
153
+ # Constructs the GnuPG command-line for use with +exec+.
154
+ def cmdline(command, options = {})
155
+ command = [command].flatten
156
+ cmdline = [where]
157
+ cmdline += @options.merge(options).map { |k, v| !v ? nil : "#{option(k)} #{v == true ? '' : v.to_s}".rstrip }.compact
158
+ cmdline << option(command.shift)
159
+ cmdline += command
160
+ cmdline.flatten.join(' ').strip
161
+ end
162
+
163
+ ##
164
+ # Translates Ruby symbols into GnuPG option arguments.
165
+ def option(option)
166
+ "--" << option.to_s.gsub('_', '-')
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,55 @@
1
+ module OpenPGP
2
+ ##
3
+ # OpenPGP message.
4
+ #
5
+ # @see http://tools.ietf.org/html/rfc4880#section-4.1
6
+ # @see http://tools.ietf.org/html/rfc4880#section-11
7
+ # @see http://tools.ietf.org/html/rfc4880#section-11.3
8
+ class Message
9
+ attr_accessor :packets
10
+
11
+ ##
12
+ # Parses an OpenPGP message.
13
+ #
14
+ # @see http://tools.ietf.org/html/rfc4880#section-4.1
15
+ # @see http://tools.ietf.org/html/rfc4880#section-4.2
16
+ def self.parse(data)
17
+ require 'stringio'
18
+ data = StringIO.new(data.to_str) if data.respond_to?(:to_str)
19
+
20
+ msg = self.new
21
+ until data.eof?
22
+ if packet = OpenPGP::Packet.parse(data)
23
+ msg << packet
24
+ else
25
+ raise "Invalid OpenPGP message data at position #{data.pos}"
26
+ end
27
+ end
28
+ msg
29
+ end
30
+
31
+ def initialize(packets = [])
32
+ @packets = packets
33
+ end
34
+
35
+ def each(&block) # :yields: packet
36
+ packets.each(&block)
37
+ end
38
+
39
+ def to_a
40
+ packets.to_a
41
+ end
42
+
43
+ def <<(packet)
44
+ packets << packet
45
+ end
46
+
47
+ def empty?
48
+ packets.empty?
49
+ end
50
+
51
+ def size
52
+ inject(0) { |sum, packet| sum + packet.size }
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,294 @@
1
+ module OpenPGP
2
+ ##
3
+ # OpenPGP packet.
4
+ #
5
+ # @see http://tools.ietf.org/html/rfc4880#section-4.1
6
+ # @see http://tools.ietf.org/html/rfc4880#section-4.3
7
+ class Packet
8
+ attr_accessor :tag
9
+ attr_accessor :size
10
+ attr_accessor :data
11
+
12
+ ##
13
+ # Parses an OpenPGP packet.
14
+ #
15
+ # @see http://tools.ietf.org/html/rfc4880#section-4.2
16
+ def self.parse(data)
17
+ require 'stringio'
18
+ data = StringIO.new(data.to_str) if data.respond_to?(:to_str)
19
+
20
+ unless data.eof?
21
+ new = ((tag = data.getc) & 64).nonzero? # bit 6 indicates new packet format if set
22
+ data.ungetc(tag)
23
+ send(new ? :parse_new_format : :parse_old_format, data)
24
+ end
25
+ end
26
+
27
+ ##
28
+ # Parses a new-format (RFC 4880) OpenPGP packet.
29
+ #
30
+ # @see http://tools.ietf.org/html/rfc4880#section-4.2.2
31
+ def self.parse_new_format(data)
32
+ tag = data.getc & 63
33
+ len = data.getc
34
+
35
+ case len
36
+ when 0..191 # 4.2.2.1. One-Octet Lengths
37
+ data_length = len
38
+ when 192..223 # 4.2.2.2. Two-Octet Lengths
39
+ data_length = ((len - 192) << 8) + data.getc + 192
40
+ when 224..254 # 4.2.2.4. Partial Body Lengths
41
+ data_length = 1 << (len & 0x1f)
42
+ when 255 # 4.2.2.3. Five-Octet Lengths
43
+ data_length = (data.getc << 24) | (data.getc << 16) | (data.getc << 8) | data.getc
44
+ end
45
+
46
+ Packet.for(tag).new(tag, data.read(data_length))
47
+ end
48
+
49
+ ##
50
+ # Parses an old-format (PGP 2.6.x) OpenPGP packet.
51
+ #
52
+ # @see http://tools.ietf.org/html/rfc4880#section-4.2.1
53
+ def self.parse_old_format(data)
54
+ len = (tag = data.getc) & 3
55
+ tag = (tag >> 2) & 15
56
+
57
+ case len
58
+ when 0 # The packet has a one-octet length. The header is 2 octets long.
59
+ data_length = data.getc
60
+ when 1 # The packet has a two-octet length. The header is 3 octets long.
61
+ data_length = data.read(2).unpack('n').first
62
+ when 2 # The packet has a four-octet length. The header is 5 octets long.
63
+ data_length = data.read(4).unpack('N').first
64
+ when 3 # The packet is of indeterminate length. The header is 1 octet long.
65
+ data_length = false # read to EOF
66
+ else
67
+ raise "Invalid OpenPGP packet length-type: expected 0..3 but got #{len}"
68
+ end
69
+
70
+ Packet.for(tag).new(tag, data_length ? data.read(data_length) : data.read)
71
+ end
72
+
73
+ def self.for(tag)
74
+ @@tags[tag.to_i] || self
75
+ end
76
+
77
+ def initialize(tag = nil, data = nil)
78
+ @tag, @data, @size = tag, data, data ? data.size : 0
79
+ end
80
+
81
+ ##
82
+ # OpenPGP Public-Key Encrypted Session Key packet (tag 1).
83
+ #
84
+ # @see http://tools.ietf.org/html/rfc4880#section-5.1
85
+ class AsymmetricSessionKey < Packet
86
+ # TODO
87
+ end
88
+
89
+ ##
90
+ # OpenPGP Signature packet (tag 2).
91
+ #
92
+ # @see http://tools.ietf.org/html/rfc4880#section-5.2
93
+ class Signature < Packet
94
+ # TODO
95
+ end
96
+
97
+ ##
98
+ # OpenPGP Symmetric-Key Encrypted Session Key packet (tag 3).
99
+ #
100
+ # @see http://tools.ietf.org/html/rfc4880#section-5.3
101
+ class SymmetricSessionKey < Packet
102
+ # TODO
103
+ end
104
+
105
+ ##
106
+ # OpenPGP One-Pass Signature packet (tag 4).
107
+ #
108
+ # @see http://tools.ietf.org/html/rfc4880#section-5.4
109
+ class OnePassSignature < Packet
110
+ # TODO
111
+ end
112
+
113
+ ##
114
+ # OpenPGP Public-Key packet (tag 6).
115
+ #
116
+ # @see http://tools.ietf.org/html/rfc4880#section-5.5.1.1
117
+ # @see http://tools.ietf.org/html/rfc4880#section-5.5.2
118
+ # @see http://tools.ietf.org/html/rfc4880#section-11.1
119
+ # @see http://tools.ietf.org/html/rfc4880#section-12
120
+ class PublicKey < Packet
121
+ # TODO
122
+ end
123
+
124
+ ##
125
+ # OpenPGP Public-Subkey packet (tag 14).
126
+ #
127
+ # @see http://tools.ietf.org/html/rfc4880#section-5.5.1.2
128
+ # @see http://tools.ietf.org/html/rfc4880#section-5.5.2
129
+ # @see http://tools.ietf.org/html/rfc4880#section-11.1
130
+ # @see http://tools.ietf.org/html/rfc4880#section-12
131
+ class PublicSubkey < PublicKey
132
+ # TODO
133
+ end
134
+
135
+ ##
136
+ # OpenPGP Secret-Key packet (tag 5).
137
+ #
138
+ # @see http://tools.ietf.org/html/rfc4880#section-5.5.1.3
139
+ # @see http://tools.ietf.org/html/rfc4880#section-5.5.3
140
+ # @see http://tools.ietf.org/html/rfc4880#section-11.2
141
+ # @see http://tools.ietf.org/html/rfc4880#section-12
142
+ class SecretKey < PublicKey
143
+ # TODO
144
+ end
145
+
146
+ ##
147
+ # OpenPGP Secret-Subkey packet (tag 7).
148
+ #
149
+ # @see http://tools.ietf.org/html/rfc4880#section-5.5.1.4
150
+ # @see http://tools.ietf.org/html/rfc4880#section-5.5.3
151
+ # @see http://tools.ietf.org/html/rfc4880#section-11.2
152
+ # @see http://tools.ietf.org/html/rfc4880#section-12
153
+ class SecretSubkey < SecretKey
154
+ # TODO
155
+ end
156
+
157
+ ##
158
+ # OpenPGP Compressed Data packet (tag 8).
159
+ #
160
+ # @see http://tools.ietf.org/html/rfc4880#section-5.6
161
+ class CompressedData < Packet
162
+ # TODO
163
+ end
164
+
165
+ ##
166
+ # OpenPGP Symmetrically Encrypted Data packet (tag 9).
167
+ #
168
+ # @see http://tools.ietf.org/html/rfc4880#section-5.7
169
+ class EncryptedData < Packet
170
+ # TODO
171
+ end
172
+
173
+ ##
174
+ # OpenPGP Marker packet (tag 10).
175
+ #
176
+ # @see http://tools.ietf.org/html/rfc4880#section-5.8
177
+ class Marker < Packet
178
+ # TODO
179
+ end
180
+
181
+ ##
182
+ # OpenPGP Literal Data packet (tag 11).
183
+ #
184
+ # @see http://tools.ietf.org/html/rfc4880#section-5.9
185
+ class LiteralData < Packet
186
+ # TODO
187
+ end
188
+
189
+ ##
190
+ # OpenPGP Trust packet (tag 12).
191
+ #
192
+ # @see http://tools.ietf.org/html/rfc4880#section-5.10
193
+ class Trust < Packet
194
+ # TODO
195
+ end
196
+
197
+ ##
198
+ # OpenPGP User ID packet (tag 13).
199
+ #
200
+ # @see http://tools.ietf.org/html/rfc4880#section-5.11
201
+ # @see http://tools.ietf.org/html/rfc2822
202
+ class UserID < Packet
203
+ attr_accessor :name, :comment, :email
204
+
205
+ def initialize(tag = nil, data = nil)
206
+ super
207
+ case data
208
+ # User IDs of the form: "name (comment) <email>"
209
+ when /^([^\(]+)\(([^\)]+)\)\s+<([^>]+)>$/
210
+ @name, @comment, @email = $1, $2, $3
211
+ # User IDs of the form: "name <email>"
212
+ when /^([^<]+)\s+<([^>]+)>$/
213
+ @name, @comment, @email = $1, nil, $2
214
+ # User IDs of the form: "name"
215
+ when /^([^<]+)$/
216
+ @name, @comment, @email = $1, nil, nil
217
+ # User IDs of the form: "<email>"
218
+ when /^<([^>]+)>$/
219
+ @name, @comment, @email = nil, nil, $2
220
+ else
221
+ @name, @comment, @email = nil
222
+ end
223
+ end
224
+
225
+ def to_s
226
+ text = []
227
+ text << name if name
228
+ text << "(#{comment})" if comment
229
+ text << "<#{email}>" if email
230
+ text.join(' ')
231
+ end
232
+ end
233
+
234
+ ##
235
+ # OpenPGP User Attribute packet (tag 17).
236
+ #
237
+ # @see http://tools.ietf.org/html/rfc4880#section-5.12
238
+ # @see http://tools.ietf.org/html/rfc4880#section-11.1
239
+ class UserAttribute < Packet
240
+ attr_accessor :packets
241
+
242
+ # TODO
243
+ end
244
+
245
+ ##
246
+ # OpenPGP Sym. Encrypted Integrity Protected Data packet (tag 18).
247
+ #
248
+ # @see http://tools.ietf.org/html/rfc4880#section-5.13
249
+ class IntegrityProtectedData < Packet
250
+ # TODO
251
+ end
252
+
253
+ ##
254
+ # OpenPGP Modification Detection Code packet (tag 19).
255
+ #
256
+ # @see http://tools.ietf.org/html/rfc4880#section-5.14
257
+ class ModificationDetectionCode < Packet
258
+ # TODO
259
+ end
260
+
261
+ ##
262
+ # OpenPGP Private or Experimental packet (tags 60..63).
263
+ #
264
+ # @see http://tools.ietf.org/html/rfc4880#section-4.3
265
+ class Experimental < Packet; end
266
+
267
+ protected
268
+ ##
269
+ # @see http://tools.ietf.org/html/rfc4880#section-4.3
270
+ @@tags = {
271
+ 1 => AsymmetricSessionKey, # Public-Key Encrypted Session Key
272
+ 2 => Signature, # Signature Packet
273
+ 3 => SymmetricSessionKey, # Symmetric-Key Encrypted Session Key Packet
274
+ 4 => OnePassSignature, # One-Pass Signature Packet
275
+ 5 => SecretKey, # Secret-Key Packet
276
+ 6 => PublicKey, # Public-Key Packet
277
+ 7 => SecretSubkey, # Secret-Subkey Packet
278
+ 8 => CompressedData, # Compressed Data Packet
279
+ 9 => EncryptedData, # Symmetrically Encrypted Data Packet
280
+ 10 => Marker, # Marker Packet
281
+ 11 => LiteralData, # Literal Data Packet
282
+ 12 => Trust, # Trust Packet
283
+ 13 => UserID, # User ID Packet
284
+ 14 => PublicSubkey, # Public-Subkey Packet
285
+ 17 => UserAttribute, # User Attribute Packet
286
+ 18 => IntegrityProtectedData, # Sym. Encrypted and Integrity Protected Data Packet
287
+ 19 => ModificationDetectionCode, # Modification Detection Code Packet
288
+ 60 => Experimental, # Private or Experimental Values
289
+ 61 => Experimental, # Private or Experimental Values
290
+ 62 => Experimental, # Private or Experimental Values
291
+ 63 => Experimental, # Private or Experimental Values
292
+ }
293
+ end
294
+ end
@@ -0,0 +1,11 @@
1
+ module OpenPGP
2
+ module Version
3
+ MAJOR = 0
4
+ MINOR = 0
5
+ TINY = 1
6
+ EXTRA = nil
7
+
8
+ STRING = [MAJOR, MINOR, TINY].join('.')
9
+ STRING << "-#{EXTRA}" if EXTRA
10
+ end
11
+ end
data/lib/openpgp.rb ADDED
@@ -0,0 +1,6 @@
1
+ require 'openpgp/version'
2
+ require 'openpgp/armor'
3
+ require 'openpgp/message'
4
+ require 'openpgp/packet'
5
+ require 'openpgp/algorithm'
6
+ require 'openpgp/gnupg'
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bendiken-openpgp
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Arto Bendiken
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-04-18 00:00:00 -07:00
13
+ default_executable: openpgp
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rakefile
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ description: OpenPGP.rb is a pure-Ruby implementation of the OpenPGP Message Format (RFC 4880).
26
+ email: arto.bendiken@gmail.com
27
+ executables:
28
+ - openpgp
29
+ extensions: []
30
+
31
+ extra_rdoc_files: []
32
+
33
+ files:
34
+ - LICENSE
35
+ - README
36
+ - Rakefile
37
+ - VERSION
38
+ - bin/openpgp
39
+ - lib/openpgp.rb
40
+ - lib/openpgp/algorithm.rb
41
+ - lib/openpgp/armor.rb
42
+ - lib/openpgp/gnupg.rb
43
+ - lib/openpgp/message.rb
44
+ - lib/openpgp/packet.rb
45
+ - lib/openpgp/version.rb
46
+ has_rdoc: false
47
+ homepage: http://github.com/bendiken/openpgp
48
+ post_install_message:
49
+ rdoc_options: []
50
+
51
+ require_paths:
52
+ - lib
53
+ required_ruby_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: 1.8.2
58
+ version:
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: "0"
64
+ version:
65
+ requirements:
66
+ - GnuPG >= 1.4.7 (not required, but enables extra functionality)
67
+ rubyforge_project: openpgp
68
+ rubygems_version: 1.2.0
69
+ signing_key:
70
+ specification_version: 2
71
+ summary: A pure-Ruby implementation of the OpenPGP Message Format (RFC 4880).
72
+ test_files: []
73
+