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.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.adoc +5 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.adoc +3 -182
  5. data/lib/rnp.rb +12 -3
  6. data/lib/rnp/error.rb +40 -0
  7. data/lib/rnp/ffi/librnp.rb +306 -0
  8. data/lib/rnp/input.rb +99 -0
  9. data/lib/rnp/key.rb +275 -0
  10. data/lib/rnp/misc.rb +71 -0
  11. data/lib/rnp/op/encrypt.rb +181 -0
  12. data/lib/rnp/op/sign.rb +139 -0
  13. data/lib/rnp/op/verify.rb +147 -0
  14. data/lib/rnp/output.rb +121 -0
  15. data/lib/rnp/rnp.rb +595 -0
  16. data/lib/rnp/utils.rb +44 -0
  17. data/lib/rnp/version.rb +8 -3
  18. metadata +124 -50
  19. data/.gitignore +0 -12
  20. data/.rspec +0 -2
  21. data/.travis.yml +0 -5
  22. data/CODE_OF_CONDUCT.md +0 -74
  23. data/Gemfile +0 -4
  24. data/Rakefile +0 -6
  25. data/Use_Cases.adoc +0 -119
  26. data/bin/console +0 -14
  27. data/bin/setup +0 -8
  28. data/example-usage.rb +0 -766
  29. data/examples/highlevel/decrypt_mem.rb +0 -44
  30. data/examples/highlevel/encrypt_mem.rb +0 -46
  31. data/examples/lowlevel/decrypt_file.rb +0 -76
  32. data/examples/lowlevel/decrypt_mem.rb +0 -80
  33. data/examples/lowlevel/encrypt_file.rb +0 -68
  34. data/examples/lowlevel/encrypt_mem.rb +0 -75
  35. data/examples/lowlevel/load_pubkey.rb +0 -118
  36. data/examples/lowlevel/print_keyring_file.rb +0 -68
  37. data/examples/lowlevel/print_keyring_mem.rb +0 -96
  38. data/examples/lowlevel/sign_file.rb +0 -104
  39. data/examples/lowlevel/sign_mem.rb +0 -96
  40. data/examples/lowlevel/verify_file.rb +0 -55
  41. data/examples/lowlevel/verify_mem.rb +0 -61
  42. data/lib/rnp/highlevel.rb +0 -5
  43. data/lib/rnp/highlevel/constants.rb +0 -96
  44. data/lib/rnp/highlevel/keyring.rb +0 -259
  45. data/lib/rnp/highlevel/publickey.rb +0 -150
  46. data/lib/rnp/highlevel/secretkey.rb +0 -318
  47. data/lib/rnp/highlevel/utils.rb +0 -119
  48. data/lib/rnp/lowlevel.rb +0 -6
  49. data/lib/rnp/lowlevel/constants.rb +0 -11
  50. data/lib/rnp/lowlevel/dynarray.rb +0 -129
  51. data/lib/rnp/lowlevel/enums.rb +0 -243
  52. data/lib/rnp/lowlevel/libc.rb +0 -28
  53. data/lib/rnp/lowlevel/libopenssl.rb +0 -15
  54. data/lib/rnp/lowlevel/librnp.rb +0 -213
  55. data/lib/rnp/lowlevel/structs.rb +0 -541
  56. data/lib/rnp/lowlevel/utils.rb +0 -25
  57. data/rnp.gemspec +0 -35
  58. data/rnp/lib/rnp.rb +0 -5
  59. data/rnp/spec/rnp_spec.rb +0 -11
@@ -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
+
@@ -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
+
@@ -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
+