openpgp 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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.
@@ -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
@@ -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,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'
@@ -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
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: openpgp
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.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 +02: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).\n"
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
+ licenses:
49
+ - MIT
50
+ post_install_message:
51
+ rdoc_options: []
52
+
53
+ require_paths:
54
+ - lib
55
+ required_ruby_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: 1.8.2
60
+ version:
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: "0"
66
+ version:
67
+ requirements:
68
+ - GnuPG >= 1.4.7 (not required, but enables extra functionality)
69
+ rubyforge_project: openpgp
70
+ rubygems_version: 1.3.2
71
+ signing_key:
72
+ specification_version: 3
73
+ summary: A pure-Ruby implementation of the OpenPGP Message Format (RFC 4880).
74
+ test_files: []
75
+