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