Python bindings for GPGME
Posted September 21th, 2016 by Justus
GPGME 1.7 includes bindings for Python >= 2.7. The bindings are a
port of the pyme
bindings to Python 3 retaining compatibility with
Python 2.7, with a small shim on top to provide a more idiomatic
interface. For the purposes of this post I will refer to the
preexisting bindings that are for Python 2 only pyme2
, and to our
new bindings as pyme3
. Existing applications using pyme2
should
continue to work no changes.
pyme2
offers an interface that is very close to that of GPGME. This
interface exposes all features of the underlying library, but it is
not very "pythonic". Therefore, we made an effort to provide a nicer
interface on top of that. Let me demonstrate how that looks.
One important aspect is how to pass data around. GPGME uses
gpgme_data_t
for that, and in pyme2
one had to explicitly create
pyme.core.Data
objects to pass data to GPGME or to receive data.
With pyme3
one can use every object that implements the buffer
protocol (e.g. bytes
), file-like objects with a fileno
method, or
explicit pyme.Data
objects in places where GPGME expects a
gpgme_data_t
object:
import pyme with pyme.Context(armor=True) as c: ciphertext, _, _ = c.encrypt(b"Hello Python world :)", passphrase="foo")
This will encrypt the given plaintext using symmetric encryption and the given passphrase, wrap it up using the OpenPGP protocol, and encode it using ASCII-armor. The plaintext is easily recovered using:
with pyme.Context() as c: plaintext, _, _ = c.decrypt(ciphertext, passphrase="foo") assert plaintext == b"Hello Python world :)"
If passphrase
is omitted, it is asked for out-of-band using GnuPG's
pinentry mechanism. Alternatively, if one or more recipients are
specified, asymmetric encryption is used. For details, please have a
look at the docstring of pyme.Context.encrypt
.
Most file-like objects can be used without explicit wrapping. This is a filter that decrypts OpenPGP messages in three lines of code:
import sys import pyme pyme.Context().decrypt(sys.stdin, sink=sys.stdout)
For more examples, have a look at the tests and examples shipped with
the bindings under lang/python
.
If you cannot wait until pyme3
is packaged by your distribution, and
you do not want to build GPGME 1.7 from source merely to get pyme3
,
you can build it out-of-tree provided you have at least GPGME 1.6, the
Python development packages, and SWIG. You can get it from pypi or
directly install it using pip
:
# As of this writing, there is no released version uploaded to pypi, # hence we need --pre. $ pip install --pre pyme3