openpgp 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +1 -2
- data/CONTRIBUTORS +1 -0
- data/README +45 -13
- data/VERSION +1 -1
- data/lib/openpgp.rb +17 -3
- data/lib/openpgp/algorithm.rb +1 -0
- data/lib/openpgp/armor.rb +37 -9
- data/lib/openpgp/buffer.rb +57 -8
- data/lib/openpgp/cipher.rb +34 -3
- data/lib/openpgp/client/gnupg.rb +230 -20
- data/lib/openpgp/digest.rb +19 -0
- data/lib/openpgp/digest/md5.rb +1 -0
- data/lib/openpgp/digest/rmd160.rb +1 -0
- data/lib/openpgp/digest/sha1.rb +1 -0
- data/lib/openpgp/digest/sha2.rb +4 -0
- data/lib/openpgp/engine.rb +17 -0
- data/lib/openpgp/engine/gnupg.rb +58 -1
- data/lib/openpgp/engine/openssl.rb +13 -1
- data/lib/openpgp/message.rb +32 -2
- data/lib/openpgp/packet.rb +31 -11
- data/lib/openpgp/random.rb +14 -2
- data/lib/openpgp/s2k.rb +70 -2
- data/lib/openpgp/util.rb +14 -10
- data/lib/openpgp/version.rb +12 -4
- metadata +50 -20
- data/Rakefile +0 -5
data/AUTHORS
CHANGED
@@ -1,2 +1 @@
|
|
1
|
-
* Arto Bendiken <arto.bendiken@gmail.com>
|
2
|
-
* Kévin Lacointe <kevinlacointe@gmail.com> (Some GnuPG patches)
|
1
|
+
* Arto Bendiken <arto.bendiken@gmail.com>
|
data/CONTRIBUTORS
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
* Kévin Lacointe <kevinlacointe@gmail.com> (Some GnuPG patches)
|
data/README
CHANGED
@@ -3,7 +3,6 @@ OpenPGP.rb: OpenPGP for Ruby
|
|
3
3
|
|
4
4
|
This is a pure-Ruby implementation of the OpenPGP Message Format (RFC 4880).
|
5
5
|
|
6
|
-
* <http://openpgp.rubyforge.org/>
|
7
6
|
* <http://github.com/bendiken/openpgp>
|
8
7
|
|
9
8
|
### About OpenPGP
|
@@ -28,12 +27,13 @@ Features
|
|
28
27
|
Examples
|
29
28
|
--------
|
30
29
|
|
30
|
+
require 'rubygems'
|
31
31
|
require 'openpgp'
|
32
32
|
|
33
33
|
### Decoding an ASCII-armored message
|
34
34
|
|
35
35
|
require 'open-uri'
|
36
|
-
text = open('http://
|
36
|
+
text = open('http://openpgp.rubyforge.org/pgp.txt').read
|
37
37
|
|
38
38
|
msg = OpenPGP::Message.parse(OpenPGP.dearmor(text))
|
39
39
|
|
@@ -56,6 +56,21 @@ Documentation
|
|
56
56
|
|
57
57
|
* <http://openpgp.rubyforge.org/>
|
58
58
|
|
59
|
+
Dependencies
|
60
|
+
------------
|
61
|
+
|
62
|
+
* [Ruby](http://ruby-lang.org/) (>= 1.8.7) or (>= 1.8.1 with [Backports][])
|
63
|
+
* [Open4](http://rubygems.org/gems/open4) (>= 1.0.1)
|
64
|
+
|
65
|
+
Installation
|
66
|
+
------------
|
67
|
+
|
68
|
+
The recommended installation method is via [RubyGems](http://rubygems.org/).
|
69
|
+
To install the latest official release of OpenPGP.rb, do:
|
70
|
+
|
71
|
+
% [sudo] gem install openpgp # Ruby 1.8.7+ or 1.9.x
|
72
|
+
% [sudo] gem install backports openpgp # Ruby 1.8.1+
|
73
|
+
|
59
74
|
Download
|
60
75
|
--------
|
61
76
|
|
@@ -68,21 +83,13 @@ as follows:
|
|
68
83
|
|
69
84
|
% wget http://github.com/bendiken/openpgp/tarball/master
|
70
85
|
|
71
|
-
Installation
|
72
|
-
------------
|
73
|
-
|
74
|
-
The recommended installation method is via RubyGems. To install the latest
|
75
|
-
official release from Gemcutter, do:
|
76
|
-
|
77
|
-
% [sudo] gem install openpgp
|
78
|
-
|
79
86
|
Resources
|
80
87
|
---------
|
81
88
|
|
82
89
|
* <http://openpgp.rubyforge.org/>
|
83
90
|
* <http://github.com/bendiken/openpgp>
|
84
|
-
* <http://
|
85
|
-
* <http://rubyforge.org/projects/openpgp
|
91
|
+
* <http://rubygems.org/gems/openpgp>
|
92
|
+
* <http://rubyforge.org/projects/openpgp/>
|
86
93
|
* <http://raa.ruby-lang.org/project/openpgp/>
|
87
94
|
* <http://www.ohloh.net/p/openpgp>
|
88
95
|
|
@@ -90,10 +97,35 @@ Authors
|
|
90
97
|
-------
|
91
98
|
|
92
99
|
* [Arto Bendiken](mailto:arto.bendiken@gmail.com) - <http://ar.to/>
|
93
|
-
|
100
|
+
|
101
|
+
Contributors
|
102
|
+
------------
|
103
|
+
|
104
|
+
* [Kévin Lacointe](mailto:kevinlacointe@gmail.com) - <http://github.com/klacointe>
|
105
|
+
|
106
|
+
Contributing
|
107
|
+
------------
|
108
|
+
|
109
|
+
* Do your best to adhere to the existing coding conventions and idioms.
|
110
|
+
* Don't use hard tabs, and don't leave trailing whitespace on any line.
|
111
|
+
* Do document every method you add using [YARD][] annotations. Read the
|
112
|
+
[tutorial][YARD-GS] or just look at the existing code for examples.
|
113
|
+
* Don't touch the `.gemspec` or `VERSION` files. If you need to change them,
|
114
|
+
do so on your private branch only.
|
115
|
+
* Do feel free to add yourself to the `CONTRIBUTORS` file and the
|
116
|
+
corresponding list in the the `README`. Alphabetical order applies.
|
117
|
+
* Don't touch the `AUTHORS` file. If your contributions are significant
|
118
|
+
enough, be assured we will eventually add you in there.
|
119
|
+
* Do note that in order for us to merge any non-trivial changes (as a rule
|
120
|
+
of thumb, additions larger than about 15 lines of code), we need an
|
121
|
+
explicit [public domain dedication][PDD] on record from you.
|
94
122
|
|
95
123
|
License
|
96
124
|
-------
|
97
125
|
|
98
126
|
OpenPGP.rb is free and unencumbered public domain software. For more
|
99
127
|
information, see <http://unlicense.org/> or the accompanying UNLICENSE file.
|
128
|
+
|
129
|
+
[YARD]: http://yardoc.org/
|
130
|
+
[YARD-GS]: http://yardoc.org/docs/yard/file:docs/GettingStarted.md
|
131
|
+
[PDD]: http://unlicense.org/#unlicensing-contributions
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.3
|
data/lib/openpgp.rb
CHANGED
@@ -1,17 +1,31 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
if RUBY_VERSION < '1.8.7'
|
2
|
+
# @see http://rubygems.org/gems/backports
|
3
|
+
begin
|
4
|
+
require 'backports/1.8.7'
|
5
|
+
rescue LoadError
|
6
|
+
begin
|
7
|
+
require 'rubygems'
|
8
|
+
require 'backports/1.8.7'
|
9
|
+
rescue LoadError
|
10
|
+
abort "OpenPGP.rb requires Ruby 1.8.7 or the Backports gem (hint: `gem install backports')."
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
3
14
|
|
4
15
|
module OpenPGP
|
16
|
+
require 'openpgp/util'
|
17
|
+
|
5
18
|
autoload :Algorithm, 'openpgp/algorithm'
|
6
19
|
autoload :Armor, 'openpgp/armor'
|
7
20
|
autoload :Buffer, 'openpgp/buffer'
|
8
21
|
autoload :Cipher, 'openpgp/cipher'
|
9
|
-
autoload :Engine, 'openpgp/engine'
|
10
22
|
autoload :Digest, 'openpgp/digest'
|
23
|
+
autoload :Engine, 'openpgp/engine'
|
11
24
|
autoload :Message, 'openpgp/message'
|
12
25
|
autoload :Packet, 'openpgp/packet'
|
13
26
|
autoload :Random, 'openpgp/random'
|
14
27
|
autoload :S2K, 'openpgp/s2k'
|
28
|
+
autoload :VERSION, 'openpgp/version'
|
15
29
|
end
|
16
30
|
|
17
31
|
OpenPGP::Engine::OpenSSL.install!
|
data/lib/openpgp/algorithm.rb
CHANGED
data/lib/openpgp/armor.rb
CHANGED
@@ -14,27 +14,42 @@ module OpenPGP
|
|
14
14
|
ARMORED_FILE = 'ARMORED FILE' # a GnuPG extension
|
15
15
|
end
|
16
16
|
|
17
|
+
##
|
18
|
+
# @param [String, #to_s] marker
|
19
|
+
# @return [String]
|
17
20
|
def self.marker(marker)
|
18
21
|
marker = Markers.const_get(marker.to_s.upcase.to_sym) if marker.is_a?(Symbol)
|
19
22
|
marker.to_s.upcase
|
20
23
|
end
|
21
24
|
|
22
25
|
##
|
23
|
-
# @
|
26
|
+
# @param [String, #to_s] marker
|
27
|
+
# @return [String]
|
28
|
+
# @see http://tools.ietf.org/html/rfc4880#section-6.2
|
24
29
|
def self.header(marker)
|
25
30
|
"-----BEGIN PGP #{marker(marker)}-----"
|
26
31
|
end
|
27
32
|
|
28
33
|
##
|
29
|
-
# @
|
34
|
+
# @param [String, #to_s] marker
|
35
|
+
# @return [String]
|
36
|
+
# @see http://tools.ietf.org/html/rfc4880#section-6.2
|
30
37
|
def self.footer(marker)
|
31
38
|
"-----END PGP #{marker(marker)}-----"
|
32
39
|
end
|
33
40
|
|
34
41
|
##
|
35
|
-
# @
|
36
|
-
# @
|
37
|
-
# @
|
42
|
+
# @param [String] data
|
43
|
+
# @param [String, #to_s] marker
|
44
|
+
# @param [Hash{Symbol => Object}] options
|
45
|
+
# @option options [String, #to_s] :version (nil)
|
46
|
+
# @option options [String, #to_s] :comment (nil)
|
47
|
+
# @option options [Hash] :headers (nil)
|
48
|
+
# @option options [Integer] :line_length (nil)
|
49
|
+
# @return [String]
|
50
|
+
# @see http://tools.ietf.org/html/rfc4880#section-6
|
51
|
+
# @see http://tools.ietf.org/html/rfc4880#section-6.2
|
52
|
+
# @see http://tools.ietf.org/html/rfc2045
|
38
53
|
def self.encode(data, marker = :message, options = {})
|
39
54
|
Buffer.write do |text|
|
40
55
|
text << self.header(marker) << "\n"
|
@@ -50,8 +65,13 @@ module OpenPGP
|
|
50
65
|
end
|
51
66
|
|
52
67
|
##
|
53
|
-
# @
|
54
|
-
# @
|
68
|
+
# @param [String] text
|
69
|
+
# @param [String, #to_s] marker
|
70
|
+
# @param [Hash{Symbol => Object}] options
|
71
|
+
# @option options [Boolean] :crc (false)
|
72
|
+
# @return [String]
|
73
|
+
# @see http://tools.ietf.org/html/rfc4880#section-6
|
74
|
+
# @see http://tools.ietf.org/html/rfc2045
|
55
75
|
def self.decode(text, marker = nil, options = {})
|
56
76
|
data, crc, state = Buffer.new, nil, :begin
|
57
77
|
|
@@ -87,13 +107,18 @@ module OpenPGP
|
|
87
107
|
data
|
88
108
|
end
|
89
109
|
|
110
|
+
##
|
90
111
|
class CRCError < IOError; end
|
91
112
|
|
92
113
|
protected
|
93
114
|
|
94
115
|
##
|
95
|
-
# Returns the Base64-encoded version of
|
116
|
+
# Returns the Base64-encoded version of `input`, with a configurable
|
96
117
|
# output line length.
|
118
|
+
#
|
119
|
+
# @param [String] input
|
120
|
+
# @param [Integer] line_length
|
121
|
+
# @return [String]
|
97
122
|
def self.encode64(input, line_length = nil)
|
98
123
|
if line_length.nil?
|
99
124
|
[input].pack('m')
|
@@ -110,7 +135,10 @@ module OpenPGP
|
|
110
135
|
end
|
111
136
|
|
112
137
|
##
|
113
|
-
# Returns the Base64-decoded version of
|
138
|
+
# Returns the Base64-decoded version of `input`.
|
139
|
+
#
|
140
|
+
# @param [String] input
|
141
|
+
# @return [String]
|
114
142
|
def self.decode64(input)
|
115
143
|
input.unpack('m').first
|
116
144
|
end
|
data/lib/openpgp/buffer.rb
CHANGED
@@ -3,22 +3,30 @@ require 'stringio'
|
|
3
3
|
module OpenPGP
|
4
4
|
##
|
5
5
|
class Buffer < StringIO
|
6
|
+
##
|
7
|
+
# @return [String]
|
6
8
|
def self.write(*args, &block)
|
7
9
|
buffer = self.new(*args, &block)
|
8
10
|
buffer.string
|
9
11
|
end
|
10
12
|
|
13
|
+
##
|
14
|
+
# @yield [buffer]
|
15
|
+
# @yieldparam [Buffer] buffer
|
11
16
|
def initialize(*args, &block)
|
12
17
|
super
|
13
18
|
block.call(self) if block_given?
|
14
19
|
end
|
15
20
|
|
16
21
|
##
|
22
|
+
# @return [String]
|
17
23
|
def read_string
|
18
24
|
read_bytes(length = read_byte)
|
19
25
|
end
|
20
26
|
|
21
27
|
##
|
28
|
+
# @param [String, #to_s] value
|
29
|
+
# @return [Buffer]
|
22
30
|
def write_string(value)
|
23
31
|
value = value.to_s
|
24
32
|
self << [value.size].pack('C')
|
@@ -26,19 +34,25 @@ module OpenPGP
|
|
26
34
|
end
|
27
35
|
|
28
36
|
##
|
29
|
-
# @
|
37
|
+
# @return [Integer]
|
38
|
+
# @see http://tools.ietf.org/html/rfc4880#section-3.5
|
30
39
|
def read_timestamp
|
31
40
|
read_unpacked(4, 'N')
|
32
41
|
end
|
33
42
|
|
34
43
|
##
|
35
|
-
# @
|
44
|
+
# @param [Integer, #to_i] value
|
45
|
+
# @return [Buffer]
|
46
|
+
# @see http://tools.ietf.org/html/rfc4880#section-3.5
|
36
47
|
def write_timestamp(value)
|
37
48
|
self << [value.to_i].pack('N')
|
38
49
|
end
|
39
50
|
|
40
51
|
##
|
41
|
-
# @
|
52
|
+
# @param [Integer] count
|
53
|
+
# @param [Integer] base
|
54
|
+
# @return [Integer]
|
55
|
+
# @see http://tools.ietf.org/html/rfc4880#section-3.1
|
42
56
|
def read_number(count, base = nil)
|
43
57
|
number, shift = 0, count * 8
|
44
58
|
read_bytes(count).each_byte do |octet|
|
@@ -48,13 +62,16 @@ module OpenPGP
|
|
48
62
|
end
|
49
63
|
|
50
64
|
##
|
51
|
-
# @
|
65
|
+
# @param [Integer] value
|
66
|
+
# @return [Buffer]
|
67
|
+
# @see http://tools.ietf.org/html/rfc4880#section-3.1
|
52
68
|
def write_number
|
53
69
|
# TODO
|
54
70
|
end
|
55
71
|
|
56
72
|
##
|
57
|
-
# @
|
73
|
+
# @return [String]
|
74
|
+
# @see http://tools.ietf.org/html/rfc4880#section-3.2
|
58
75
|
def read_mpi
|
59
76
|
length = read_unpacked(2, 'n') # length in bits
|
60
77
|
length = ((length + 7) / 8.0).floor # length in bytes
|
@@ -62,39 +79,71 @@ module OpenPGP
|
|
62
79
|
end
|
63
80
|
|
64
81
|
##
|
65
|
-
# @
|
82
|
+
# @param [String] value
|
83
|
+
# @return [Buffer]
|
84
|
+
# @see http://tools.ietf.org/html/rfc4880#section-3.2
|
66
85
|
def write_mpi
|
67
86
|
# TODO
|
68
87
|
end
|
69
88
|
|
70
89
|
##
|
71
|
-
# @
|
90
|
+
# @return [S2K]
|
91
|
+
# @see http://tools.ietf.org/html/rfc4880#section-3.7
|
72
92
|
def read_s2k() S2K.parse(self) end
|
73
93
|
|
94
|
+
##
|
95
|
+
# @param [S2K] s2k
|
96
|
+
# @return [Buffer]
|
74
97
|
def write_s2k(s2k) s2k.write(self) end
|
75
98
|
|
99
|
+
##
|
100
|
+
# @param [Integer] count
|
101
|
+
# @param [String] format
|
102
|
+
# @return [Integer]
|
76
103
|
def read_unpacked(count, format)
|
77
104
|
read_bytes(count).unpack(format).first
|
78
105
|
end
|
79
106
|
|
107
|
+
##
|
108
|
+
# @param [Integer] value
|
109
|
+
# @return [Buffer]
|
80
110
|
def write_unpacked
|
81
111
|
# TODO
|
82
112
|
end
|
83
113
|
|
114
|
+
##
|
115
|
+
# @param [Integer] count
|
116
|
+
# @return [String]
|
84
117
|
def read_bytes(count)
|
85
118
|
read(count)
|
86
119
|
end
|
87
120
|
|
121
|
+
##
|
122
|
+
# @param [String] value
|
123
|
+
# @return [Buffer]
|
88
124
|
def write_bytes(value)
|
89
125
|
self << value
|
90
126
|
end
|
91
127
|
|
128
|
+
##
|
129
|
+
# @return [String]
|
92
130
|
def read_byte
|
93
|
-
|
131
|
+
getbyte
|
94
132
|
end
|
95
133
|
|
134
|
+
##
|
135
|
+
# @param [#chr, #to_s] value
|
136
|
+
# @return [Buffer]
|
96
137
|
def write_byte(value)
|
97
138
|
self << (value.respond_to?(:chr) ? value : value.to_s[0]).chr
|
98
139
|
end
|
140
|
+
|
141
|
+
##
|
142
|
+
# @return [String]
|
143
|
+
def string
|
144
|
+
string = super
|
145
|
+
string.force_encoding(Encoding::ASCII_8BIT) if string.respond_to?(:force_encoding)
|
146
|
+
string
|
147
|
+
end
|
99
148
|
end
|
100
149
|
end
|
data/lib/openpgp/cipher.rb
CHANGED
@@ -16,7 +16,9 @@ module OpenPGP
|
|
16
16
|
DEFAULT = AES128
|
17
17
|
|
18
18
|
##
|
19
|
-
# @
|
19
|
+
# @param [Symbol, String, Integer] identifier
|
20
|
+
# @return [Class]
|
21
|
+
# @see http://tools.ietf.org/html/rfc4880#section-9.2
|
20
22
|
def self.for(identifier)
|
21
23
|
case identifier
|
22
24
|
when Symbol then const_get(identifier.to_s.upcase)
|
@@ -32,9 +34,18 @@ module OpenPGP
|
|
32
34
|
end
|
33
35
|
end
|
34
36
|
|
35
|
-
|
37
|
+
# @return [S2K]
|
38
|
+
attr_accessor :key
|
39
|
+
|
40
|
+
# @return [Hash]
|
41
|
+
attr_accessor :options
|
42
|
+
|
43
|
+
# @return [String]
|
36
44
|
attr_accessor :engine
|
37
45
|
|
46
|
+
##
|
47
|
+
# @param [S2K] key
|
48
|
+
# @param [Hash{Symbol => Object}] options
|
38
49
|
def initialize(key, options = {})
|
39
50
|
@key = case key
|
40
51
|
when S2K then key.to_key(key_size)
|
@@ -43,24 +54,36 @@ module OpenPGP
|
|
43
54
|
@options = options
|
44
55
|
end
|
45
56
|
|
57
|
+
##
|
58
|
+
# @return [Integer]
|
46
59
|
def self.to_i() identifier end
|
47
60
|
|
61
|
+
##
|
62
|
+
# @return [Integer]
|
48
63
|
def self.identifier
|
49
64
|
const_get(:IDENTIFIER)
|
50
65
|
end
|
51
66
|
|
67
|
+
##
|
68
|
+
# @return [Integer]
|
52
69
|
def identifier()
|
53
70
|
self.class.identifier
|
54
71
|
end
|
55
72
|
|
73
|
+
##
|
74
|
+
# @return [Integer]
|
56
75
|
def key_size
|
57
76
|
@key_size ||= engine.key_len
|
58
77
|
end
|
59
78
|
|
79
|
+
##
|
80
|
+
# @return [Integer]
|
60
81
|
def block_size
|
61
82
|
@block_size ||= engine.block_size
|
62
83
|
end
|
63
84
|
|
85
|
+
##
|
86
|
+
# @return [String]
|
64
87
|
def engine
|
65
88
|
@engine ||= Engine::OpenSSL.use do
|
66
89
|
OpenSSL::Cipher.new(self.class.const_get(:ENGINE))
|
@@ -68,7 +91,9 @@ module OpenPGP
|
|
68
91
|
end
|
69
92
|
|
70
93
|
##
|
71
|
-
# @
|
94
|
+
# @param [String] plaintext
|
95
|
+
# @return [String]
|
96
|
+
# @see http://tools.ietf.org/html/rfc4880#section-13.9
|
72
97
|
def encrypt(plaintext)
|
73
98
|
ciphertext = String.new
|
74
99
|
|
@@ -101,12 +126,18 @@ module OpenPGP
|
|
101
126
|
ciphertext
|
102
127
|
end
|
103
128
|
|
129
|
+
##
|
130
|
+
# @param [String] ciphertext
|
131
|
+
# @return [String]
|
104
132
|
def decrypt(ciphertext)
|
105
133
|
# TODO
|
106
134
|
engine.reset
|
107
135
|
engine.decrypt
|
108
136
|
end
|
109
137
|
|
138
|
+
##
|
139
|
+
# @param [String] block
|
140
|
+
# @return [String]
|
110
141
|
def encrypt_block(block)
|
111
142
|
engine.encrypt
|
112
143
|
engine.key = @key
|