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