# gpgme.rb # Copyright (C) 2003 Daiki Ueno # This file is a part of Ruby-GPGME. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with GNU Emacs; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # This module provides OO interface to the GPGME library. require 'gpgme_n' module GPGME class GpgmeError < StandardError def initialize(error) @error = error end attr_reader :error def message GPGME::gpgme_strerror(@error) end end def check_error(meth, *args) err = method(meth).call(*args) if err == GPGME_EOF raise EOFError end unless err == GPGME_No_Error raise GpgmeError.new(err) end end module_function :check_error # A class for managing data buffers. class GpgmeData BLOCK_SIZE = 4096 # Create a new GpgmeData instance. def self.new dh = [] GPGME::check_error(:gpgme_data_new, dh) dh[0] end # Create a new GpgmeData instance with internal buffer. def self.new_from_mem(buf) dh = [] GPGME::check_error(:gpgme_data_new_from_mem, dh, buf) dh[0] end def _read(len) buf = "\x0" * len nread = [] GPGME::check_error(:gpgme_data_read, self, buf, len, nread) buf[0 .. nread[0] - 1] end private :_read # Read bytes from this object. If len is supplied, it causes # this method to read up to the number of bytes. def read(len = nil) if len _read(len) else buf = '' begin loop do buf << _read(BLOCK_SIZE) end rescue EOFError buf end end end # Reset the read pointer. def rewind GPGME::check_error(:gpgme_data_rewind, self) end # Write bytes into this object. If len is supplied, it causes # this method to write up to the number of bytes. def write(buf, len = buf.length) GPGME::check_error(:gpgme_data_write, self, buf, len) end # Return the type of the underlying data. def data_type GPGME::gpgme_data_type(self) end # Return the encoding of the underlying data. def encoding GPGME::gpgme_data_get_encoding(self) end # Set the encoding of the underlying data. def encoding=(enc) GPGME::check_error(:gpgme_data_set_encoding, self, enc) enc end end # A context within which all cryptographic operations are performed. class GpgmeCtx # Create a new GpgmeCtx object. def self.new ctx = [] GPGME::check_error(:gpgme_new, ctx) ctx[0] end # Set the protocol used within this context. def protocol=(proto) GPGME::check_error(:gpgme_set_protocol, self, proto) proto end # Return the protocol used within this context. def protocol GPGME::gpgme_get_protocol(self) end # Tell whether the output should be ASCII armored. def armor=(yes) GPGME::gpgme_set_armor(self, yes ? 1 : 0) yes end # Return true if the output is ASCII armored. def armor GPGME::gpgme_get_armor(self) end # Tell whether canonical text mode should be used. def textmode=(yes) GPGME::gpgme_set_textmode(self, yes ? 1 : 0) yes end # Return true if canonical text mode is enabled. def textmode GPGME::gpgme_get_textmode(self) end # Change the default behaviour of the key listing functions. def keylist_mode=(mode) GPGME::gpgme_set_keylist_mode(self, mode) mode end # Returns the current key listing mode. def keylist_mode GPGME::gpgme_get_keylist_mode(self) end # Set the passphrase callback with given hook value. def set_passphrase_cb(passfunc, hook_value = nil) GPGME::gpgme_set_passphrase_cb(self, passfunc, hook_value) end # An array which contains a Proc and an Object. # The former is the passphrase callback and the latter is hook value # passed to it. attr_reader :passphrase_cb # Set the progress callback with given hook value. def set_progress_cb(progfunc, hook_value = nil) GPGME::gpgme_set_progress_cb(self, progfunc, hook_value) end # An array which contains a Proc and an Object. # The former is the progress callback used when progress # information is available and the latter is hook value # passed to it. attr_reader :progress_cb # Initiates a key listing operation for given pattern. # If pattern is nil, all available keys are returned. # If secret_only is true, the list is restricted to secret keys only. def keylist_start(pattern = nil, secret_only = false) GPGME::check_error(:gpgme_op_keylist_start, self, pattern, secret_only ? 1 : 0) end # Returns the next key in the list created by a previous # keylist_start operation. def keylist_next key = [] GPGME::check_error(:gpgme_op_keylist_next, self, key) key[0] end # End a pending key list operation. def keylist_end GPGME::check_error(:gpgme_op_keylist_end, self) end # Convenient method to iterate over keylist. def each_keys(pattern = nil, secret_only = false, &block) keylist_start(pattern, secret_only) begin loop do yield keylist_next end rescue EOFError # The last key in the list has already been returned. rescue keylist_end end end # Generates a new key pair. # If store is true, this method puts the key pair into the # standard key ring. def genkey(parms, store = false) if store pubkey, seckey = nil, nil else pubkey, seckey = GpgmeData.new, GpgmeData.new end GPGME::check_error(:gpgme_op_genkey, self, parms, pubkey, seckey) [pubkey, seckey] end # Extracts the public keys of the recipients. def export(recipients) keydata = GpgmeData.new GPGME::check_error(:gpgme_op_export, self, recipients, keydata) keydata end # Add the keys in the data buffer to the key ring. def import(keydata) GPGME::check_error(:gpgme_op_export, self, keydata) end # Delete the key from the key ring. # If allow_secret is false, only public keys are deleted, # otherwise secret keys are deleted as well. def delete(key, allow_secret = false) GPGME::check_error(:gpgme_op_delete, self, key, allow_secret ? 1 : 0) end # Decrypt the ciphertext and return the plaintext. def decrypt(cipher) plain = GpgmeData.new GPGME::check_error(:gpgme_op_decrypt, self, cipher, plain) plain end # Verify that the signature in the data object is a valid signature. def verify(sig, plain) stat = [] GPGME::check_error(:gpgme_op_verify, self, sig, plain, stat) stat[0] end # Removes the list of signers from this object. def clear_signers gpgme_signers_clear(self) end # Add the key to the list of signers. def add_signer(key) GPGME::check_error(:gpgme_signers_add, self, key) end # Create a signature for the text in the data object. def sign(plain, mode = GPGME::GPGME_SIG_MODE_NORMAL) sig = GpgmeData.new GPGME::check_error(:gpgme_op_sign, self, plain, sig, mode) sig end # Encrypt the plaintext in the data object for the recipients and # return the ciphertext. def encrypt(rset, plain) cipher = GpgmeData.new GPGME::check_error(:gpgme_op_encrypt, self, rset, plain, cipher) cipher end end # A public or secret key. class GpgmeKey private_class_method :new # Return a string in XML format describing the key. def xml GPGME::gpgme_key_get_as_xml(self) end # Return the value of the attribute of the key. def [](what, idx = 0) GPGME::gpgme_key_get_string_attr(self, what, idx) end end # A set of recipients that can be used in an encryption process. class GpgmeRecipients # Create a new GpgmeRecipients instance. def self.new rset = [] GPGME::check_error(:gpgme_recipients_new, rset) rset[0] end # Add the recipient to this set. def add_name(name) GPGME::check_error(:gpgme_recipients_add_name, self, name) end # Return all of the recipient names in an array. def to_a @names.dup.freeze end end end