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