rnp 0.2.0 → 1.0.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.adoc +5 -0
- data/LICENSE.txt +21 -0
- data/README.adoc +3 -182
- data/lib/rnp.rb +12 -3
- data/lib/rnp/error.rb +40 -0
- data/lib/rnp/ffi/librnp.rb +306 -0
- data/lib/rnp/input.rb +99 -0
- data/lib/rnp/key.rb +275 -0
- data/lib/rnp/misc.rb +71 -0
- data/lib/rnp/op/encrypt.rb +181 -0
- data/lib/rnp/op/sign.rb +139 -0
- data/lib/rnp/op/verify.rb +147 -0
- data/lib/rnp/output.rb +121 -0
- data/lib/rnp/rnp.rb +595 -0
- data/lib/rnp/utils.rb +44 -0
- data/lib/rnp/version.rb +8 -3
- metadata +124 -50
- data/.gitignore +0 -12
- data/.rspec +0 -2
- data/.travis.yml +0 -5
- data/CODE_OF_CONDUCT.md +0 -74
- data/Gemfile +0 -4
- data/Rakefile +0 -6
- data/Use_Cases.adoc +0 -119
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/example-usage.rb +0 -766
- data/examples/highlevel/decrypt_mem.rb +0 -44
- data/examples/highlevel/encrypt_mem.rb +0 -46
- data/examples/lowlevel/decrypt_file.rb +0 -76
- data/examples/lowlevel/decrypt_mem.rb +0 -80
- data/examples/lowlevel/encrypt_file.rb +0 -68
- data/examples/lowlevel/encrypt_mem.rb +0 -75
- data/examples/lowlevel/load_pubkey.rb +0 -118
- data/examples/lowlevel/print_keyring_file.rb +0 -68
- data/examples/lowlevel/print_keyring_mem.rb +0 -96
- data/examples/lowlevel/sign_file.rb +0 -104
- data/examples/lowlevel/sign_mem.rb +0 -96
- data/examples/lowlevel/verify_file.rb +0 -55
- data/examples/lowlevel/verify_mem.rb +0 -61
- data/lib/rnp/highlevel.rb +0 -5
- data/lib/rnp/highlevel/constants.rb +0 -96
- data/lib/rnp/highlevel/keyring.rb +0 -259
- data/lib/rnp/highlevel/publickey.rb +0 -150
- data/lib/rnp/highlevel/secretkey.rb +0 -318
- data/lib/rnp/highlevel/utils.rb +0 -119
- data/lib/rnp/lowlevel.rb +0 -6
- data/lib/rnp/lowlevel/constants.rb +0 -11
- data/lib/rnp/lowlevel/dynarray.rb +0 -129
- data/lib/rnp/lowlevel/enums.rb +0 -243
- data/lib/rnp/lowlevel/libc.rb +0 -28
- data/lib/rnp/lowlevel/libopenssl.rb +0 -15
- data/lib/rnp/lowlevel/librnp.rb +0 -213
- data/lib/rnp/lowlevel/structs.rb +0 -541
- data/lib/rnp/lowlevel/utils.rb +0 -25
- data/rnp.gemspec +0 -35
- data/rnp/lib/rnp.rb +0 -5
- data/rnp/spec/rnp_spec.rb +0 -11
data/lib/rnp/input.rb
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# (c) 2018 Ribose Inc.
|
4
|
+
|
5
|
+
require 'English'
|
6
|
+
|
7
|
+
require 'ffi'
|
8
|
+
|
9
|
+
require 'rnp/error'
|
10
|
+
require 'rnp/ffi/librnp'
|
11
|
+
require 'rnp/utils'
|
12
|
+
|
13
|
+
class Rnp
|
14
|
+
# Class used to feed data into RNP.
|
15
|
+
#
|
16
|
+
# @note When dealing with very large data sources, prefer {from_path} which
|
17
|
+
# should be the most efficient. {from_io} is likely to have more overhead.
|
18
|
+
#
|
19
|
+
# @example input from a string
|
20
|
+
# Rnp::Input.from_string('my data')
|
21
|
+
#
|
22
|
+
# @example input from a file
|
23
|
+
# Rnp::Input.from_path('/path/to/my/file')
|
24
|
+
#
|
25
|
+
# @example input from a Ruby IO object
|
26
|
+
# Rnp::Input.from_io(File.open('/path/to/file', 'rb'))
|
27
|
+
class Input
|
28
|
+
# @api private
|
29
|
+
attr_reader :ptr
|
30
|
+
|
31
|
+
# @api private
|
32
|
+
def initialize(ptr, reader = nil)
|
33
|
+
raise Rnp::Error, 'NULL pointer' if ptr.null?
|
34
|
+
@ptr = FFI::AutoPointer.new(ptr, self.class.method(:destroy))
|
35
|
+
@reader = reader
|
36
|
+
end
|
37
|
+
|
38
|
+
# @api private
|
39
|
+
def self.destroy(ptr)
|
40
|
+
LibRnp.rnp_input_destroy(ptr)
|
41
|
+
end
|
42
|
+
|
43
|
+
def inspect
|
44
|
+
Rnp.inspect_ptr(self)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Create an Input to read from a string.
|
48
|
+
#
|
49
|
+
# @param data [String] the string data
|
50
|
+
# @return [Input]
|
51
|
+
def self.from_string(data)
|
52
|
+
pptr = FFI::MemoryPointer.new(:pointer)
|
53
|
+
buf = FFI::MemoryPointer.from_data(data)
|
54
|
+
Rnp.call_ffi(:rnp_input_from_memory, pptr, buf, buf.size, true)
|
55
|
+
Input.new(pptr.read_pointer)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Create an Input to read from a path.
|
59
|
+
#
|
60
|
+
# @param path [String] the path
|
61
|
+
# @return [Input]
|
62
|
+
def self.from_path(path)
|
63
|
+
pptr = FFI::MemoryPointer.new(:pointer)
|
64
|
+
Rnp.call_ffi(:rnp_input_from_path, pptr, path)
|
65
|
+
Input.new(pptr.read_pointer)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Create an Input to read from an IO object.
|
69
|
+
#
|
70
|
+
# @param io [IO, #read] the IO object
|
71
|
+
# @return [Input]
|
72
|
+
def self.from_io(io)
|
73
|
+
from_callback(io.method(:read))
|
74
|
+
end
|
75
|
+
|
76
|
+
# @api private
|
77
|
+
READER = lambda do |reader, _ctx, buf, buf_len|
|
78
|
+
begin
|
79
|
+
data = reader.call(buf_len)
|
80
|
+
return 0 unless data
|
81
|
+
raise Rnp::Error, 'Read exceeded buffer size' if data.size > buf_len
|
82
|
+
buf.write_bytes(data)
|
83
|
+
return data.size
|
84
|
+
rescue
|
85
|
+
puts $ERROR_INFO
|
86
|
+
return -1
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# @api private
|
91
|
+
def self.from_callback(reader)
|
92
|
+
pptr = FFI::MemoryPointer.new(:pointer)
|
93
|
+
readercb = READER.curry[reader]
|
94
|
+
Rnp.call_ffi(:rnp_input_from_callback, pptr, readercb, nil, nil)
|
95
|
+
Input.new(pptr.read_pointer, readercb)
|
96
|
+
end
|
97
|
+
end # class
|
98
|
+
end # class
|
99
|
+
|
data/lib/rnp/key.rb
ADDED
@@ -0,0 +1,275 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# (c) 2018 Ribose Inc.
|
4
|
+
|
5
|
+
require 'ffi'
|
6
|
+
|
7
|
+
require 'rnp/error'
|
8
|
+
require 'rnp/ffi/librnp'
|
9
|
+
require 'rnp/utils'
|
10
|
+
|
11
|
+
class Rnp
|
12
|
+
# Class that represents a PGP key (potentially encompassing both the public
|
13
|
+
# and private portions).
|
14
|
+
class Key
|
15
|
+
# @api private
|
16
|
+
attr_reader :ptr
|
17
|
+
|
18
|
+
# @api private
|
19
|
+
def initialize(ptr, free = true)
|
20
|
+
raise Rnp::Error, 'NULL pointer' if ptr.null?
|
21
|
+
if free
|
22
|
+
@ptr = FFI::AutoPointer.new(ptr, self.class.method(:destroy))
|
23
|
+
else
|
24
|
+
@ptr = ptr
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# @api private
|
29
|
+
def self.destroy(ptr)
|
30
|
+
LibRnp.rnp_key_handle_destroy(ptr)
|
31
|
+
end
|
32
|
+
|
33
|
+
def inspect
|
34
|
+
Rnp.inspect_ptr(self)
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_s
|
38
|
+
"#<#{self.class}:#{keyid}>"
|
39
|
+
end
|
40
|
+
|
41
|
+
# Get the fingerprint of the key
|
42
|
+
#
|
43
|
+
# @return [String]
|
44
|
+
def fingerprint
|
45
|
+
string_property(:rnp_key_get_fprint)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Get the keyid of the key
|
49
|
+
#
|
50
|
+
# @return [String]
|
51
|
+
def keyid
|
52
|
+
string_property(:rnp_key_get_keyid)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Get the grip of the key
|
56
|
+
#
|
57
|
+
# @return [String]
|
58
|
+
def grip
|
59
|
+
string_property(:rnp_key_get_grip)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Get the primary userid of the key
|
63
|
+
#
|
64
|
+
# @return [String]
|
65
|
+
def primary_userid
|
66
|
+
string_property(:rnp_key_get_primary_uid)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Enumerate each userid for this key.
|
70
|
+
#
|
71
|
+
# @return [self, Enumerator]
|
72
|
+
def each_userid(&block)
|
73
|
+
block or return enum_for(:userid_iterator)
|
74
|
+
userid_iterator(&block)
|
75
|
+
self
|
76
|
+
end
|
77
|
+
|
78
|
+
# Get a list of all userids for this key.
|
79
|
+
#
|
80
|
+
# @return [Array<String>]
|
81
|
+
def userids
|
82
|
+
each_userid.to_a
|
83
|
+
end
|
84
|
+
|
85
|
+
# Add a userid to a key.
|
86
|
+
#
|
87
|
+
# @param userid [String] the userid to add
|
88
|
+
# @param hash (see Sign#hash=)
|
89
|
+
# @param expiration_time (see Sign#expiration_time=)
|
90
|
+
# @param key_flags [Integer]
|
91
|
+
# @param primary [Boolean] if true then this userid will be marked as the
|
92
|
+
# primary userid
|
93
|
+
# @return [void]
|
94
|
+
def add_userid(userid, hash: nil, expiration_time: nil, key_flags: 0,
|
95
|
+
primary: false)
|
96
|
+
Rnp.call_ffi(:rnp_key_add_uid, @ptr, userid, hash, expiration_time,
|
97
|
+
key_flags, primary)
|
98
|
+
end
|
99
|
+
|
100
|
+
# Returns true if the key is currently locked.
|
101
|
+
#
|
102
|
+
# @return [Boolean]
|
103
|
+
def locked?
|
104
|
+
bool_property(:rnp_key_is_locked)
|
105
|
+
end
|
106
|
+
|
107
|
+
# Lock the key.
|
108
|
+
#
|
109
|
+
# @return [self]
|
110
|
+
def lock
|
111
|
+
Rnp.call_ffi(:rnp_key_lock, @ptr)
|
112
|
+
self
|
113
|
+
end
|
114
|
+
|
115
|
+
# Unlock the key.
|
116
|
+
#
|
117
|
+
# @param password [String, nil] the password to unlock the key. If nil, the
|
118
|
+
# current password provider will be used (see {Rnp#password_provider=}).
|
119
|
+
# @return [self]
|
120
|
+
def unlock(password = nil)
|
121
|
+
Rnp.call_ffi(:rnp_key_unlock, @ptr, password)
|
122
|
+
self
|
123
|
+
end
|
124
|
+
|
125
|
+
# Returns true if the key is currently protected.
|
126
|
+
#
|
127
|
+
# @return [Boolean]
|
128
|
+
def protected?
|
129
|
+
bool_property(:rnp_key_is_protected)
|
130
|
+
end
|
131
|
+
|
132
|
+
# Protect or re-protect the key.
|
133
|
+
#
|
134
|
+
# @param password [String] the password with which to encrypt the key.
|
135
|
+
# @param cipher [String] the cipher algorithm to encrypt with
|
136
|
+
# @param cipher_mode [String] the cipher mode
|
137
|
+
# @param s2k_hash (see Encrypt#add_password)
|
138
|
+
# @param s2k_iterations (see Encrypt#add_password)
|
139
|
+
# @return [self]
|
140
|
+
def protect(password, cipher: nil, cipher_mode: nil, s2k_hash: nil,
|
141
|
+
s2k_iterations: 0)
|
142
|
+
Rnp.call_ffi(:rnp_key_protect, @ptr, password, cipher, cipher_mode,
|
143
|
+
s2k_hash, s2k_iterations)
|
144
|
+
self
|
145
|
+
end
|
146
|
+
|
147
|
+
# Unprotect the key.
|
148
|
+
#
|
149
|
+
# @param password [String, nil] the password to unlock the key. If nil,
|
150
|
+
# the current password provider will be used (see {Rnp#password_provider=}).
|
151
|
+
# @return [self]
|
152
|
+
def unprotect(password = nil)
|
153
|
+
Rnp.call_ffi(:rnp_key_unprotect, @ptr, password)
|
154
|
+
self
|
155
|
+
end
|
156
|
+
|
157
|
+
# Returns true if the key is a primary key.
|
158
|
+
#
|
159
|
+
# @return [Boolean]
|
160
|
+
def primary?
|
161
|
+
bool_property(:rnp_key_is_primary)
|
162
|
+
end
|
163
|
+
|
164
|
+
# Returns true if the key is a subkey.
|
165
|
+
#
|
166
|
+
# @return [Boolean]
|
167
|
+
def sub?
|
168
|
+
bool_property(:rnp_key_is_sub)
|
169
|
+
end
|
170
|
+
|
171
|
+
# Returns true if the public key packet is available.
|
172
|
+
#
|
173
|
+
# @return [Boolean]
|
174
|
+
def public_key_present?
|
175
|
+
bool_property(:rnp_key_have_public)
|
176
|
+
end
|
177
|
+
|
178
|
+
# Returns true if the secret key packet is available.
|
179
|
+
#
|
180
|
+
# @return [Boolean]
|
181
|
+
def secret_key_present?
|
182
|
+
bool_property(:rnp_key_have_secret)
|
183
|
+
end
|
184
|
+
|
185
|
+
# Returns the raw public key data as PGP packets.
|
186
|
+
#
|
187
|
+
# @return [String]
|
188
|
+
def public_key_data
|
189
|
+
buf_property(:rnp_get_public_key_data)
|
190
|
+
end
|
191
|
+
|
192
|
+
# Returns the raw secret key data.
|
193
|
+
#
|
194
|
+
# The format may be either PGP packets or an s-expr/G10.
|
195
|
+
#
|
196
|
+
# @return [String]
|
197
|
+
def secret_key_data
|
198
|
+
buf_property(:rnp_get_secret_key_data)
|
199
|
+
end
|
200
|
+
|
201
|
+
# Return a JSON representation of this key (as a Hash).
|
202
|
+
#
|
203
|
+
# @param public_mpis [Boolean] if true then public MPIs will be included
|
204
|
+
# @param secret_mpis [Boolean] if true then secret MPIs will be included
|
205
|
+
# @param signatures [Boolean] if true then signatures will be included
|
206
|
+
# @param signature_mpis [Boolean] if true then signature MPIs will be
|
207
|
+
# included
|
208
|
+
# @return [Hash]
|
209
|
+
def json(public_mpis: false, secret_mpis: false, signatures: true,
|
210
|
+
signature_mpis: false)
|
211
|
+
flags = 0
|
212
|
+
flags |= LibRnp::RNP_JSON_PUBLIC_MPIS if public_mpis
|
213
|
+
flags |= LibRnp::RNP_JSON_SECRET_MPIS if secret_mpis
|
214
|
+
flags |= LibRnp::RNP_JSON_SIGNATURES if signatures
|
215
|
+
flags |= LibRnp::RNP_JSON_SIGNATURE_MPIS if signature_mpis
|
216
|
+
pptr = FFI::MemoryPointer.new(:pointer)
|
217
|
+
Rnp.call_ffi(:rnp_key_to_json, @ptr, flags, pptr)
|
218
|
+
begin
|
219
|
+
presult = pptr.read_pointer
|
220
|
+
JSON.parse(presult.read_string) unless presult.null?
|
221
|
+
ensure
|
222
|
+
LibRnp.rnp_buffer_destroy(presult)
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
private
|
227
|
+
|
228
|
+
def string_property(func)
|
229
|
+
pptr = FFI::MemoryPointer.new(:pointer)
|
230
|
+
Rnp.call_ffi(func, @ptr, pptr)
|
231
|
+
begin
|
232
|
+
pvalue = pptr.read_pointer
|
233
|
+
pvalue.read_string unless pvalue.null?
|
234
|
+
ensure
|
235
|
+
LibRnp.rnp_buffer_destroy(pvalue)
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
def bool_property(func)
|
240
|
+
presult = FFI::MemoryPointer.new(:bool)
|
241
|
+
Rnp.call_ffi(func, @ptr, presult)
|
242
|
+
presult.read(:bool)
|
243
|
+
end
|
244
|
+
|
245
|
+
def buf_property(func)
|
246
|
+
pptr = FFI::MemoryPointer.new(:pointer)
|
247
|
+
pbuflen = FFI::MemoryPointer.new(:size_t)
|
248
|
+
Rnp.call_ffi(func, @ptr, pptr, pbuflen)
|
249
|
+
begin
|
250
|
+
pbuf = pptr.read_pointer
|
251
|
+
buflen = pbuflen.read(:size_t)
|
252
|
+
pbuf.read_bytes(buflen) unless pbuf.null?
|
253
|
+
ensure
|
254
|
+
LibRnp.rnp_buffer_destroy(pbuf)
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
def userid_iterator
|
259
|
+
pcount = FFI::MemoryPointer.new(:size_t)
|
260
|
+
Rnp.call_ffi(:rnp_key_get_uid_count, @ptr, pcount)
|
261
|
+
count = pcount.read(:size_t)
|
262
|
+
pptr = FFI::MemoryPointer.new(:pointer)
|
263
|
+
(0...count).each do |i|
|
264
|
+
Rnp.call_ffi(:rnp_key_get_uid_at, @ptr, i, pptr)
|
265
|
+
begin
|
266
|
+
puserid = pptr.read_pointer
|
267
|
+
yield puserid.read_string unless puserid.null?
|
268
|
+
ensure
|
269
|
+
LibRnp.rnp_buffer_destroy(puserid)
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end # class
|
274
|
+
end # class
|
275
|
+
|
data/lib/rnp/misc.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# (c) 2018 Ribose Inc.
|
4
|
+
|
5
|
+
require 'ffi'
|
6
|
+
|
7
|
+
require 'rnp/utils'
|
8
|
+
require 'rnp/ffi/librnp'
|
9
|
+
|
10
|
+
class Rnp
|
11
|
+
# Get the default homedir for RNP.
|
12
|
+
#
|
13
|
+
# @return [String]
|
14
|
+
def self.default_homedir
|
15
|
+
pptr = FFI::MemoryPointer.new(:pointer)
|
16
|
+
Rnp.call_ffi(:rnp_get_default_homedir, pptr)
|
17
|
+
begin
|
18
|
+
phomedir = pptr.read_pointer
|
19
|
+
phomedir.read_string unless phomedir.null?
|
20
|
+
ensure
|
21
|
+
LibRnp.rnp_buffer_destroy(phomedir)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Attempt to detect information about a homedir.
|
26
|
+
#
|
27
|
+
# @param homedir [String] the homedir
|
28
|
+
# @return [Hash<Symbol>]
|
29
|
+
# * :public [Hash<Symbol>]
|
30
|
+
# * :format [String]
|
31
|
+
# * :path [String]
|
32
|
+
# * :secret [Hash<Symbol>]
|
33
|
+
# * :format [String]
|
34
|
+
# * :path [String]
|
35
|
+
def self.homedir_info(homedir)
|
36
|
+
pptrs = FFI::MemoryPointer.new(:pointer, 4)
|
37
|
+
Rnp.call_ffi(:rnp_detect_homedir_info, homedir, pptrs[0], pptrs[1],
|
38
|
+
pptrs[2], pptrs[3])
|
39
|
+
ptrs = (0..3).collect { |i| pptrs[i] }.map(&:read_pointer)
|
40
|
+
return if ptrs.all?(&:null?)
|
41
|
+
{
|
42
|
+
public: {
|
43
|
+
format: ptrs[0].read_string,
|
44
|
+
path: ptrs[1].read_string
|
45
|
+
},
|
46
|
+
secret: {
|
47
|
+
format: ptrs[2].read_string,
|
48
|
+
path: ptrs[3].read_string
|
49
|
+
}
|
50
|
+
}
|
51
|
+
ensure
|
52
|
+
ptrs&.each { |ptr| LibRnp.rnp_buffer_destroy(ptr) }
|
53
|
+
end
|
54
|
+
|
55
|
+
# Attempt to detect the format of a key.
|
56
|
+
#
|
57
|
+
# @param key_data [String] the key data
|
58
|
+
# @return [String]
|
59
|
+
def self.key_format(key_data)
|
60
|
+
pptr = FFI::MemoryPointer.new(:pointer)
|
61
|
+
data = FFI::MemoryPointer.from_data(key_data)
|
62
|
+
Rnp.call_ffi(:rnp_detect_key_format, data, data.size, pptr)
|
63
|
+
begin
|
64
|
+
pformat = pptr.read_pointer
|
65
|
+
pformat.read_string unless pformat.null?
|
66
|
+
ensure
|
67
|
+
LibRnp.rnp_buffer_destroy(pformat)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end # class
|
71
|
+
|
@@ -0,0 +1,181 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# (c) 2018 Ribose Inc.
|
4
|
+
|
5
|
+
require 'set'
|
6
|
+
|
7
|
+
require 'ffi'
|
8
|
+
|
9
|
+
require 'rnp/error'
|
10
|
+
require 'rnp/ffi/librnp'
|
11
|
+
require 'rnp/utils'
|
12
|
+
|
13
|
+
class Rnp
|
14
|
+
# Encryption operation
|
15
|
+
class Encrypt
|
16
|
+
# @api private
|
17
|
+
attr_reader :ptr
|
18
|
+
|
19
|
+
# @api private
|
20
|
+
def initialize(ptr)
|
21
|
+
raise Rnp::Error, 'NULL pointer' if ptr.null?
|
22
|
+
@ptr = FFI::AutoPointer.new(ptr, self.class.method(:destroy))
|
23
|
+
end
|
24
|
+
|
25
|
+
# @api private
|
26
|
+
def self.destroy(ptr)
|
27
|
+
LibRnp.rnp_op_encrypt_destroy(ptr)
|
28
|
+
end
|
29
|
+
|
30
|
+
def inspect
|
31
|
+
Rnp.inspect_ptr(self)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Add a recipient.
|
35
|
+
#
|
36
|
+
# @param recipient [Key] the recipient
|
37
|
+
# @return [self]
|
38
|
+
def add_recipient(recipient)
|
39
|
+
Rnp.call_ffi(:rnp_op_encrypt_add_recipient, @ptr, recipient.ptr)
|
40
|
+
self
|
41
|
+
end
|
42
|
+
|
43
|
+
# Add a signer.
|
44
|
+
#
|
45
|
+
# @param signer [Key] the signer
|
46
|
+
# @param hash (see #hash=)
|
47
|
+
# @param creation_time (see #creation_time=)
|
48
|
+
# @param expiration_time (see #expiration_time=)
|
49
|
+
# @return [self]
|
50
|
+
def add_signer(signer, hash: nil, creation_time: nil, expiration_time: nil)
|
51
|
+
pptr = FFI::MemoryPointer.new(:pointer)
|
52
|
+
Rnp.call_ffi(:rnp_op_encrypt_add_signature, @ptr, signer.ptr, pptr)
|
53
|
+
psig = pptr.read_pointer
|
54
|
+
Sign.set_signature_options(
|
55
|
+
psig,
|
56
|
+
hash: hash,
|
57
|
+
creation_time: creation_time,
|
58
|
+
expiration_time: expiration_time
|
59
|
+
)
|
60
|
+
self
|
61
|
+
end
|
62
|
+
|
63
|
+
# Add a password.
|
64
|
+
#
|
65
|
+
# @param password [String] the password
|
66
|
+
# @param s2k_hash [String] the hash algorithm to use for the
|
67
|
+
# string-to-key key derivation.
|
68
|
+
# @param s2k_iterations [Integer] the number of iterations for the
|
69
|
+
# string-to-key key derivation. A value of 0 will choose
|
70
|
+
# a default.
|
71
|
+
# @param s2k_cipher [String] the cipher algorithm used to wrap the key.
|
72
|
+
# @note This is a separate cipher from the one used to encrypt the main
|
73
|
+
# payload/stream (see {#cipher=}). This cipher may not be used in all
|
74
|
+
# circumstances. For example, when encrypting with *only* a password
|
75
|
+
# (no public keys), this cipher would generally not be used.
|
76
|
+
# When encrypting with a combination of one or more passwords and one
|
77
|
+
# or more public keys, this cipher would generally be used.
|
78
|
+
# @return [self]
|
79
|
+
def add_password(password, s2k_hash: nil, s2k_iterations: 0,
|
80
|
+
s2k_cipher: nil)
|
81
|
+
Rnp.call_ffi(:rnp_op_encrypt_add_password, @ptr, password, s2k_hash,
|
82
|
+
s2k_iterations, s2k_cipher)
|
83
|
+
self
|
84
|
+
end
|
85
|
+
|
86
|
+
# Set a group of options.
|
87
|
+
#
|
88
|
+
# @note Some options are related to signatures and will have no effect if
|
89
|
+
# there are no signers.
|
90
|
+
#
|
91
|
+
# @param armored (see #armored=)
|
92
|
+
# @param compression (see #compression=)
|
93
|
+
# @param cipher (see #cipher=)
|
94
|
+
# @param hash (see #hash=)
|
95
|
+
# @param creation_time (see #creation_time=)
|
96
|
+
# @param expiration_time (see #expiration_time=)
|
97
|
+
def options=(armored: nil, compression: nil, cipher: nil, hash: nil,
|
98
|
+
creation_time: nil, expiration_time: nil)
|
99
|
+
self.armored = armored unless armored.nil?
|
100
|
+
self.compression = compression unless compression.nil?
|
101
|
+
self.cipher = cipher unless cipher.nil?
|
102
|
+
self.hash = hash unless hash.nil?
|
103
|
+
self.creation_time = creation_time unless creation_time.nil?
|
104
|
+
self.expiration_time = expiration_time unless expiration_time.nil?
|
105
|
+
end
|
106
|
+
|
107
|
+
# Set whether the output will be ASCII-armored.
|
108
|
+
#
|
109
|
+
# @param armored [Boolean] true if the output should be
|
110
|
+
# ASCII-armored, false otherwise.
|
111
|
+
def armored=(armored)
|
112
|
+
Rnp.call_ffi(:rnp_op_encrypt_set_armor, @ptr, armored)
|
113
|
+
end
|
114
|
+
|
115
|
+
# Set the compression algorithm and level.
|
116
|
+
#
|
117
|
+
# @param [Hash<Symbol>] compression
|
118
|
+
# @option compression [String] :algorithm the compression algorithm
|
119
|
+
# (bzip2, etc)
|
120
|
+
# @option compression [Integer] :level the compression level. This should
|
121
|
+
# generally be between 0 (no compression) and 9 (best compression).
|
122
|
+
def compression=(compression)
|
123
|
+
if !compression.is_a?(Hash) || Set.new(compression.keys) != Set.new(%i[algorithm level])
|
124
|
+
raise ArgumentError,
|
125
|
+
'Compression option must be of the form: {algorithm: \'zlib\', level: 5}'
|
126
|
+
end
|
127
|
+
Rnp.call_ffi(:rnp_op_encrypt_set_compression, @ptr,
|
128
|
+
compression[:algorithm], compression[:level])
|
129
|
+
end
|
130
|
+
|
131
|
+
# Set the cipher used to encrypt the input.
|
132
|
+
#
|
133
|
+
# @param cipher [String] the cipher algorithm name
|
134
|
+
def cipher=(cipher)
|
135
|
+
Rnp.call_ffi(:rnp_op_encrypt_set_cipher, @ptr, cipher)
|
136
|
+
end
|
137
|
+
|
138
|
+
# Set the hash algorithm used for calculating signatures.
|
139
|
+
#
|
140
|
+
# @note This is only valid when there is one or more signer.
|
141
|
+
#
|
142
|
+
# @param hash [String] the hash algorithm name
|
143
|
+
def hash=(hash)
|
144
|
+
Rnp.call_ffi(:rnp_op_encrypt_set_hash, @ptr, hash)
|
145
|
+
end
|
146
|
+
|
147
|
+
# Set the creation time for signatures.
|
148
|
+
#
|
149
|
+
# @note This is only valid when there is one or more signer.
|
150
|
+
#
|
151
|
+
# @param creation_time [Time, Integer] the creation time to use for all
|
152
|
+
# signatures. As an integer, this is the number of seconds
|
153
|
+
# since the unix epoch.
|
154
|
+
def creation_time=(creation_time)
|
155
|
+
creation_time = creation_time.to_i if creation_time.is_a?(::Time)
|
156
|
+
Rnp.call_ffi(:rnp_op_encrypt_set_creation_time, @ptr, creation_time)
|
157
|
+
end
|
158
|
+
|
159
|
+
# Set the expiration time for signatures.
|
160
|
+
#
|
161
|
+
# @note This is only valid when there is one or more signer.
|
162
|
+
#
|
163
|
+
# @param expiration_time [Integer] the lifetime of the signatures, as the number
|
164
|
+
# of seconds. The actual expiration date/time is the creation time
|
165
|
+
# plus this value. A value of 0 will create signatures that do not
|
166
|
+
# expire.
|
167
|
+
def expiration_time=(expiration_time)
|
168
|
+
Rnp.call_ffi(:rnp_op_encrypt_set_expiration_time, @ptr, expiration_time)
|
169
|
+
end
|
170
|
+
|
171
|
+
# Execute the operation.
|
172
|
+
#
|
173
|
+
# This should only be called once.
|
174
|
+
#
|
175
|
+
# @return [void]
|
176
|
+
def execute
|
177
|
+
Rnp.call_ffi(:rnp_op_encrypt_execute, @ptr)
|
178
|
+
end
|
179
|
+
end # class
|
180
|
+
end # class
|
181
|
+
|