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