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