Class: Rnp

Inherits:
Object
  • Object
show all
Defined in:
lib/rnp/rnp.rb,
lib/rnp/key.rb,
lib/rnp/misc.rb,
lib/rnp/error.rb,
lib/rnp/input.rb,
lib/rnp/utils.rb,
lib/rnp/output.rb,
lib/rnp/userid.rb,
lib/rnp/op/sign.rb,
lib/rnp/version.rb,
lib/rnp/op/verify.rb,
lib/rnp/signature.rb,
lib/rnp/op/encrypt.rb,
lib/rnp/op/generate.rb

Overview

© 2018-2023 Ribose Inc.

Defined Under Namespace

Classes: BadFormatError, BadPasswordError, Encrypt, Error, FeatureNotAvailableError, Generate, Input, InvalidSignatureError, Key, NoSuitableKeyError, Output, Sign, Signature, UserID, Verify

Constant Summary collapse

FEATURES =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

{
  # Support for setting hash, creation, and expiration time for individual
  # signatures in a sign operation. Older versions of rnp returned a
  # "not implemented" error.
  "per-signature-opts" => Rnp.version > Rnp.version("0.11.0") ||
    Rnp.commit_time >= 1546035818,
  # Correct grip calculation for Elgamal/DSA keys. This was actually before
  # the commit timestamp API was added, so this isn't accurate in one case.
  "dsa-elg-grip-calc" => Rnp.version > Rnp.version("0.11.0") ||
    Rnp.commit_time >= 1538219020,
  # Input reader callback signature was changed:
  # ssize_t(void *app_ctx, void *buf, size_t len)
  # bool(void *app_ctx, void *buf, size_t len, size_t *read)
  "input-reader-cb-no-ssize_t" => Rnp.version >= Rnp.version("0.14.0") ||
    Rnp.commit_time >= 1585833163,
  # Behavior on primary userid retrieveing was changed:
  # Now userid is not considered as primary if it is revoked/expired/etc.
  "primary-userid-must-be-valid" => Rnp.version >= Rnp.version("0.14.0") ||
    Rnp.commit_time >= 1605875599,
  # Behavior was changed in v0.15.2 (issue #1509):
  # userid is valid even if key expiration in userid expiration expires key.
  "relax-userid-validity-checks" => Rnp.version >= Rnp.version("0.15.2") ||
    Rnp.commit_time >= 1624526708,
  # Behavior on default key expiration time was changed:
  # Now default key expiration time is 2 years
  "default-key-expiration-2-years" => Rnp.version >= Rnp.version("0.16.1") ||
    Rnp.commit_time >= 1645578982,
  # Behaviour on signature validation was changed:
  # Now at least one valid signature is required for success
  "require-single-valid-signature" => Rnp.version >= Rnp.version("0.16.1") ||
    Rnp.commit_time >= 1661781294,
}.freeze
ERRORS_MAP =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

{
  LibRnp::RNP_ERROR_BAD_PASSWORD => BadPasswordError,
  LibRnp::RNP_ERROR_SIGNATURE_INVALID => InvalidSignatureError,
  LibRnp::RNP_ERROR_BAD_FORMAT => BadFormatError,
  LibRnp::RNP_ERROR_NO_SUITABLE_KEY => NoSuitableKeyError
}.freeze
VERSION =
"1.0.5"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(pubfmt = 'GPG', secfmt = 'GPG') ⇒ Rnp

Create a new interface to RNP.



28
29
30
31
32
33
34
# File 'lib/rnp/rnp.rb', line 28

def initialize(pubfmt = 'GPG', secfmt = 'GPG')
  pptr = FFI::MemoryPointer.new(:pointer)
  Rnp.call_ffi(:rnp_ffi_create, pptr, pubfmt, secfmt)
  @ptr = FFI::AutoPointer.new(pptr.read_pointer, self.class.method(:destroy))
  @key_provider = nil
  @password_provider = nil
end

Instance Attribute Details

#ptrObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



22
23
24
# File 'lib/rnp/rnp.rb', line 22

def ptr
  @ptr
end

Class Method Details

.call_ffi(fn, *args) ⇒ void

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This method returns an undefined value.

Calls the LibRnp FFI function indicated. If the return code is <0, an error will be raised.



19
20
21
22
23
# File 'lib/rnp/utils.rb', line 19

def self.call_ffi(fn, *args)
  rc = LibRnp.method(fn).call(*args)
  Rnp.raise_error("#{fn} failed", rc) unless rc.zero?
  nil
end

.commit_timeInteger

Retrieve the commit time of the latest commit.

This will return 0 for release/non-master builds.



165
166
167
# File 'lib/rnp/misc.rb', line 165

def self.commit_time
  LibRnp.rnp_version_commit_timestamp
end

.dearmor(input:, output: nil) ⇒ nil, String

Remove ASCII Armor from data.



98
99
100
101
102
# File 'lib/rnp/misc.rb', line 98

def self.dearmor(input:, output: nil)
  Output.default(output) do |output_|
    Rnp.call_ffi(:rnp_dearmor, input.ptr, output_.ptr)
  end
end

.default_homedirString

Get the default homedir for RNP.



15
16
17
18
19
20
21
22
23
24
# File 'lib/rnp/misc.rb', line 15

def self.default_homedir
  pptr = FFI::MemoryPointer.new(:pointer)
  Rnp.call_ffi(:rnp_get_default_homedir, pptr)
  begin
    phomedir = pptr.read_pointer
    phomedir.read_string unless phomedir.null?
  ensure
    LibRnp.rnp_buffer_destroy(phomedir)
  end
end

.destroy(ptr) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



37
38
39
# File 'lib/rnp/rnp.rb', line 37

def self.destroy(ptr)
  LibRnp.rnp_ffi_destroy(ptr)
end

.disable_debugvoid

This method returns an undefined value.

Disable previously-enabled debugging



213
214
215
# File 'lib/rnp/misc.rb', line 213

def self.disable_debug
  Rnp.call_ffi(:rnp_disable_debug)
end

.enable_debug(file = nil) ⇒ void

This method returns an undefined value.

Enable debugging



206
207
208
# File 'lib/rnp/misc.rb', line 206

def self.enable_debug(file = nil)
  Rnp.call_ffi(:rnp_enable_debug, file)
end

.enarmor(input:, output: nil, type: nil) ⇒ nil, String

Add ASCII Armor to data.



86
87
88
89
90
# File 'lib/rnp/misc.rb', line 86

def self.enarmor(input:, output: nil, type: nil)
  Output.default(output) do |output_|
    Rnp.call_ffi(:rnp_enarmor, input.ptr, output_.ptr, type)
  end
end

.guess_contents(input) ⇒ String

Guess the contents of an input



222
223
224
225
226
227
228
229
230
231
# File 'lib/rnp/misc.rb', line 222

def self.guess_contents(input)
  pptr = FFI::MemoryPointer.new(:pointer)
  Rnp.call_ffi(:rnp_guess_contents, input.ptr, pptr)
  begin
    presult = pptr.read_pointer
    presult.read_string unless presult.null?
  ensure
    LibRnp.rnp_buffer_destroy(presult)
  end
end

.has?(feature) ⇒ Boolean

Raises:

  • (ArgumentError)


293
294
295
296
# File 'lib/rnp/misc.rb', line 293

def self.has?(feature)
  raise ArgumentError unless FEATURES.include?(feature)
  FEATURES[feature]
end

.homedir_info(homedir) ⇒ Hash<Symbol>

Attempt to detect information about a homedir.



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/rnp/misc.rb', line 36

def self.homedir_info(homedir)
  pptrs = FFI::MemoryPointer.new(:pointer, 4)
  Rnp.call_ffi(:rnp_detect_homedir_info, homedir, pptrs[0], pptrs[1],
               pptrs[2], pptrs[3])
  ptrs = (0..3).collect { |i| pptrs[i] }.map(&:read_pointer)
  return if ptrs.all?(&:null?)
  {
    public: {
      format: ptrs[0].read_string,
      path: ptrs[1].read_string
    },
    secret: {
      format: ptrs[2].read_string,
      path: ptrs[3].read_string
    }
  }
ensure
  ptrs&.each { |ptr| LibRnp.rnp_buffer_destroy(ptr) }
end

.inspect_ptr(myself) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



26
27
28
29
30
31
# File 'lib/rnp/utils.rb', line 26

def self.inspect_ptr(myself)
  ptr_format = "0x%0#{FFI::Pointer.size * 2}x"
  ptr_s = format(ptr_format, myself.instance_variable_get(:@ptr).address)
  class_name = myself.class.to_s
  "#<#{class_name}:#{ptr_s}>"
end

.key_format(key_data) ⇒ String

Attempt to detect the format of a key.



60
61
62
63
64
65
66
67
68
69
70
# File 'lib/rnp/misc.rb', line 60

def self.key_format(key_data)
  pptr = FFI::MemoryPointer.new(:pointer)
  data = FFI::MemoryPointer.from_data(key_data)
  Rnp.call_ffi(:rnp_detect_key_format, data, data.size, pptr)
  begin
    pformat = pptr.read_pointer
    pformat.read_string unless pformat.null?
  ensure
    LibRnp.rnp_buffer_destroy(pformat)
  end
end

.parse(input:, mpi: false, raw: false, grip: false) ⇒ Array

Parse OpenPGP data to JSON.



176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/rnp/misc.rb', line 176

def self.parse(input:, mpi: false, raw: false, grip: false)
  flags = 0
  flags |= LibRnp::RNP_JSON_DUMP_MPI if mpi
  flags |= LibRnp::RNP_JSON_DUMP_RAW if raw
  flags |= LibRnp::RNP_JSON_DUMP_GRIP if grip
  pptr = FFI::MemoryPointer.new(:pointer)
  Rnp.call_ffi(:rnp_dump_packets_to_json, input.ptr, flags, pptr)
  begin
    pjson = pptr.read_pointer
    JSON.parse(pjson.read_string) unless pjson.null?
  ensure
    LibRnp.rnp_buffer_destroy(pjson)
  end
end

.raise_error(msg, rc = nil) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Raises:

  • (klass)


33
34
35
36
# File 'lib/rnp/error.rb', line 33

def self.raise_error(msg, rc = nil)
  klass = ERRORS_MAP.fetch(rc, Error)
  raise klass.new(msg, rc)
end

.s2k_iterations(hash:, msec:) ⇒ Integer

Calculate s2k iterations



196
197
198
199
200
# File 'lib/rnp/misc.rb', line 196

def self.s2k_iterations(hash:, msec:)
  piters = FFI::MemoryPointer.new(:size_t)
  Rnp.call_ffi(:rnp_calculate_iterations, hash, msec, piters)
  piters.read(:size_t)
end

.supported_features(type) ⇒ Array

Get a list of supported features (by type)



248
249
250
251
252
253
254
255
256
257
# File 'lib/rnp/misc.rb', line 248

def self.supported_features(type)
  pptr = FFI::MemoryPointer.new(:pointer)
  Rnp.call_ffi(:rnp_supported_features, type, pptr)
  begin
    presult = pptr.read_pointer
    JSON.parse(presult.read_string) unless presult.null?
  ensure
    LibRnp.rnp_buffer_destroy(presult)
  end
end

.supports?(type, name) ⇒ Boolean

Check if a specific feature is supported



238
239
240
241
242
# File 'lib/rnp/misc.rb', line 238

def self.supports?(type, name)
  presult = FFI::MemoryPointer.new(:bool)
  Rnp.call_ffi(:rnp_supports_feature, type, name, presult)
  presult.read(:bool)
end

.version(str = nil) ⇒ Integer

Get the version stamp of the rnp library as an unsigned 32-bit integer. This number can be compared against other stamps generated with version_for.



123
124
125
126
127
128
129
# File 'lib/rnp/misc.rb', line 123

def self.version(str = nil)
  if str.nil?
    LibRnp.rnp_version
  else
    LibRnp.rnp_version_for(*str.split('.').map(&:to_i))
  end
end

.version_for(major, minor, patch) ⇒ Integer

Encode the given major, minor, and patch numbers into a version stamp.



135
136
137
# File 'lib/rnp/misc.rb', line 135

def self.version_for(major, minor, patch)
  LibRnp.rnp_version_for(major, minor, patch)
end

.version_major(version) ⇒ Integer

Extract the major version component from the given version stamp.



142
143
144
# File 'lib/rnp/misc.rb', line 142

def self.version_major(version)
  LibRnp.rnp_version_major(version)
end

.version_minor(version) ⇒ Integer

Extract the minor version component from the given version stamp.



149
150
151
# File 'lib/rnp/misc.rb', line 149

def self.version_minor(version)
  LibRnp.rnp_version_minor(version)
end

.version_patch(version) ⇒ Integer

Extract the patch version component from the given version stamp.



156
157
158
# File 'lib/rnp/misc.rb', line 156

def self.version_patch(version)
  LibRnp.rnp_version_patch(version)
end

.version_stringString

Get the version of the rnp library as a string.



107
108
109
# File 'lib/rnp/misc.rb', line 107

def self.version_string
  LibRnp.rnp_version_string
end

.version_string_fullString

Get the detailed version of the rnp library as a string.



114
115
116
# File 'lib/rnp/misc.rb', line 114

def self.version_string_full
  LibRnp.rnp_version_string_full
end

Instance Method Details

#cleartext_sign(input:, output: nil, signers:, compression: nil, creation_time: nil, expiration_time: nil, hash: nil) ⇒ nil, String

Create a cleartext signature.



369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
# File 'lib/rnp/rnp.rb', line 369

def cleartext_sign(input:, output: nil, signers:,
                   compression: nil,
                   creation_time: nil,
                   expiration_time: nil,
                   hash: nil)
  Output.default(output) do |output_|
    sign = start_cleartext_sign(input: input, output: output_)
    sign.options = {
      compression: compression,
      creation_time: creation_time,
      expiration_time: expiration_time,
      hash: hash
    }
    simple_sign(sign, signers)
  end
end

#decrypt(input:, output: nil) ⇒ nil, String

Decrypt encrypted data.



544
545
546
547
548
# File 'lib/rnp/rnp.rb', line 544

def decrypt(input:, output: nil)
  Output.default(output) do |output_|
    Rnp.call_ffi(:rnp_decrypt, @ptr, input.ptr, output_.ptr)
  end
end

#detached_sign(input:, output: nil, signers:, armored: nil, compression: nil, creation_time: nil, expiration_time: nil, hash: nil) ⇒ nil, String

Create a detached signature.



397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
# File 'lib/rnp/rnp.rb', line 397

def detached_sign(input:, output: nil, signers:,
                  armored: nil,
                  compression: nil,
                  creation_time: nil,
                  expiration_time: nil,
                  hash: nil)
  Output.default(output) do |output_|
    sign = start_detached_sign(input: input, output: output_)
    sign.options = {
      armored: armored,
      compression: compression,
      creation_time: creation_time,
      expiration_time: expiration_time,
      hash: hash
    }
    simple_sign(sign, signers)
  end
end

#detached_verify(data:, signature:) ⇒ Object

Verify a detached signature.



429
430
431
432
# File 'lib/rnp/rnp.rb', line 429

def detached_verify(data:, signature:)
  verify = start_detached_verify(data: data, signature: signature)
  verify.execute
end

#each_fingerprint(&block) ⇒ self, Enumerator

Enumerate all fingerprints.



# File 'lib/rnp/rnp.rb', line 291


#each_grip(&block) ⇒ self, Enumerator

Enumerate all grips.



306
307
308
309
310
311
312
313
314
# File 'lib/rnp/rnp.rb', line 306

%w[userid keyid fingerprint grip].each do |identifier_type|
  define_method("each_#{identifier_type}".to_sym) do |&block|
    each_identifier(identifier_type, &block)
  end

  define_method("#{identifier_type}s".to_sym) do
    each_identifier(identifier_type).to_a
  end
end

#each_keyid(&block) ⇒ self, Enumerator

Enumerate all keyids.



# File 'lib/rnp/rnp.rb', line 281


#each_userid(&block) ⇒ self, Enumerator

Enumerate all userids.



# File 'lib/rnp/rnp.rb', line 271


#encrypt(input:, output: nil, recipients:, armored: nil, compression: nil, cipher: nil, aead: nil) ⇒ Object

Encrypt data with a public key.



444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
# File 'lib/rnp/rnp.rb', line 444

def encrypt(input:, output: nil, recipients:,
            armored: nil,
            compression: nil,
            cipher: nil,
            aead: nil)
  Output.default(output) do |output_|
    enc = start_encrypt(input: input, output: output_)
    enc.options = {
      armored: armored,
      compression: compression,
      cipher: cipher,
      aead: aead,
    }
    simple_encrypt(enc, recipients: recipients)
  end
end

#encrypt_and_sign(input:, output: nil, recipients:, signers:, armored: nil, compression: nil, cipher: nil, aead: nil, hash: nil, creation_time: nil, expiration_time: nil) ⇒ Object

Encrypt and sign data with a public key.



474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
# File 'lib/rnp/rnp.rb', line 474

def encrypt_and_sign(input:, output: nil, recipients:, signers:,
                     armored: nil,
                     compression: nil,
                     cipher: nil,
                     aead: nil,
                     hash: nil,
                     creation_time: nil,
                     expiration_time: nil)
  Output.default(output) do |output_|
    enc = start_encrypt(input: input, output: output_)
    enc.options = {
      armored: armored,
      compression: compression,
      cipher: cipher,
      aead: aead,
      hash: hash,
      creation_time: creation_time,
      expiration_time: expiration_time
    }
    simple_encrypt(enc, recipients: recipients, signers: signers)
  end
end

#find_key(criteria) ⇒ Key?

Find a key.

Raises:



256
257
258
259
260
261
262
263
264
# File 'lib/rnp/rnp.rb', line 256

def find_key(criteria)
  raise Rnp::Error, 'Invalid search criteria' if !criteria.is_a?(::Hash) ||
                                                 criteria.size != 1
  pptr = FFI::MemoryPointer.new(:pointer)
  Rnp.call_ffi(:rnp_locate_key, @ptr, criteria.keys[0].to_s,
               criteria.values[0], pptr)
  pkey = pptr.read_pointer
  Rnp::Key.new(pkey) unless pkey.null?
end

#fingerprintsArray<String>

Get a list of all fingerprints.



# File 'lib/rnp/rnp.rb', line 286


#generate(type:, userid:, bits:, curve: nil, password:, subtype: nil, subbits: 0, subcurve: nil) ⇒ Object

Generate a key and optional subkey.



206
207
208
209
210
211
212
213
# File 'lib/rnp/rnp.rb', line 206

def generate(type:, userid:, bits:, curve: nil, password:,
             subtype: nil, subbits: 0, subcurve: nil)
  pptr = FFI::MemoryPointer.new(:pointer)
  Rnp.call_ffi(:rnp_generate_key_ex, @ptr, type, subtype, bits, subbits,
               curve, subcurve, userid, password, pptr)
  pkey = pptr.read_pointer
  Key.new(pkey) unless pkey.null?
end

#generate_dsa_elgamal(userid:, bits:, subbits: 0, password:) ⇒ Object

Generate a DSA (w/optional ElGamal subkey) key.



156
157
158
159
160
161
162
# File 'lib/rnp/rnp.rb', line 156

def generate_dsa_elgamal(userid:, bits:, subbits: 0, password:)
  pptr = FFI::MemoryPointer.new(:pointer)
  Rnp.call_ffi(:rnp_generate_key_dsa_eg, @ptr, bits, subbits, userid,
               password, pptr)
  pkey = pptr.read_pointer
  Key.new(pkey) unless pkey.null?
end

#generate_ecdsa_ecdh(userid:, curve:, password:) ⇒ Object

Generate an ECDSA+ECDH key pair.



170
171
172
173
174
175
# File 'lib/rnp/rnp.rb', line 170

def generate_ecdsa_ecdh(userid:, curve:, password:)
  pptr = FFI::MemoryPointer.new(:pointer)
  Rnp.call_ffi(:rnp_generate_key_ec, @ptr, curve, userid, password, pptr)
  pkey = pptr.read_pointer
  Key.new(pkey) unless pkey.null?
end

#generate_eddsa_25519(userid:, password:) ⇒ Object

Generate an EdDSA+x25519 key pair.



182
183
184
185
186
187
# File 'lib/rnp/rnp.rb', line 182

def generate_eddsa_25519(userid:, password:)
  pptr = FFI::MemoryPointer.new(:pointer)
  Rnp.call_ffi(:rnp_generate_key_25519, @ptr, userid, password, pptr)
  pkey = pptr.read_pointer
  Key.new(pkey) unless pkey.null?
end

#generate_key(description) ⇒ Hash<Symbol, Key>

Note:

The generated key(s) will be unprotected and unlocked. The application should protect and lock the keys with Rnp::Key#protect and Rnp::Key#lock.

Generate a new key or pair of keys.

Examples

examples/key_generation.rb



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/rnp/rnp.rb', line 113

def generate_key(description)
  description = JSON.generate(description) unless description.is_a?(String)
  pptr = FFI::MemoryPointer.new(:pointer)
  Rnp.call_ffi(:rnp_generate_key_json, @ptr, description, pptr)
  begin
    presults = pptr.read_pointer
    return nil if presults.null?
    results = JSON.parse(presults.read_string)
    generated = {}
    results.each do |k, v|
      key = find_key(v.keys[0].to_sym => v.values[0])
      generated[k.to_sym] = key
    end
    generated
  ensure
    LibRnp.rnp_buffer_destroy(presults)
  end
end

#generate_rsa(userid:, bits:, subbits: 0, password:) ⇒ Object

Generate an RSA key (w/optional subkey).



140
141
142
143
144
145
146
# File 'lib/rnp/rnp.rb', line 140

def generate_rsa(userid:, bits:, subbits: 0, password:)
  pptr = FFI::MemoryPointer.new(:pointer)
  Rnp.call_ffi(:rnp_generate_key_rsa, @ptr, bits, subbits, userid, password,
               pptr)
  pkey = pptr.read_pointer
  Key.new(pkey) unless pkey.null?
end

#generate_sm2(userid:, password:) ⇒ Object

Generate an SM2 key pair.



194
195
196
197
198
199
# File 'lib/rnp/rnp.rb', line 194

def generate_sm2(userid:, password:)
  pptr = FFI::MemoryPointer.new(:pointer)
  Rnp.call_ffi(:rnp_generate_key_sm2, @ptr, userid, password, pptr)
  pkey = pptr.read_pointer
  Key.new(pkey) unless pkey.null?
end

#gripsArray<String>

Get a list of all grips.



# File 'lib/rnp/rnp.rb', line 296


#import_keys(input:, public_keys: true, secret_keys: true) ⇒ Hash

Import keys



632
633
634
635
636
637
638
639
640
641
642
643
644
# File 'lib/rnp/rnp.rb', line 632

def import_keys(input:, public_keys: true, secret_keys: true)
  flags = 0
  flags |= LibRnp::RNP_LOAD_SAVE_PUBLIC_KEYS if public_keys
  flags |= LibRnp::RNP_LOAD_SAVE_SECRET_KEYS if secret_keys
  pptr = FFI::MemoryPointer.new(:pointer)
  Rnp.call_ffi(:rnp_import_keys, @ptr, input.ptr, flags, pptr)
  begin
    presults = pptr.read_pointer
    JSON.parse(presults.read_string) unless pptr.null?
  ensure
    LibRnp.rnp_buffer_destroy(presults)
  end
end

#import_signatures(input:) ⇒ Hash

Import signatures



650
651
652
653
654
655
656
657
658
659
# File 'lib/rnp/rnp.rb', line 650

def import_signatures(input:)
  pptr = FFI::MemoryPointer.new(:pointer)
  Rnp.call_ffi(:rnp_import_signatures, @ptr, input.ptr, 0, pptr)
  begin
    presults = pptr.read_pointer
    JSON.parse(presults.read_string) unless pptr.null?
  ensure
    LibRnp.rnp_buffer_destroy(presults)
  end
end

#inspectObject



41
42
43
# File 'lib/rnp/rnp.rb', line 41

def inspect
  Rnp.inspect_ptr(self)
end

#key_provider=(provider) ⇒ Object

Set a key provider.

The key provider is useful if, for example, you have a database of keys and you do not want to load all of them, and you don’t know which will be needed for a given operation.

The key provider will be called to request that a key be loaded, and the key provider is responsible for loading the appropriate key (if available) using #load_keys.

The provider may be called multiple times for the same key, but with different identifiers. For example, it may first be called with a fingerprint, then (if the key was not loaded), it may be called with a keyid.

Examples

examples/key_provider.rb



74
75
76
77
78
# File 'lib/rnp/rnp.rb', line 74

def key_provider=(provider)
  @key_provider = provider
  @key_provider = KEY_PROVIDER.curry[provider] if provider
  Rnp.call_ffi(:rnp_ffi_set_key_provider, @ptr, @key_provider, nil)
end

#keyidsArray<String>

Get a list of all keyids.



# File 'lib/rnp/rnp.rb', line 276


#load_keys(input:, format:, public_keys: true, secret_keys: true) ⇒ void

This method returns an undefined value.

Load keys.

Raises:

  • (ArgumentError)


222
223
224
225
226
# File 'lib/rnp/rnp.rb', line 222

def load_keys(input:, format:, public_keys: true, secret_keys: true)
  raise ArgumentError, 'At least one of public_keys or secret_keys must be true' if !public_keys && !secret_keys
  flags = load_save_flags(public_keys: public_keys, secret_keys: secret_keys)
  Rnp.call_ffi(:rnp_load_keys, @ptr, format, input.ptr, flags)
end

#log=(fd) ⇒ Object

Set a logging destination.



49
50
51
52
# File 'lib/rnp/rnp.rb', line 49

def log=(fd)
  fd = fd.to_i if fd.is_a(::IO)
  Rnp.call_ffi(:rnp_ffi_set_log_fd, @ptr, fd)
end

#password_provider=(provider) ⇒ Object

Set a password provider.

The password provider is used for retrieving passwords for various operations, including:

  • Signing data

  • Decrypting data (public-key or symmetric)

  • Adding a userid to a key

  • Unlocking a key

  • Unprotecting a key

Examples

examples/password_provider.rb



95
96
97
98
99
# File 'lib/rnp/rnp.rb', line 95

def password_provider=(provider)
  @password_provider = provider
  @password_provider = PASS_PROVIDER.curry[provider] if provider
  Rnp.call_ffi(:rnp_ffi_set_pass_provider, @ptr, @password_provider, nil)
end

#public_key_countObject



316
317
318
319
320
# File 'lib/rnp/rnp.rb', line 316

def public_key_count
  pcount = FFI::MemoryPointer.new(:size_t)
  Rnp.call_ffi(:rnp_get_public_key_count, @ptr, pcount)
  pcount.read(:size_t)
end

#save_keys(output:, format:, public_keys: false, secret_keys: false) ⇒ void

This method returns an undefined value.

Save keys.

Raises:

  • (ArgumentError)


242
243
244
245
246
# File 'lib/rnp/rnp.rb', line 242

def save_keys(output:, format:, public_keys: false, secret_keys: false)
  raise ArgumentError, 'At least one of public_keys or secret_keys must be true' if !public_keys && !secret_keys
  flags = load_save_flags(public_keys: public_keys, secret_keys: secret_keys)
  Rnp.call_ffi(:rnp_save_keys, @ptr, format, output.ptr, flags)
end

#secret_key_countObject



322
323
324
325
326
# File 'lib/rnp/rnp.rb', line 322

def secret_key_count
  pcount = FFI::MemoryPointer.new(:size_t)
  Rnp.call_ffi(:rnp_get_secret_key_count, @ptr, pcount)
  pcount.read(:size_t)
end

#sign(input:, output: nil, signers:, armored: nil, compression: nil, creation_time: nil, expiration_time: nil, hash: nil) ⇒ nil, String

Create a signature.



340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
# File 'lib/rnp/rnp.rb', line 340

def sign(input:, output: nil, signers:,
         armored: nil,
         compression: nil,
         creation_time: nil,
         expiration_time: nil,
         hash: nil)
  Output.default(output) do |output_|
    sign = start_sign(input: input, output: output_)
    sign.options = {
      armored: armored,
      compression: compression,
      creation_time: creation_time,
      expiration_time: expiration_time,
      hash: hash
    }
    simple_sign(sign, signers)
  end
end

#start_cleartext_sign(input:, output:) ⇒ Object

Create a cleartext Sign operation.



586
587
588
# File 'lib/rnp/rnp.rb', line 586

def start_cleartext_sign(input:, output:)
  _start_sign(:rnp_op_sign_cleartext_create, input, output)
end

#start_detached_sign(input:, output:) ⇒ Object

Create a detached Sign operation.



594
595
596
# File 'lib/rnp/rnp.rb', line 594

def start_detached_sign(input:, output:)
  _start_sign(:rnp_op_sign_detached_create, input, output)
end

#start_detached_verify(data:, signature:) ⇒ Object

Create a detached Verify operation.



611
612
613
# File 'lib/rnp/rnp.rb', line 611

def start_detached_verify(data:, signature:)
  _start_verify(:rnp_op_verify_detached_create, data, signature)
end

#start_encrypt(input:, output:) ⇒ Object

Create an Encrypt operation.



619
620
621
622
623
624
# File 'lib/rnp/rnp.rb', line 619

def start_encrypt(input:, output:)
  pptr = FFI::MemoryPointer.new(:pointer)
  Rnp.call_ffi(:rnp_op_encrypt_create, pptr, @ptr, input.ptr, output.ptr)
  pencrypt = pptr.read_pointer
  Encrypt.new(pencrypt) unless pencrypt.null?
end

#start_generate(type:) ⇒ Generate

Start a Generate operation.



554
555
556
557
558
559
# File 'lib/rnp/rnp.rb', line 554

def start_generate(type:)
  pptr = FFI::MemoryPointer.new(:pointer)
  Rnp.call_ffi(:rnp_op_generate_create, pptr, @ptr, type.to_s)
  pgen = pptr.read_pointer
  Generate.new(pgen) unless pgen.null?
end

#start_generate_subkey(primary:, type:) ⇒ Generate

Start a Generate operation.



566
567
568
569
570
571
572
# File 'lib/rnp/rnp.rb', line 566

def start_generate_subkey(primary:, type:)
  pptr = FFI::MemoryPointer.new(:pointer)
  Rnp.call_ffi(:rnp_op_generate_subkey_create, pptr, @ptr, primary.ptr,
               type.to_s)
  pgen = pptr.read_pointer
  Generate.new(pgen) unless pgen.null?
end

#start_sign(input:, output:) ⇒ Object

Create a Sign operation.



578
579
580
# File 'lib/rnp/rnp.rb', line 578

def start_sign(input:, output:)
  _start_sign(:rnp_op_sign_create, input, output)
end

#start_verify(input:, output: nil) ⇒ Object

Create a Verify operation.



602
603
604
605
# File 'lib/rnp/rnp.rb', line 602

def start_verify(input:, output: nil)
  output = Output.to_null unless output
  _start_verify(:rnp_op_verify_create, input, output)
end

#symmetric_encrypt(input:, output: nil, passwords:, armored: nil, compression: nil, cipher: nil, aead: nil, s2k_hash: nil, s2k_iterations: 0, s2k_cipher: nil) ⇒ void

This method returns an undefined value.

Encrypt with a password only.



511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
# File 'lib/rnp/rnp.rb', line 511

def symmetric_encrypt(input:, output: nil, passwords:,
                      armored: nil,
                      compression: nil,
                      cipher: nil,
                      aead: nil,
                      s2k_hash: nil,
                      s2k_iterations: 0,
                      s2k_cipher: nil)
  Output.default(output) do |output_|
    enc = start_encrypt(input: input, output: output_)
    enc.options = {
      armored: armored,
      compression: compression,
      cipher: cipher,
      aead: aead,
    }
    passwords = [passwords] if passwords.is_a?(String)
    passwords.each do |password|
      enc.add_password(password,
                       s2k_hash: s2k_hash,
                       s2k_iterations: s2k_iterations,
                       s2k_cipher: s2k_cipher)
    end
    enc.execute
  end
end

#unload_keys(public_keys: true, secret_keys: true) ⇒ Object

Raises:

  • (ArgumentError)


228
229
230
231
232
233
# File 'lib/rnp/rnp.rb', line 228

def unload_keys(public_keys: true, secret_keys: true)
  raise ArgumentError, "At least one of public_keys or secret_keys must be true" \
    if !public_keys && !secret_keys
  flags = unload_keys_flags(public_keys: public_keys, secret_keys: secret_keys)
  Rnp.call_ffi(:rnp_unload_keys, @ptr, flags)
end

#useridsArray<String>

Get a list of all userids.



# File 'lib/rnp/rnp.rb', line 266


#verify(input:, output: nil) ⇒ Object

Verify a signature.



420
421
422
423
# File 'lib/rnp/rnp.rb', line 420

def verify(input:, output: nil)
  verify = start_verify(input: input, output: output)
  verify.execute
end