dpcs: python howto
[gpgme.git] / lang / python / docs / rst / gpgme-python-howto.rst
1 .. _intro:
2
3 Introduction
4 ============
5
6 +-----------------------------------+-----------------------------------+
7 | Version:                          | 0.1.4                             |
8 +-----------------------------------+-----------------------------------+
9 | GPGME Version:                    | 1.12.0                            |
10 +-----------------------------------+-----------------------------------+
11 | Author:                           | `Ben                              |
12 |                                   | McGinnes <https://gnupg.org/peopl |
13 |                                   | e/index.html#sec-1-5>`__          |
14 |                                   | <ben@gnupg.org>                   |
15 +-----------------------------------+-----------------------------------+
16 | Author GPG Key:                   | DB4724E6FA4286C92B4E55C4321E4E237 |
17 |                                   | 3590E5D                           |
18 +-----------------------------------+-----------------------------------+
19 | Language:                         | Australian English, British       |
20 |                                   | English                           |
21 +-----------------------------------+-----------------------------------+
22 | xml:lang:                         | en-AU, en-GB, en                  |
23 +-----------------------------------+-----------------------------------+
24
25 This document provides basic instruction in how to use the GPGME Python
26 bindings to programmatically leverage the GPGME library.
27
28 .. _py2-vs-py3:
29
30 Python 2 versus Python 3
31 ------------------------
32
33 Though the GPGME Python bindings themselves provide support for both
34 Python 2 and 3, the focus is unequivocally on Python 3 and specifically
35 from Python 3.4 and above. As a consequence all the examples and
36 instructions in this guide use Python 3 code.
37
38 Much of it will work with Python 2, but much of it also deals with
39 Python 3 byte literals, particularly when reading and writing data.
40 Developers concentrating on Python 2.7, and possibly even 2.6, will need
41 to make the appropriate modifications to support the older string and
42 unicode types as opposed to bytes.
43
44 There are multiple reasons for concentrating on Python 3; some of which
45 relate to the immediate integration of these bindings, some of which
46 relate to longer term plans for both GPGME and the python bindings and
47 some of which relate to the impending EOL period for Python 2.7.
48 Essentially, though, there is little value in tying the bindings to a
49 version of the language which is a dead end and the advantages offered
50 by Python 3 over Python 2 make handling the data types with which GPGME
51 deals considerably easier.
52
53 .. _howto-python3-examples:
54
55 Examples
56 --------
57
58 All of the examples found in this document can be found as Python 3
59 scripts in the ``lang/python/examples/howto`` directory.
60
61 Unofficial Drafts
62 -----------------
63
64 In addition to shipping with each release of GPGME, there is a section
65 on locations to read or download `draft editions <#draft-editions>`__ of
66 this document from at the end of it. These are unofficial versions
67 produced in between major releases.
68
69 .. _new-stuff:
70
71 What\'s New
72 -----------
73
74 The most obviously new point for those reading this guide is this
75 section on other new things, but that\'s hardly important. Not given all
76 the other things which spurred the need for adding this section and its
77 subsections.
78
79 .. _new-stuff-1-12-0:
80
81 New in GPGME 1·12·0
82 ~~~~~~~~~~~~~~~~~~~
83
84 There have been quite a number of additions to GPGME and the Python
85 bindings to it since the last release of GPGME with versions 1.11.0 and
86 1.11.1 in April, 2018.
87
88 The bullet points of new additiions are:
89
90 -  an expanded section on `installing <#installation>`__ and
91    `troubleshooting <#snafu>`__ the Python bindings.
92 -  The release of Python 3.7.0; which appears to be working just fine
93    with our bindings, in spite of intermittent reports of problems for
94    many other Python projects with that new release.
95 -  Python 3.7 has been moved to the head of the specified python
96    versions list in the build process.
97 -  In order to fix some other issues, there are certain underlying
98    functions which are more exposed through the
99    `gpg.Context() <#howto-get-context>`__, but ongoing documentation
100    ought to clarify that or otherwise provide the best means of using
101    the bindings. Some additions to ``gpg.core`` and the ``Context()``,
102    however, were intended (see below).
103 -  Continuing work in identifying and confirming the cause of
104    oft-reported `problems installing the Python bindings on
105    Windows <#snafu-runtime-not-funtime>`__.
106 -  GSOC: Google\'s Surreptitiously Ordered Conscription ... erm ... oh,
107    right; Google\'s Summer of Code. Though there were two hopeful
108    candidates this year; only one ended up involved with the GnuPG
109    Project directly, the other concentrated on an unrelated third party
110    project with closer ties to one of the GNU/Linux distributions than
111    to the GnuPG Project. Thus the Python bindings benefited from GSOC
112    participant Jacob Adams, who added the key\ :sub:`import` function;
113    building on prior work by Tobias Mueller.
114 -  Several new methods functions were added to the gpg.Context(),
115    including: `key\ import <#howto-import-key>`__,
116    `key\ export <#howto-export-key>`__,
117    `key\ exportminimal <#howto-export-public-key>`__ and
118    `key\ exportsecret <#howto-export-secret-key>`__.
119 -  Importing and exporting examples include versions integrated with
120    Marcel Fest\'s recently released `HKP for
121    Python <https://github.com/Selfnet/hkp4py>`__ module. Some
122    `additional notes on this module <#hkp4py>`__ are included at the end
123    of the HOWTO.
124 -  Instructions for dealing with semi-walled garden implementations like
125    ProtonMail are also included. This is intended to make things a
126    little easier when communicating with users of ProtonMail\'s services
127    and should not be construed as an endorsement of said service. The
128    GnuPG Project neither favours, nor disfavours ProtonMail and the
129    majority of this deals with interacting with the ProtonMail
130    keyserver.
131 -  Semi-formalised the location where `draft
132    versions <#draft-editions>`__ of this HOWTO may periodically be
133    accessible. This is both for the reference of others and testing the
134    publishing of the document itself. Renamed this file at around the
135    same time.
136 -  The Texinfo documentation build configuration has been replicated
137    from the parent project in order to make to maintain consistency with
138    that project (and actually ship with each release).
139 -  a reStructuredText (``.rst``) version is also generated for Python
140    developers more used to and comfortable with that format as it is the
141    standard Python documentation format and Python developers may wish
142    to use it with Sphinx. Please note that there has been no testing of
143    the reStructuredText version with Sphinx at all. The reST file was
144    generated by the simple expedient of using
145    `Pandoc <https://pandoc.org/>`__.
146 -  Added a new section for `advanced or experimental
147    use <#advanced-use>`__.
148 -  Began the advanced use cases with `a section <#cython>`__ on using
149    the module with `Cython <http://cython.org/>`__.
150 -  Added a number of new scripts to the ``example/howto/`` directory;
151    some of which may be in advance of their planned sections of the
152    HOWTO (and some are just there because it seemed like a good idea at
153    the time).
154 -  Cleaned up a lot of things under the hood.
155
156 GPGME Concepts
157 ==============
158
159 .. _gpgme-c-api:
160
161 A C API
162 -------
163
164 Unlike many modern APIs with which programmers will be more familiar
165 with these days, the GPGME API is a C API. The API is intended for use
166 by C coders who would be able to access its features by including the
167 ``gpgme.h`` header file with their own C source code and then access its
168 functions just as they would any other C headers.
169
170 This is a very effective method of gaining complete access to the API
171 and in the most efficient manner possible. It does, however, have the
172 drawback that it cannot be directly used by other languages without some
173 means of providing an interface to those languages. This is where the
174 need for bindings in various languages stems.
175
176 .. _gpgme-python-bindings:
177
178 Python bindings
179 ---------------
180
181 The Python bindings for GPGME provide a higher level means of accessing
182 the complete feature set of GPGME itself. It also provides a more
183 pythonic means of calling these API functions.
184
185 The bindings are generated dynamically with SWIG and the copy of
186 ``gpgme.h`` generated when GPGME is compiled.
187
188 This means that a version of the Python bindings is fundamentally tied
189 to the exact same version of GPGME used to generate that copy of
190 ``gpgme.h``.
191
192 .. _gpgme-python-bindings-diffs:
193
194 Difference between the Python bindings and other GnuPG Python packages
195 ----------------------------------------------------------------------
196
197 There have been numerous attempts to add GnuPG support to Python over
198 the years. Some of the most well known are listed here, along with what
199 differentiates them.
200
201 .. _diffs-python-gnupg:
202
203 The python-gnupg package maintained by Vinay Sajip
204 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
205
206 This is arguably the most popular means of integrating GPG with Python.
207 The package utilises the ``subprocess`` module to implement wrappers for
208 the ``gpg`` and ``gpg2`` executables normally invoked on the command
209 line (``gpg.exe`` and ``gpg2.exe`` on Windows).
210
211 The popularity of this package stemmed from its ease of use and
212 capability in providing the most commonly required features.
213
214 Unfortunately it has been beset by a number of security issues in the
215 past; most of which stemmed from using unsafe methods of accessing the
216 command line via the ``subprocess`` calls. While some effort has been
217 made over the last two to three years (as of 2018) to mitigate this,
218 particularly by no longer providing shell access through those
219 subprocess calls, the wrapper is still somewhat limited in the scope of
220 its GnuPG features coverage.
221
222 The python-gnupg package is available under the MIT license.
223
224 .. _diffs-isis-gnupg:
225
226 The gnupg package created and maintained by Isis Lovecruft
227 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
228
229 In 2015 Isis Lovecruft from the Tor Project forked and then
230 re-implemented the python-gnupg package as just gnupg. This new package
231 also relied on subprocess to call the ``gpg`` or ``gpg2`` binaries, but
232 did so somewhat more securely.
233
234 The naming and version numbering selected for this package, however,
235 resulted in conflicts with the original python-gnupg and since its
236 functions were called in a different manner to python-gnupg, the release
237 of this package also resulted in a great deal of consternation when
238 people installed what they thought was an upgrade that subsequently
239 broke the code relying on it.
240
241 The gnupg package is available under the GNU General Public License
242 version 3.0 (or any later version).
243
244 .. _diffs-pyme:
245
246 The PyME package maintained by Martin Albrecht
247 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
248
249 This package is the origin of these bindings, though they are somewhat
250 different now. For details of when and how the PyME package was folded
251 back into GPGME itself see the *Short History* document [1]_ in the
252 Python bindings ``docs`` directory. [2]_
253
254 The PyME package was first released in 2002 and was also the first
255 attempt to implement a low level binding to GPGME. In doing so it
256 provided access to considerably more functionality than either the
257 ``python-gnupg`` or ``gnupg`` packages.
258
259 The PyME package is only available for Python 2.6 and 2.7.
260
261 Porting the PyME package to Python 3.4 in 2015 is what resulted in it
262 being folded into the GPGME project and the current bindings are the end
263 result of that effort.
264
265 The PyME package is available under the same dual licensing as GPGME
266 itself: the GNU General Public License version 2.0 (or any later
267 version) and the GNU Lesser General Public License version 2.1 (or any
268 later version).
269
270 .. _gpgme-python-install:
271
272 GPGME Python bindings installation
273 ==================================
274
275 .. _do-not-use-pypi:
276
277 No PyPI
278 -------
279
280 Most third-party Python packages and modules are available and
281 distributed through the Python Package Installer, known as PyPI.
282
283 Due to the nature of what these bindings are and how they work, it is
284 infeasible to install the GPGME Python bindings in the same way.
285
286 This is because the bindings use SWIG to dynamically generate C bindings
287 against ``gpgme.h`` and ``gpgme.h`` is generated from ``gpgme.h.in`` at
288 compile time when GPGME is built from source. Thus to include a package
289 in PyPI which actually built correctly would require either statically
290 built libraries for every architecture bundled with it or a full
291 implementation of C for each architecture.
292
293 See the additional notes regarding `CFFI and SWIG <#snafu-cffi>`__ at
294 the end of this section for further details.
295
296 .. _gpgme-python-requirements:
297
298 Requirements
299 ------------
300
301 The GPGME Python bindings only have three requirements:
302
303 #. A suitable version of Python 2 or Python 3. With Python 2 that means
304    CPython 2.7 and with Python 3 that means CPython 3.4 or higher.
305 #. `SWIG <https://www.swig.org>`__.
306 #. GPGME itself. Which also means that all of GPGME\'s dependencies must
307    be installed too.
308
309 .. _gpgme-python-recommendations:
310
311 Recommended Additions
312 ~~~~~~~~~~~~~~~~~~~~~
313
314 Though none of the following are absolute requirements, they are all
315 recommended for use with the Python bindings. In some cases these
316 recommendations refer to which version(s) of CPython to use the bindings
317 with, while others refer to third party modules which provide a
318 significant advantage in some way.
319
320 #. If possible, use Python 3 instead of 2.
321 #. Favour a more recent version of Python since even 3.4 is due to reach
322    EOL soon. In production systems and services, Python 3.6 should be
323    robust enough to be relied on.
324 #. If possible add the following Python modules which are not part of
325    the standard library:
326    `Requests <http://docs.python-requests.org/en/latest/index.html>`__,
327    `Cython <http://cython.org/>`__ and
328    `hkp4py <https://github.com/Selfnet/hkp4py>`__. Chances are quite
329    high that at least the first one and maybe two of those will already
330    be installed.
331
332 Note that, as with Cython, some of the planned additions to the
333 `Advanced <#advanced-use>`__ section, will bring with them additional
334 requirements. Most of these will be fairly well known and commonly
335 installed ones, however, which are in many cases likely to have already
336 been installed on many systems or be familiar to Python programmers.
337
338 Installation
339 ------------
340
341 Installing the Python bindings is effectively achieved by compiling and
342 installing GPGME itself.
343
344 Once SWIG is installed with Python and all the dependencies for GPGME
345 are installed you only need to confirm that the version(s) of Python you
346 want the bindings installed for are in your ``$PATH``.
347
348 By default GPGME will attempt to install the bindings for the most
349 recent or highest version number of Python 2 and Python 3 it detects in
350 ``$PATH``. It specifically checks for the ``python`` and ``python3``
351 executables first and then checks for specific version numbers.
352
353 For Python 2 it checks for these executables in this order: ``python``,
354 ``python2`` and ``python2.7``.
355
356 For Python 3 it checks for these executables in this order: ``python3``,
357 ``python3.7``, ``python3.6``, ``python3.5`` and ``python3.4``. [3]_
358
359 On systems where ``python`` is actually ``python3`` and not ``python2``
360 it may be possible that ``python2`` may be overlooked, but there have
361 been no reports of that actually occurring as yet.
362
363 In the three months or so since the release of Python 3.7.0 there has
364 been extensive testing and work with these bindings with no issues
365 specifically relating to the new version of Python or any of the new
366 features of either the language or the bindings. This has also been the
367 case with Python 3.7.1rc1. With that in mind and given the release of
368 Python 3.7.1 is scheduled for around the same time as GPGME 1.12.0, the
369 order of preferred Python versions has been changed to move Python 3.7
370 ahead of Python 3.6.
371
372 .. _install-gpgme:
373
374 Installing GPGME
375 ~~~~~~~~~~~~~~~~
376
377 See the GPGME ``README`` file for details of how to install GPGME from
378 source.
379
380 .. _snafu:
381
382 Known Issues
383 ------------
384
385 There are a few known issues with the current build process and the
386 Python bindings. For the most part these are easily addressed should
387 they be encountered.
388
389 .. _snafu-a-swig-of-this-builds-character:
390
391 Breaking Builds
392 ~~~~~~~~~~~~~~~
393
394 Occasionally when installing GPGME with the Python bindings included it
395 may be observed that the ``make`` portion of that process induces a
396 large very number of warnings and, eventually errors which end that part
397 of the build process. Yet following that with ``make check`` and
398 ``make install`` appears to work seamlessly.
399
400 The cause of this is related to the way SWIG needs to be called to
401 dynamically generate the C bindings for GPGME in the first place. So the
402 entire process will always produce ``lang/python/python2-gpg/`` and
403 ``lang/python/python3-gpg/`` directories. These should contain the build
404 output generated during compilation, including the complete bindings and
405 module installed into ``site-packages``.
406
407 Occasionally the errors in the early part or some other conflict (e.g.
408 not installing as **root** or **su**) may result in nothing being
409 installed to the relevant ``site-packages`` directory and the build
410 directory missing a lot of expected files. Even when this occurs, the
411 solution is actually quite simple and will always work.
412
413 That solution is simply to run the following commands as either the
414 **root** user or prepended with ``sudo -H``\  [4]_ in the
415 ``lang/python/`` directory:
416
417 .. code:: shell
418
419    /path/to/pythonX.Y setup.py build
420    /path/to/pythonX.Y setup.py build
421    /path/to/pythonX.Y setup.py install
422
423 Yes, the build command does need to be run twice. Yes, you still need to
424 run the potentially failing or incomplete steps during the
425 ``configure``, ``make`` and ``make install`` steps with installing
426 GPGME. This is because those steps generate a lot of essential files
427 needed, both by and in order to create, the bindings (including both the
428 ``setup.py`` and ``gpgme.h`` files).
429
430 #. IMPORTANT Note
431
432    If specifying a selected number of languages to create bindings for,
433    try to leave Python last. Currently the majority of the other
434    language bindings are also preceding Python of either version when
435    listed alphabetically and so that just happens by default currently.
436
437    If Python is set to precede one of the other languages then it is
438    possible that the errors described here may interrupt the build
439    process before generating bindings for those other languages. In
440    these cases it may be preferable to configure all preferred language
441    bindings separately with alternative ``configure`` steps for GPGME
442    using the ``--enable-languages=$LANGUAGE`` option.
443
444 .. _snafu-lessons-for-the-lazy:
445
446 Reinstalling Responsibly
447 ~~~~~~~~~~~~~~~~~~~~~~~~
448
449 Regardless of whether you\'re installing for one version of Python or
450 several, there will come a point where reinstallation is required. With
451 most Python module installations, the installed files go into the
452 relevant site-packages directory and are then forgotten about. Then the
453 module is upgraded, the new files are copied over the old and that\'s
454 the end of the matter.
455
456 While the same is true of these bindings, there have been intermittent
457 issues observed on some platforms which have benefited significantly
458 from removing all the previous installations of the bindings before
459 installing the updated versions.
460
461 Removing the previous version(s) is simply a matter of changing to the
462 relevant ``site-packages`` directory for the version of Python in
463 question and removing the ``gpg/`` directory and any accompanying
464 egg-info files for that module.
465
466 In most cases this will require root or administration privileges on the
467 system, but the same is true of installing the module in the first
468 place.
469
470 .. _snafu-the-full-monty:
471
472 Multiple installations
473 ~~~~~~~~~~~~~~~~~~~~~~
474
475 For a veriety of reasons it may be either necessary or just preferable
476 to install the bindings to alternative installed Python versions which
477 meet the requirements of these bindings.
478
479 On POSIX systems this will generally be most simply achieved by running
480 the manual installation commands (build, build, install) as described in
481 the previous section for each Python installation the bindings need to
482 be installed to.
483
484 As per the SWIG documentation: the compilers, libraries and runtime used
485 to build GPGME and the Python Bindings **must** match those used to
486 compile Python itself, including the version number(s) (at least going
487 by major version numbers and probably minor numbers too).
488
489 On most POSIX systems, including OS X, this will very likely be the case
490 in most, if not all, cases.
491
492 .. _snafu-runtime-not-funtime:
493
494 Won\'t Work With Windows
495 ~~~~~~~~~~~~~~~~~~~~~~~~
496
497 There are semi-regular reports of Windows users having considerable
498 difficulty in installing and using the Python bindings at all. Very
499 often, possibly even always, these reports come from Cygwin users and/or
500 MinGW users and/or Msys2 users. Though not all of them have been
501 confirmed, it appears that these reports have also come from people who
502 installed Python using the Windows installer files from the `Python
503 website <https://python.org>`__ (i.e. mostly MSI installers, sometimes
504 self-extracting ``.exe`` files).
505
506 The Windows versions of Python are not built using Cygwin, MinGW or
507 Msys2; they\'re built using Microsoft Visual Studio. Furthermore the
508 version used is *considerably* more advanced than the version which
509 MinGW obtained a small number of files from many years ago in order to
510 be able to compile anything at all. Not only that, but there are changes
511 to the version of Visual Studio between some micro releases, though that
512 is is particularly the case with Python 2.7, since it has been kept
513 around far longer than it should have been.
514
515 There are two theoretical solutions to this issue:
516
517 #. Compile and install the GnuPG stack, including GPGME and the Python
518    bibdings using the same version of Microsoft Visual Studio used by
519    the Python Foundation to compile the version of Python installed.
520
521    If there are multiple versions of Python then this will need to be
522    done with each different version of Visual Studio used.
523
524 #. Compile and install Python using the same tools used by choice, such
525    as MinGW or Msys2.
526
527 Do **not** use the official Windows installer for Python unless
528 following the first method.
529
530 In this type of situation it may even be for the best to accept that
531 there are less limitations on permissive software than free software and
532 simply opt to use a recent version of the Community Edition of Microsoft
533 Visual Studio to compile and build all of it, no matter what.
534
535 Investigations into the extent or the limitations of this issue are
536 ongoing.
537
538 .. _snafu-cffi:
539
540 CFFI is the Best™ and GPGME should use it instead of SWIG
541 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
542
543 There are many reasons for favouring
544 `CFFI <https://cffi.readthedocs.io/en/latest/overview.html>`__ and
545 proponents of it are quite happy to repeat these things as if all it
546 would take to switch from SWIG to CFFI is repeating that list as if it
547 were a new concept.
548
549 The fact is that there are things which Python\'s CFFI implementation
550 cannot handle in the GPGME C code. Beyond that there are features of
551 SWIG which are simply not available with CFFI at all. SWIG generates the
552 bindings to Python using the ``gpgme.h`` file, but that file is not a
553 single version shipped with each release, it too is generated when GPGME
554 is compiled.
555
556 CFFI is currently unable to adapt to such a potentially mutable
557 codebase. If there were some means of applying SWIG\'s dynamic code
558 generation to produce the Python/CFFI API modes of accessing the GPGME
559 libraries (or the source source code directly), but such a thing does
560 not exist yet either and it currently appears that work is needed in at
561 least one of CFFI\'s dependencies before any of this can be addressed.
562
563 So if you\'re a massive fan of CFFI; that\'s great, but if you want this
564 project to switch to CFFI then rather than just insisting that it
565 should, I\'d suggest you volunteer to bring CFFI up to the level this
566 project needs.
567
568 If you\'re actually seriously considering doing so, then I\'d suggest
569 taking the ``gpgme-tool.c`` file in the GPGME ``src/`` directory and
570 getting that to work with any of the CFFI API methods (not the ABI
571 methods, they\'ll work with pretty much anything). When you start
572 running into trouble with \"ifdefs\" then you\'ll know what sort of
573 things are lacking. That doesn\'t even take into account the amount of
574 work saved via SWIG\'s code generation techniques either.
575
576 .. _snafu-venv:
577
578 Virtualised Environments
579 ~~~~~~~~~~~~~~~~~~~~~~~~
580
581 It is fairly common practice amongst Python developers to, as much as
582 possible, use packages like virtualenv to keep various things that are
583 to be installed from interfering with each other. Given how much of the
584 GPGME bindings is often at odds with the usual pythonic way of doing
585 things, it stands to reason that this would be called into question too.
586
587 As it happens the answer as to whether or not the bindings can be used
588 with virtualenv, the answer is both yes and no.
589
590 In general we recommend installing to the relevant path and matching
591 prefix of GPGME itself. Which means that when GPGME, and ideally the
592 rest of the GnuPG stack, is installed to a prefix like ``/usr/local`` or
593 ``/opt/local`` then the bindings would need to be installed to the main
594 Python installation and not a virtualised abstraction. Attempts to
595 separate the two in the past have been known to cause weird and
596 intermittent errors ranging from minor annoyances to complete failures
597 in the build process.
598
599 As a consequence we only recommend building with and installing to the
600 main Python installations within the same prefix as GPGME is installed
601 to or which are found by GPGME\'s configuration stage immediately prior
602 to running the make commands. Which is exactly what the compiling and
603 installing process of GPGME does by default.
604
605 Once that is done, however, it appears that a copy the compiled module
606 may be installed into a virtualenv of the same major and minor version
607 matching the build. Alternatively it is possible to utilise a
608 ``sites.pth`` file in the ``site-packages/`` directory of a viertualenv
609 installation, which links back to the system installations corresponding
610 directory in order to import anything installed system wide. This may or
611 may not be appropriate on a case by case basis.
612
613 Though extensive testing of either of these options is not yet complete,
614 preliminary testing of them indicates that both are viable as long as
615 the main installation is complete. Which means that certain other
616 options normally restricted to virtual environments are also available,
617 including integration with pythonic test suites (e.g.
618 `pytest <https://docs.pytest.org/en/latest/index.html>`__) and other
619 large projects.
620
621 That said, it is worth reiterating the warning regarding non-standard
622 installations. If one were to attempt to install the bindings only to a
623 virtual environment without somehow also including the full GnuPG stack
624 (or enough of it as to include GPGME) then it is highly likely that
625 errors would be encountered at some point and more than a little likely
626 that the build process itself would break.
627
628 If a degree of separation from the main operating system is still
629 required in spite of these warnings, then consider other forms of
630 virtualisation. Either a virtual machine (e.g.
631 `VirtualBox <https://www.virtualbox.org/>`__), a hardware emulation
632 layer (e.g. `QEMU <https://www.qemu.org/>`__) or an application
633 container (e.g. `Docker <https://www.docker.com/why-docker>`__).
634
635 Finally it should be noted that the limited tests conducted thus far
636 have been using the ``virtualenv`` command in a new directory to create
637 the virtual python environment. As opposed to the standard ``python3
638 -m venv`` and it is possible that this will make a difference depending
639 on the system and version of Python in use. Another option is to run the
640 command ``python3 -m virtualenv /path/to/install/virtual/thingy``
641 instead.
642
643 .. _howto-fund-a-mental:
644
645 Fundamentals
646 ============
647
648 Before we can get to the fun stuff, there are a few matters regarding
649 GPGME\'s design which hold true whether you\'re dealing with the C code
650 directly or these Python bindings.
651
652 .. _no-rest-for-the-wicked:
653
654 No REST
655 -------
656
657 The first part of which is or will be fairly blatantly obvious upon
658 viewing the first example, but it\'s worth reiterating anyway. That
659 being that this API is **not** a REST API. Nor indeed could it ever be
660 one.
661
662 Most, if not all, Python programmers (and not just Python programmers)
663 know how easy it is to work with a RESTful API. In fact they\'ve become
664 so popular that many other APIs attempt to emulate REST-like behaviour
665 as much as they are able. Right down to the use of JSON formatted output
666 to facilitate the use of their API without having to retrain developers.
667
668 This API does not do that. It would not be able to do that and also
669 provide access to the entire C API on which it\'s built. It does,
670 however, provide a very pythonic interface on top of the direct bindings
671 and it\'s this pythonic layer that this HOWTO deals with.
672
673 .. _howto-get-context:
674
675 Context
676 -------
677
678 One of the reasons which prevents this API from being RESTful is that
679 most operations require more than one instruction to the API to perform
680 the task. Sure, there are certain functions which can be performed
681 simultaneously, particularly if the result known or strongly anticipated
682 (e.g. selecting and encrypting to a key known to be in the public
683 keybox).
684
685 There are many more, however, which cannot be manipulated so readily:
686 they must be performed in a specific sequence and the result of one
687 operation has a direct bearing on the outcome of subsequent operations.
688 Not merely by generating an error either.
689
690 When dealing with this type of persistent state on the web, full of both
691 the RESTful and REST-like, it\'s most commonly referred to as a session.
692 In GPGME, however, it is called a context and every operation type has
693 one.
694
695 .. _howto-keys:
696
697 Working with keys
698 =================
699
700 .. _howto-keys-selection:
701
702 Key selection
703 -------------
704
705 Selecting keys to encrypt to or to sign with will be a common occurrence
706 when working with GPGMe and the means available for doing so are quite
707 simple.
708
709 They do depend on utilising a Context; however once the data is recorded
710 in another variable, that Context does not need to be the same one which
711 subsequent operations are performed.
712
713 The easiest way to select a specific key is by searching for that key\'s
714 key ID or fingerprint, preferably the full fingerprint without any
715 spaces in it. A long key ID will probably be okay, but is not advised
716 and short key IDs are already a problem with some being generated to
717 match specific patterns. It does not matter whether the pattern is upper
718 or lower case.
719
720 So this is the best method:
721
722 .. code:: python
723
724    import gpg
725
726    k = gpg.Context().keylist(pattern="258E88DCBD3CD44D8E7AB43F6ECB6AF0DEADBEEF")
727    keys = list(k)
728
729 This is passable and very likely to be common:
730
731 .. code:: python
732
733    import gpg
734
735    k = gpg.Context().keylist(pattern="0x6ECB6AF0DEADBEEF")
736    keys = list(k)
737
738 And this is a really bad idea:
739
740 .. code:: python
741
742    import gpg
743
744    k = gpg.Context().keylist(pattern="0xDEADBEEF")
745    keys = list(k)
746
747 Alternatively it may be that the intention is to create a list of keys
748 which all match a particular search string. For instance all the
749 addresses at a particular domain, like this:
750
751 .. code:: python
752
753    import gpg
754
755    ncsc = gpg.Context().keylist(pattern="ncsc.mil")
756    nsa = list(ncsc)
757
758 .. _howto-keys-counting:
759
760 Counting keys
761 ~~~~~~~~~~~~~
762
763 Counting the number of keys in your public keybox (``pubring.kbx``), the
764 format which has superseded the old keyring format (``pubring.gpg`` and
765 ``secring.gpg``), or the number of secret keys is a very simple task.
766
767 .. code:: python
768
769    import gpg
770
771    c = gpg.Context()
772    seckeys = c.keylist(pattern=None, secret=True)
773    pubkeys = c.keylist(pattern=None, secret=False)
774
775    seclist = list(seckeys)
776    secnum = len(seclist)
777
778    publist = list(pubkeys)
779    pubnum = len(publist)
780
781    print("""
782      Number of secret keys:  {0}
783      Number of public keys:  {1}
784    """.format(secnum, pubnum))
785
786 NOTE: The `Cython <#cython>`__ introduction in the `Advanced and
787 Experimental <#advanced-use>`__ section uses this same key counting code
788 with Cython to demonstrate some areas where Cython can improve
789 performance even with the bindings. Users with large public keyrings or
790 keyboxes, for instance, should consider these options if they are
791 comfortable with using Cython.
792
793 .. _howto-get-key:
794
795 Get key
796 -------
797
798 An alternative method of getting a single key via its fingerprint is
799 available directly within a Context with ``Context().get_key``. This is
800 the preferred method of selecting a key in order to modify it, sign or
801 certify it and for obtaining relevant data about a single key as a part
802 of other functions; when verifying a signature made by that key, for
803 instance.
804
805 By default this method will select public keys, but it can select secret
806 keys as well.
807
808 This first example demonstrates selecting the current key of Werner
809 Koch, which is due to expire at the end of 2018:
810
811 .. code:: python
812
813    import gpg
814
815    fingerprint = "80615870F5BAD690333686D0F2AD85AC1E42B367"
816    key = gpg.Context().get_key(fingerprint)
817
818 Whereas this example demonstrates selecting the author\'s current key
819 with the ``secret`` key word argument set to ``True``:
820
821 .. code:: python
822
823    import gpg
824
825    fingerprint = "DB4724E6FA4286C92B4E55C4321E4E2373590E5D"
826    key = gpg.Context().get_key(fingerprint, secret=True)
827
828 It is, of course, quite possible to select expired, disabled and revoked
829 keys with this function, but only to effectively display information
830 about those keys.
831
832 It is also possible to use both unicode or string literals and byte
833 literals with the fingerprint when getting a key in this way.
834
835 .. _howto-import-key:
836
837 Importing keys
838 --------------
839
840 Importing keys is possible with the ``key_import()`` method and takes
841 one argument which is a bytes literal object containing either the
842 binary or ASCII armoured key data for one or more keys.
843
844 The following example retrieves one or more keys from the SKS keyservers
845 via the web using the requests module. Since requests returns the
846 content as a bytes literal object, we can then use that directly to
847 import the resulting data into our keybox.
848
849 .. code:: python
850
851    import gpg
852    import os.path
853    import requests
854
855    c = gpg.Context()
856    url = "https://sks-keyservers.net/pks/lookup"
857    pattern = input("Enter the pattern to search for key or user IDs: ")
858    payload = {"op": "get", "search": pattern}
859
860    r = requests.get(url, verify=True, params=payload)
861    result = c.key_import(r.content)
862
863    if result is not None and hasattr(result, "considered") is False:
864        print(result)
865    elif result is not None and hasattr(result, "considered") is True:
866        num_keys = len(result.imports)
867        new_revs = result.new_revocations
868        new_sigs = result.new_signatures
869        new_subs = result.new_sub_keys
870        new_uids = result.new_user_ids
871        new_scrt = result.secret_imported
872        nochange = result.unchanged
873        print("""
874      The total number of keys considered for import was:  {0}
875
876         Number of keys revoked:  {1}
877       Number of new signatures:  {2}
878          Number of new subkeys:  {3}
879         Number of new user IDs:  {4}
880      Number of new secret keys:  {5}
881       Number of unchanged keys:  {6}
882
883      The key IDs for all considered keys were:
884    """.format(num_keys, new_revs, new_sigs, new_subs, new_uids, new_scrt,
885               nochange))
886        for i in range(num_keys):
887            print("{0}\n".format(result.imports[i].fpr))
888    else:
889        pass
890
891 NOTE: When searching for a key ID of any length or a fingerprint
892 (without spaces), the SKS servers require the the leading ``0x``
893 indicative of hexadecimal be included. Also note that the old short key
894 IDs (e.g. ``0xDEADBEEF``) should no longer be used due to the relative
895 ease by which such key IDs can be reproduced, as demonstrated by the
896 Evil32 Project in 2014 (which was subsequently exploited in 2016).
897
898 .. _import-protonmail:
899
900 Working with ProtonMail
901 ~~~~~~~~~~~~~~~~~~~~~~~
902
903 Here is a variation on the example above which checks the constrained
904 ProtonMail keyserver for ProtonMail public keys.
905
906 .. code:: python
907
908    import gpg
909    import requests
910    import sys
911
912    print("""
913    This script searches the ProtonMail key server for the specified key and
914    imports it.
915    """)
916
917    c = gpg.Context(armor=True)
918    url = "https://api.protonmail.ch/pks/lookup"
919    ksearch = []
920
921    if len(sys.argv) >= 2:
922        keyterm = sys.argv[1]
923    else:
924        keyterm = input("Enter the key ID, UID or search string: ")
925
926    if keyterm.count("@") == 2 and keyterm.startswith("@") is True:
927        ksearch.append(keyterm[1:])
928        ksearch.append(keyterm[1:])
929        ksearch.append(keyterm[1:])
930    elif keyterm.count("@") == 1 and keyterm.startswith("@") is True:
931        ksearch.append("{0}@protonmail.com".format(keyterm[1:]))
932        ksearch.append("{0}@protonmail.ch".format(keyterm[1:]))
933        ksearch.append("{0}@pm.me".format(keyterm[1:]))
934    elif keyterm.count("@") == 0:
935        ksearch.append("{0}@protonmail.com".format(keyterm))
936        ksearch.append("{0}@protonmail.ch".format(keyterm))
937        ksearch.append("{0}@pm.me".format(keyterm))
938    elif keyterm.count("@") == 2 and keyterm.startswith("@") is False:
939        uidlist = keyterm.split("@")
940        for uid in uidlist:
941            ksearch.append("{0}@protonmail.com".format(uid))
942            ksearch.append("{0}@protonmail.ch".format(uid))
943            ksearch.append("{0}@pm.me".format(uid))
944    elif keyterm.count("@") > 2:
945        uidlist = keyterm.split("@")
946        for uid in uidlist:
947            ksearch.append("{0}@protonmail.com".format(uid))
948            ksearch.append("{0}@protonmail.ch".format(uid))
949            ksearch.append("{0}@pm.me".format(uid))
950    else:
951        ksearch.append(keyterm)
952
953    for k in ksearch:
954        payload = {"op": "get", "search": k}
955        try:
956            r = requests.get(url, verify=True, params=payload)
957            if r.ok is True:
958                result = c.key_import(r.content)
959            elif r.ok is False:
960                result = r.content
961        except Exception as e:
962            result = None
963
964        if result is not None and hasattr(result, "considered") is False:
965            print("{0} for {1}".format(result.decode(), k))
966        elif result is not None and hasattr(result, "considered") is True:
967            num_keys = len(result.imports)
968            new_revs = result.new_revocations
969            new_sigs = result.new_signatures
970            new_subs = result.new_sub_keys
971            new_uids = result.new_user_ids
972            new_scrt = result.secret_imported
973            nochange = result.unchanged
974            print("""
975    The total number of keys considered for import was:  {0}
976
977    With UIDs wholely or partially matching the following string:
978
979            {1}
980
981       Number of keys revoked:  {2}
982     Number of new signatures:  {3}
983        Number of new subkeys:  {4}
984       Number of new user IDs:  {5}
985    Number of new secret keys:  {6}
986     Number of unchanged keys:  {7}
987
988    The key IDs for all considered keys were:
989    """.format(num_keys, k, new_revs, new_sigs, new_subs, new_uids, new_scrt,
990               nochange))
991            for i in range(num_keys):
992                print(result.imports[i].fpr)
993            print("")
994        elif result is None:
995            print(e)
996
997 Both the above example,
998 `pmkey-import.py <../examples/howto/pmkey-import.py>`__, and a version
999 which prompts for an alternative GnuPG home directory,
1000 `pmkey-import-alt.py <../examples/howto/pmkey-import-alt.py>`__, are
1001 available with the other examples and are executable scripts.
1002
1003 Note that while the ProtonMail servers are based on the SKS servers,
1004 their server is related more to their API and is not feature complete by
1005 comparison to the servers in the SKS pool. One notable difference being
1006 that the ProtonMail server does not permit non ProtonMail users to
1007 update their own keys, which could be a vector for attacking ProtonMail
1008 users who may not receive a key\'s revocation if it had been
1009 compromised.
1010
1011 .. _import-hkp4py:
1012
1013 Importing with HKP for Python
1014 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1015
1016 Performing the same tasks with the `hkp4py
1017 module <https://github.com/Selfnet/hkp4py>`__ (available via PyPI) is
1018 not too much different, but does provide a number of options of benefit
1019 to end users. Not least of which being the ability to perform some
1020 checks on a key before importing it or not. For instance it may be the
1021 policy of a site or project to only import keys which have not been
1022 revoked. The hkp4py module permits such checks prior to the importing of
1023 the keys found.
1024
1025 .. code:: python
1026
1027    import gpg
1028    import hkp4py
1029    import sys
1030
1031    c = gpg.Context()
1032    server = hkp4py.KeyServer("hkps://hkps.pool.sks-keyservers.net")
1033    results = []
1034
1035    if len(sys.argv) > 2:
1036        pattern = " ".join(sys.argv[1:])
1037    elif len(sys.argv) == 2:
1038        pattern = sys.argv[1]
1039    else:
1040        pattern = input("Enter the pattern to search for keys or user IDs: ")
1041
1042    try:
1043        keys = server.search(pattern)
1044        print("Found {0} key(s).".format(len(keys)))
1045    except Exception as e:
1046        keys = []
1047        for logrus in pattern.split():
1048            if logrus.startswith("0x") is True:
1049                key = server.search(logrus)
1050            else:
1051                key = server.search("0x{0}".format(logrus))
1052            keys.append(key[0])
1053        print("Found {0} key(s).".format(len(keys)))
1054
1055    for key in keys:
1056        import_result = c.key_import(key.key_blob)
1057        results.append(import_result)
1058
1059    for result in results:
1060        if result is not None and hasattr(result, "considered") is False:
1061            print(result)
1062        elif result is not None and hasattr(result, "considered") is True:
1063            num_keys = len(result.imports)
1064            new_revs = result.new_revocations
1065            new_sigs = result.new_signatures
1066            new_subs = result.new_sub_keys
1067            new_uids = result.new_user_ids
1068            new_scrt = result.secret_imported
1069            nochange = result.unchanged
1070            print("""
1071    The total number of keys considered for import was:  {0}
1072
1073       Number of keys revoked:  {1}
1074     Number of new signatures:  {2}
1075        Number of new subkeys:  {3}
1076       Number of new user IDs:  {4}
1077    Number of new secret keys:  {5}
1078     Number of unchanged keys:  {6}
1079
1080    The key IDs for all considered keys were:
1081    """.format(num_keys, new_revs, new_sigs, new_subs, new_uids, new_scrt,
1082               nochange))
1083            for i in range(num_keys):
1084                print(result.imports[i].fpr)
1085            print("")
1086        else:
1087            pass
1088
1089 Since the hkp4py module handles multiple keys just as effectively as one
1090 (``keys`` is a list of responses per matching key), the example above is
1091 able to do a little bit more with the returned data before anything is
1092 actually imported.
1093
1094 .. _import-protonmail-hkp4py:
1095
1096 Importing from ProtonMail with HKP for Python
1097 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1098
1099 Though this can provide certain benefits even when working with
1100 ProtonMail, the scope is somewhat constrained there due to the
1101 limitations of the ProtonMail keyserver.
1102
1103 For instance, searching the SKS keyserver pool for the term \"gnupg\"
1104 produces hundreds of results from any time the word appears in any part
1105 of a user ID. Performing the same search on the ProtonMail keyserver
1106 returns zero results, even though there are at least two test accounts
1107 which include it as part of the username.
1108
1109 The cause of this discrepancy is the deliberate configuration of that
1110 server by ProtonMail to require an exact match of the full email address
1111 of the ProtonMail user whose key is being requested. Presumably this is
1112 intended to reduce breaches of privacy of their users as an email
1113 address must already be known before a key for that address can be
1114 obtained.
1115
1116 #. Import from ProtonMail via HKP for Python Example no. 1
1117
1118    The following script is avalable with the rest of the examples under
1119    the somewhat less than original name, ``pmkey-import-hkp.py``.
1120
1121    .. code:: python
1122
1123       import gpg
1124       import hkp4py
1125       import os.path
1126       import sys
1127
1128       print("""
1129       This script searches the ProtonMail key server for the specified key and
1130       imports it.
1131
1132       Usage:  pmkey-import-hkp.py [search strings]
1133       """)
1134
1135       c = gpg.Context(armor=True)
1136       server = hkp4py.KeyServer("hkps://api.protonmail.ch")
1137       keyterms = []
1138       ksearch = []
1139       allkeys = []
1140       results = []
1141       paradox = []
1142       homeless = None
1143
1144       if len(sys.argv) > 2:
1145           keyterms = sys.argv[1:]
1146       elif len(sys.argv) == 2:
1147           keyterm = sys.argv[1]
1148           keyterms.append(keyterm)
1149       else:
1150           key_term = input("Enter the key ID, UID or search string: ")
1151           keyterms = key_term.split()
1152
1153       for keyterm in keyterms:
1154           if keyterm.count("@") == 2 and keyterm.startswith("@") is True:
1155               ksearch.append(keyterm[1:])
1156               ksearch.append(keyterm[1:])
1157               ksearch.append(keyterm[1:])
1158           elif keyterm.count("@") == 1 and keyterm.startswith("@") is True:
1159               ksearch.append("{0}@protonmail.com".format(keyterm[1:]))
1160               ksearch.append("{0}@protonmail.ch".format(keyterm[1:]))
1161               ksearch.append("{0}@pm.me".format(keyterm[1:]))
1162           elif keyterm.count("@") == 0:
1163               ksearch.append("{0}@protonmail.com".format(keyterm))
1164               ksearch.append("{0}@protonmail.ch".format(keyterm))
1165               ksearch.append("{0}@pm.me".format(keyterm))
1166           elif keyterm.count("@") == 2 and keyterm.startswith("@") is False:
1167               uidlist = keyterm.split("@")
1168               for uid in uidlist:
1169                   ksearch.append("{0}@protonmail.com".format(uid))
1170                   ksearch.append("{0}@protonmail.ch".format(uid))
1171                   ksearch.append("{0}@pm.me".format(uid))
1172           elif keyterm.count("@") > 2:
1173               uidlist = keyterm.split("@")
1174               for uid in uidlist:
1175                   ksearch.append("{0}@protonmail.com".format(uid))
1176                   ksearch.append("{0}@protonmail.ch".format(uid))
1177                   ksearch.append("{0}@pm.me".format(uid))
1178           else:
1179               ksearch.append(keyterm)
1180
1181       for k in ksearch:
1182           print("Checking for key for: {0}".format(k))
1183           try:
1184               keys = server.search(k)
1185               if isinstance(keys, list) is True:
1186                   for key in keys:
1187                       allkeys.append(key)
1188                       try:
1189                           import_result = c.key_import(key.key_blob)
1190                       except Exception as e:
1191                           import_result = c.key_import(key.key)
1192               else:
1193                   paradox.append(keys)
1194                   import_result = None
1195           except Exception as e:
1196               import_result = None
1197           results.append(import_result)
1198
1199       for result in results:
1200           if result is not None and hasattr(result, "considered") is False:
1201               print("{0} for {1}".format(result.decode(), k))
1202           elif result is not None and hasattr(result, "considered") is True:
1203               num_keys = len(result.imports)
1204               new_revs = result.new_revocations
1205               new_sigs = result.new_signatures
1206               new_subs = result.new_sub_keys
1207               new_uids = result.new_user_ids
1208               new_scrt = result.secret_imported
1209               nochange = result.unchanged
1210               print("""
1211       The total number of keys considered for import was:  {0}
1212
1213       With UIDs wholely or partially matching the following string:
1214
1215               {1}
1216
1217          Number of keys revoked:  {2}
1218        Number of new signatures:  {3}
1219           Number of new subkeys:  {4}
1220          Number of new user IDs:  {5}
1221       Number of new secret keys:  {6}
1222        Number of unchanged keys:  {7}
1223
1224       The key IDs for all considered keys were:
1225       """.format(num_keys, k, new_revs, new_sigs, new_subs, new_uids, new_scrt,
1226                  nochange))
1227               for i in range(num_keys):
1228                   print(result.imports[i].fpr)
1229               print("")
1230           elif result is None:
1231               pass
1232
1233 #. Import from ProtonMail via HKP for Python Example no. 2
1234
1235    Like its counterpart above, this script can also be found with the
1236    rest of the examples, by the name pmkey-import-hkp-alt.py.
1237
1238    With this script a modicum of effort has been made to treat anything
1239    passed as a ``homedir`` which either does not exist or which is not a
1240    directory, as also being a pssible user ID to check for. It\'s not
1241    guaranteed to pick up on all such cases, but it should cover most of
1242    them.
1243
1244    .. code:: python
1245
1246       import gpg
1247       import hkp4py
1248       import os.path
1249       import sys
1250
1251       print("""
1252       This script searches the ProtonMail key server for the specified key and
1253       imports it.  Optionally enables specifying a different GnuPG home directory.
1254
1255       Usage:  pmkey-import-hkp.py [homedir] [search string]
1256          or:  pmkey-import-hkp.py [search string]
1257       """)
1258
1259       c = gpg.Context(armor=True)
1260       server = hkp4py.KeyServer("hkps://api.protonmail.ch")
1261       keyterms = []
1262       ksearch = []
1263       allkeys = []
1264       results = []
1265       paradox = []
1266       homeless = None
1267
1268       if len(sys.argv) > 3:
1269           homedir = sys.argv[1]
1270           keyterms = sys.argv[2:]
1271       elif len(sys.argv) == 3:
1272           homedir = sys.argv[1]
1273           keyterm = sys.argv[2]
1274           keyterms.append(keyterm)
1275       elif len(sys.argv) == 2:
1276           homedir = ""
1277           keyterm = sys.argv[1]
1278           keyterms.append(keyterm)
1279       else:
1280           keyterm = input("Enter the key ID, UID or search string: ")
1281           homedir = input("Enter the GPG configuration directory path (optional): ")
1282           keyterms.append(keyterm)
1283
1284       if len(homedir) == 0:
1285           homedir = None
1286           homeless = False
1287
1288       if homedir is not None:
1289           if homedir.startswith("~"):
1290               if os.path.exists(os.path.expanduser(homedir)) is True:
1291                   if os.path.isdir(os.path.expanduser(homedir)) is True:
1292                       c.home_dir = os.path.realpath(os.path.expanduser(homedir))
1293                   else:
1294                       homeless = True
1295               else:
1296                   homeless = True
1297           elif os.path.exists(os.path.realpath(homedir)) is True:
1298               if os.path.isdir(os.path.realpath(homedir)) is True:
1299                   c.home_dir = os.path.realpath(homedir)
1300               else:
1301                   homeless = True
1302           else:
1303               homeless = True
1304
1305       # First check to see if the homedir really is a homedir and if not, treat it as
1306       # a search string.
1307       if homeless is True:
1308           keyterms.append(homedir)
1309           c.home_dir = None
1310       else:
1311           pass
1312
1313       for keyterm in keyterms:
1314           if keyterm.count("@") == 2 and keyterm.startswith("@") is True:
1315               ksearch.append(keyterm[1:])
1316               ksearch.append(keyterm[1:])
1317               ksearch.append(keyterm[1:])
1318           elif keyterm.count("@") == 1 and keyterm.startswith("@") is True:
1319               ksearch.append("{0}@protonmail.com".format(keyterm[1:]))
1320               ksearch.append("{0}@protonmail.ch".format(keyterm[1:]))
1321               ksearch.append("{0}@pm.me".format(keyterm[1:]))
1322           elif keyterm.count("@") == 0:
1323               ksearch.append("{0}@protonmail.com".format(keyterm))
1324               ksearch.append("{0}@protonmail.ch".format(keyterm))
1325               ksearch.append("{0}@pm.me".format(keyterm))
1326           elif keyterm.count("@") == 2 and keyterm.startswith("@") is False:
1327               uidlist = keyterm.split("@")
1328               for uid in uidlist:
1329                   ksearch.append("{0}@protonmail.com".format(uid))
1330                   ksearch.append("{0}@protonmail.ch".format(uid))
1331                   ksearch.append("{0}@pm.me".format(uid))
1332           elif keyterm.count("@") > 2:
1333               uidlist = keyterm.split("@")
1334               for uid in uidlist:
1335                   ksearch.append("{0}@protonmail.com".format(uid))
1336                   ksearch.append("{0}@protonmail.ch".format(uid))
1337                   ksearch.append("{0}@pm.me".format(uid))
1338           else:
1339               ksearch.append(keyterm)
1340
1341       for k in ksearch:
1342           print("Checking for key for: {0}".format(k))
1343           try:
1344               keys = server.search(k)
1345               if isinstance(keys, list) is True:
1346                   for key in keys:
1347                       allkeys.append(key)
1348                       try:
1349                           import_result = c.key_import(key.key_blob)
1350                       except Exception as e:
1351                           import_result = c.key_import(key.key)
1352               else:
1353                   paradox.append(keys)
1354                   import_result = None
1355           except Exception as e:
1356               import_result = None
1357           results.append(import_result)
1358
1359       for result in results:
1360           if result is not None and hasattr(result, "considered") is False:
1361               print("{0} for {1}".format(result.decode(), k))
1362           elif result is not None and hasattr(result, "considered") is True:
1363               num_keys = len(result.imports)
1364               new_revs = result.new_revocations
1365               new_sigs = result.new_signatures
1366               new_subs = result.new_sub_keys
1367               new_uids = result.new_user_ids
1368               new_scrt = result.secret_imported
1369               nochange = result.unchanged
1370               print("""
1371       The total number of keys considered for import was:  {0}
1372
1373       With UIDs wholely or partially matching the following string:
1374
1375               {1}
1376
1377          Number of keys revoked:  {2}
1378        Number of new signatures:  {3}
1379           Number of new subkeys:  {4}
1380          Number of new user IDs:  {5}
1381       Number of new secret keys:  {6}
1382        Number of unchanged keys:  {7}
1383
1384       The key IDs for all considered keys were:
1385       """.format(num_keys, k, new_revs, new_sigs, new_subs, new_uids, new_scrt,
1386                  nochange))
1387               for i in range(num_keys):
1388                   print(result.imports[i].fpr)
1389               print("")
1390           elif result is None:
1391               pass
1392
1393 .. _howto-export-key:
1394
1395 Exporting keys
1396 --------------
1397
1398 Exporting keys remains a reasonably simple task, but has been separated
1399 into three different functions for the OpenPGP cryptographic engine. Two
1400 of those functions are for exporting public keys and the third is for
1401 exporting secret keys.
1402
1403 .. _howto-export-public-key:
1404
1405 Exporting public keys
1406 ~~~~~~~~~~~~~~~~~~~~~
1407
1408 There are two methods of exporting public keys, both of which are very
1409 similar to the other. The default method, ``key_export()``, will export
1410 a public key or keys matching a specified pattern as normal. The
1411 alternative, the ``key_export_minimal()`` method, will do the same thing
1412 except producing a minimised output with extra signatures and third
1413 party signatures or certifications removed.
1414
1415 .. code:: python
1416
1417    import gpg
1418    import os.path
1419    import sys
1420
1421    print("""
1422    This script exports one or more public keys.
1423    """)
1424
1425    c = gpg.Context(armor=True)
1426
1427    if len(sys.argv) >= 4:
1428        keyfile = sys.argv[1]
1429        logrus = sys.argv[2]
1430        homedir = sys.argv[3]
1431    elif len(sys.argv) == 3:
1432        keyfile = sys.argv[1]
1433        logrus = sys.argv[2]
1434        homedir = input("Enter the GPG configuration directory path (optional): ")
1435    elif len(sys.argv) == 2:
1436        keyfile = sys.argv[1]
1437        logrus = input("Enter the UID matching the key(s) to export: ")
1438        homedir = input("Enter the GPG configuration directory path (optional): ")
1439    else:
1440        keyfile = input("Enter the path and filename to save the secret key to: ")
1441        logrus = input("Enter the UID matching the key(s) to export: ")
1442        homedir = input("Enter the GPG configuration directory path (optional): ")
1443
1444    if homedir.startswith("~"):
1445        if os.path.exists(os.path.expanduser(homedir)) is True:
1446            c.home_dir = os.path.expanduser(homedir)
1447        else:
1448            pass
1449    elif os.path.exists(homedir) is True:
1450        c.home_dir = homedir
1451    else:
1452        pass
1453
1454    try:
1455        result = c.key_export(pattern=logrus)
1456    except:
1457        result = c.key_export(pattern=None)
1458
1459    if result is not None:
1460        with open(keyfile, "wb") as f:
1461            f.write(result)
1462    else:
1463        pass
1464
1465 It should be noted that the result will only return ``None`` when a
1466 search pattern has been entered, but has not matched any keys. When the
1467 search pattern itself is set to ``None`` this triggers the exporting of
1468 the entire public keybox.
1469
1470 .. code:: python
1471
1472    import gpg
1473    import os.path
1474    import sys
1475
1476    print("""
1477    This script exports one or more public keys in minimised form.
1478    """)
1479
1480    c = gpg.Context(armor=True)
1481
1482    if len(sys.argv) >= 4:
1483        keyfile = sys.argv[1]
1484        logrus = sys.argv[2]
1485        homedir = sys.argv[3]
1486    elif len(sys.argv) == 3:
1487        keyfile = sys.argv[1]
1488        logrus = sys.argv[2]
1489        homedir = input("Enter the GPG configuration directory path (optional): ")
1490    elif len(sys.argv) == 2:
1491        keyfile = sys.argv[1]
1492        logrus = input("Enter the UID matching the key(s) to export: ")
1493        homedir = input("Enter the GPG configuration directory path (optional): ")
1494    else:
1495        keyfile = input("Enter the path and filename to save the secret key to: ")
1496        logrus = input("Enter the UID matching the key(s) to export: ")
1497        homedir = input("Enter the GPG configuration directory path (optional): ")
1498
1499    if homedir.startswith("~"):
1500        if os.path.exists(os.path.expanduser(homedir)) is True:
1501            c.home_dir = os.path.expanduser(homedir)
1502        else:
1503            pass
1504    elif os.path.exists(homedir) is True:
1505        c.home_dir = homedir
1506    else:
1507        pass
1508
1509    try:
1510        result = c.key_export_minimal(pattern=logrus)
1511    except:
1512        result = c.key_export_minimal(pattern=None)
1513
1514    if result is not None:
1515        with open(keyfile, "wb") as f:
1516            f.write(result)
1517    else:
1518        pass
1519
1520 .. _howto-export-secret-key:
1521
1522 Exporting secret keys
1523 ~~~~~~~~~~~~~~~~~~~~~
1524
1525 Exporting secret keys is, functionally, very similar to exporting public
1526 keys; save for the invocation of ``pinentry`` via ``gpg-agent`` in order
1527 to securely enter the key\'s passphrase and authorise the export.
1528
1529 The following example exports the secret key to a file which is then set
1530 with the same permissions as the output files created by the command
1531 line secret key export options.
1532
1533 .. code:: python
1534
1535    import gpg
1536    import os
1537    import os.path
1538    import sys
1539
1540    print("""
1541    This script exports one or more secret keys.
1542
1543    The gpg-agent and pinentry are invoked to authorise the export.
1544    """)
1545
1546    c = gpg.Context(armor=True)
1547
1548    if len(sys.argv) >= 4:
1549        keyfile = sys.argv[1]
1550        logrus = sys.argv[2]
1551        homedir = sys.argv[3]
1552    elif len(sys.argv) == 3:
1553        keyfile = sys.argv[1]
1554        logrus = sys.argv[2]
1555        homedir = input("Enter the GPG configuration directory path (optional): ")
1556    elif len(sys.argv) == 2:
1557        keyfile = sys.argv[1]
1558        logrus = input("Enter the UID matching the secret key(s) to export: ")
1559        homedir = input("Enter the GPG configuration directory path (optional): ")
1560    else:
1561        keyfile = input("Enter the path and filename to save the secret key to: ")
1562        logrus = input("Enter the UID matching the secret key(s) to export: ")
1563        homedir = input("Enter the GPG configuration directory path (optional): ")
1564
1565    if len(homedir) == 0:
1566        homedir = None
1567    elif homedir.startswith("~"):
1568        userdir = os.path.expanduser(homedir)
1569        if os.path.exists(userdir) is True:
1570            homedir = os.path.realpath(userdir)
1571        else:
1572            homedir = None
1573    else:
1574        homedir = os.path.realpath(homedir)
1575
1576    if os.path.exists(homedir) is False:
1577        homedir = None
1578    else:
1579        if os.path.isdir(homedir) is False:
1580            homedir = None
1581        else:
1582            pass
1583
1584    if homedir is not None:
1585        c.home_dir = homedir
1586    else:
1587        pass
1588
1589    try:
1590        result = c.key_export_secret(pattern=logrus)
1591    except:
1592        result = c.key_export_secret(pattern=None)
1593
1594    if result is not None:
1595        with open(keyfile, "wb") as f:
1596            f.write(result)
1597        os.chmod(keyfile, 0o600)
1598    else:
1599        pass
1600
1601 Alternatively the approach of the following script can be used. This
1602 longer example saves the exported secret key(s) in files in the GnuPG
1603 home directory, in addition to setting the file permissions as only
1604 readable and writable by the user. It also exports the secret key(s)
1605 twice in order to output both GPG binary (``.gpg``) and ASCII armoured
1606 (``.asc``) files.
1607
1608 .. code:: python
1609
1610    import gpg
1611    import os
1612    import os.path
1613    import subprocess
1614    import sys
1615
1616    print("""
1617    This script exports one or more secret keys as both ASCII armored and binary
1618    file formats, saved in files within the user's GPG home directory.
1619
1620    The gpg-agent and pinentry are invoked to authorise the export.
1621    """)
1622
1623    if sys.platform == "win32":
1624        gpgconfcmd = "gpgconf.exe --list-dirs homedir"
1625    else:
1626        gpgconfcmd = "gpgconf --list-dirs homedir"
1627
1628    a = gpg.Context(armor=True)
1629    b = gpg.Context()
1630    c = gpg.Context()
1631
1632    if len(sys.argv) >= 4:
1633        keyfile = sys.argv[1]
1634        logrus = sys.argv[2]
1635        homedir = sys.argv[3]
1636    elif len(sys.argv) == 3:
1637        keyfile = sys.argv[1]
1638        logrus = sys.argv[2]
1639        homedir = input("Enter the GPG configuration directory path (optional): ")
1640    elif len(sys.argv) == 2:
1641        keyfile = sys.argv[1]
1642        logrus = input("Enter the UID matching the secret key(s) to export: ")
1643        homedir = input("Enter the GPG configuration directory path (optional): ")
1644    else:
1645        keyfile = input("Enter the filename to save the secret key to: ")
1646        logrus = input("Enter the UID matching the secret key(s) to export: ")
1647        homedir = input("Enter the GPG configuration directory path (optional): ")
1648
1649    if len(homedir) == 0:
1650        homedir = None
1651    elif homedir.startswith("~"):
1652        userdir = os.path.expanduser(homedir)
1653        if os.path.exists(userdir) is True:
1654            homedir = os.path.realpath(userdir)
1655        else:
1656            homedir = None
1657    else:
1658        homedir = os.path.realpath(homedir)
1659
1660    if os.path.exists(homedir) is False:
1661        homedir = None
1662    else:
1663        if os.path.isdir(homedir) is False:
1664            homedir = None
1665        else:
1666            pass
1667
1668    if homedir is not None:
1669        c.home_dir = homedir
1670    else:
1671        pass
1672
1673    if c.home_dir is not None:
1674        if c.home_dir.endswith("/"):
1675            gpgfile = "{0}{1}.gpg".format(c.home_dir, keyfile)
1676            ascfile = "{0}{1}.asc".format(c.home_dir, keyfile)
1677        else:
1678            gpgfile = "{0}/{1}.gpg".format(c.home_dir, keyfile)
1679            ascfile = "{0}/{1}.asc".format(c.home_dir, keyfile)
1680    else:
1681        if os.path.exists(os.environ["GNUPGHOME"]) is True:
1682            hd = os.environ["GNUPGHOME"]
1683        else:
1684            try:
1685                hd = subprocess.getoutput(gpgconfcmd)
1686            except:
1687                process = subprocess.Popen(gpgconfcmd.split(),
1688                                           stdout=subprocess.PIPE)
1689                procom = process.communicate()
1690                if sys.version_info[0] == 2:
1691                    hd = procom[0].strip()
1692                else:
1693                    hd = procom[0].decode().strip()
1694        gpgfile = "{0}/{1}.gpg".format(hd, keyfile)
1695        ascfile = "{0}/{1}.asc".format(hd, keyfile)
1696
1697    try:
1698        a_result = a.key_export_secret(pattern=logrus)
1699        b_result = b.key_export_secret(pattern=logrus)
1700    except:
1701        a_result = a.key_export_secret(pattern=None)
1702        b_result = b.key_export_secret(pattern=None)
1703
1704    if a_result is not None:
1705        with open(ascfile, "wb") as f:
1706            f.write(a_result)
1707        os.chmod(ascfile, 0o600)
1708    else:
1709        pass
1710
1711    if b_result is not None:
1712        with open(gpgfile, "wb") as f:
1713            f.write(b_result)
1714        os.chmod(gpgfile, 0o600)
1715    else:
1716        pass
1717
1718 .. _howto-send-public-key:
1719
1720 Sending public keys to the SKS Keyservers
1721 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1722
1723 As with the previous section on importing keys, the ``hkp4py`` module
1724 adds another option with exporting keys in order to send them to the
1725 public keyservers.
1726
1727 The following example demonstrates how this may be done.
1728
1729 .. code:: python
1730
1731    import gpg
1732    import hkp4py
1733    import os.path
1734    import sys
1735
1736    print("""
1737    This script sends one or more public keys to the SKS keyservers and is
1738    essentially a slight variation on the export-key.py script.
1739    """)
1740
1741    c = gpg.Context(armor=True)
1742    server = hkp4py.KeyServer("hkps://hkps.pool.sks-keyservers.net")
1743
1744    if len(sys.argv) > 2:
1745        logrus = " ".join(sys.argv[1:])
1746    elif len(sys.argv) == 2:
1747        logrus = sys.argv[1]
1748    else:
1749        logrus = input("Enter the UID matching the key(s) to send: ")
1750
1751    if len(logrus) > 0:
1752        try:
1753            export_result = c.key_export(pattern=logrus)
1754        except Exception as e:
1755            print(e)
1756            export_result = None
1757    else:
1758        export_result = c.key_export(pattern=None)
1759
1760    if export_result is not None:
1761        try:
1762            try:
1763                send_result = server.add(export_result)
1764            except:
1765                send_result = server.add(export_result.decode())
1766            if send_result is not None:
1767                print(send_result)
1768            else:
1769                pass
1770        except Exception as e:
1771            print(e)
1772    else:
1773        pass
1774
1775 An expanded version of this script with additional functions for
1776 specifying an alternative homedir location is in the examples directory
1777 as ``send-key-to-keyserver.py``.
1778
1779 The ``hkp4py`` module appears to handle both string and byte literal
1780 text data equally well, but the GPGME bindings deal primarily with byte
1781 literal data only and so this script sends in that format first, then
1782 tries the string literal form.
1783
1784 .. _howto-the-basics:
1785
1786 Basic Functions
1787 ===============
1788
1789 The most frequently called features of any cryptographic library will be
1790 the most fundamental tasks for encryption software. In this section we
1791 will look at how to programmatically encrypt data, decrypt it, sign it
1792 and verify signatures.
1793
1794 .. _howto-basic-encryption:
1795
1796 Encryption
1797 ----------
1798
1799 Encrypting is very straight forward. In the first example below the
1800 message, ``text``, is encrypted to a single recipient\'s key. In the
1801 second example the message will be encrypted to multiple recipients.
1802
1803 .. _howto-basic-encryption-single:
1804
1805 Encrypting to one key
1806 ~~~~~~~~~~~~~~~~~~~~~
1807
1808 Once the the Context is set the main issues with encrypting data is
1809 essentially reduced to key selection and the keyword arguments specified
1810 in the ``gpg.Context().encrypt()`` method.
1811
1812 Those keyword arguments are: ``recipients``, a list of keys encrypted to
1813 (covered in greater detail in the following section); ``sign``, whether
1814 or not to sign the plaintext data, see subsequent sections on signing
1815 and verifying signatures below (defaults to ``True``); ``sink``, to
1816 write results or partial results to a secure sink instead of returning
1817 it (defaults to ``None``); ``passphrase``, only used when utilising
1818 symmetric encryption (defaults to ``None``); ``always_trust``, used to
1819 override the trust model settings for recipient keys (defaults to
1820 ``False``); ``add_encrypt_to``, utilises any preconfigured
1821 ``encrypt-to`` or ``default-key`` settings in the user\'s ``gpg.conf``
1822 file (defaults to ``False``); ``prepare``, prepare for encryption
1823 (defaults to ``False``); ``expect_sign``, prepare for signing (defaults
1824 to ``False``); ``compress``, compresses the plaintext prior to
1825 encryption (defaults to ``True``).
1826
1827 .. code:: python
1828
1829    import gpg
1830
1831    a_key = "0x12345678DEADBEEF"
1832    text = b"""Some text to test with.
1833
1834    Since the text in this case must be bytes, it is most likely that
1835    the input form will be a separate file which is opened with "rb"
1836    as this is the simplest method of obtaining the correct data format.
1837    """
1838
1839    c = gpg.Context(armor=True)
1840    rkey = list(c.keylist(pattern=a_key, secret=False))
1841    ciphertext, result, sign_result = c.encrypt(text, recipients=rkey, sign=False)
1842
1843    with open("secret_plans.txt.asc", "wb") as afile:
1844        afile.write(ciphertext)
1845
1846 Though this is even more likely to be used like this; with the plaintext
1847 input read from a file, the recipient keys used for encryption
1848 regardless of key trust status and the encrypted output also encrypted
1849 to any preconfigured keys set in the ``gpg.conf`` file:
1850
1851 .. code:: python
1852
1853    import gpg
1854
1855    a_key = "0x12345678DEADBEEF"
1856
1857    with open("secret_plans.txt", "rb") as afile:
1858        text = afile.read()
1859
1860    c = gpg.Context(armor=True)
1861    rkey = list(c.keylist(pattern=a_key, secret=False))
1862    ciphertext, result, sign_result = c.encrypt(text, recipients=rkey, sign=True,
1863                                                always_trust=True,
1864                                                add_encrypt_to=True)
1865
1866    with open("secret_plans.txt.asc", "wb") as afile:
1867        afile.write(ciphertext)
1868
1869 If the ``recipients`` paramater is empty then the plaintext is encrypted
1870 symmetrically. If no ``passphrase`` is supplied as a parameter or via a
1871 callback registered with the ``Context()`` then an out-of-band prompt
1872 for the passphrase via pinentry will be invoked.
1873
1874 .. _howto-basic-encryption-multiple:
1875
1876 Encrypting to multiple keys
1877 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
1878
1879 Encrypting to multiple keys essentially just expands upon the key
1880 selection process and the recipients from the previous examples.
1881
1882 The following example encrypts a message (``text``) to everyone with an
1883 email address on the ``gnupg.org`` domain, [5]_ but does *not* encrypt
1884 to a default key or other key which is configured to normally encrypt
1885 to.
1886
1887 .. code:: python
1888
1889    import gpg
1890
1891    text = b"""Oh look, another test message.
1892
1893    The same rules apply as with the previous example and more likely
1894    than not, the message will actually be drawn from reading the
1895    contents of a file or, maybe, from entering data at an input()
1896    prompt.
1897
1898    Since the text in this case must be bytes, it is most likely that
1899    the input form will be a separate file which is opened with "rb"
1900    as this is the simplest method of obtaining the correct data
1901    format.
1902    """
1903
1904    c = gpg.Context(armor=True)
1905    rpattern = list(c.keylist(pattern="@gnupg.org", secret=False))
1906    logrus = []
1907
1908    for i in range(len(rpattern)):
1909        if rpattern[i].can_encrypt == 1:
1910            logrus.append(rpattern[i])
1911
1912    ciphertext, result, sign_result = c.encrypt(text, recipients=logrus,
1913                                                sign=False, always_trust=True)
1914
1915    with open("secret_plans.txt.asc", "wb") as afile:
1916        afile.write(ciphertext)
1917
1918 All it would take to change the above example to sign the message and
1919 also encrypt the message to any configured default keys would be to
1920 change the ``c.encrypt`` line to this:
1921
1922 .. code:: python
1923
1924    ciphertext, result, sign_result = c.encrypt(text, recipients=logrus,
1925                                                always_trust=True,
1926                                                add_encrypt_to=True)
1927
1928 The only keyword arguments requiring modification are those for which
1929 the default values are changing. The default value of ``sign`` is
1930 ``True``, the default of ``always_trust`` is ``False``, the default of
1931 ``add_encrypt_to`` is ``False``.
1932
1933 If ``always_trust`` is not set to ``True`` and any of the recipient keys
1934 are not trusted (e.g. not signed or locally signed) then the encryption
1935 will raise an error. It is possible to mitigate this somewhat with
1936 something more like this:
1937
1938 .. code:: python
1939
1940    import gpg
1941
1942    with open("secret_plans.txt.asc", "rb") as afile:
1943        text = afile.read()
1944
1945    c = gpg.Context(armor=True)
1946    rpattern = list(c.keylist(pattern="@gnupg.org", secret=False))
1947    logrus = []
1948
1949    for i in range(len(rpattern)):
1950        if rpattern[i].can_encrypt == 1:
1951            logrus.append(rpattern[i])
1952
1953        try:
1954            ciphertext, result, sign_result = c.encrypt(text, recipients=logrus,
1955                                                        add_encrypt_to=True)
1956        except gpg.errors.InvalidRecipients as e:
1957            for i in range(len(e.recipients)):
1958                for n in range(len(logrus)):
1959                    if logrus[n].fpr == e.recipients[i].fpr:
1960                        logrus.remove(logrus[n])
1961                    else:
1962                        pass
1963            try:
1964                ciphertext, result, sign_result = c.encrypt(text,
1965                                                            recipients=logrus,
1966                                                            add_encrypt_to=True)
1967                with open("secret_plans.txt.asc", "wb") as afile:
1968                    afile.write(ciphertext)
1969            except:
1970                pass
1971
1972 This will attempt to encrypt to all the keys searched for, then remove
1973 invalid recipients if it fails and try again.
1974
1975 .. _howto-basic-decryption:
1976
1977 Decryption
1978 ----------
1979
1980 Decrypting something encrypted to a key in one\'s secret keyring is
1981 fairly straight forward.
1982
1983 In this example code, however, preconfiguring either ``gpg.Context()``
1984 or ``gpg.core.Context()`` as ``c`` is unnecessary because there is no
1985 need to modify the Context prior to conducting the decryption and since
1986 the Context is only used once, setting it to ``c`` simply adds lines for
1987 no gain.
1988
1989 .. code:: python
1990
1991    import gpg
1992
1993    ciphertext = input("Enter path and filename of encrypted file: ")
1994    newfile = input("Enter path and filename of file to save decrypted data to: ")
1995
1996    with open(ciphertext, "rb") as cfile:
1997        try:
1998            plaintext, result, verify_result = gpg.Context().decrypt(cfile)
1999        except gpg.errors.GPGMEError as e:
2000            plaintext = None
2001            print(e)
2002
2003    if plaintext is not None:
2004        with open(newfile, "wb") as nfile:
2005            nfile.write(plaintext)
2006        else:
2007            pass
2008
2009 The data available in ``plaintext`` in this example is the decrypted
2010 content as a byte object, the recipient key IDs and algorithms in
2011 ``result`` and the results of verifying any signatures of the data in
2012 ``verify_result``.
2013
2014 .. _howto-basic-signing:
2015
2016 Signing text and files
2017 ----------------------
2018
2019 The following sections demonstrate how to specify keys to sign with.
2020
2021 .. _howto-basic-signing-signers:
2022
2023 Signing key selection
2024 ~~~~~~~~~~~~~~~~~~~~~
2025
2026 By default GPGME and the Python bindings will use the default key
2027 configured for the user invoking the GPGME API. If there is no default
2028 key specified and there is more than one secret key available it may be
2029 necessary to specify the key or keys with which to sign messages and
2030 files.
2031
2032 .. code:: python
2033
2034    import gpg
2035
2036    logrus = input("Enter the email address or string to match signing keys to: ")
2037    hancock = gpg.Context().keylist(pattern=logrus, secret=True)
2038    sig_src = list(hancock)
2039
2040 The signing examples in the following sections include the explicitly
2041 designated ``signers`` parameter in two of the five examples; once where
2042 the resulting signature would be ASCII armoured and once where it would
2043 not be armoured.
2044
2045 While it would be possible to enter a key ID or fingerprint here to
2046 match a specific key, it is not possible to enter two fingerprints and
2047 match two keys since the patten expects a string, bytes or None and not
2048 a list. A string with two fingerprints won\'t match any single key.
2049
2050 .. _howto-basic-signing-normal:
2051
2052 Normal or default signing messages or files
2053 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2054
2055 The normal or default signing process is essentially the same as is most
2056 often invoked when also encrypting a message or file. So when the
2057 encryption component is not utilised, the result is to produce an
2058 encoded and signed output which may or may not be ASCII armoured and
2059 which may or may not also be compressed.
2060
2061 By default compression will be used unless GnuPG detects that the
2062 plaintext is already compressed. ASCII armouring will be determined
2063 according to the value of ``gpg.Context().armor``.
2064
2065 The compression algorithm is selected in much the same way as the
2066 symmetric encryption algorithm or the hash digest algorithm is when
2067 multiple keys are involved; from the preferences saved into the key
2068 itself or by comparison with the preferences with all other keys
2069 involved.
2070
2071 .. code:: python
2072
2073    import gpg
2074
2075    text0 = """Declaration of ... something.
2076
2077    """
2078    text = text0.encode()
2079
2080    c = gpg.Context(armor=True, signers=sig_src)
2081    signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.NORMAL)
2082
2083    with open("/path/to/statement.txt.asc", "w") as afile:
2084        afile.write(signed_data.decode())
2085
2086 Though everything in this example is accurate, it is more likely that
2087 reading the input data from another file and writing the result to a new
2088 file will be performed more like the way it is done in the next example.
2089 Even if the output format is ASCII armoured.
2090
2091 .. code:: python
2092
2093    import gpg
2094
2095    with open("/path/to/statement.txt", "rb") as tfile:
2096        text = tfile.read()
2097
2098    c = gpg.Context()
2099    signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.NORMAL)
2100
2101    with open("/path/to/statement.txt.sig", "wb") as afile:
2102        afile.write(signed_data)
2103
2104 .. _howto-basic-signing-detached:
2105
2106 Detached signing messages and files
2107 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2108
2109 Detached signatures will often be needed in programmatic uses of GPGME,
2110 either for signing files (e.g. tarballs of code releases) or as a
2111 component of message signing (e.g. PGP/MIME encoded email).
2112
2113 .. code:: python
2114
2115    import gpg
2116
2117    text0 = """Declaration of ... something.
2118
2119    """
2120    text = text0.encode()
2121
2122    c = gpg.Context(armor=True)
2123    signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.DETACH)
2124
2125    with open("/path/to/statement.txt.asc", "w") as afile:
2126        afile.write(signed_data.decode())
2127
2128 As with normal signatures, detached signatures are best handled as byte
2129 literals, even when the output is ASCII armoured.
2130
2131 .. code:: python
2132
2133    import gpg
2134
2135    with open("/path/to/statement.txt", "rb") as tfile:
2136        text = tfile.read()
2137
2138    c = gpg.Context(signers=sig_src)
2139    signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.DETACH)
2140
2141    with open("/path/to/statement.txt.sig", "wb") as afile:
2142        afile.write(signed_data)
2143
2144 .. _howto-basic-signing-clear:
2145
2146 Clearsigning messages or text
2147 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2148
2149 Though PGP/in-line messages are no longer encouraged in favour of
2150 PGP/MIME, there is still sometimes value in utilising in-line
2151 signatures. This is where clear-signed messages or text is of value.
2152
2153 .. code:: python
2154
2155    import gpg
2156
2157    text0 = """Declaration of ... something.
2158
2159    """
2160    text = text0.encode()
2161
2162    c = gpg.Context()
2163    signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.CLEAR)
2164
2165    with open("/path/to/statement.txt.asc", "w") as afile:
2166        afile.write(signed_data.decode())
2167
2168 In spite of the appearance of a clear-signed message, the data handled
2169 by GPGME in signing it must still be byte literals.
2170
2171 .. code:: python
2172
2173    import gpg
2174
2175    with open("/path/to/statement.txt", "rb") as tfile:
2176        text = tfile.read()
2177
2178    c = gpg.Context()
2179    signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.CLEAR)
2180
2181    with open("/path/to/statement.txt.asc", "wb") as afile:
2182        afile.write(signed_data)
2183
2184 .. _howto-basic-verification:
2185
2186 Signature verification
2187 ----------------------
2188
2189 Essentially there are two principal methods of verification of a
2190 signature. The first of these is for use with the normal or default
2191 signing method and for clear-signed messages. The second is for use with
2192 files and data with detached signatures.
2193
2194 The following example is intended for use with the default signing
2195 method where the file was not ASCII armoured:
2196
2197 .. code:: python
2198
2199    import gpg
2200    import time
2201
2202    filename = "statement.txt"
2203    gpg_file = "statement.txt.gpg"
2204
2205    c = gpg.Context()
2206
2207    try:
2208        data, result = c.verify(open(gpg_file))
2209        verified = True
2210    except gpg.errors.BadSignatures as e:
2211        verified = False
2212        print(e)
2213
2214    if verified is True:
2215        for i in range(len(result.signatures)):
2216            sign = result.signatures[i]
2217            print("""Good signature from:
2218    {0}
2219    with key {1}
2220    made at {2}
2221    """.format(c.get_key(sign.fpr).uids[0].uid, sign.fpr,
2222               time.ctime(sign.timestamp)))
2223    else:
2224        pass
2225
2226 Whereas this next example, which is almost identical would work with
2227 normal ASCII armoured files and with clear-signed files:
2228
2229 .. code:: python
2230
2231    import gpg
2232    import time
2233
2234    filename = "statement.txt"
2235    asc_file = "statement.txt.asc"
2236
2237    c = gpg.Context()
2238
2239    try:
2240        data, result = c.verify(open(asc_file))
2241        verified = True
2242    except gpg.errors.BadSignatures as e:
2243        verified = False
2244        print(e)
2245
2246    if verified is True:
2247        for i in range(len(result.signatures)):
2248            sign = result.signatures[i]
2249            print("""Good signature from:
2250    {0}
2251    with key {1}
2252    made at {2}
2253    """.format(c.get_key(sign.fpr).uids[0].uid, sign.fpr,
2254               time.ctime(sign.timestamp)))
2255    else:
2256        pass
2257
2258 In both of the previous examples it is also possible to compare the
2259 original data that was signed against the signed data in ``data`` to see
2260 if it matches with something like this:
2261
2262 .. code:: python
2263
2264    with open(filename, "rb") as afile:
2265        text = afile.read()
2266
2267    if text == data:
2268        print("Good signature.")
2269    else:
2270        pass
2271
2272 The following two examples, however, deal with detached signatures. With
2273 his method of verification the data that was signed does not get
2274 returned since it is already being explicitly referenced in the first
2275 argument of ``c.verify``. So ``data`` is ``None`` and only the
2276 information in ``result`` is available.
2277
2278 .. code:: python
2279
2280    import gpg
2281    import time
2282
2283    filename = "statement.txt"
2284    sig_file = "statement.txt.sig"
2285
2286    c = gpg.Context()
2287
2288    try:
2289        data, result = c.verify(open(filename), open(sig_file))
2290        verified = True
2291    except gpg.errors.BadSignatures as e:
2292        verified = False
2293        print(e)
2294
2295    if verified is True:
2296        for i in range(len(result.signatures)):
2297            sign = result.signatures[i]
2298            print("""Good signature from:
2299    {0}
2300    with key {1}
2301    made at {2}
2302    """.format(c.get_key(sign.fpr).uids[0].uid, sign.fpr,
2303               time.ctime(sign.timestamp)))
2304    else:
2305        pass
2306
2307 .. code:: python
2308
2309    import gpg
2310    import time
2311
2312    filename = "statement.txt"
2313    asc_file = "statement.txt.asc"
2314
2315    c = gpg.Context()
2316
2317    try:
2318        data, result = c.verify(open(filename), open(asc_file))
2319        verified = True
2320    except gpg.errors.BadSignatures as e:
2321        verified = False
2322        print(e)
2323
2324    if verified is True:
2325        for i in range(len(result.signatures)):
2326            sign = result.signatures[i]
2327            print("""Good signature from:
2328    {0}
2329    with key {1}
2330    made at {2}
2331    """.format(c.get_key(sign.fpr).uids[0].uid, sign.fpr,
2332               time.ctime(sign.timestamp)))
2333    else:
2334        pass
2335
2336 .. _key-generation:
2337
2338 Creating keys and subkeys
2339 =========================
2340
2341 The one thing, aside from GnuPG itself, that GPGME depends on, of
2342 course, is the keys themselves. So it is necessary to be able to
2343 generate them and modify them by adding subkeys, revoking or disabling
2344 them, sometimes deleting them and doing the same for user IDs.
2345
2346 In the following examples a key will be created for the world\'s
2347 greatest secret agent, Danger Mouse. Since Danger Mouse is a secret
2348 agent he needs to be able to protect information to ``SECRET`` level
2349 clearance, so his keys will be 3072-bit keys.
2350
2351 The pre-configured ``gpg.conf`` file which sets cipher, digest and other
2352 preferences contains the following configuration parameters:
2353
2354 .. code:: conf
2355
2356    expert
2357    allow-freeform-uid
2358    allow-secret-key-import
2359    trust-model tofu+pgp
2360    tofu-default-policy unknown
2361    enable-large-rsa
2362    enable-dsa2
2363    cert-digest-algo SHA512
2364    default-preference-list TWOFISH CAMELLIA256 AES256 CAMELLIA192 AES192 CAMELLIA128 AES BLOWFISH IDEA CAST5 3DES SHA512 SHA384 SHA256 SHA224 RIPEMD160 SHA1 ZLIB BZIP2 ZIP Uncompressed
2365    personal-cipher-preferences TWOFISH CAMELLIA256 AES256 CAMELLIA192 AES192 CAMELLIA128 AES BLOWFISH IDEA CAST5 3DES
2366    personal-digest-preferences SHA512 SHA384 SHA256 SHA224 RIPEMD160 SHA1
2367    personal-compress-preferences ZLIB BZIP2 ZIP Uncompressed
2368
2369 .. _keygen-primary:
2370
2371 Primary key
2372 -----------
2373
2374 Generating a primary key uses the ``create_key`` method in a Context. It
2375 contains multiple arguments and keyword arguments, including:
2376 ``userid``, ``algorithm``, ``expires_in``, ``expires``, ``sign``,
2377 ``encrypt``, ``certify``, ``authenticate``, ``passphrase`` and
2378 ``force``. The defaults for all of those except ``userid``,
2379 ``algorithm``, ``expires_in``, ``expires`` and ``passphrase`` is
2380 ``False``. The defaults for ``algorithm`` and ``passphrase`` is
2381 ``None``. The default for ``expires_in`` is ``0``. The default for
2382 ``expires`` is ``True``. There is no default for ``userid``.
2383
2384 If ``passphrase`` is left as ``None`` then the key will not be generated
2385 with a passphrase, if ``passphrase`` is set to a string then that will
2386 be the passphrase and if ``passphrase`` is set to ``True`` then
2387 gpg-agent will launch pinentry to prompt for a passphrase. For the sake
2388 of convenience, these examples will keep ``passphrase`` set to ``None``.
2389
2390 .. code:: python
2391
2392    import gpg
2393
2394    c = gpg.Context()
2395
2396    c.home_dir = "~/.gnupg-dm"
2397    userid = "Danger Mouse <dm@secret.example.net>"
2398
2399    dmkey = c.create_key(userid, algorithm="rsa3072", expires_in=31536000,
2400                         sign=True, certify=True)
2401
2402 One thing to note here is the use of setting the ``c.home_dir``
2403 parameter. This enables generating the key or keys in a different
2404 location. In this case to keep the new key data created for this example
2405 in a separate location rather than adding it to existing and active key
2406 store data. As with the default directory, ``~/.gnupg``, any temporary
2407 or separate directory needs the permissions set to only permit access by
2408 the directory owner. On posix systems this means setting the directory
2409 permissions to 700.
2410
2411 The ``temp-homedir-config.py`` script in the HOWTO examples directory
2412 will create an alternative homedir with these configuration options
2413 already set and the correct directory and file permissions.
2414
2415 The successful generation of the key can be confirmed via the returned
2416 ``GenkeyResult`` object, which includes the following data:
2417
2418 .. code:: python
2419
2420    print("""
2421     Fingerprint:  {0}
2422     Primary Key:  {1}
2423      Public Key:  {2}
2424      Secret Key:  {3}
2425     Sub Key:  {4}
2426    User IDs:  {5}
2427    """.format(dmkey.fpr, dmkey.primary, dmkey.pubkey, dmkey.seckey, dmkey.sub,
2428               dmkey.uid))
2429
2430 Alternatively the information can be confirmed using the command line
2431 program:
2432
2433 .. code:: shell
2434
2435    bash-4.4$ gpg --homedir ~/.gnupg-dm -K
2436    ~/.gnupg-dm/pubring.kbx
2437    ----------------------
2438    sec   rsa3072 2018-03-15 [SC] [expires: 2019-03-15]
2439      177B7C25DB99745EE2EE13ED026D2F19E99E63AA
2440    uid           [ultimate] Danger Mouse <dm@secret.example.net>
2441
2442    bash-4.4$
2443
2444 As with generating keys manually, to preconfigure expanded preferences
2445 for the cipher, digest and compression algorithms, the ``gpg.conf`` file
2446 must contain those details in the home directory in which the new key is
2447 being generated. I used a cut down version of my own ``gpg.conf`` file
2448 in order to be able to generate this:
2449
2450 .. code:: shell
2451
2452    bash-4.4$ gpg --homedir ~/.gnupg-dm --edit-key 177B7C25DB99745EE2EE13ED026D2F19E99E63AA showpref quit
2453    Secret key is available.
2454
2455    sec  rsa3072/026D2F19E99E63AA
2456         created: 2018-03-15  expires: 2019-03-15  usage: SC
2457         trust: ultimate      validity: ultimate
2458    [ultimate] (1). Danger Mouse <dm@secret.example.net>
2459
2460    [ultimate] (1). Danger Mouse <dm@secret.example.net>
2461         Cipher: TWOFISH, CAMELLIA256, AES256, CAMELLIA192, AES192, CAMELLIA128, AES, BLOWFISH, IDEA, CAST5, 3DES
2462         Digest: SHA512, SHA384, SHA256, SHA224, RIPEMD160, SHA1
2463         Compression: ZLIB, BZIP2, ZIP, Uncompressed
2464         Features: MDC, Keyserver no-modify
2465
2466    bash-4.4$
2467
2468 .. _keygen-subkeys:
2469
2470 Subkeys
2471 -------
2472
2473 Adding subkeys to a primary key is fairly similar to creating the
2474 primary key with the ``create_subkey`` method. Most of the arguments are
2475 the same, but not quite all. Instead of the ``userid`` argument there is
2476 now a ``key`` argument for selecting which primary key to add the subkey
2477 to.
2478
2479 In the following example an encryption subkey will be added to the
2480 primary key. Since Danger Mouse is a security conscious secret agent,
2481 this subkey will only be valid for about six months, half the length of
2482 the primary key.
2483
2484 .. code:: python
2485
2486    import gpg
2487
2488    c = gpg.Context()
2489    c.home_dir = "~/.gnupg-dm"
2490
2491    key = c.get_key(dmkey.fpr, secret=True)
2492    dmsub = c.create_subkey(key, algorithm="rsa3072", expires_in=15768000,
2493                            encrypt=True)
2494
2495 As with the primary key, the results here can be checked with:
2496
2497 .. code:: python
2498
2499    print("""
2500     Fingerprint:  {0}
2501     Primary Key:  {1}
2502      Public Key:  {2}
2503      Secret Key:  {3}
2504     Sub Key:  {4}
2505    User IDs:  {5}
2506    """.format(dmsub.fpr, dmsub.primary, dmsub.pubkey, dmsub.seckey, dmsub.sub,
2507               dmsub.uid))
2508
2509 As well as on the command line with:
2510
2511 .. code:: shell
2512
2513    bash-4.4$ gpg --homedir ~/.gnupg-dm -K
2514    ~/.gnupg-dm/pubring.kbx
2515    ----------------------
2516    sec   rsa3072 2018-03-15 [SC] [expires: 2019-03-15]
2517      177B7C25DB99745EE2EE13ED026D2F19E99E63AA
2518    uid           [ultimate] Danger Mouse <dm@secret.example.net>
2519    ssb   rsa3072 2018-03-15 [E] [expires: 2018-09-13]
2520
2521    bash-4.4$
2522
2523 .. _keygen-uids:
2524
2525 User IDs
2526 --------
2527
2528 .. _keygen-uids-add:
2529
2530 Adding User IDs
2531 ~~~~~~~~~~~~~~~
2532
2533 By comparison to creating primary keys and subkeys, adding a new user ID
2534 to an existing key is much simpler. The method used to do this is
2535 ``key_add_uid`` and the only arguments it takes are for the ``key`` and
2536 the new ``uid``.
2537
2538 .. code:: python
2539
2540    import gpg
2541
2542    c = gpg.Context()
2543    c.home_dir = "~/.gnupg-dm"
2544
2545    dmfpr = "177B7C25DB99745EE2EE13ED026D2F19E99E63AA"
2546    key = c.get_key(dmfpr, secret=True)
2547    uid = "Danger Mouse <danger.mouse@secret.example.net>"
2548
2549    c.key_add_uid(key, uid)
2550
2551 Unsurprisingly the result of this is:
2552
2553 .. code:: shell
2554
2555    bash-4.4$ gpg --homedir ~/.gnupg-dm -K
2556    ~/.gnupg-dm/pubring.kbx
2557    ----------------------
2558    sec   rsa3072 2018-03-15 [SC] [expires: 2019-03-15]
2559      177B7C25DB99745EE2EE13ED026D2F19E99E63AA
2560    uid           [ultimate] Danger Mouse <danger.mouse@secret.example.net>
2561    uid           [ultimate] Danger Mouse <dm@secret.example.net>
2562    ssb   rsa3072 2018-03-15 [E] [expires: 2018-09-13]
2563
2564    bash-4.4$
2565
2566 .. _keygen-uids-revoke:
2567
2568 Revokinging User IDs
2569 ~~~~~~~~~~~~~~~~~~~~
2570
2571 Revoking a user ID is a fairly similar process, except that it uses the
2572 ``key_revoke_uid`` method.
2573
2574 .. code:: python
2575
2576    import gpg
2577
2578    c = gpg.Context()
2579    c.home_dir = "~/.gnupg-dm"
2580
2581    dmfpr = "177B7C25DB99745EE2EE13ED026D2F19E99E63AA"
2582    key = c.get_key(dmfpr, secret=True)
2583    uid = "Danger Mouse <danger.mouse@secret.example.net>"
2584
2585    c.key_revoke_uid(key, uid)
2586
2587 .. _key-sign:
2588
2589 Key certification
2590 -----------------
2591
2592 Since key certification is more frequently referred to as key signing,
2593 the method used to perform this function is ``key_sign``.
2594
2595 The ``key_sign`` method takes four arguments: ``key``, ``uids``,
2596 ``expires_in`` and ``local``. The default value of ``uids`` is ``None``
2597 and which results in all user IDs being selected. The default value of
2598 both ``expires_in`` and ``local`` is ``False``; which results in the
2599 signature never expiring and being able to be exported.
2600
2601 The ``key`` is the key being signed rather than the key doing the
2602 signing. To change the key doing the signing refer to the signing key
2603 selection above for signing messages and files.
2604
2605 If the ``uids`` value is not ``None`` then it must either be a string to
2606 match a single user ID or a list of strings to match multiple user IDs.
2607 In this case the matching of those strings must be precise and it is
2608 case sensitive.
2609
2610 To sign Danger Mouse\'s key for just the initial user ID with a
2611 signature which will last a little over a month, do this:
2612
2613 .. code:: python
2614
2615    import gpg
2616
2617    c = gpg.Context()
2618    uid = "Danger Mouse <dm@secret.example.net>"
2619
2620    dmfpr = "177B7C25DB99745EE2EE13ED026D2F19E99E63AA"
2621    key = c.get_key(dmfpr, secret=True)
2622    c.key_sign(key, uids=uid, expires_in=2764800)
2623
2624 .. _advanced-use:
2625
2626 Advanced or Experimental Use Cases
2627 ==================================
2628
2629 .. _cython:
2630
2631 C plus Python plus SWIG plus Cython
2632 -----------------------------------
2633
2634 In spite of the apparent incongruence of using Python bindings to a C
2635 interface only to generate more C from the Python; it is in fact quite
2636 possible to use the GPGME bindings with
2637 `Cython <http://docs.cython.org/en/latest/index.html>`__. Though in many
2638 cases the benefits may not be obvious since the most computationally
2639 intensive work never leaves the level of the C code with which GPGME
2640 itself is interacting with.
2641
2642 Nevertheless, there are some situations where the benefits are
2643 demonstrable. One of the better and easier examples being the one of the
2644 early examples in this HOWTO, the `key
2645 counting <#howto-keys-counting>`__ code. Running that example as an
2646 executable Python script, ``keycount.py`` (available in the
2647 ``examples/howto/`` directory), will take a noticable amount of time to
2648 run on most systems where the public keybox or keyring contains a few
2649 thousand public keys.
2650
2651 Earlier in the evening, prior to starting this section, I ran that
2652 script on my laptop; as I tend to do periodically and timed it using
2653 ``time`` utility, with the following results:
2654
2655 .. code:: shell
2656
2657    bash-4.4$ time keycount.py
2658
2659    Number of secret keys:  23
2660    Number of public keys:  12112
2661
2662
2663    real  11m52.945s
2664    user  0m0.913s
2665    sys   0m0.752s
2666
2667    bash-4.4$
2668
2669 Sometime after that I imported another key and followed it with a little
2670 test of Cython. This test was kept fairly basic, essentially lifting the
2671 material from the `Cython Basic
2672 Tutorial <http://docs.cython.org/en/latest/src/tutorial/cython_tutorial.html>`__
2673 to demonstrate compiling Python code to C. The first step was to take
2674 the example key counting code quoted previously, essentially from the
2675 importing of the ``gpg`` module to the end of the script:
2676
2677 .. code:: python
2678
2679    import gpg
2680
2681    c = gpg.Context()
2682    seckeys = c.keylist(pattern=None, secret=True)
2683    pubkeys = c.keylist(pattern=None, secret=False)
2684
2685    seclist = list(seckeys)
2686    secnum = len(seclist)
2687
2688    publist = list(pubkeys)
2689    pubnum = len(publist)
2690
2691    print("""
2692        Number of secret keys:  {0}
2693        Number of public keys:  {1}
2694
2695    """.format(secnum, pubnum))
2696
2697 Save that into a file called ``keycount.pyx`` and then create a
2698 ``setup.py`` file which contains this:
2699
2700 .. code:: python
2701
2702    from distutils.core import setup
2703    from Cython.Build import cythonize
2704
2705    setup(
2706        ext_modules = cythonize("keycount.pyx")
2707    )
2708
2709 Compile it:
2710
2711 .. code:: shell
2712
2713    bash-4.4$ python setup.py build_ext --inplace
2714    bash-4.4$
2715
2716 Then run it in a similar manner to ``keycount.py``:
2717
2718 .. code:: shell
2719
2720    bash-4.4$ time python3.7 -c "import keycount"
2721
2722    Number of secret keys:  23
2723    Number of public keys:  12113
2724
2725
2726    real  6m47.905s
2727    user  0m0.785s
2728    sys   0m0.331s
2729
2730    bash-4.4$
2731
2732 Cython turned ``keycount.pyx`` into an 81KB ``keycount.o`` file in the
2733 ``build/`` directory, a 24KB ``keycount.cpython-37m-darwin.so`` file to
2734 be imported into Python 3.7 and a 113KB ``keycount.c`` generated C
2735 source code file of nearly three thousand lines. Quite a bit bigger than
2736 the 314 bytes of the ``keycount.pyx`` file or the full 1,452 bytes of
2737 the full executable ``keycount.py`` example script.
2738
2739 On the other hand it ran in nearly half the time; taking 6 minutes and
2740 47.905 seconds to run. As opposed to the 11 minutes and 52.945 seconds
2741 which the CPython script alone took.
2742
2743 The ``keycount.pyx`` and ``setup.py`` files used to generate this
2744 example have been added to the ``examples/howto/advanced/cython/``
2745 directory The example versions include some additional options to
2746 annotate the existing code and to detect Cython\'s use. The latter comes
2747 from the `Magic
2748 Attributes <http://docs.cython.org/en/latest/src/tutorial/pure.html#magic-attributes-within-the-pxd>`__
2749 section of the Cython documentation.
2750
2751 .. _cheats-and-hacks:
2752
2753 Miscellaneous extras and work-arounds
2754 =====================================
2755
2756 Most of the things in the following sections are here simply because
2757 there was no better place to put them, even though some are only
2758 peripherally related to the GPGME Python bindings. Some are also
2759 workarounds for functions not integrated with GPGME as yet. This is
2760 especially true of the first of these, dealing with `group
2761 lines <#group-lines>`__.
2762
2763 Group lines
2764 -----------
2765
2766 There is not yet an easy way to access groups configured in the gpg.conf
2767 file from within GPGME. As a consequence these central groupings of keys
2768 cannot be shared amongst multiple programs, such as MUAs readily.
2769
2770 The following code, however, provides a work-around for obtaining this
2771 information in Python.
2772
2773 .. code:: python
2774
2775    import subprocess
2776    import sys
2777
2778    if sys.platform == "win32":
2779        gpgconfcmd = "gpgconf.exe --list-options gpg"
2780    else:
2781        gpgconfcmd = "gpgconf --list-options gpg"
2782
2783    try:
2784        lines = subprocess.getoutput(gpgconfcmd).splitlines()
2785    except:
2786        process = subprocess.Popen(gpgconfcmd.split(), stdout=subprocess.PIPE)
2787        procom = process.communicate()
2788        if sys.version_info[0] == 2:
2789            lines = procom[0].splitlines()
2790        else:
2791            lines = procom[0].decode().splitlines()
2792
2793    for i in range(len(lines)):
2794        if lines[i].startswith("group") is True:
2795            line = lines[i]
2796        else:
2797            pass
2798
2799    groups = line.split(":")[-1].replace('"', '').split(',')
2800
2801    group_lines = []
2802    group_lists = []
2803
2804    for i in range(len(groups)):
2805        group_lines.append(groups[i].split("="))
2806        group_lists.append(groups[i].split("="))
2807
2808    for i in range(len(group_lists)):
2809        group_lists[i][1] = group_lists[i][1].split()
2810
2811 The result of that code is that ``group_lines`` is a list of lists where
2812 ``group_lines[i][0]`` is the name of the group and ``group_lines[i][1]``
2813 is the key IDs of the group as a string.
2814
2815 The ``group_lists`` result is very similar in that it is a list of
2816 lists. The first part, ``group_lists[i][0]`` matches
2817 ``group_lines[i][0]`` as the name of the group, but
2818 ``group_lists[i][1]`` is the key IDs of the group as a string.
2819
2820 A demonstration of using the ``groups.py`` module is also available in
2821 the form of the executable ``mutt-groups.py`` script. This second script
2822 reads all the group entries in a user\'s ``gpg.conf`` file and converts
2823 them into crypt-hooks suitable for use with the Mutt and Neomutt mail
2824 clients.
2825
2826 .. _hkp4py:
2827
2828 Keyserver access for Python
2829 ---------------------------
2830
2831 The `hkp4py <https://github.com/Selfnet/hkp4py>`__ module by Marcel Fest
2832 was originally a port of the old
2833 `python-hkp <https://github.com/dgladkov/python-hkp>`__ module from
2834 Python 2 to Python 3 and updated to use the
2835 `requests <http://docs.python-requests.org/en/latest/index.html>`__
2836 module instead. It has since been modified to provide support for Python
2837 2.7 as well and is available via PyPI.
2838
2839 Since it rewrites the ``hkp`` protocol prefix as ``http`` and ``hkps``
2840 as ``https``, the module is able to be used even with servers which do
2841 not support the full scope of keyserver functions. [6]_ It also works
2842 quite readily when incorporated into a `Cython <#cython>`__ generated
2843 and compiled version of any code.
2844
2845 .. _hkp4py-strings:
2846
2847 Key import format
2848 ~~~~~~~~~~~~~~~~~
2849
2850 The hkp4py module returns key data via requests as string literals
2851 (``r.text``) instead of byte literals (``r.content``). This means that
2852 the retrurned key data must be encoded to UTF-8 when importing that key
2853 material using a ``gpg.Context().key_import()`` method.
2854
2855 For this reason an alternative method has been added to the ``search``
2856 function of ``hkp4py.KeyServer()`` which returns the key in the correct
2857 format as expected by ``key_import``. When importing using this module,
2858 it is now possible to import with this:
2859
2860 .. code:: python
2861
2862    for key in keys:
2863        if key.revoked is False:
2864            gpg.Context().key_import(key.key_blob)
2865        else:
2866            pass
2867
2868 Without that recent addition it would have been necessary to encode the
2869 contents of each ``hkp4py.KeyServer().search()[i].key`` in
2870 ``hkp4py.KeyServer().search()`` before trying to import it.
2871
2872 An example of this is included in the `Importing
2873 Keys <#howto-import-key>`__ section of this HOWTO and the corresponding
2874 executable version of that example is available in the
2875 ``lang/python/examples/howto`` directory as normal; the executable
2876 version is the ``import-keys-hkp.py`` file.
2877
2878 .. _copyright-and-license:
2879
2880 Copyright and Licensing
2881 =======================
2882
2883 Copyright
2884 ---------
2885
2886 Copyright © The GnuPG Project, 2018.
2887
2888 Copyright (C) The GnuPG Project, 2018.
2889
2890 .. _draft-editions:
2891
2892 Draft Editions of this HOWTO
2893 ----------------------------
2894
2895 Draft editions of this HOWTO may be periodically available directly from
2896 the author at any of the following URLs:
2897
2898 -  `GPGME Python Bindings HOWTO draft (XHTML AWS S3
2899    SSL) <https://files.au.adversary.org/crypto/gpgme-python-howto.html>`__
2900 -  `GPGME Python Bindings HOWTO draft (XHTML AWS S3 no
2901    SSL) <http://files.au.adversary.org/crypto/gpgme-python-howto.html>`__
2902 -  `GPGME Python Bindings HOWTO draft (Texinfo file AWS S3
2903    SSL) <https://files.au.adversary.org/crypto/gpgme-python-howto.texi>`__
2904 -  `GPGME Python Bindings HOWTO draft (Texinfo file AWS S3 no
2905    SSL) <http://files.au.adversary.org/crypto/gpgme-python-howto.texi>`__
2906 -  `GPGME Python Bindings HOWTO draft (Info file AWS S3
2907    SSL) <https://files.au.adversary.org/crypto/gpgme-python-howto.info>`__
2908 -  `GPGME Python Bindings HOWTO draft (Info file AWS S3 no
2909    SSL) <http://files.au.adversary.org/crypto/gpgme-python-howto.info>`__
2910 -  `GPGME Python Bindings HOWTO draft (reST file AWS S3
2911    SSL) <https://files.au.adversary.org/crypto/gpgme-python-howto.rst>`__
2912 -  `GPGME Python Bindings HOWTO draft (reST file AWS S3 no
2913    SSL) <http://files.au.adversary.org/crypto/gpgme-python-howto.rst>`__
2914 -  `GPGME Python Bindings HOWTO draft (Docbook 4.2 AWS S3
2915    SSL) <https://files.au.adversary.org/crypto/gpgme-python-howto.xml>`__
2916 -  `GPGME Python Bindings HOWTO draft (Docbook 4.2 AWS S3 no
2917    SSL) <http://files.au.adversary.org/crypto/gpgme-python-howto.xml>`__
2918
2919 All of these draft versions except for one have been generated from this
2920 document via Emacs `Org mode <https://orgmode.org/>`__ and `GNU
2921 Texinfo <https://www.gnu.org/software/texinfo/>`__. Though it is likely
2922 that the specific
2923 `file <https://files.au.adversary.org/crypto/gpgme-python-howto.org>`__
2924 `version <http://files.au.adversary.org/crypto/gpgme-python-howto.org>`__
2925 used will be on the same server with the generated output formats.
2926
2927 The one exception is the reStructuredText version, which was converted
2928 using the latest version of Pandoc from the Org mode source file using
2929 the following command:
2930
2931 .. code:: shell
2932
2933    pandoc -f org -t rst+smart -o gpgme-python-howto.rst gpgme-python-howto.org
2934
2935 In addition to these there is a significantly less frequently updated
2936 version as a HTML `WebHelp
2937 site <https://files.au.adversary.org/crypto/gpgme-python-howto/webhelp/index.html>`__
2938 (AWS S3 SSL); generated from DITA XML source files, which can be found
2939 in `an alternative
2940 branch <https://dev.gnupg.org/source/gpgme/browse/ben%252Fhowto-dita/>`__
2941 of the GPGME git repository.
2942
2943 These draft editions are not official documents and the version of
2944 documentation in the master branch or which ships with released versions
2945 is the only official documentation. Nevertheless, these draft editions
2946 may occasionally be of use by providing more accessible web versions
2947 which are updated between releases. They are provided on the
2948 understanding that they may contain errors or may contain content
2949 subject to change prior to an official release.
2950
2951 .. _license:
2952
2953 License GPL compatible
2954 ----------------------
2955
2956 This file is free software; as a special exception the author gives
2957 unlimited permission to copy and/or distribute it, with or without
2958 modifications, as long as this notice is preserved.
2959
2960 This file is distributed in the hope that it will be useful, but WITHOUT
2961 ANY WARRANTY, to the extent permitted by law; without even the implied
2962 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
2963
2964 Footnotes
2965 =========
2966
2967 .. [1]
2968    ``short-history.org`` and/or ``short-history.html``.
2969
2970 .. [2]
2971    The ``lang/python/docs/`` directory in the GPGME source.
2972
2973 .. [3]
2974    With no issues reported specific to Python 3.7, the release of Python
2975    3.7.1 at around the same time as GPGME 1.12.0 and the testing with
2976    Python 3.7.1rc1, there is no reason to delay moving 3.7 ahead of 3.6
2977    now. Production environments with more conservative requirements will
2978    always enforce their own policies anyway and installation to each
2979    supported minor release is quite possible too.
2980
2981 .. [4]
2982    Yes, even if you use virtualenv with everything you do in Python. If
2983    you want to install this module as just your user account then you
2984    will need to manually configure, compile and install the *entire*
2985    GnuPG stack as that user as well. This includes libraries which are
2986    not often installed that way. It can be done and there are
2987    circumstances under which it is worthwhile, but generally only on
2988    POSIX systems which utilise single user mode (some even require it).
2989
2990 .. [5]
2991    You probably don\'t really want to do this. Searching the keyservers
2992    for \"gnupg.org\" produces over 400 results, the majority of which
2993    aren\'t actually at the gnupg.org domain, but just included a comment
2994    regarding the project in their key somewhere.
2995
2996 .. [6]
2997    Such as with ProtonMail servers. This also means that restricted
2998    servers which only advertise either HTTP or HTTPS end points and not
2999    HKP or HKPS end points must still be identified as as HKP or HKPS
3000    within the Python Code. The ``hkp4py`` module will rewrite these
3001    appropriately when the connection is made to the server.