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