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