Class: GPGME::Crypto

Inherits:
Object
  • Object
show all
Defined in:
lib/gpgme/crypto.rb

Overview

Different, independent methods providing the simplest possible API to execute crypto operations via GPG. All methods accept as options the same common options as GPGME::Ctx.new. Read the documentation for that class to know how to customize things further (like output stuff in ASCII armored format, for example).

Examples:

crypto = GPGME::Crypto.new :armor => true
encrypted = crypto.encrypt 'Plain text'

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Crypto

Returns a new instance of Crypto.



18
19
20
# File 'lib/gpgme/crypto.rb', line 18

def initialize(options = {})
  @default_options = options
end

Instance Attribute Details

#default_optionsObject (readonly)

Returns the value of attribute default_options.



16
17
18
# File 'lib/gpgme/crypto.rb', line 16

def default_options
  @default_options
end

Class Method Details

.method_missing(method, *args, &block) ⇒ Object

Allows calling of methods directly in the module without the need to create a new instance.



347
348
349
350
351
352
353
354
# File 'lib/gpgme/crypto.rb', line 347

def self.method_missing(method, *args, &block)
  if GPGME::Crypto.instance_methods(false).include?(method)
    crypto = GPGME::Crypto.new
    crypto.send method, *args, &block
  else
    super
  end
end

Instance Method Details

#clearsign(text, options = {}) ⇒ Object

Clearsigns an element

crypto.clearsign text, options

Same functionality of #sign only doing clearsigns by default.



330
331
332
# File 'lib/gpgme/crypto.rb', line 330

def clearsign(text, options = {})
  sign text, options.merge(:mode => GPGME::SIG_MODE_CLEAR)
end

#decrypt(cipher, options = {}) ⇒ GPGME::Data

Decrypts a previously encrypted element

crypto.decrypt cipher, options, &block

Must have the appropiate key to be able to decrypt, of course. Returns a Data object which can then be read.

Examples:

Simple decrypt

crypto.decrypt encrypted_data

symmetric encryption, or passwored key

crypto.decrypt encrypted_data, :password => "gpgme"

Output to file

file = File.open("decrypted.txt", "w+")
crypto.decrypt encrypted_data, :output => file

Verifying signatures

crypto.decrypt encrypted_data do |signature|
  raise "Signature could not be verified" unless signature.valid?
end

Parameters:

  • cipher

    Must be something that can be converted into a Data object, or a Data object itself. It is the element that will be decrypted.

  • options (Hash) (defaults to: {})

    The optional parameters:

    • :output if specified, it will write the output into it. It will me converted to a Data object, so it can also be a file, for example.

    • If the file was encrypted with symmetric encryption, must provide a :password option.

    • Any other option accepted by GPGME::Ctx.new

  • &block

    In the block all the signatures are yielded, so one could verify them. See examples.

Returns:

Raises:



164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/gpgme/crypto.rb', line 164

def decrypt(cipher, options = {})
  options = @default_options.merge options

  plain_data   = Data.new(options[:output])
  cipher_data  = Data.new(cipher)

  GPGME::Ctx.new(options) do |ctx|
    begin
      ctx.decrypt_verify(cipher_data, plain_data)
    rescue GPGME::Error::UnsupportedAlgorithm => exc
      exc.algorithm = ctx.decrypt_result.unsupported_algorithm
      raise exc
    rescue GPGME::Error::WrongKeyUsage => exc
      exc.key_usage = ctx.decrypt_result.wrong_key_usage
      raise exc
    end

    verify_result = ctx.verify_result
    if verify_result && block_given?
      verify_result.signatures.each do |signature|
        yield signature
      end
    end

  end

  plain_data.seek(0)
  plain_data
end

#detach_sign(text, options = {}) ⇒ Object

Creates a detached signature of an element

crypto.detach_sign text, options

Same functionality of #sign only doing detached signs by default.



340
341
342
# File 'lib/gpgme/crypto.rb', line 340

def detach_sign(text, options = {})
  sign text, options.merge(:mode => GPGME::SIG_MODE_DETACH)
end

#encrypt(plain, options = {}) ⇒ GPGME::Data

Encrypts an element

crypto.encrypt something, options

Will return a Data element which can then be read.

Must have some key imported, look for Key.import to know how to import one, or the gpg documentation to know how to create one

Examples:

returns a Data that can be later encrypted

encrypted = crypto.encrypt "Hello world!"
encrypted.read # => Encrypted stuff

to be decrypted by [email protected].

crypto.encrypt "Hello", :recipients => "[email protected]"

If I didn’t trust any of my keys by default

crypto.encrypt "Hello" # => GPGME::Error::General
crypto.encrypt "Hello", :always_trust => true # => Will work fine

encrypted string that can be decrypted and/or verified

crypto.encrypt "Hello", :sign => true

multiple signers

crypto.encrypt "Hello", :sign => true, :signers => "[email protected]"

writing to a file instead

file = File.open("signed.sec","w+")
crypto.encrypt "Hello", :output => file # output written to signed.sec

Parameters:

  • plain

    Must be something that can be converted into a Data object, or a Data object itself.

  • options (Hash) (defaults to: {})

    The optional parameters are as follows:

    * +:recipients+ for which recipient do you want to encrypt this file. It
      will pick the first one available if none specified. Can be an array of
      identifiers or just one (a string).
    * +:symmetric+ if set to true, will ignore +:recipients+, and will perform
      a symmetric encryption. Must provide a password via the +:password+
      option.
    * +:always_trust+ if set to true specifies all the recipients to be
      trusted, thus not requiring confirmation.
    * +:sign+ if set to true, performs a combined sign and encrypt operation.
    * +:signers+ if +:sign+ specified to true, a list of additional possible
      signers. Must be an array of sign identifiers.
    * +:output+ if specified, it will write the output into it. It will be
      converted to a {GPGME::Data} object, so it could be a file for example.
    * Any other option accepted by {GPGME::Ctx.new}
    

Returns:

Raises:

  • (GPGME::Error::General)

    when trying to encrypt with a key that is not trusted, and :always_trust wasn’t specified



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/gpgme/crypto.rb', line 79

def encrypt(plain, options = {})
  options = @default_options.merge options

  plain_data  = Data.new(plain)
  cipher_data = Data.new(options[:output])
  keys        = Key.find(:public, options[:recipients])
  keys        = nil if options[:symmetric]

  flags = 0
  flags |= GPGME::ENCRYPT_ALWAYS_TRUST if options[:always_trust]

  GPGME::Ctx.new(options) do |ctx|
    begin
      if options[:sign]
        if options[:signers]
          signers = Key.find(:public, options[:signers], :sign)
          ctx.add_signer(*signers)
        end
        ctx.encrypt_sign(keys, plain_data, cipher_data, flags)
      else
        ctx.encrypt(keys, plain_data, cipher_data, flags)
      end
    rescue GPGME::Error::UnusablePublicKey => exc
      exc.keys = ctx.encrypt_result.invalid_recipients
      raise exc
    rescue GPGME::Error::UnusableSecretKey => exc
      exc.keys = ctx.sign_result.invalid_signers
      raise exc
    end
  end

  cipher_data.seek(0)
  cipher_data
end

#sign(text, options = {}) ⇒ GPGME::Data

Creates a signature of a text

crypto.sign text, options

Must have the appropiate key to be able to decrypt, of course. Returns a Data object which can then be read.

Examples:

normal sign

crypto.sign "Hi there"

outputing to a file

file = File.open("text.sign", "w+")
crypto.sign "Hi there", :options => file

doing a detached signature

crypto.sign "Hi there", :mode => GPGME::SIG_MODE_DETACH

specifying the signer

crypto.sign "Hi there", :signer => "[email protected]"

Parameters:

  • text

    The object that will be signed. Must be something that can be converted to Data.

  • options (Hash) (defaults to: {})

    Optional parameters.

    * +:signer+ sign identifier to sign the text with. Will use the first
     key it finds if none specified.
    * +:output+ if specified, it will write the output into it. It will be
      converted to a {GPGME::Data} object, so it could be a file for example.
    * +:mode+ Desired type of signature. Options are:
     - +GPGME::SIG_MODE_NORMAL+ for a normal signature. The default one if
       not specified.
     - +GPGME::SIG_MODE_DETACH+ for a detached signature
     - +GPGME::SIG_MODE_CLEAR+ for a cleartext signature
    * Any other option accepted by {GPGME::Ctx.new}
    

Returns:

Raises:



235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
# File 'lib/gpgme/crypto.rb', line 235

def sign(text, options = {})
  options = @default_options.merge options

  plain  = Data.new(text)
  output = Data.new(options[:output])
  mode   = options[:mode] || GPGME::SIG_MODE_NORMAL

  GPGME::Ctx.new(options) do |ctx|
    if options[:signer]
      signers = Key.find(:secret, options[:signer], :sign)
      ctx.add_signer(*signers)
    end

    begin
      ctx.sign(plain, output, mode)
    rescue GPGME::Error::UnusableSecretKey => exc
      exc.keys = ctx.sign_result.invalid_signers
      raise exc
    end
  end

  output.seek(0)
  output
end

#verify(sig, options = {}) ⇒ GPGME::Data

Verifies a previously signed element

crypto.verify sig, options, &block

Must have the proper keys available.

Examples:

simple verification

sign = crypto.sign("Hi there")
data = crypto.verify(sign) { |signature| signature.valid? }
data.read # => "Hi there"

saving output to file

sign = crypto.sign("Hi there")
out  = File.open("test.asc", "w+")
crypto.verify(sign, :output => out) {|signature| signature.valid?}
out.read # => "Hi there"

verifying a detached signature

sign = crypto.detach_sign("Hi there")
# Will fail
crypto.verify(sign) { |signature| signature.valid? }
# Will succeed
crypto.verify(sign, :signed_text => "hi there") do |signature|
  signature.valid?
end

Parameters:

  • sig

    The signature itself. Must be possible to convert into a Data object, so can be a file.

  • options (Hash) (defaults to: {})
    • :signed_text if the sign is detached, then must be the plain text for which the signature was created.

    • :output where to store the result of the signature. Will be converted to a Data object.

    • Any other option accepted by GPGME::Ctx.new

  • &block

    In the block all the signatures are yielded, so one could verify them. See examples.

Returns:

  • (GPGME::Data)

    unless the sign is detached, the Data object with the plain text. If the sign is detached, will return nil.



304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
# File 'lib/gpgme/crypto.rb', line 304

def verify(sig, options = {})
  options = @default_options.merge options

  sig         = Data.new(sig)
  signed_text = Data.new(options[:signed_text])
  output      = Data.new(options[:output]) unless options[:signed_text]

  GPGME::Ctx.new(options) do |ctx|
    ctx.verify(sig, signed_text, output)
    ctx.verify_result.signatures.each do |signature|
      yield signature
    end
  end

  if output
    output.seek(0)
    output
  end
end