1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 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 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 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 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
|
= GPGME
This README is better viewed through the YARD formatted documentation:
https://www.rubydoc.info/github/ueno/ruby-gpgme for latest github version,
or https://www.rubydoc.info/gems/gpgme for latest gem release.
{<img src="https://github.com/ueno/ruby-gpgme/actions/workflows/test.yml/badge.svg" alt="Build Status" />}[https://github.com/ueno/ruby-gpgme/actions/workflows/test.yml]
{<img src="https://coveralls.io/repos/ueno/ruby-gpgme/badge.png" alt="Coverage Status" />}[https://coveralls.io/r/ueno/ruby-gpgme]
== Requirements
* Ruby 1.8 or later
* GPGME 1.1.2 or later
* gpg-agent (optional, but recommended)
== Installation
$ gem install gpgme
== API
GPGME provides three levels of API. The highest level API is as simple as it
gets, the mid level API provides more functionality but might be less
user-friendly, and the lowest level API is close to the C interface of GPGME.
=== The highest level API
For example, to create a cleartext signature of the plaintext from
stdin and write the result to stdout can be written as follows.
crypto = GPGME::Crypto.new
crypto.clearsign $stdin, :output => $stdout
=== The mid level API
The same example can be rewritten in the mid level API as follows.
plain = GPGME::Data.new($stdin)
sig = GPGME::Data.new($stdout)
GPGME::Ctx.new do |ctx|
ctx.sign(plain, sig, GPGME::SIG_MODE_CLEAR)
end
=== The lowest level API
The same example can be rewritten in the lowest level API as follows.
ret = []
GPGME::gpgme_new(ret)
ctx = ret.shift
GPGME::gpgme_data_new_from_fd(ret, 0)
plain = ret.shift
GPGME::gpgme_data_new_from_fd(ret, 1)
sig = ret.shift
GPGME::gpgme_op_sign(ctx, plain, sig, GPGME::SIG_MODE_CLEAR)
As you see, it's much harder to write a program in this API than the
highest level API. However, if you are already familiar with the C
interface of GPGME and want to control detailed behavior of GPGME, it
might be useful.
== Usage
All the high level methods attack the mid level <tt>GPGME::Ctx</tt> API. It is
recommended to read through the <tt>GPGME::Ctx.new</tt> methods for common options.
Also, most of the input/output is done via <tt>GPGME::Data</tt> objects that create a
common interface for reading/writing to normal strings, or other common
objects like files. Read the <tt>GPGME::Data</tt> documentation to understand
how it works. Every time the lib needs a <tt>GPGME::Data</tt> object, it will be
automatically converted to it.
=== Crypto
The <tt>GPGME::Crypto</tt> class has the high level convenience methods to encrypt,
decrypt, sign and verify signatures. Here are some examples, but it is
recommended to read through the <tt>GPGME::Crypto</tt> class to see all the options.
* Document encryption via <tt>GPGME::Crypto#encrypt</tt>:
crypto = GPGME::Crypto.new
crypto.encrypt "Hello world!", :recipients => "someone@example.com"
* Symmetric encryption:
crypto = GPGME::Crypto.new :password => "gpgme"
crypto.encrypt "Hello world!", :symmetric => true
* Document decryption via <tt>GPGME::Crypto#decrypt</tt> (including signature verification):
crypto.decrypt File.open("text.gpg")
* Document signing via <tt>GPGME::Crypto#sign</tt>. Also the clearsigning and detached signing.
crypto.sign "I hereby proclaim Github the beneficiary of all my money when I die"
* Sign verification via <tt>GPGME::Crypto#verify</tt>
sign = crypto.sign "Some text"
data = crypto.verify(sign) { |signature| signature.valid? }
=== Key
The <tt>GPGME::Key</tt> object represents a key, and has the high level related
methods to work with them and find them, export, import, deletetion and
creation.
* Key listing
GPGME::Key.find(:secret, "someone@example.com")
# => Returns an array with all the secret keys available in the keychain.
# that match "someone@example.com"
* Key exporting
GPGME::Key.export("someone@example.com")
# => Returns a GPGME::Data object with the exported key.
key = GPGME::Key.find(:secret, "someone@example.com").first
key.export
# => Returns a GPGME::Data object with the exported key.
* Key importing
GPGME::Key.import(File.open("my.key"))
* Key validation
GPGME::Key.valid?(public_key)
# => Returns wheter this key is valid or not
* TODO: Key generation
=== Engine
Provides three convenience methods to obtain information about the gpg engine
one is currently using. For example:
* Getting current information
GPGME::Engine.info.first
# => #<GPGME::EngineInfo:0x00000100d4fbd8
@file_name="/usr/local/bin/gpg",
@protocol=0,
@req_version="1.3.0",
@version="1.4.11">
* Changing home directory to work with different settings:
GPGME::Engine.home_dir = '/tmp'
=== Round trip example using keychain keys
Rather than importing the keys it's possible to specify the recipient
when performing crypto functions. Here's a roundtrip example,
and note that as this is for a console, the <tt>conf.echo = false</tt>
line is to stop IRB complaining when echoing binary data
# Stop IRB echoing everything, which errors with binary data.
# Not required for production code
conf.echo = false
class PassphraseCallback
def initialize(passphrase)
@passphrase = passphrase
end
def call(*args)
fd = args.last
io = IO.for_fd(fd, 'w')
io.puts(@passphrase)
io.flush
end
end
# recipients can be found using $ gpg --list-keys --homedir ./keychain_location
# pub 2048R/A1B2C3D4 2014-01-17
# Use that line to substitute your own. 2048R is the key length and type (RSA in this case)
# If you want to substitute a non-default keychain into the engine do this:
# home_dir = Rails.root.join('keychain_location').to_s
# GPGME::Engine.set_info(GPGME::PROTOCOL_OpenPGP, '/usr/local/bin/gpg', home_dir)
# Note GPG executable location will change across platforms
crypto = GPGME::Crypto.new
options = {:recipients => 'A1B2C3D4'}
plaintext = GPGME::Data.new(File.open(Rails.root.join('Gemfile')))
data = crypto.encrypt plaintext, options
f = File.open(Rails.root.join('Gemfile.gpg'), 'wb')
bytes_written = f.write(data)
f.close
puts bytes_written
crypto = GPGME::Crypto.new
options = {:recipients => 'A1B2C3D4', :passphrase_callback => PassphraseCallback.new('my_passphrase')}
cipthertext = GPGME::Data.new(File.open(Rails.root.join('Gemfile.gpg')))
data = crypto.decrypt cipthertext, options
puts data
== Contributing
To run the local test suite you need bundler and gpg:
bundle
rake compile # simple rake task to compile the extension
rake # runs the test suite
== License
The library itself is licensed under LGPLv2.1+. See the file
COPYING.LESSER and each file for copyright and warranty information.
|