├── doc ├── rst │ ├── _templates │ │ └── README │ ├── _build │ │ └── README │ └── _static │ │ └── README ├── src │ ├── index.org │ └── what-is-new.org ├── DCO ├── README └── Makefile.am ├── examples ├── howto │ ├── advanced │ │ └── cython │ │ │ ├── requirements.txt │ │ │ ├── setup.py │ │ │ └── keycount.pyx │ ├── requirements.txt │ ├── keycount.py │ ├── decrypt-file.py │ ├── README.org │ ├── verify-signed-file.py │ ├── groups.py │ ├── clear-sign-file.py │ ├── verify-signatures.py │ ├── add-userid.py │ ├── revoke-userid.py │ ├── sign-key.py │ ├── symcrypt-file.py │ ├── sign-file.py │ ├── detach-sign-file.py │ ├── mutt-groups.py │ ├── import-keys.py │ ├── encrypt-file.py │ ├── encrypt-to-group-gullible.py │ ├── encrypt-sign-file.py │ ├── import-keybasekey.py │ ├── export-key.py │ ├── export-minimised-key.py │ ├── encrypt-to-group-trustno1.py │ ├── export-secret-key.py │ ├── encrypt-to-group.py │ ├── send-key-to-keyserver.py │ ├── create-key.py │ └── import-key.py ├── sign.py ├── decryption-filter.py ├── assuan.py ├── delkey.py ├── testCMSgetkey.py ├── genkey.py ├── signverify.py ├── simple.py ├── inter-edit.py ├── low_level-encrypt_to_all.py ├── exportimport.py ├── verifydetails.py └── Makefile.am ├── tests ├── 13CBE3758AFE42B5E5E2AE4CED27AFA455E3F87F ├── 13CD0F3BDF24BE53FE192D62F18737256FF6E4FD ├── 76F7E2B35832976B50A27A282D9B87E44577EB66 ├── 7A030357C0F253A5BBCD282FFC4E521B37558F5C ├── A0747D5F9425E6664F4FFBEED20FBCA79FDED2BD ├── cipher-1.asc ├── cipher-no-sig.asc ├── pinentry ├── cipher-2.asc ├── cipher-3.asc ├── t-wrapper.py ├── final.py ├── t-export.py ├── t-wait.py ├── t-file-name.py ├── pubkey-1.asc ├── initial.py ├── seckey-1.asc ├── sign-only.asc ├── encrypt-only.asc ├── t-decrypt.py ├── t-encrypt-large.py ├── start-stop-agent ├── t-edit.py ├── t-protocol-assuan.py ├── t-encrypt.py ├── t-sig-notation.py ├── t-idiomatic.py ├── t-encrypt-sym.py ├── t-decrypt-verify.py ├── t-import.py ├── t-signers.py ├── t-encrypt-sign.py └── secdemo.asc ├── .gitignore ├── autogen.rc ├── src ├── constants │ ├── keylist │ │ ├── __init__.py │ │ └── mode.py │ ├── data │ │ ├── __init__.py │ │ └── encoding.py │ ├── sig │ │ ├── __init__.py │ │ ├── notation.py │ │ └── mode.py │ ├── tofu │ │ ├── __init__.py │ │ └── policy.py │ ├── create.py │ ├── keysign.py │ ├── md.py │ ├── pk.py │ ├── event.py │ ├── sigsum.py │ ├── import_type.py │ ├── protocol.py │ └── validity.py ├── Makefile.am ├── callbacks.py └── util.py ├── MANIFEST.in ├── ChangeLog ├── m4 └── ltversion.m4 ├── NEWS ├── helpers.h ├── private.h ├── AUTHORS ├── README.GIT ├── README.org ├── README ├── pyproject.toml └── version.py.in /doc/rst/_templates/README: -------------------------------------------------------------------------------- 1 | Directory for HTML templates. -------------------------------------------------------------------------------- /examples/howto/advanced/cython/requirements.txt: -------------------------------------------------------------------------------- 1 | cython 2 | -------------------------------------------------------------------------------- /examples/howto/requirements.txt: -------------------------------------------------------------------------------- 1 | hkp4py 2 | requests 3 | -------------------------------------------------------------------------------- /doc/rst/_build/README: -------------------------------------------------------------------------------- 1 | Directory for Sphinx's built documentation. 2 | -------------------------------------------------------------------------------- /doc/rst/_static/README: -------------------------------------------------------------------------------- 1 | Directory for static site data (e.g. CSS files). -------------------------------------------------------------------------------- /tests/13CBE3758AFE42B5E5E2AE4CED27AFA455E3F87F: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gpg/gpgmepy/master/tests/13CBE3758AFE42B5E5E2AE4CED27AFA455E3F87F -------------------------------------------------------------------------------- /tests/13CD0F3BDF24BE53FE192D62F18737256FF6E4FD: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gpg/gpgmepy/master/tests/13CD0F3BDF24BE53FE192D62F18737256FF6E4FD -------------------------------------------------------------------------------- /tests/76F7E2B35832976B50A27A282D9B87E44577EB66: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gpg/gpgmepy/master/tests/76F7E2B35832976B50A27A282D9B87E44577EB66 -------------------------------------------------------------------------------- /tests/7A030357C0F253A5BBCD282FFC4E521B37558F5C: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gpg/gpgmepy/master/tests/7A030357C0F253A5BBCD282FFC4E521B37558F5C -------------------------------------------------------------------------------- /tests/A0747D5F9425E6664F4FFBEED20FBCA79FDED2BD: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gpg/gpgmepy/master/tests/A0747D5F9425E6664F4FFBEED20FBCA79FDED2BD -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # GnuPG exclusions 2 | /aclocal.m4 3 | /autom4te.cache 4 | /configure 5 | /config.h.in 6 | /VERSION 7 | Makefile.in 8 | 9 | # Hidden files 10 | *~ 11 | -------------------------------------------------------------------------------- /examples/howto/advanced/cython/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | from Cython.Build import cythonize 3 | 4 | setup( 5 | ext_modules = cythonize("keycount.pyx", annotate=True) 6 | ) 7 | -------------------------------------------------------------------------------- /autogen.rc: -------------------------------------------------------------------------------- 1 | # autogen.sh configuration for Python bindings of GPGME -*- sh -*- 2 | 3 | package_subdir="lang/python" 4 | 5 | final_info="mkdir build && cd build && ../configure --enable-maintainer-mode && make" 6 | -------------------------------------------------------------------------------- /src/constants/keylist/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, print_function, unicode_literals 2 | 3 | from . import mode 4 | __all__ = ['mode'] 5 | 6 | del absolute_import, print_function, unicode_literals 7 | -------------------------------------------------------------------------------- /src/constants/data/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, print_function, unicode_literals 2 | 3 | from . import encoding 4 | __all__ = ['encoding'] 5 | 6 | del absolute_import, print_function, unicode_literals 7 | -------------------------------------------------------------------------------- /src/constants/sig/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, print_function, unicode_literals 2 | 3 | from . import mode, notation 4 | __all__ = ['mode', 'notation'] 5 | 6 | del absolute_import, print_function, unicode_literals 7 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include doc *.org 2 | recursive-include doc *.rst 3 | recursive-include doc *.tex 4 | recursive-include doc *.texi 5 | recursive-include doc *.info 6 | recursive-include examples *.py *.pyx 7 | include README README.org 8 | include gpgme.i 9 | include helpers.c helpers.h private.h 10 | include version.py 11 | recursive-include gpg *.py 12 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | No ChangeLog file 2 | ================= 3 | 4 | Do not modify the ChangeLog file of the Python bindings of GpgME. We 5 | put change information only in the GIT commit log, and generate a 6 | top-level ChangeLog file from logs at "make dist" time. As such, 7 | there are strict requirements on the form of the commit log messages. 8 | See doc/HACKING for details. 9 | 10 | Change information before the Python bindings were added to gpgme 11 | can be found in doc/meta/old-commits.log. 12 | 13 | 14 | Local Variables: 15 | buffer-read-only: t 16 | mode: text 17 | End: 18 | -------------------------------------------------------------------------------- /examples/howto/advanced/cython/keycount.pyx: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | import cython 4 | import gpg 5 | 6 | c = gpg.Context() 7 | seckeys = c.keylist(pattern=None, secret=True) 8 | pubkeys = c.keylist(pattern=None, secret=False) 9 | 10 | seclist = list(seckeys) 11 | secnum = len(seclist) 12 | 13 | publist = list(pubkeys) 14 | pubnum = len(publist) 15 | 16 | if cython.compiled is True: 17 | cc = "Powered by Cython compiled C code." 18 | else: 19 | cc = "Powered by Python." 20 | 21 | print(""" 22 | Number of secret keys: {0} 23 | Number of public keys: {1} 24 | 25 | {2} 26 | """.format(secnum, pubnum, cc)) 27 | -------------------------------------------------------------------------------- /tests/cipher-1.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP MESSAGE----- 2 | 3 | hQEOA2rm1+5GqHH4EAP/XKz8pdonnZg2dqJhjdas4vQHPxspxLhgf7OuYigodBpI 4 | l7srTvqtuRsDFNorgURW6DjPqfGqpZsn2uf8enUskunHVMQFBILX38d+G5SkisqF 5 | uOZUlmh0ZfVocCBGYt8ZPfa9ObmitPmZvhCReCHFlTj588ZjofKuNjmfw+QfmNcD 6 | /j4z4ijv6dKHQCm7EAjnOsCw9SbrAVpRXjibN7KT+w6QT6m+5w9k4RfhkTOlqrHq 7 | 5d3ZyxLctdTkXlk0hXz1Mey4AEKTtlZGvrQVIhaX4hcB4NFJB0fZJ/pnKypi1H6q 8 | 0bSBq2p6kCzJuNvrEr4wk4B1NsOTBacUSffXLrfsEH2F0ngBzN7d/KHBImu81F8w 9 | x96f6dELyYetV0UwhyFrPrA3lBQf9q5cNDqPiCHooUFOudQ5t0h7VtSU3fyaYoit 10 | cJGPFkIxhv+VAbEW/h5muEg3KO1iEqLP4RK3y0Jjy4pyEauAgviM68Vjf4OVvgta 11 | /IblIrp1FHxoCpA= 12 | =sEuD 13 | -----END PGP MESSAGE----- 14 | -------------------------------------------------------------------------------- /tests/cipher-no-sig.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP MESSAGE----- 2 | 3 | hQEOA++dwnahcsiBEAP8CPkDWzZrcMJ1fyaPoQAhlx18p44+7vTF5zYCkMVT+i4E 4 | X/zcIreDYDpFNHzK2orNW/LGGNpMf3ZyDAYw7eDWgPwld2PJh2/ZfR/dXoGcAEd4 5 | vhbhA1D/ymQn+lxgSXNLMonxaoCqFK7cKStLCHfaPMbQ0S5GXU0IRwjfSn76oxwE 6 | AKzTa/54g8XNL9Dku9c/KATzopdDLzAzN6oBJlgRbjhc3T8mzTVJF91s+ow8dEC+ 7 | 0U2GBwkL5ZOKTFelSO3dBsH7RBNbYiJA+DbZ6nZia2KAtlLgyr4Z5vGh9bmltJl/ 8 | 1qdIdRF/La3wA/6bL10YMYF+7IJ9DiuDi/NRmSsO/ZWt0nMBXnzOeyLgxdbW1RS1 9 | NPWzKC/4RqvnWJmm7W3p0JG8v2ad+97O5KsOcqJnaKJOY0jKXeORrhih2DG32rpe 10 | 4bhskRTIBJBaPtPnRGevlxardQi+Spbd75yqccCLjkQF0HhCLiHW9SJiLSMdnY1U 11 | U9th3ZR5 12 | =uvfB 13 | -----END PGP MESSAGE----- 14 | -------------------------------------------------------------------------------- /tests/pinentry: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # Dummy pinentry 3 | # 4 | # Copyright 2008 g10 Code GmbH 5 | # 6 | # This file is free software; as a special exception the author gives 7 | # unlimited permission to copy and/or distribute it, with or without 8 | # modifications, as long as this notice is preserved. 9 | # 10 | # This file is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the 12 | # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | # PURPOSE. 14 | 15 | echo OK Your orders please 16 | 17 | while read cmd; do 18 | case $cmd in 19 | GETPIN) echo D abc; echo OK;; 20 | *) echo OK;; 21 | esac 22 | done 23 | -------------------------------------------------------------------------------- /m4/ltversion.m4: -------------------------------------------------------------------------------- 1 | # ltversion.m4 -- version numbers -*- Autoconf -*- 2 | # 3 | # Copyright (C) 2004 Free Software Foundation, Inc. 4 | # Written by Scott James Remnant, 2004 5 | # 6 | # This file is free software; the Free Software Foundation gives 7 | # unlimited permission to copy and/or distribute it, with or without 8 | # modifications, as long as this notice is preserved. 9 | 10 | # @configure_input@ 11 | 12 | # serial 3337 ltversion.m4 13 | # This file is part of GNU Libtool 14 | 15 | m4_define([LT_PACKAGE_VERSION], [2.4.2]) 16 | m4_define([LT_PACKAGE_REVISION], [1.3337]) 17 | 18 | AC_DEFUN([LTVERSION_VERSION], 19 | [macro_version='2.4.2' 20 | macro_revision='1.3337' 21 | _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) 22 | _LT_DECL(, macro_revision, 0) 23 | ]) 24 | -------------------------------------------------------------------------------- /tests/cipher-2.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP MESSAGE----- 2 | 3 | hQEOA++dwnahcsiBEAQAqaF1yuTJ26FmJHndyaHUjazx7j8/Z/Ht3O+jSAOaoJFR 4 | 84rK4Tte0JQYTCl3XxwSEwr48OAtyeTstLjabGAvBoHrXVP3xC0U7kBalZm2lwcq 5 | A8dDDoa3uMkWi1OJ3e2o79/z6SdTHEgRIRomAku1JaXFGTd8OsFhW782RpKUBOID 6 | /jMs9o2sa/gDhWVaeC3SaQovl2xb45ev0nMibED916BQvv3NkH5/EzeM6v788h63 7 | 4yUkWWNr0/bnJ21chlxIbvICjHfuGAEDw+i4HhK/nLBL3Ep4ADtLP7OPZJHlcQgI 8 | g8mAztasBxTGGUuFYvRT0X7sbaSPxLR26vbTCYAo/P/80sA4AYGhBuYPsRN4JzX9 9 | QaSrToKjPbaZqq+nHQYCvi6m5xAjMT0HVdXejMtZMKwv4TRm7IVCimtIZqrlvw7c 10 | Kj+ZcDGq9qb7urnzC5mdAZkXyNtZxmMKYFI0ci7zMnflvIM87JrVEjZbjjiXlcVy 11 | mSxhufOOweLJARkJ4mKVq1tr8REu8/ots4fDzUIAITM3z8pKA7doWAH2VTo0Idmc 12 | wYOoTLkiq1Z8fxeryB6U66C831PDiWe7W0usRSVo5rZ7laLZeOGl33fAAZCNLTgv 13 | tOPWWg5rCpRTVXgQ6Edl7DtzKI1z4EJbuEUs6shW+OT3bNISiDz2am8remU= 14 | =9AEU 15 | -----END PGP MESSAGE----- 16 | -------------------------------------------------------------------------------- /doc/src/index.org: -------------------------------------------------------------------------------- 1 | # -*- mode: org -*- 2 | #+TITLE: GNU Privacy Guard (GnuPG) Made Easy Python Bindings 3 | #+AUTHOR: Ben McGinnes 4 | #+LATEX_COMPILER: xelatex 5 | #+LATEX_CLASS: article 6 | #+LATEX_CLASS_OPTIONS: [12pt] 7 | #+LATEX_HEADER: \usepackage{xltxtra} 8 | #+LATEX_HEADER: \usepackage[margin=1in]{geometry} 9 | #+LATEX_HEADER: \setmainfont[Ligatures={Common}]{Times New Roman} 10 | #+LATEX_HEADER: \author{Ben McGinnes } 11 | 12 | 13 | * GPGME Python Bindings 14 | :PROPERTIES: 15 | :CUSTOM_ID: top 16 | :END: 17 | 18 | 19 | ** Contents 20 | :PROPERTIES: 21 | :CUSTOM_ID: contents 22 | :END: 23 | 24 | 25 | - [[file:short-history][A short history of the project]] 26 | - [[file:what-is-new][What's New]] 27 | - [[file:maintenance-mode][Maintenance Mode]] (from January, 2019) 28 | - [[file:what-was-new][What Was New]] 29 | - [[file:gpgme-python-howto][GPGME Python Bindings HOWTO]] 30 | -------------------------------------------------------------------------------- /tests/cipher-3.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP MESSAGE----- 2 | 3 | hQEOA++dwnahcsiBEAQApowkbz0idxMfLIT/a1G4QbZy77cWyaYOM/qh4lH4h7ra 4 | f19MZzbRViZYBtJeITszTFmulp31qrF++6gBy8tU7l8VfVfOtvwn1WlRvn2+bsns 5 | SicJAXtUiwIF8fbapSrkN6qpg2l+Fnx3SYV7+lh/7Fbf93DquwVEn+GwvgkyCQkD 6 | /j5UVU6PJ+k5E5JG7CMzLZHnpW1MtKUqKRG9sTW83SvvI5Wl9VMgjmdO6bZRPKPY 7 | Fr5udYJ1v4CIpVTb0O/TgAaiw7/Ak4SOg6jK0H0l1vuPPRjyzx43G4Y4lZ/EoCzT 8 | gU+0kiDD+O7xLDml5jPWTYov7LkhRMKI4Ugp37FzbF9p0sClAR1mY4WlAN23ku0W 9 | 3bw54zSi7S6sh+i/uOmjZ+ziXr/S1pHFN2TNAkpH42o6VDhJ4vYk5KIB/mn/IoP1 10 | G57JUhLqpSHO7LF8X45eBLT3tKC3rIaILHXcXE5PeyMiOrl1snIClrpX+Qn6dRPX 11 | cYssX/0OQwE77bAla5QpZEy6YLOC4Ej4oTX5QU1rHNyLfvIDhwtphKMvbbssmsVI 12 | tAMvrGQudEwLSlvNlnJsI79jqmbi5W8PYr+ssvOvrd5hWoKti7EdglWddFNVVjZl 13 | ooJgztXUnPcufhaimQtNvX0Tj2hI8QwTxGPNO3aesPCQI0GbSUSqpvu6mlaQY2Qe 14 | NJNkfTH23fzoG61nFxIQ0HYbuBp0hJnGOXfHtMNxyjoAs1yEJbyQ20Lso/Vrsf3J 15 | sY7jkisFrURxTGQyBxxbnIO+nJPemOzV9Q/qo6Lj9yW0KagaffWogw/6X/xOvL4u 16 | aM8pI7NOi48b 17 | =mh2s 18 | -----END PGP MESSAGE----- 19 | -------------------------------------------------------------------------------- /src/constants/tofu/__init__.py: -------------------------------------------------------------------------------- 1 | # TOFU 2 | # 3 | # Copyright (C) 2017 g10 Code GmbH 4 | # 5 | # This file is part of GPGME. 6 | # 7 | # GPGME is free software; you can redistribute it and/or modify it 8 | # under the terms of the GNU Lesser General Public License as 9 | # published by the Free Software Foundation; either version 2.1 of the 10 | # License, or (at your option) any later version. 11 | # 12 | # GPGME is distributed in the hope that it will be useful, but WITHOUT 13 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 15 | # Public License for more details. 16 | # 17 | # You should have received a copy of the GNU Lesser General Public 18 | # License along with this program; if not, see . 19 | 20 | from __future__ import absolute_import, print_function, unicode_literals 21 | 22 | from . import policy 23 | __all__ = ['policy'] 24 | 25 | del absolute_import, print_function, unicode_literals 26 | -------------------------------------------------------------------------------- /src/constants/create.py: -------------------------------------------------------------------------------- 1 | # Flags for key creation 2 | # 3 | # Copyright (C) 2017 g10 Code GmbH 4 | # 5 | # This file is part of GPGME. 6 | # 7 | # GPGME is free software; you can redistribute it and/or modify it 8 | # under the terms of the GNU Lesser General Public License as 9 | # published by the Free Software Foundation; either version 2.1 of the 10 | # License, or (at your option) any later version. 11 | # 12 | # GPGME is distributed in the hope that it will be useful, but WITHOUT 13 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 15 | # Public License for more details. 16 | # 17 | # You should have received a copy of the GNU Lesser General Public 18 | # License along with this program; if not, see . 19 | 20 | from __future__ import absolute_import, print_function, unicode_literals 21 | 22 | from gpg import util 23 | util.process_constants('GPGME_CREATE_', globals()) 24 | del absolute_import, print_function, unicode_literals, util 25 | -------------------------------------------------------------------------------- /src/constants/keysign.py: -------------------------------------------------------------------------------- 1 | # Flags for key signing 2 | # 3 | # Copyright (C) 2017 g10 Code GmbH 4 | # 5 | # This file is part of GPGME. 6 | # 7 | # GPGME is free software; you can redistribute it and/or modify it 8 | # under the terms of the GNU Lesser General Public License as 9 | # published by the Free Software Foundation; either version 2.1 of the 10 | # License, or (at your option) any later version. 11 | # 12 | # GPGME is distributed in the hope that it will be useful, but WITHOUT 13 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 15 | # Public License for more details. 16 | # 17 | # You should have received a copy of the GNU Lesser General Public 18 | # License along with this program; if not, see . 19 | 20 | from __future__ import absolute_import, print_function, unicode_literals 21 | 22 | from gpg import util 23 | util.process_constants('GPGME_KEYSIGN_', globals()) 24 | del absolute_import, print_function, unicode_literals, util 25 | -------------------------------------------------------------------------------- /src/constants/tofu/policy.py: -------------------------------------------------------------------------------- 1 | # TOFU policies 2 | # 3 | # Copyright (C) 2017 g10 Code GmbH 4 | # 5 | # This file is part of GPGME. 6 | # 7 | # GPGME is free software; you can redistribute it and/or modify it 8 | # under the terms of the GNU Lesser General Public License as 9 | # published by the Free Software Foundation; either version 2.1 of the 10 | # License, or (at your option) any later version. 11 | # 12 | # GPGME is distributed in the hope that it will be useful, but WITHOUT 13 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 15 | # Public License for more details. 16 | # 17 | # You should have received a copy of the GNU Lesser General Public 18 | # License along with this program; if not, see . 19 | 20 | from __future__ import absolute_import, print_function, unicode_literals 21 | 22 | from gpg import util 23 | util.process_constants('GPGME_TOFU_POLICY_', globals()) 24 | del absolute_import, print_function, unicode_literals, util 25 | -------------------------------------------------------------------------------- /src/constants/sig/notation.py: -------------------------------------------------------------------------------- 1 | # Constants for signature notation data. 2 | # 3 | # Copyright (C) 2016 g10 Code GmbH 4 | # 5 | # This file is part of GPGME. 6 | # 7 | # GPGME is free software; you can redistribute it and/or modify it 8 | # under the terms of the GNU Lesser General Public License as 9 | # published by the Free Software Foundation; either version 2.1 of the 10 | # License, or (at your option) any later version. 11 | # 12 | # GPGME is distributed in the hope that it will be useful, but WITHOUT 13 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 15 | # Public License for more details. 16 | # 17 | # You should have received a copy of the GNU Lesser General Public 18 | # License along with this program; if not, see . 19 | 20 | from __future__ import absolute_import, print_function, unicode_literals 21 | 22 | from gpg import util 23 | util.process_constants('GPGME_SIG_NOTATION_', globals()) 24 | del absolute_import, print_function, unicode_literals, util 25 | -------------------------------------------------------------------------------- /tests/t-wrapper.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright (C) 2016 g10 Code GmbH 4 | # 5 | # This file is part of GPGME. 6 | # 7 | # GPGME is free software; you can redistribute it and/or modify it 8 | # under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # GPGME is distributed in the hope that it will be useful, but WITHOUT 13 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 15 | # Public License for more details. 16 | # 17 | # You should have received a copy of the GNU Lesser General Public 18 | # License along with this program; if not, see . 19 | 20 | import gpg 21 | import support 22 | _ = support # to appease pyflakes. 23 | 24 | d0 = gpg.Data() 25 | d0.seek # trigger on-demand-wrapping 26 | assert d0.seek == d0.seek, "Generated wrapper functions are not cached" 27 | assert hasattr(gpg.Data, 'seek'), "Generated wrapper functions are not shared" 28 | -------------------------------------------------------------------------------- /src/constants/md.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2004 Igor Belyi 2 | # Copyright (C) 2002 John Goerzen 3 | # 4 | # This library is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU Lesser General Public 6 | # License as published by the Free Software Foundation; either 7 | # version 2.1 of the License, or (at your option) any later version. 8 | # 9 | # This library is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # Lesser General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU Lesser General Public 15 | # License along with this library; if not, write to the Free Software 16 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 | 18 | from __future__ import absolute_import, print_function, unicode_literals 19 | 20 | from gpg import util 21 | util.process_constants('GPGME_MD_', globals()) 22 | del absolute_import, print_function, unicode_literals, util 23 | -------------------------------------------------------------------------------- /src/constants/pk.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2004 Igor Belyi 2 | # Copyright (C) 2002 John Goerzen 3 | # 4 | # This library is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU Lesser General Public 6 | # License as published by the Free Software Foundation; either 7 | # version 2.1 of the License, or (at your option) any later version. 8 | # 9 | # This library is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # Lesser General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU Lesser General Public 15 | # License along with this library; if not, write to the Free Software 16 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 | 18 | from __future__ import absolute_import, print_function, unicode_literals 19 | 20 | from gpg import util 21 | util.process_constants('GPGME_PK_', globals()) 22 | del absolute_import, print_function, unicode_literals, util 23 | -------------------------------------------------------------------------------- /src/constants/event.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2004 Igor Belyi 2 | # Copyright (C) 2002 John Goerzen 3 | # 4 | # This library is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU Lesser General Public 6 | # License as published by the Free Software Foundation; either 7 | # version 2.1 of the License, or (at your option) any later version. 8 | # 9 | # This library is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # Lesser General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU Lesser General Public 15 | # License along with this library; if not, write to the Free Software 16 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 | 18 | from __future__ import absolute_import, print_function, unicode_literals 19 | 20 | from gpg import util 21 | util.process_constants('GPGME_EVENT_', globals()) 22 | del absolute_import, print_function, unicode_literals, util 23 | -------------------------------------------------------------------------------- /src/constants/sigsum.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2004 Igor Belyi 2 | # Copyright (C) 2002 John Goerzen 3 | # 4 | # This library is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU Lesser General Public 6 | # License as published by the Free Software Foundation; either 7 | # version 2.1 of the License, or (at your option) any later version. 8 | # 9 | # This library is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # Lesser General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU Lesser General Public 15 | # License along with this library; if not, write to the Free Software 16 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 | 18 | from __future__ import absolute_import, print_function, unicode_literals 19 | 20 | from gpg import util 21 | util.process_constants('GPGME_SIGSUM_', globals()) 22 | del absolute_import, print_function, unicode_literals, util 23 | -------------------------------------------------------------------------------- /examples/sign.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright (C) 2016 g10 Code GmbH 4 | # Copyright (C) 2002 John Goerzen 5 | # 6 | # This program is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 2 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, but 12 | # WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | # General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program; if not, see . 18 | 19 | from __future__ import absolute_import, print_function, unicode_literals 20 | 21 | import sys 22 | import gpg 23 | from gpg.constants.sig import mode 24 | 25 | del absolute_import, print_function, unicode_literals 26 | 27 | with gpg.Context() as c: 28 | signed, _ = c.sign(b"Test message", mode=mode.CLEAR) 29 | sys.stdout.buffer.write(signed) 30 | -------------------------------------------------------------------------------- /src/constants/import_type.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2004 Igor Belyi 2 | # Copyright (C) 2002 John Goerzen 3 | # 4 | # This library is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU Lesser General Public 6 | # License as published by the Free Software Foundation; either 7 | # version 2.1 of the License, or (at your option) any later version. 8 | # 9 | # This library is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # Lesser General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU Lesser General Public 15 | # License along with this library; if not, write to the Free Software 16 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 | 18 | from __future__ import absolute_import, print_function, unicode_literals 19 | 20 | from gpg import util 21 | util.process_constants('GPGME_IMPORT_', globals()) 22 | del absolute_import, print_function, unicode_literals, util 23 | -------------------------------------------------------------------------------- /src/constants/protocol.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2004 Igor Belyi 2 | # Copyright (C) 2002 John Goerzen 3 | # 4 | # This library is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU Lesser General Public 6 | # License as published by the Free Software Foundation; either 7 | # version 2.1 of the License, or (at your option) any later version. 8 | # 9 | # This library is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # Lesser General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU Lesser General Public 15 | # License along with this library; if not, write to the Free Software 16 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 | 18 | from __future__ import absolute_import, print_function, unicode_literals 19 | 20 | from gpg import util 21 | util.process_constants('GPGME_PROTOCOL_', globals()) 22 | del absolute_import, print_function, unicode_literals, util 23 | -------------------------------------------------------------------------------- /src/constants/sig/mode.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2004 Igor Belyi 2 | # Copyright (C) 2002 John Goerzen 3 | # 4 | # This library is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU Lesser General Public 6 | # License as published by the Free Software Foundation; either 7 | # version 2.1 of the License, or (at your option) any later version. 8 | # 9 | # This library is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # Lesser General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU Lesser General Public 15 | # License along with this library; if not, write to the Free Software 16 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 | 18 | from __future__ import absolute_import, print_function, unicode_literals 19 | 20 | from gpg import util 21 | util.process_constants('GPGME_SIG_MODE_', globals()) 22 | del absolute_import, print_function, unicode_literals, util 23 | -------------------------------------------------------------------------------- /src/constants/validity.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2004 Igor Belyi 2 | # Copyright (C) 2002 John Goerzen 3 | # 4 | # This library is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU Lesser General Public 6 | # License as published by the Free Software Foundation; either 7 | # version 2.1 of the License, or (at your option) any later version. 8 | # 9 | # This library is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # Lesser General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU Lesser General Public 15 | # License along with this library; if not, write to the Free Software 16 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 | 18 | from __future__ import absolute_import, print_function, unicode_literals 19 | 20 | from gpg import util 21 | util.process_constants('GPGME_VALIDITY_', globals()) 22 | del absolute_import, print_function, unicode_literals, util 23 | -------------------------------------------------------------------------------- /tests/final.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright (C) 2016 g10 Code GmbH 4 | # 5 | # This file is part of GPGME. 6 | # 7 | # GPGME is free software; you can redistribute it and/or modify it 8 | # under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # GPGME is distributed in the hope that it will be useful, but WITHOUT 13 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 15 | # Public License for more details. 16 | # 17 | # You should have received a copy of the GNU Lesser General Public 18 | # License along with this program; if not, see . 19 | 20 | from __future__ import absolute_import, print_function, unicode_literals 21 | 22 | import os 23 | import subprocess 24 | import support 25 | _ = support # to appease pyflakes. 26 | 27 | del absolute_import, print_function, unicode_literals 28 | 29 | subprocess.check_call([ 30 | os.path.join(os.getenv('top_srcdir'), "tests", "start-stop-agent"), 31 | "--stop" 32 | ]) 33 | -------------------------------------------------------------------------------- /src/constants/data/encoding.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2004 Igor Belyi 2 | # Copyright (C) 2002 John Goerzen 3 | # 4 | # This library is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU Lesser General Public 6 | # License as published by the Free Software Foundation; either 7 | # version 2.1 of the License, or (at your option) any later version. 8 | # 9 | # This library is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # Lesser General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU Lesser General Public 15 | # License along with this library; if not, write to the Free Software 16 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 | 18 | from __future__ import absolute_import, print_function, unicode_literals 19 | 20 | from gpg import util 21 | util.process_constants('GPGME_DATA_ENCODING_', globals()) 22 | del absolute_import, print_function, unicode_literals, util 23 | -------------------------------------------------------------------------------- /src/constants/keylist/mode.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2004 Igor Belyi 2 | # Copyright (C) 2002 John Goerzen 3 | # 4 | # This library is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU Lesser General Public 6 | # License as published by the Free Software Foundation; either 7 | # version 2.1 of the License, or (at your option) any later version. 8 | # 9 | # This library is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # Lesser General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU Lesser General Public 15 | # License along with this library; if not, write to the Free Software 16 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 | 18 | from __future__ import absolute_import, print_function, unicode_literals 19 | 20 | from gpg import util 21 | util.process_constants('GPGME_KEYLIST_MODE_', globals()) 22 | del absolute_import, print_function, unicode_literals, util 23 | -------------------------------------------------------------------------------- /examples/decryption-filter.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright (C) 2016, 2018 g10 Code GmbH 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program; if not, see . 17 | """A decryption filter 18 | 19 | This demonstrates decryption using gpg in three lines of code. To 20 | be used like this: 21 | 22 | ./decryption-filter.py < message.gpg > message.plain 23 | 24 | """ 25 | 26 | from __future__ import absolute_import, print_function, unicode_literals 27 | 28 | import sys 29 | import gpg 30 | 31 | del absolute_import, print_function, unicode_literals 32 | 33 | gpg.Context().decrypt(sys.stdin, sink=sys.stdout) 34 | -------------------------------------------------------------------------------- /examples/assuan.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright (C) 2016 g10 Code GmbH 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program; if not, see . 17 | """Demonstrate the use of the Assuan protocol engine""" 18 | 19 | from __future__ import absolute_import, print_function, unicode_literals 20 | 21 | import gpg 22 | 23 | del absolute_import, print_function, unicode_literals 24 | 25 | with gpg.Context(protocol=gpg.constants.protocol.ASSUAN) as c: 26 | # Invoke the pinentry to get a confirmation. 27 | err = c.assuan_transact(['GET_CONFIRMATION', 'Hello there']) 28 | print("You chose {}.".format("cancel" if err else "ok")) 29 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | Noteworthy changes in version 2.0.1 (unreleased) 2 | ------------------------------------------------- 3 | 4 | 5 | 6 | Noteworthy changes in version 2.0.0 (2025-06-17) 7 | ------------------------------------------------- 8 | 9 | * Python 3.13 is now supported. 10 | 11 | * Project metadata has been migrated to pyproject.toml. 12 | 13 | * Issues with make sdist have been resolved. 14 | 15 | * Compiler warnings have been fixed. 16 | 17 | * Uninstall issues on Debian-based systems have been addressed. 18 | 19 | * swig has been added to build requirements. 20 | 21 | * Header search has been improved to include /usr/include. 22 | 23 | * Python 2 and 3.8 support has been removed. 24 | 25 | 26 | Noteworthy changes in version 1.24.x and earlier can be found in the 27 | NEWS file of gpgme. 28 | 29 | 30 | Copyright 2024 g10 Code GmbH 31 | 32 | This file is free software; as a special exception the author gives 33 | unlimited permission to copy and/or distribute it, with or without 34 | modifications, as long as this notice is preserved. 35 | 36 | This file is distributed in the hope that it will be useful, but 37 | WITHOUT ANY WARRANTY, to the extent permitted by law; without even the 38 | implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 39 | -------------------------------------------------------------------------------- /examples/delkey.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright (C) 2016 g10 Code GmbH 4 | # Copyright (C) 2004,2008 Igor Belyi 5 | # 6 | # This program is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 2 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, but 12 | # WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | # General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program; if not, see . 18 | 19 | # Sample of key deletion 20 | # It deletes keys for joe@example.org generated by genkey.py script 21 | 22 | from __future__ import absolute_import, print_function, unicode_literals 23 | 24 | import gpg 25 | 26 | del absolute_import, print_function, unicode_literals 27 | 28 | with gpg.Context() as c: 29 | # Note: We must not modify the key store during iteration, 30 | # therefore, we explicitly make a list. 31 | keys = list(c.keylist("joe+gpg@example.org")) 32 | 33 | for k in keys: 34 | c.op_delete(k, True) 35 | -------------------------------------------------------------------------------- /examples/testCMSgetkey.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright (C) 2016 g10 Code GmbH 4 | # Copyright (C) 2008 Bernhard Reiter 5 | # 6 | # This program is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 2 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, but 12 | # WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | # General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program; if not, see . 18 | """A test applicaton for the CMS protocol.""" 19 | 20 | from __future__ import absolute_import, print_function, unicode_literals 21 | 22 | import sys 23 | import gpg 24 | 25 | del absolute_import, print_function, unicode_literals 26 | 27 | if len(sys.argv) != 2: 28 | sys.exit("fingerprint or unique key ID for gpgme_get_key()") 29 | 30 | with gpg.Context(protocol=gpg.constants.protocol.CMS) as c: 31 | key = c.get_key(sys.argv[1]) 32 | 33 | print("got key: ", key.subkeys[0].fpr) 34 | for uid in key.uids: 35 | print(uid.uid) 36 | -------------------------------------------------------------------------------- /tests/t-export.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright (C) 2016 g10 Code GmbH 4 | # 5 | # This file is part of GPGME. 6 | # 7 | # GPGME is free software; you can redistribute it and/or modify it 8 | # under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # GPGME is distributed in the hope that it will be useful, but WITHOUT 13 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 15 | # Public License for more details. 16 | # 17 | # You should have received a copy of the GNU Lesser General Public 18 | # License along with this program; if not, see . 19 | 20 | from __future__ import absolute_import, print_function, unicode_literals 21 | 22 | import gpg 23 | import support 24 | 25 | del absolute_import, print_function, unicode_literals 26 | 27 | c = gpg.Context() 28 | c.set_armor(True) 29 | 30 | sink = gpg.Data() 31 | c.op_export_ext(['Alpha', 'Bob'], 0, sink) 32 | support.print_data(sink) 33 | 34 | # Again. Now using a key array. 35 | keys = [] 36 | keys.append(c.get_key("0x68697734", False)) # Alpha 37 | keys.append(c.get_key("0xA9E3B0B2", False)) # Bob 38 | sink = gpg.Data() 39 | c.op_export_keys(keys, 0, sink) 40 | support.print_data(sink) 41 | -------------------------------------------------------------------------------- /doc/DCO: -------------------------------------------------------------------------------- 1 | GPGME Python Bindings Developer's Certificate of Origin. Version 1.0 2 | ===================================================================== 3 | 4 | By making a contribution to the GPGME Python Bindings project, I 5 | certify that: 6 | 7 | (a) The contribution was created in whole or in part by me and I 8 | have the right to submit it under the free software license 9 | indicated in the file; or 10 | 11 | (b) The contribution is based upon previous work that, to the 12 | best of my knowledge, is covered under an appropriate free 13 | software license and I have the right under that license to 14 | submit that work with modifications, whether created in whole 15 | or in part by me, under the same free software license 16 | (unless I am permitted to submit under a different license), 17 | as indicated in the file; or 18 | 19 | (c) The contribution was provided directly to me by some other 20 | person who certified (a), (b) or (c) and I have not modified 21 | it. 22 | 23 | (d) I understand and agree that this project and the contribution 24 | are public and that a record of the contribution (including 25 | all personal information I submit with it, including my 26 | sign-off) is maintained indefinitely and may be redistributed 27 | consistent with this project or the free software license(s) 28 | involved. 29 | 30 | Signed-off-by: [Your name and mail address] 31 | -------------------------------------------------------------------------------- /tests/t-wait.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright (C) 2016 g10 Code GmbH 4 | # 5 | # This file is part of GPGME. 6 | # 7 | # GPGME is free software; you can redistribute it and/or modify it 8 | # under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # GPGME is distributed in the hope that it will be useful, but WITHOUT 13 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 15 | # Public License for more details. 16 | # 17 | # You should have received a copy of the GNU Lesser General Public 18 | # License along with this program; if not, see . 19 | 20 | from __future__ import absolute_import, print_function, unicode_literals 21 | 22 | import time 23 | import gpg 24 | import support 25 | _ = support # to appease pyflakes. 26 | 27 | del absolute_import, print_function, unicode_literals 28 | 29 | c = gpg.Context() 30 | c.set_armor(True) 31 | 32 | # Checking a message without a signature. 33 | sig = gpg.Data("foo\n") 34 | text = gpg.Data() 35 | c.op_verify_start(sig, None, text) 36 | 37 | try: 38 | while True: 39 | err = c.wait(False) 40 | if err: 41 | break 42 | time.sleep(0.1) 43 | except Exception as e: 44 | assert e.getcode() == gpg.errors.NO_DATA 45 | else: 46 | assert False, "Expected an error, got none" 47 | -------------------------------------------------------------------------------- /tests/t-file-name.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright (C) 2016 g10 Code GmbH 4 | # 5 | # This file is part of GPGME. 6 | # 7 | # GPGME is free software; you can redistribute it and/or modify it 8 | # under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # GPGME is distributed in the hope that it will be useful, but WITHOUT 13 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 15 | # Public License for more details. 16 | # 17 | # You should have received a copy of the GNU Lesser General Public 18 | # License along with this program; if not, see . 19 | 20 | from __future__ import absolute_import, print_function, unicode_literals 21 | 22 | import os 23 | import gpg 24 | import support 25 | _ = support # to appease pyflakes. 26 | 27 | del absolute_import, print_function, unicode_literals 28 | 29 | testname = "abcde12345" 30 | 31 | c = gpg.Context() 32 | c.set_armor(True) 33 | 34 | source = gpg.Data("Hallo Leute\n") 35 | source.set_file_name(testname) 36 | cipher = gpg.Data() 37 | plain = gpg.Data() 38 | 39 | keys = [] 40 | keys.append(c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False)) 41 | 42 | c.op_encrypt(keys, gpg.constants.ENCRYPT_ALWAYS_TRUST, source, cipher) 43 | cipher.seek(0, os.SEEK_SET) 44 | c.op_decrypt(cipher, plain) 45 | result = c.op_decrypt_result() 46 | assert result.file_name == testname 47 | -------------------------------------------------------------------------------- /helpers.h: -------------------------------------------------------------------------------- 1 | /* 2 | # Copyright (C) 2016 g10 Code GmbH 3 | # Copyright (C) 2004 Igor Belyi 4 | # Copyright (C) 2002 John Goerzen 5 | # 6 | # This library is free software; you can redistribute it and/or 7 | # modify it under the terms of the GNU Lesser General Public 8 | # License as published by the Free Software Foundation; either 9 | # version 2.1 of the License, or (at your option) any later version. 10 | # 11 | # This library is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | # Lesser General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU Lesser General Public 17 | # License along with this library; if not, write to the Free Software 18 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 | */ 20 | 21 | #ifdef HAVE_CONFIG_H 22 | #include "config.h" 23 | #endif 24 | 25 | #include 26 | #include "Python.h" 27 | 28 | /* Flag specifying whether this is an in-tree build. */ 29 | extern int gpg_in_tree_build; 30 | 31 | PyObject *gpg_raise_callback_exception(PyObject *self); 32 | 33 | PyObject *gpg_set_passphrase_cb(PyObject *self, PyObject *cb); 34 | PyObject *gpg_set_progress_cb(PyObject *self, PyObject *cb); 35 | PyObject *gpg_set_status_cb(PyObject *self, PyObject *cb); 36 | 37 | PyObject *gpg_data_new_from_cbs(PyObject *self, PyObject *pycbs, 38 | gpgme_data_t *r_data); 39 | -------------------------------------------------------------------------------- /tests/pubkey-1.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP PUBLIC KEY BLOCK----- 2 | Version: GnuPG v2.1.0-gitb3c71eb (GNU/Linux) 3 | 4 | mQGiBDo41NoRBADSfQazKGYf8nokq6zUKH/6INtV6MypSzSGmX2XErnARkIIPPYj 5 | cQRQ8zCbGV7ZU2ezVbzhFLUSJveE8PZUzzCrLp1O2NSyBTRcR5HVSXW95nJfY8eV 6 | pOvZRAKul0BVLh81kYTsrfzaaCjh9VWNP26LoeN2r+PjZyktXe7gM3C4SwCgoTxK 7 | WUVi9HoT2HCLY7p7oig5hEcEALdCJal0UYomX3nJapIVLVZg3vkidr1RICYMb2vz 8 | 58i17h8sxEtobD1vdIKNejulntaRAXs4n0tDYD9z7pRlwG1CLz1R9WxYzeOOqUDr 9 | fnVXdmU8L/oVWABat8v1V7QQhjMMf+41fuzVwDMMGqjVPLhu4X6wp3A8uyM3YDnQ 10 | VMN1A/4n2G5gHoOvjqxn8Ch5tBAdMGfO8gH4RjQOwzm2R1wPQss/yzUN1+tlMZGX 11 | K2dQ2FCWC/hDUSNaEQRlI15wxxBNZ2RQwlzE2A8v113DpvyzOtv0QO95gJ1teCXC 12 | 7j/BN9asgHaBBc39JLO/TcpuI7Hf8PQ5VcP2F0UE3lczGhXbLLRESm9lIFJhbmRv 13 | bSBIYWNrZXIgKHRlc3Qga2V5IHdpdGggcGFzc3BocmFzZSAiYWJjIikgPGpvZUBl 14 | eGFtcGxlLmNvbT6IYgQTEQIAIgUCTbdXqQIbIwYLCQgHAwIGFQgCCQoLBBYCAwEC 15 | HgECF4AACgkQr4IkT5zZ/VUcCACfQvSPi//9/gBv8SVrK6O4DiyD+jAAn3LEnfF1 16 | 4j6MjwlqXTqol2VgQn1yuQENBDo41N0QBACedJb7Qhm50JSPe1V+rSZKLHT5nc3l 17 | 2k1n7//wNsJkgDW2J7snIRjGtSzeNxMPh+hVzFidzAf3sbOlARQoBrMPPKpnJWtm 18 | 6LEDf2lSwO36l0/bo6qDRmiFRJoHWytTJEjxVwRclVt4bXqHfNw9FKhZZbcKeAN2 19 | oHgmBVSU6edHdwADBQP+OGAkEG4PcfSb8x191R+wkV/q2hA5Ay9z289Dx2rO28CO 20 | 4M2fhhcjSmgr6x0DsrkfESCiG47UGJ169eu+QqJwk3HiF4crGN9rE5+VelBVFtrd 21 | MWkX2rPLGQWyw8iCZKbeH8g/ujmkaLovSmalzDcLe4v1xSLaP7Fnfzit0iIGZAGI 22 | RgQYEQIABgUCOjjU3QAKCRCvgiRPnNn9VVSaAJ9+rj1lIQnRl20i8Rom2Hwbe3re 23 | 9QCfSYFnkZUw0yKF2DfCfqrDzdGAsbaIRgQYEQIABgUCOjjU3gAKCRCvgiRPnNn9 24 | Ve4iAJ9FrGMlFR7s+GWf1scTeeyrthKrPQCfSpc/Yps72aFI7hPfyIa9MuerVZ4= 25 | =QRit 26 | -----END PGP PUBLIC KEY BLOCK----- 27 | -------------------------------------------------------------------------------- /examples/howto/keycount.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | from __future__ import absolute_import, division, unicode_literals 5 | 6 | # Copyright (C) 2018 Ben McGinnes 7 | # 8 | # This program is free software; you can redistribute it and/or modify it under 9 | # the terms of the GNU General Public License as published by the Free Software 10 | # Foundation; either version 2 of the License, or (at your option) any later 11 | # version. 12 | # 13 | # This program is free software; you can redistribute it and/or modify it under 14 | # the terms of the GNU Lesser General Public License as published by the Free 15 | # Software Foundation; either version 2.1 of the License, or (at your option) 16 | # any later version. 17 | # 18 | # This program is distributed in the hope that it will be useful, but WITHOUT 19 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 20 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License and the GNU 21 | # Lesser General Public License for more details. 22 | # 23 | # You should have received a copy of the GNU General Public License and the GNU 24 | # Lesser General Public License along with this program; if not, see 25 | # . 26 | 27 | import gpg 28 | 29 | c = gpg.Context() 30 | seckeys = c.keylist(pattern=None, secret=True) 31 | pubkeys = c.keylist(pattern=None, secret=False) 32 | 33 | seclist = list(seckeys) 34 | secnum = len(seclist) 35 | 36 | publist = list(pubkeys) 37 | pubnum = len(publist) 38 | 39 | print(""" 40 | Number of secret keys: {0} 41 | Number of public keys: {1} 42 | """.format(secnum, pubnum)) 43 | -------------------------------------------------------------------------------- /examples/genkey.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright (C) 2016 g10 Code GmbH 4 | # Copyright (C) 2004 Igor Belyi 5 | # Copyright (C) 2002 John Goerzen 6 | # 7 | # This program is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, but 13 | # WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | # General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program; if not, see . 19 | 20 | from __future__ import absolute_import, print_function, unicode_literals 21 | 22 | import gpg 23 | 24 | del absolute_import, print_function, unicode_literals 25 | 26 | # This is the example from the GPGME manual. 27 | 28 | parms = """ 29 | Key-Type: RSA 30 | Key-Length: 2048 31 | Subkey-Type: RSA 32 | Subkey-Length: 2048 33 | Name-Real: Joe Tester 34 | Name-Comment: with stupid passphrase 35 | Name-Email: joe+gpg@example.org 36 | Passphrase: Crypt0R0cks 37 | Expire-Date: 2020-12-31 38 | 39 | """ 40 | 41 | with gpg.Context() as c: 42 | c.set_progress_cb(gpg.callbacks.progress_stdout) 43 | c.op_genkey(parms, None, None) 44 | print("Generated key with fingerprint {0}.".format( 45 | c.op_genkey_result().fpr)) 46 | -------------------------------------------------------------------------------- /tests/initial.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright (C) 2016 g10 Code GmbH 4 | # 5 | # This file is part of GPGME. 6 | # 7 | # GPGME is free software; you can redistribute it and/or modify it 8 | # under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # GPGME is distributed in the hope that it will be useful, but WITHOUT 13 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 15 | # Public License for more details. 16 | # 17 | # You should have received a copy of the GNU Lesser General Public 18 | # License along with this program; if not, see . 19 | 20 | from __future__ import absolute_import, print_function, unicode_literals 21 | 22 | import os 23 | import subprocess 24 | import gpg 25 | import support 26 | 27 | del absolute_import, print_function, unicode_literals 28 | 29 | print("Using gpg module from {0!r}.".format(os.path.dirname(gpg.__file__))) 30 | 31 | subprocess.check_call([ 32 | os.path.join(os.getenv('top_srcdir'), "tests", "start-stop-agent"), 33 | "--start" 34 | ]) 35 | 36 | with gpg.Context() as c: 37 | alpha = c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False) 38 | bob = c.get_key("D695676BDCEDCC2CDD6152BCFE180B1DA9E3B0B2", False) 39 | 40 | # Mark alpha as trusted. The signature verification tests expect 41 | # this. 42 | support.mark_key_trusted(c, alpha) 43 | 44 | c.op_import(open(support.in_srcdir("encrypt-only.asc"))) 45 | c.op_import(open(support.in_srcdir("sign-only.asc"))) 46 | -------------------------------------------------------------------------------- /examples/signverify.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright (C) 2016 g10 Code GmbH 4 | # Copyright (C) 2004,2008 Igor Belyi 5 | # 6 | # This program is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 2 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, but 12 | # WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | # General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program; if not, see . 18 | 19 | # Sample of unattended signing/verifying of a message. 20 | # It uses keys for joe+gpg@example.org generated by genkey.py script 21 | 22 | from __future__ import absolute_import, print_function, unicode_literals 23 | 24 | import sys 25 | import gpg 26 | from gpg.constants.sig import mode 27 | 28 | del absolute_import, print_function, unicode_literals 29 | 30 | user = "joe+gpg" 31 | 32 | with gpg.Context(pinentry_mode=gpg.constants.PINENTRY_MODE_LOOPBACK) as c: 33 | keys = list(c.keylist(user)) 34 | if len(keys) == 0: 35 | sys.exit("No key matching {}.".format(user)) 36 | 37 | c.signers = keys[:1] 38 | c.set_passphrase_cb(lambda *args: "Crypt0R0cks") 39 | signed_data, _ = c.sign(b"Test message", mode=mode.CLEAR) 40 | 41 | data, result = c.verify(signed_data, verify=keys[:1]) 42 | print("Data: {!r}\nSignature: {!s}".format(data, result.signatures[0])) 43 | -------------------------------------------------------------------------------- /tests/seckey-1.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP PRIVATE KEY BLOCK----- 2 | Version: GnuPG v2.1.0-gitb3c71eb (GNU/Linux) 3 | 4 | lQHpBDo41NoRBADSfQazKGYf8nokq6zUKH/6INtV6MypSzSGmX2XErnARkIIPPYj 5 | cQRQ8zCbGV7ZU2ezVbzhFLUSJveE8PZUzzCrLp1O2NSyBTRcR5HVSXW95nJfY8eV 6 | pOvZRAKul0BVLh81kYTsrfzaaCjh9VWNP26LoeN2r+PjZyktXe7gM3C4SwCgoTxK 7 | WUVi9HoT2HCLY7p7oig5hEcEALdCJal0UYomX3nJapIVLVZg3vkidr1RICYMb2vz 8 | 58i17h8sxEtobD1vdIKNejulntaRAXs4n0tDYD9z7pRlwG1CLz1R9WxYzeOOqUDr 9 | fnVXdmU8L/oVWABat8v1V7QQhjMMf+41fuzVwDMMGqjVPLhu4X6wp3A8uyM3YDnQ 10 | VMN1A/4n2G5gHoOvjqxn8Ch5tBAdMGfO8gH4RjQOwzm2R1wPQss/yzUN1+tlMZGX 11 | K2dQ2FCWC/hDUSNaEQRlI15wxxBNZ2RQwlzE2A8v113DpvyzOtv0QO95gJ1teCXC 12 | 7j/BN9asgHaBBc39JLO/TcpuI7Hf8PQ5VcP2F0UE3lczGhXbLP4HAwL0A7A1a/jY 13 | 6s5JxysLUpKA31U2SrKxePmkmzYSuAiValUVdfkmLRrLSwmNJSy5NcrBHGimja1O 14 | fUUmPTg465j1+vD/tERKb2UgUmFuZG9tIEhhY2tlciAodGVzdCBrZXkgd2l0aCBw 15 | YXNzcGhyYXNlICJhYmMiKSA8am9lQGV4YW1wbGUuY29tPohiBBMRAgAiBQJNt1ep 16 | AhsjBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRCvgiRPnNn9VRwIAJ9C9I+L 17 | //3+AG/xJWsro7gOLIP6MACfcsSd8XXiPoyPCWpdOqiXZWBCfXKdAWAEOjjU3RAE 18 | AJ50lvtCGbnQlI97VX6tJkosdPmdzeXaTWfv//A2wmSANbYnuychGMa1LN43Ew+H 19 | 6FXMWJ3MB/exs6UBFCgGsw88qmcla2bosQN/aVLA7fqXT9ujqoNGaIVEmgdbK1Mk 20 | SPFXBFyVW3hteod83D0UqFlltwp4A3ageCYFVJTp50d3AAMFA/44YCQQbg9x9Jvz 21 | HX3VH7CRX+raEDkDL3Pbz0PHas7bwI7gzZ+GFyNKaCvrHQOyuR8RIKIbjtQYnXr1 22 | 675ConCTceIXhysY32sTn5V6UFUW2t0xaRfas8sZBbLDyIJkpt4fyD+6OaRoui9K 23 | ZqXMNwt7i/XFIto/sWd/OK3SIgZkAf4HAwIoimqPHVJZM85dNw6JtvLKFvvmkm3X 24 | uoCUG5nU6cgk6vetUYiykuKpU4zG3mDtdZdIZf76hJJ6lZTSHH9frLy7bRYPfu/k 25 | U1AFd1T1OxENiEYEGBECAAYFAjo41N0ACgkQr4IkT5zZ/VVUmgCffq49ZSEJ0Zdt 26 | IvEaJth8G3t63vUAn0mBZ5GVMNMihdg3wn6qw83RgLG2iEYEGBECAAYFAjo41N4A 27 | CgkQr4IkT5zZ/VXuIgCfRaxjJRUe7Phln9bHE3nsq7YSqz0An0qXP2KbO9mhSO4T 28 | 38iGvTLnq1We 29 | =m0YJ 30 | -----END PGP PRIVATE KEY BLOCK----- 31 | -------------------------------------------------------------------------------- /examples/simple.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright (C) 2016 g10 Code GmbH 4 | # Copyright (C) 2005 Igor Belyi 5 | # Copyright (C) 2002 John Goerzen 6 | # 7 | # This program is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, but 13 | # WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | # General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program; if not, see . 19 | 20 | from __future__ import absolute_import, print_function, unicode_literals 21 | 22 | import sys 23 | import gpg 24 | 25 | del absolute_import, print_function, unicode_literals 26 | 27 | with gpg.Context(armor=True) as c: 28 | recipients = [] 29 | print("Enter name of your recipient(s), end with a blank line.") 30 | while True: 31 | line = input() 32 | if not line: 33 | break 34 | new = list(c.keylist(line)) 35 | if not new: 36 | print("Matched no known keys.") 37 | else: 38 | print("Adding {}.".format(", ".join(k.uids[0].name for k in new))) 39 | recipients.extend(new) 40 | 41 | if not recipients: 42 | sys.exit("No recipients.") 43 | 44 | print("Encrypting for {}.".format(", ".join( 45 | k.uids[0].name for k in recipients))) 46 | 47 | ciphertext, _, _ = c.encrypt(b"This is my message,", recipients) 48 | sys.stdout.buffer.write(ciphertext) 49 | -------------------------------------------------------------------------------- /examples/inter-edit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright (C) 2016 g10 Code GmbH 4 | # Copyright (C) 2005 Igor Belyi 5 | # 6 | # This program is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 2 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, but 12 | # WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | # General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program; if not, see . 18 | """Simple interactive editor to test editor scripts""" 19 | 20 | from __future__ import absolute_import, print_function, unicode_literals 21 | 22 | import sys 23 | import gpg 24 | 25 | del absolute_import, print_function, unicode_literals 26 | 27 | if len(sys.argv) != 2: 28 | sys.exit("Usage: %s \n" % sys.argv[0]) 29 | 30 | name = sys.argv[1] 31 | 32 | with gpg.Context() as c: 33 | keys = list(c.keylist(name)) 34 | if len(keys) == 0: 35 | sys.exit("No key matching {}.".format(name)) 36 | if len(keys) > 1: 37 | sys.exit("More than one key matching {}.".format(name)) 38 | 39 | key = keys[0] 40 | print("Editing key {} ({}):".format(key.uids[0].uid, key.subkeys[0].fpr)) 41 | 42 | def edit_fnc(keyword, args): 43 | print("Status: {}, args: {} > ".format(keyword, args), end="") 44 | 45 | if 'GET' not in keyword: 46 | # no prompt 47 | print() 48 | return None 49 | 50 | try: 51 | return input() 52 | except EOFError: 53 | return "quit" 54 | 55 | c.interact(key, edit_fnc, sink=sys.stdout) 56 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | # Makefile.am for the Python bindings. 2 | # Copyright (C) 2019 g10 Code GmbH 3 | # 4 | # This file is part of GPGME. 5 | # 6 | # GPGME is free software; you can redistribute it and/or modify it 7 | # under the terms of the GNU Lesser General Public License as 8 | # published by the Free Software Foundation; either version 2.1 of the 9 | # License, or (at your option) any later version. 10 | # 11 | # GPGME is distributed in the hope that it will be useful, but WITHOUT 12 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 13 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 14 | # Public License for more details. 15 | # 16 | # You should have received a copy of the GNU Lesser General Public 17 | # License along with this program; if not, see . 18 | # SPDX-License-Identifier: LGPL-2.1-or-later 19 | 20 | # Created by: 21 | # find . -type f -print | sed 's/^.\// /;$q;s/$/ \\/' | sort 22 | EXTRA_DIST = callbacks.py \ 23 | constants/create.py \ 24 | constants/data/encoding.py \ 25 | constants/data/__init__.py \ 26 | constants/event.py \ 27 | constants/import_type.py \ 28 | constants/__init__.py \ 29 | constants/keylist/__init__.py \ 30 | constants/keylist/mode.py \ 31 | constants/keysign.py \ 32 | constants/md.py \ 33 | constants/pk.py \ 34 | constants/protocol.py \ 35 | constants/sig/__init__.py \ 36 | constants/sig/mode.py \ 37 | constants/sig/notation.py \ 38 | constants/sigsum.py \ 39 | constants/status.py \ 40 | constants/tofu/__init__.py \ 41 | constants/tofu/policy.py \ 42 | constants/validity.py \ 43 | core.py \ 44 | errors.py \ 45 | __init__.py \ 46 | results.py \ 47 | util.py 48 | -------------------------------------------------------------------------------- /tests/sign-only.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP PRIVATE KEY BLOCK----- 2 | Version: GnuPG v2 3 | 4 | lQPFBFd/jO8BCADiull4EVJiKmJqclPyU6GhTlbJXw7Ch0zbFAauOWYT3ACmgr1U 5 | KfJlZ2sPe2EezZkVSACxgIjTCzcgKQLh/swXdhO8uEgWEIN8f07WcSVDrcRGYwDS 6 | KFSRsK0bfO/OQQDUsSkNQSHjcOdLnCHCinMrQi1mBZOs+Y/DXOkkEV1zbFFV7q6X 7 | 4vX9HSWwTRQTdOV9CFZykbwM+X1YIZlVtpOAKqSNJi3P17uQF7P9zko6HWKKKQ5S 8 | 96BfXUOIpBRl82R85/yQgeGrWlvZ2BT2ittscNQlBKqLHJ7LIeDr9ctbKlKZjHTn 9 | Da7NYg+PoMHspbizjSONbEzpcR/9ZUq16oJJABEBAAH+BwMC7hQZNJSmlX/W6sfL 10 | 0wakX6kTsiCEMy2vMCRcZ769JKT234avHtkL/g7MBJEzqdG9HSEp7+LHGuOWJhfa 11 | 20f61WvPT5ujUIy//QXJ9a8z877jCm+fHKCTDXGYLLfCkJLfr3/GfTRy6gaIGTSw 12 | BqZaRelPvHbMp+eiFqDkf8W/E1LO3/83k87+pXggjz4p0OasyMw8RcDmy+IKBMGG 13 | bzet5WIKHIhpblIzuuucQHOjtwA8vCedub3F4lcRuULe2GW6sNuCB9kjSC9g6D1d 14 | bJ+WYi5GiUUQARGSNXiWVoVPLpEo0i6/2bKJ7vBYGRewNp42ebVQU2bFW7uzhaIq 15 | 4itzNTjFNTpcxX3Lo0/mzJpe7pVRJwN+HGahNGT0EtPDsT/nNTFDUq8e8nt0U9/8 16 | 0eekg4MRBJEzE3A+wosIHPjzCkQgu98+nh79rPMbCpZVxNfLb136cTkubmHCWptN 17 | T2MbqK2L4hMcOxHGGOmI9SjFltNeKtTsVtkxh3Vj67UESPdN550centfasJYA0bj 18 | guRQfHWHJXYIfFwblIFkl8xtIVLTeWlQMEvc7oI8jcJOc2ri8Zdjj/55xxv/RvjC 19 | ZKzfjPpdkLYcN1zP/hETLD68u7WmiMAYCr8Eq9YQ3oKklUpWxRMCAAtmgjGGpm5P 20 | QQW+36s96Q3cuG8R0Z4Wo8y89FgWzCEzuAhemCdffoUA8kn0HJQaVndnExJb1Ebz 21 | wp+zsX/JqiOFvcKHJAWCaXkk0oXVi1aIV4tQyCPfhyjnd846K7g8UabAz51IJHvF 22 | CXRAmqJvu26NqjYOfWBJJxZQsPH4FjPfYx+e/MFPZa+UTKCfzaOHClrePHUDHw58 23 | Ez5ItcORYn51IWW33r+c4tlhW5mrjMD7FcjFOuYT4EIivd5BSnwLP0fjBz8TBVAY 24 | yyFO+YAXTQ+0MVNpZ24gT25seSAodGVzdCBrZXksIGRvIG5vdCB1c2UpIDxzb0Bl 25 | eGFtcGxlLm9yZz6JATcEEwEIACEFAld/jO8CGwMFCwkIBwIGFQgJCgsCBBYCAwEC 26 | HgECF4AACgkQ/tFT8S8Y9F3PAwgAvKav6+luvcAhrpBMO4z/Q8kDMtO5AW1KTEcz 27 | neqpj5eTVJVbYUgDuBlEXbFYtcZmYyYtJC5KQkN3bxPmehVUzGk27UYWMWbPIWyU 28 | riGcFL5BWWQaKSqiWUypzhNVnxYoiWVhHeJ36LICVMpLBaubgcpwCSW/j58yZo/7 29 | XRwf40OblXr4cevIW4Oq5GSxKOQF+DCErF6BeikC2i+NoqSxwNiIO/1NUxs8QfAI 30 | z8UT/bSUXr62BWLfeCIDGgXutMMPth3tKi4DlvLCzI6eYJrd8E3Rt7iUZm9IH8OQ 31 | Djv2DKnL/E/AP8oITItrOmICqfEWcj+Tk2Xep4pCCMNU+Pa0yg== 32 | =gG5b 33 | -----END PGP PRIVATE KEY BLOCK----- 34 | -------------------------------------------------------------------------------- /private.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 g10 Code GmbH 3 | * 4 | * This file is part of GPGME. 5 | * 6 | * GPGME is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * GPGME is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this program; if not, see . 18 | */ 19 | 20 | #include 21 | 22 | #ifndef _GPG_PRIVATE_H_ 23 | #define _GPG_PRIVATE_H_ 24 | 25 | /* GPGME glue. Implemented in helpers.c. */ 26 | 27 | void _gpg_exception_init(void); 28 | gpgme_error_t _gpg_exception2code(void); 29 | 30 | PyObject *_gpg_obj2gpgme_t(PyObject *input, const char *objtype, int argnum); 31 | PyObject *_gpg_obj2gpgme_data_t(PyObject *input, int argnum, 32 | gpgme_data_t *wrapper, 33 | PyObject **bytesio, Py_buffer *view); 34 | 35 | PyObject *_gpg_wrap_result(PyObject *fragile, const char *classname); 36 | 37 | gpgme_error_t _gpg_interact_cb(void *opaque, const char *keyword, 38 | const char *args, int fd); 39 | gpgme_error_t _gpg_assuan_data_cb (void *hook, 40 | const void *data, size_t datalen); 41 | gpgme_error_t _gpg_assuan_inquire_cb (void *hook, 42 | const char *name, const char *args, 43 | gpgme_data_t *r_data); 44 | gpgme_error_t _gpg_assuan_status_cb (void *hook, 45 | const char *status, const char *args); 46 | 47 | 48 | 49 | /* SWIG runtime support. Implemented in gpgme.i. */ 50 | 51 | PyObject *_gpg_wrap_gpgme_data_t(gpgme_data_t data); 52 | gpgme_ctx_t _gpg_unwrap_gpgme_ctx_t(PyObject *wrapped); 53 | 54 | #endif /* _GPG_PRIVATE_H_ */ 55 | -------------------------------------------------------------------------------- /tests/encrypt-only.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP PRIVATE KEY BLOCK----- 2 | Version: GnuPG v2 3 | 4 | lQPGBFd/jL0BCAD8jfoblIrlHS0shDCbSiO7RFaT6sEa/6tSPkv6XzBba9oXOkuO 5 | FLTkNpIwPb92U8SOS+27j7n9v6U5NW2tyZwIoeLb8lUyKnCBr22IUhTFVXf7fros 6 | zmPugsJaDBi9f7RL0bqiCn4EV3DGKyAukZklk1k1JV4Ec3dEPMAmL9LmnvXreEjU 7 | pQZZN9sJV32ew8CYkZ6AB8foFQwfxn4x0iUoKvj8kW9RsY1KMPucp4YiFhHeMZW1 8 | 5wGAZdEIZYKyWEp4bi/wC9yn/TUR5uNWc0uVJzQvuHwaYjolPW89DinjBkPEJCBr 9 | RwumaOWfbu/hb51wBoUTmUr9diVw93L2ROLPABEBAAH+BwMC1bmUAoPJKI/WBiHm 10 | P6tSNRLdd+7etfjAFvKL7Ob2pNTrc3hbtyOLIQ9tuEaqXEyfnCms/DCg8QdkaFUv 11 | Nkoj0W5+G/MQuR2jIvrq/wyL/4jIw0AFbp9/V1JbSXZh2g1eJLnnykn7uPxCbDFY 12 | FrVeFmkhoxZ3pid6ZQSWlxXsdW+YMvbUfNIIZpbygI/alIBvbDS1YJYEBDCwFZjU 13 | 7quE2Ufxo8dm34EHcmbpYpn4r3DUrU5AHQ2fIprLIVqHn4+NUrR8WZS9nCnIeu/z 14 | OaJUZ2lJFRjUC6Gpsbsw6Xwh4Ntwzyt2SsXc+UVZngjozw3yw0VpDifxMBqcd+9x 15 | baSc7dfbOZF2BCZOwnB7/QrFZDaqe5b3n6rTdj1va/CrJMuxbgaNAjvLpdT2EUPZ 16 | fHDAdPAjASofxBREv+HIKwksuPJ9cvavZU6Q4KQA7buo25hd7yjuba4WbLQhp0jH 17 | AT1P7SdakMhk/IFcUKFdB3ZyZZZ1JTTPa2xZn9yDa3Jb1t7IMLYLwY6EFbjvaxH5 18 | WEGZvOAq2iEa941mxv4miwgf7MQPx6g9u0+dXc7iZApwWs9MNfJo3J25sKhWK5Be 19 | Bu3w7c6nrlg40GtPuDRgaBvYWbVerJcepTA/EPfugEJtRsDJkt7wZq1H9lWHU7Ih 20 | Up6/+XKtBzlCIqYjorzFLnC721pcKFcPhLgvtjjNJvUsLXbr9CwnBub/eTFcfRb2 21 | ro60H9cOhf0fQSQyvkZWfzq0BN6rG27G1KhyprsJAmpW0fTHHkB4V19788C2sTQv 22 | D93VU3Nd6MWocwAYtPWmtwXPpuOAU9IcwAvVTxBeBJCXxbH3uyx1frwDXA7lf4Pb 23 | a8hMoMMVU+rAG1uepKI5h4seBIKP7qKEKAPloI6/Vtf7/Ump4DKprS1QpfOW+lsX 24 | aR48lgNR6sQXtDdFbmNyeXB0aW9uIE9ubHkgKHRlc3Qga2V5LCBkbyBub3QgdXNl 25 | KSA8ZW9AZXhhbXBsZS5vcmc+iQE3BBMBCAAhBQJXf4y9AhsNBQsJCAcCBhUICQoL 26 | AgQWAgMBAh4BAheAAAoJEJIFcnabn+Gc/KgH/07wzrsBzTqdI5L6cIqQ81Vq8ASj 27 | tsuYoVfFxymB8F/AxpnLMhYRuWQTcoUHQ/olG2yA0C6o4e1JPAmh6LQGwr0eRnc2 28 | 2tr4cbnQAhXpJ8xOR6kH9eE8nGeC7tlEeeV/Wnj3SLZOXOjYjnA9bA3JX9DP3qcz 29 | w1sKQPEHsGkMJuT0ZadnlJ1qw8AnnNKLDlG4kIO9hz3qB8BjxFZf+j5f/nhFNv5I 30 | pnNdMcDwQqHVrwD6WO+Xmmdykab0awL9To0S9DG9ohcXuJiTMa8vtXFSBM0koUDk 31 | BWajEq+QAcDpmdFsQr4/gbzvHkAIVTQb0seJr4gpmXFZu3TMuGVD9j13GaI= 32 | =38ri 33 | -----END PGP PRIVATE KEY BLOCK----- 34 | -------------------------------------------------------------------------------- /examples/howto/decrypt-file.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | from __future__ import absolute_import, division, unicode_literals 5 | 6 | # Copyright (C) 2018 Ben McGinnes 7 | # 8 | # This program is free software; you can redistribute it and/or modify it under 9 | # the terms of the GNU General Public License as published by the Free Software 10 | # Foundation; either version 2 of the License, or (at your option) any later 11 | # version. 12 | # 13 | # This program is free software; you can redistribute it and/or modify it under 14 | # the terms of the GNU Lesser General Public License as published by the Free 15 | # Software Foundation; either version 2.1 of the License, or (at your option) 16 | # any later version. 17 | # 18 | # This program is distributed in the hope that it will be useful, but WITHOUT 19 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 20 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License and the GNU 21 | # Lesser General Public License for more details. 22 | # 23 | # You should have received a copy of the GNU General Public License and the GNU 24 | # Lesser General Public License along with this program; if not, see 25 | # . 26 | 27 | import gpg 28 | import sys 29 | 30 | if len(sys.argv) == 3: 31 | ciphertext = sys.argv[1] 32 | newfile = sys.argv[2] 33 | elif len(sys.argv) == 2: 34 | ciphertext = sys.argv[1] 35 | newfile = input("Enter path and filename to save decrypted data to: ") 36 | else: 37 | ciphertext = input("Enter path and filename of encrypted file: ") 38 | newfile = input("Enter path and filename to save decrypted data to: ") 39 | 40 | with open(ciphertext, "rb") as cfile: 41 | try: 42 | plaintext, result, verify_result = gpg.Context().decrypt(cfile) 43 | except gpg.errors.GPGMEError as e: 44 | plaintext = None 45 | print(e) 46 | 47 | if plaintext is not None: 48 | with open(newfile, "wb") as nfile: 49 | nfile.write(plaintext) 50 | else: 51 | pass 52 | -------------------------------------------------------------------------------- /examples/howto/README.org: -------------------------------------------------------------------------------- 1 | #+TITLE: GPGME Python Bindings HOWTO Examples 2 | #+LATEX_COMPILER: xelatex 3 | #+LATEX_CLASS: article 4 | #+LATEX_CLASS_OPTIONS: [12pt] 5 | #+LATEX_HEADER: \usepackage{xltxtra} 6 | #+LATEX_HEADER: \usepackage[margin=1in]{geometry} 7 | #+LATEX_HEADER: \setmainfont[Ligatures={Common}]{Times New Roman} 8 | #+LATEX_HEADER: \author{Ben McGinnes } 9 | 10 | 11 | * Examples 12 | :PROPERTIES: 13 | :CUSTOM_ID: gpgme-python3-examples 14 | :END: 15 | 16 | The contents of this directory are the examples included in the /GNU 17 | Privacy Guard (GnuPG) Made Easy Python Bindings HOWTO/ file. Each 18 | script is explicitly for Python 3 and specifically for Python 3.4 or 19 | later. 20 | 21 | Some of these scripts may work with Python 2.7, but there are no 22 | guarantees. They will include the relevant imports from the 23 | =__future__= module to facilitate that if possible. 24 | 25 | 26 | * Copyright and Licensing 27 | :PROPERTIES: 28 | :CUSTOM_ID: copyright-and-license 29 | :END: 30 | 31 | Unless otherwise stated, all the examples in this directory are 32 | released under the same terms as GPGME itself; that is they are dual 33 | licensed under the terms of both the GNU General Public License 34 | version 2.0 (or any later version) *and* the GNU Lesser General 35 | Public License version 2.1 (or any later version). 36 | 37 | 38 | ** Copyright (C) The GnuPG Project, 2018 39 | :PROPERTIES: 40 | :CUSTOM_ID: copyright 41 | :END: 42 | 43 | Copyright © The GnuPG Project, 2018. 44 | 45 | 46 | ** License GPL compatible 47 | :PROPERTIES: 48 | :CUSTOM_ID: license 49 | :END: 50 | 51 | This file is free software; as a special exception the author gives 52 | unlimited permission to copy and/or distribute it, with or without 53 | modifications, as long as this notice is preserved. 54 | 55 | This file is distributed in the hope that it will be useful, but 56 | WITHOUT ANY WARRANTY, to the extent permitted by law; without even 57 | the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 58 | PURPOSE. 59 | -------------------------------------------------------------------------------- /doc/README: -------------------------------------------------------------------------------- 1 | GPGME Python Bindings Documentation 2 | =================================== 3 | 4 | As the GPGME Python bindings exist in two worlds within the FOSS 5 | universe, it's always had a little issue with regards to its 6 | documentation and specifically to the format of it. The GnuPG 7 | Project, like much of the rest of the GNU Project, uses Texinfo to 8 | build its documentation. While the actual format used to write and 9 | edit that documentation is Org mode. Largely because most, if not 10 | all, of the GnuPG developers use GNU Emacs for much of their work. 11 | 12 | The Python world, however, utilises reStructuredText almost 13 | universally. This in turn is used by Sphinx or Docutils directly to 14 | build the documentation. 15 | 16 | Each has various advantages for their own ecisystems, but this part of 17 | the GnuPG effort is aimed at both sides. So, long story short, this 18 | documentation is provided as both Texinfo and reStructuredText files. 19 | 20 | This docs directory contains four main subdirectories: 21 | 22 | 1. meta 23 | 2. src 24 | 3. rst 25 | 4. texinfo 26 | 27 | The Meta directory is for docs that are not intended for distribution 28 | or are about the docs themselves. The sole exception being this 29 | README file. 30 | 31 | The Src directory is where the original edited files are, from which 32 | the following two formats are generated initially. Most, if not all, 33 | of these are written in Org Mode. 34 | 35 | The ReST directory contains reStructuredText files which have been 36 | converted to that format from the Org Mode files via Pandoc. 37 | 38 | The Texinfo directory contains Texinfo files which have been exported 39 | to that format from the Org Mode files by Org Mode itself within GNU 40 | Emacs. 41 | 42 | Those latter two directories should then be used by their respective 43 | build systems to produce the various output file formats they normally 44 | do. They should not spill out into this parent directory. 45 | Particularly since it is quite possible, perhaps even likely, that 46 | alternatives to both of them may be added to this parent documentation 47 | directory at some future point. 48 | -------------------------------------------------------------------------------- /examples/howto/verify-signed-file.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | from __future__ import absolute_import, division, unicode_literals 5 | 6 | # Copyright (C) 2018 Ben McGinnes 7 | # 8 | # This program is free software; you can redistribute it and/or modify it under 9 | # the terms of the GNU General Public License as published by the Free Software 10 | # Foundation; either version 2 of the License, or (at your option) any later 11 | # version. 12 | # 13 | # This program is free software; you can redistribute it and/or modify it under 14 | # the terms of the GNU Lesser General Public License as published by the Free 15 | # Software Foundation; either version 2.1 of the License, or (at your option) 16 | # any later version. 17 | # 18 | # This program is distributed in the hope that it will be useful, but WITHOUT 19 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 20 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License and the GNU 21 | # Lesser General Public License for more details. 22 | # 23 | # You should have received a copy of the GNU General Public License and the GNU 24 | # Lesser General Public License along with this program; if not, see 25 | # . 26 | 27 | import gpg 28 | import sys 29 | import time 30 | 31 | """ 32 | Verifies a signed file which has been signed with either NORMAL or CLEAR modes. 33 | """ 34 | 35 | if len(sys.argv) > 2: 36 | filename = " ".join(sys.argv[1:]) 37 | elif len(sys.argv) == 2: 38 | filename = sys.argv[1] 39 | else: 40 | filename = input("Enter the path and filename to sign: ") 41 | 42 | c = gpg.Context() 43 | 44 | try: 45 | data, result = c.verify(open(filename)) 46 | verified = True 47 | except gpg.errors.BadSignatures as e: 48 | verified = False 49 | print(e) 50 | 51 | if verified is True: 52 | for i in range(len(result.signatures)): 53 | sign = result.signatures[i] 54 | print("""Good signature from: 55 | {0} 56 | with key {1} 57 | made at {2} 58 | """.format(c.get_key(sign.fpr).uids[0].uid, sign.fpr, 59 | time.ctime(sign.timestamp))) 60 | else: 61 | pass 62 | -------------------------------------------------------------------------------- /tests/t-decrypt.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright (C) 2016 g10 Code GmbH 4 | # 5 | # This file is part of GPGME. 6 | # 7 | # GPGME is free software; you can redistribute it and/or modify it 8 | # under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # GPGME is distributed in the hope that it will be useful, but WITHOUT 13 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 15 | # Public License for more details. 16 | # 17 | # You should have received a copy of the GNU Lesser General Public 18 | # License along with this program; if not, see . 19 | 20 | from __future__ import absolute_import, print_function, unicode_literals 21 | 22 | import gpg 23 | import support 24 | 25 | del absolute_import, print_function, unicode_literals 26 | 27 | c = gpg.Context() 28 | 29 | source = gpg.Data(file=support.make_filename("cipher-1.asc")) 30 | sink = gpg.Data() 31 | 32 | c.op_decrypt(source, sink) 33 | result = c.op_decrypt_result() 34 | assert not result.unsupported_algorithm, \ 35 | "Unsupported algorithm: {}".format(result.unsupported_algorithm) 36 | 37 | support.print_data(sink) 38 | 39 | # Idiomatic interface. 40 | with gpg.Context() as c: 41 | plaintext, _, _ = c.decrypt(open(support.make_filename("cipher-1.asc")), verify=False) 42 | assert len(plaintext) > 0 43 | assert plaintext.find(b'Wenn Sie dies lesen k') >= 0, \ 44 | 'Plaintext not found' 45 | 46 | plaintext, _, _ = c.decrypt(open(support.make_filename("cipher-3.asc")), verify=False) 47 | assert len(plaintext) > 0 48 | assert plaintext.find(b'Reenact Studied Thermos Bonehead Unclasp Opposing') >= 0, \ 49 | 'second Plaintext not found' 50 | 51 | plaintext, _, _ = c.decrypt(open(support.make_filename("cipher-no-sig.asc")), verify=False) 52 | assert len(plaintext) > 0 53 | assert plaintext.find(b'Viscosity Dispersal Thimble Saturday Flaxseed Deflected') >= 0, \ 54 | 'third Plaintext was not found' 55 | -------------------------------------------------------------------------------- /src/callbacks.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2004 Igor Belyi 2 | # Copyright (C) 2002 John Goerzen 3 | # 4 | # This library is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU Lesser General Public 6 | # License as published by the Free Software Foundation; either 7 | # version 2.1 of the License, or (at your option) any later version. 8 | # 9 | # This library is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # Lesser General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU Lesser General Public 15 | # License along with this library; if not, write to the Free Software 16 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 | 18 | from __future__ import absolute_import, print_function, unicode_literals 19 | 20 | from getpass import getpass 21 | 22 | del absolute_import, print_function, unicode_literals 23 | 24 | 25 | def passphrase_stdin(hint, desc, prev_bad, hook=None): 26 | """This is a sample callback that will read a passphrase from 27 | the terminal. The hook here, if present, will be used to describe 28 | why the passphrase is needed.""" 29 | why = '' 30 | if hook is not None: 31 | why = ' ' + hook 32 | if prev_bad: 33 | why += ' (again)' 34 | print("Please supply %s' password%s:" % (hint, why)) 35 | return getpass() 36 | 37 | 38 | def progress_stdout(what, type, current, total, hook=None): 39 | print("PROGRESS UPDATE: what = %s, type = %d, current = %d, total = %d" % 40 | (what, type, current, total)) 41 | 42 | 43 | def readcb_fh(count, hook): 44 | """A callback for data. hook should be a Python file-like object.""" 45 | if count: 46 | # Should return '' on EOF 47 | return hook.read(count) 48 | else: 49 | # Wants to rewind. 50 | if not hasattr(hook, 'seek'): 51 | return None 52 | hook.seek(0, 0) 53 | return None 54 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Package: gpg-py 2 | Homepage: https://gnupg.org/software/gpgme/ 3 | Download: https://gnupg.org/ftp/gcrypt/gpgme/ 4 | Repository: git://git.gnupg.org/gpgme.git 5 | Maintainer: Werner Koch 6 | Bug reports: https://bugs.gnupg.org 7 | Security related bug reports: security@gnupg.org 8 | License (software): LGPL-2.1-or-later 9 | License (examples, tests): GPL-2.0-or-later 10 | 11 | 12 | GPGME is free software. See the files COPYING.LESSER and COPYING for 13 | copying conditions. License copyright years may be listed using range 14 | notation, e.g., 2000-2013, indicating that every year in the range, 15 | inclusive, is a copyrightable year that would otherwise be listed 16 | individually. 17 | 18 | 19 | List of Copyright holders 20 | ========================= 21 | 22 | Copyright (C) 1985, 1986, 1988, 1990-2022 Free Software Foundation, Inc. 23 | Copyright (C) 2000 Werner Koch 24 | Copyright (C) 2001-2022, 2024 g10 Code GmbH 25 | Copyright (C) 2004-2008 Igor Belyi 26 | Copyright (C) 2002 John Goerzen 27 | Copyright (C) 2008 Bernhard Reiter 28 | Copyright (C) 2014, 2015 Martin Albrecht 29 | Copyright (C) 2015, 2018, 2019 Ben McGinnes 30 | Copyright (C) 2016 Tobias Mueller 31 | 32 | 33 | Authors with a DCO 34 | ================== 35 | 36 | Daniel Kahn Gillmor 37 | 2014-09-24:878ul9w4j8.fsf@alice.fifthhorseman.net: 38 | 39 | Tobias Mueller 40 | 2016-11-23:1479937342.11180.3.camel@cryptobitch.de: 41 | 42 | Ben McGinnes 43 | 2017-12-16:20171216002102.l6aejk5xdp6xhtfi@adversary.org: 44 | 45 | Lucas Hoffmann 46 | 2025-03-23:174277003465.373069.17602536947672357293@yoga: 47 | 48 | 49 | Copyright 2001, 2002, 2012, 2013 g10 Code GmbH 50 | 51 | This file is free software; as a special exception the author gives 52 | unlimited permission to copy and/or distribute it, with or without 53 | modifications, as long as this notice is preserved. 54 | 55 | This file is distributed in the hope that it will be useful, but 56 | WITHOUT ANY WARRANTY, to the extent permitted by law; without even the 57 | implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 58 | -------------------------------------------------------------------------------- /examples/howto/groups.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from __future__ import absolute_import, division, unicode_literals 4 | 5 | # Copyright (C) 2018 Ben McGinnes 6 | # 7 | # This program is free software; you can redistribute it and/or modify it under 8 | # the terms of the GNU General Public License as published by the Free Software 9 | # Foundation; either version 2 of the License, or (at your option) any later 10 | # version. 11 | # 12 | # This program is free software; you can redistribute it and/or modify it under 13 | # the terms of the GNU Lesser General Public License as published by the Free 14 | # Software Foundation; either version 2.1 of the License, or (at your option) 15 | # any later version. 16 | # 17 | # This program is distributed in the hope that it will be useful, but WITHOUT 18 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 19 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License and the GNU 20 | # Lesser General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU General Public License and the GNU 23 | # Lesser General Public License along with this program; if not, see 24 | # . 25 | 26 | import subprocess 27 | import sys 28 | 29 | """ 30 | Intended for use with other scripts. 31 | 32 | Usage: from groups import group_lists 33 | """ 34 | 35 | if sys.platform == "win32": 36 | gpgconfcmd = "gpgconf.exe --list-options gpg" 37 | else: 38 | gpgconfcmd = "gpgconf --list-options gpg" 39 | 40 | process = subprocess.Popen(gpgconfcmd.split(), stdout=subprocess.PIPE) 41 | procom = process.communicate() 42 | 43 | if sys.version_info[0] == 2: 44 | lines = procom[0].splitlines() 45 | else: 46 | lines = procom[0].decode().splitlines() 47 | 48 | for line in lines: 49 | if line.startswith("group") is True: 50 | break 51 | 52 | groups = line.split(":")[-1].replace('"', '').split(',') 53 | 54 | group_lines = [] 55 | group_lists = [] 56 | 57 | for group in groups: 58 | group_lines.append(group.split("=")) 59 | group_lists.append(group.split("=")) 60 | 61 | for glist in group_lists: 62 | glist[1] = glist[1].split() 63 | -------------------------------------------------------------------------------- /src/util.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016 g10 Code GmbH 2 | # Copyright (C) 2004,2008 Igor Belyi 3 | # Copyright (C) 2002 John Goerzen 4 | # 5 | # This library is free software; you can redistribute it and/or 6 | # modify it under the terms of the GNU Lesser General Public 7 | # License as published by the Free Software Foundation; either 8 | # version 2.1 of the License, or (at your option) any later version. 9 | # 10 | # This library is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # Lesser General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU Lesser General Public 16 | # License along with this library; if not, write to the Free Software 17 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | 19 | from __future__ import absolute_import, print_function, unicode_literals 20 | 21 | import sys 22 | 23 | del absolute_import, print_function, unicode_literals 24 | 25 | 26 | def process_constants(prefix, scope): 27 | """Called by the constant modules to load up the constants from the C 28 | library starting with PREFIX. Matching constants will be inserted 29 | into SCOPE with PREFIX stripped from the names. Returns the names 30 | of inserted constants. 31 | 32 | """ 33 | from . import gpgme 34 | index = len(prefix) 35 | constants = { 36 | identifier[index:]: getattr(gpgme, identifier) 37 | for identifier in dir(gpgme) if identifier.startswith(prefix) 38 | } 39 | scope.update(constants) 40 | return list(constants.keys()) 41 | 42 | 43 | def percent_escape(s): 44 | return ''.join('%{0:2x}'.format(ord(c)) 45 | if c == '+' or c == '"' or c == '%' or ord(c) <= 0x20 else c 46 | for c in s) 47 | 48 | 49 | # Python2/3 compatibility 50 | if sys.version_info[0] == 3: 51 | # Python3 52 | def is_a_string(x): 53 | return isinstance(x, str) 54 | else: 55 | # Python2 56 | def is_a_string(x): 57 | return isinstance(x, basestring) 58 | -------------------------------------------------------------------------------- /examples/low_level-encrypt_to_all.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright (C) 2016 g10 Code GmbH 4 | # Copyright (C) 2008 Igor Belyi 5 | # Copyright (C) 2002 John Goerzen 6 | # 7 | # This program is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, but 13 | # WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | # General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program; if not, see . 19 | """ 20 | This program will try to encrypt a simple message to each key on your 21 | keyring. If your keyring has any invalid keys on it, those keys will 22 | be skipped and it will re-try the encryption.""" 23 | 24 | from __future__ import absolute_import, print_function, unicode_literals 25 | 26 | import sys 27 | import gpg 28 | 29 | del absolute_import, print_function, unicode_literals 30 | 31 | with gpg.Context(armor=True) as c: 32 | recipients = list() 33 | for key in c.keylist(): 34 | valid = 0 35 | if any(sk.can_encrypt for sk in key.subkeys): 36 | recipients.append(key) 37 | print("Adding recipient {0}.".format(key.uids[0].uid)) 38 | 39 | ciphertext = None 40 | while not ciphertext: 41 | print("Encrypting to %d recipients" % len(recipients)) 42 | try: 43 | ciphertext, _, _ = c.encrypt( 44 | b'This is my message.', recipients=recipients) 45 | except gpg.errors.InvalidRecipients as e: 46 | print("Encryption failed for these keys:\n{0!s}".format(e)) 47 | 48 | # filter out the bad keys 49 | bad_keys = {bad.fpr for bad in e.recipients} 50 | recipients = [ 51 | r for r in recipients if not r.subkeys[0].fpr in bad_keys 52 | ] 53 | 54 | sys.stdout.buffer.write(ciphertext) 55 | -------------------------------------------------------------------------------- /examples/howto/clear-sign-file.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | from __future__ import absolute_import, division, unicode_literals 5 | 6 | # Copyright (C) 2018 Ben McGinnes 7 | # 8 | # This program is free software; you can redistribute it and/or modify it under 9 | # the terms of the GNU General Public License as published by the Free Software 10 | # Foundation; either version 2 of the License, or (at your option) any later 11 | # version. 12 | # 13 | # This program is free software; you can redistribute it and/or modify it under 14 | # the terms of the GNU Lesser General Public License as published by the Free 15 | # Software Foundation; either version 2.1 of the License, or (at your option) 16 | # any later version. 17 | # 18 | # This program is distributed in the hope that it will be useful, but WITHOUT 19 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 20 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License and the GNU 21 | # Lesser General Public License for more details. 22 | # 23 | # You should have received a copy of the GNU General Public License and the GNU 24 | # Lesser General Public License along with this program; if not, see 25 | # . 26 | 27 | import gpg 28 | import sys 29 | 30 | """ 31 | Clear-signs a file with a specified key. If entering both the key and the 32 | filename on the command line, the key must be entered first. 33 | """ 34 | 35 | if len(sys.argv) > 3: 36 | logrus = sys.argv[1] 37 | filename = " ".join(sys.argv[2:]) 38 | elif len(sys.argv) == 3: 39 | logrus = sys.argv[1] 40 | filename = sys.argv[2] 41 | elif len(sys.argv) == 2: 42 | logrus = sys.argv[1] 43 | filename = input("Enter the path and filename to sign: ") 44 | else: 45 | logrus = input("Enter the fingerprint or key ID to sign with: ") 46 | filename = input("Enter the path and filename to sign: ") 47 | 48 | with open(filename, "rb") as f: 49 | text = f.read() 50 | 51 | key = list(gpg.Context().keylist(pattern=logrus)) 52 | 53 | with gpg.Context(armor=True, signers=key) as c: 54 | signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.CLEAR) 55 | with open("{0}.asc".format(filename), "wb") as f: 56 | f.write(signed_data) 57 | -------------------------------------------------------------------------------- /examples/exportimport.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright (C) 2016 g10 Code GmbH 4 | # Copyright (C) 2004,2008 Igor Belyi 5 | # 6 | # This program is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 2 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, but 12 | # WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | # General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program; if not, see . 18 | 19 | # Sample of export and import of keys 20 | # It uses keys for joe+gpg@example.org generated by genkey.py script 21 | 22 | from __future__ import absolute_import, print_function, unicode_literals 23 | 24 | import sys 25 | import os 26 | import gpg 27 | 28 | del absolute_import, print_function, unicode_literals 29 | 30 | user = "joe+gpg@example.org" 31 | 32 | with gpg.Context(armor=True) as c, gpg.Data() as expkey: 33 | print(" - Export %s's public keys - " % user) 34 | c.op_export(user, 0, expkey) 35 | 36 | # print out exported data to see how it looks in armor. 37 | expkey.seek(0, os.SEEK_SET) 38 | expstring = expkey.read() 39 | if expstring: 40 | sys.stdout.buffer.write(expstring) 41 | else: 42 | sys.exit("No %s's keys to export!" % user) 43 | 44 | # delete keys to ensure that they came from our imported data. Note 45 | # that if joe's key has private part as well we can only delete both 46 | # of them. 47 | with gpg.Context() as c: 48 | # Note: We must not modify the key store during iteration, 49 | # therefore, we explicitly make a list. 50 | keys = list(c.keylist(user)) 51 | 52 | for k in keys: 53 | c.op_delete(k, True) 54 | 55 | with gpg.Context() as c: 56 | print(" - Import exported keys - ") 57 | c.op_import(expstring) 58 | result = c.op_import_result() 59 | if result: 60 | print(result) 61 | else: 62 | sys.exit(" - No import result - ") 63 | -------------------------------------------------------------------------------- /tests/t-encrypt-large.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright (C) 2016 g10 Code GmbH 4 | # 5 | # This file is part of GPGME. 6 | # 7 | # GPGME is free software; you can redistribute it and/or modify it 8 | # under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # GPGME is distributed in the hope that it will be useful, but WITHOUT 13 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 15 | # Public License for more details. 16 | # 17 | # You should have received a copy of the GNU Lesser General Public 18 | # License along with this program; if not, see . 19 | 20 | from __future__ import absolute_import, print_function, unicode_literals 21 | 22 | import sys 23 | import random 24 | import gpg 25 | import support 26 | 27 | del absolute_import, print_function, unicode_literals 28 | 29 | if len(sys.argv) == 2: 30 | nbytes = int(sys.argv[1]) 31 | else: 32 | nbytes = 100000 33 | 34 | c = gpg.Context() 35 | 36 | ntoread = nbytes 37 | 38 | 39 | def read_cb(amount): 40 | global ntoread 41 | chunk = ntoread if ntoread < amount else amount 42 | ntoread -= chunk 43 | assert ntoread >= 0 44 | assert chunk >= 0 45 | return bytes(bytearray(random.randrange(256) for i in range(chunk))) 46 | 47 | 48 | nwritten = 0 49 | 50 | 51 | def write_cb(data): 52 | global nwritten 53 | nwritten += len(data) 54 | return len(data) 55 | 56 | 57 | source = gpg.Data(cbs=(read_cb, None, None, lambda: None)) 58 | sink = gpg.Data(cbs=(None, write_cb, None, lambda: None)) 59 | 60 | keys = [] 61 | keys.append(c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False)) 62 | keys.append(c.get_key("D695676BDCEDCC2CDD6152BCFE180B1DA9E3B0B2", False)) 63 | 64 | c.op_encrypt(keys, gpg.constants.ENCRYPT_ALWAYS_TRUST, source, sink) 65 | result = c.op_encrypt_result() 66 | assert not result.invalid_recipients, \ 67 | "Invalid recipient encountered: {}".format(result.invalid_recipients.fpr) 68 | assert ntoread == 0 69 | 70 | if support.verbose: 71 | sys.stderr.write("plaintext={} bytes, ciphertext={} bytes\n".format( 72 | nbytes, nwritten)) 73 | -------------------------------------------------------------------------------- /examples/howto/verify-signatures.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | from __future__ import absolute_import, division, unicode_literals 5 | 6 | # Copyright (C) 2018 Ben McGinnes 7 | # 8 | # This program is free software; you can redistribute it and/or modify it under 9 | # the terms of the GNU General Public License as published by the Free Software 10 | # Foundation; either version 2 of the License, or (at your option) any later 11 | # version. 12 | # 13 | # This program is free software; you can redistribute it and/or modify it under 14 | # the terms of the GNU Lesser General Public License as published by the Free 15 | # Software Foundation; either version 2.1 of the License, or (at your option) 16 | # any later version. 17 | # 18 | # This program is distributed in the hope that it will be useful, but WITHOUT 19 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 20 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License and the GNU 21 | # Lesser General Public License for more details. 22 | # 23 | # You should have received a copy of the GNU General Public License and the GNU 24 | # Lesser General Public License along with this program; if not, see 25 | # . 26 | 27 | import gpg 28 | import sys 29 | import time 30 | 31 | """ 32 | Verifies a signed file which has been signed with a detached signature. 33 | """ 34 | 35 | if len(sys.argv) > 2: 36 | filename = sys.argv[1] 37 | sig_file = sys.argv[2] 38 | elif len(sys.argv) == 2: 39 | filename = sys.argv[1] 40 | sig_file = input("Enter the path and filename of the detached signature: ") 41 | else: 42 | filename = input("Enter the path and filename to verify: ") 43 | sig_file = input("Enter the path and filename of the detached signature: ") 44 | 45 | c = gpg.Context() 46 | 47 | try: 48 | data, result = c.verify(open(filename), open(sig_file)) 49 | verified = True 50 | except gpg.errors.BadSignatures as e: 51 | verified = False 52 | print(e) 53 | 54 | if verified is True: 55 | for i in range(len(result.signatures)): 56 | sign = result.signatures[i] 57 | print("""Good signature from: 58 | {0} 59 | with key {1} 60 | made at {2} 61 | """.format(c.get_key(sign.fpr).uids[0].uid, sign.fpr, 62 | time.ctime(sign.timestamp))) 63 | else: 64 | pass 65 | -------------------------------------------------------------------------------- /examples/howto/add-userid.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | from __future__ import absolute_import, division, unicode_literals 5 | 6 | # Copyright (C) 2018 Ben McGinnes 7 | # 8 | # This program is free software; you can redistribute it and/or modify it under 9 | # the terms of the GNU General Public License as published by the Free Software 10 | # Foundation; either version 2 of the License, or (at your option) any later 11 | # version. 12 | # 13 | # This program is free software; you can redistribute it and/or modify it under 14 | # the terms of the GNU Lesser General Public License as published by the Free 15 | # Software Foundation; either version 2.1 of the License, or (at your option) 16 | # any later version. 17 | # 18 | # This program is distributed in the hope that it will be useful, but WITHOUT 19 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 20 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License and the GNU 21 | # Lesser General Public License for more details. 22 | # 23 | # You should have received a copy of the GNU General Public License and the GNU 24 | # Lesser General Public License along with this program; if not, see 25 | # . 26 | 27 | import gpg 28 | import os.path 29 | 30 | print(""" 31 | This script adds a new user ID to an existing key. 32 | 33 | The gpg-agent and pinentry are invoked to enter the passphrase. 34 | """) 35 | 36 | c = gpg.Context() 37 | 38 | homedir = input("Enter the GPG configuration directory path (optional): ") 39 | fpr0 = input("Enter the fingerprint of the key to modify: ") 40 | uid_name = input("Enter the name of the user ID: ") 41 | uid_email = input("Enter the email address of the user ID: ") 42 | uid_cmnt = input("Enter a comment to include (optional): ") 43 | 44 | if homedir.startswith("~"): 45 | if os.path.exists(os.path.expanduser(homedir)) is True: 46 | c.home_dir = os.path.expanduser(homedir) 47 | else: 48 | pass 49 | elif os.path.exists(homedir) is True: 50 | c.home_dir = homedir 51 | else: 52 | pass 53 | 54 | fpr = "".join(fpr0.split()) 55 | 56 | if uid_cmnt: 57 | userid = "{0} ({1}) <{2}>".format(uid_name, uid_cmnt, uid_email) 58 | else: 59 | userid = "{0} <{2}>".format(uid_name, uid_email) 60 | 61 | key = c.get_key(fpr, secret=True) 62 | c.key_add_uid(key, userid) 63 | -------------------------------------------------------------------------------- /examples/howto/revoke-userid.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | from __future__ import absolute_import, division, unicode_literals 5 | 6 | # Copyright (C) 2018 Ben McGinnes 7 | # 8 | # This program is free software; you can redistribute it and/or modify it under 9 | # the terms of the GNU General Public License as published by the Free Software 10 | # Foundation; either version 2 of the License, or (at your option) any later 11 | # version. 12 | # 13 | # This program is free software; you can redistribute it and/or modify it under 14 | # the terms of the GNU Lesser General Public License as published by the Free 15 | # Software Foundation; either version 2.1 of the License, or (at your option) 16 | # any later version. 17 | # 18 | # This program is distributed in the hope that it will be useful, but WITHOUT 19 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 20 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License and the GNU 21 | # Lesser General Public License for more details. 22 | # 23 | # You should have received a copy of the GNU General Public License and the GNU 24 | # Lesser General Public License along with this program; if not, see 25 | # . 26 | 27 | import gpg 28 | import os.path 29 | 30 | print(""" 31 | This script revokes a user ID on an existing key. 32 | 33 | The gpg-agent and pinentry are invoked to enter the passphrase. 34 | """) 35 | 36 | c = gpg.Context() 37 | 38 | homedir = input("Enter the GPG configuration directory path (optional): ") 39 | fpr0 = input("Enter the fingerprint of the key to modify: ") 40 | uid_name = input("Enter the name of the user ID: ") 41 | uid_email = input("Enter the email address of the user ID: ") 42 | uid_cmnt = input("Enter a comment to include (optional): ") 43 | 44 | if homedir.startswith("~"): 45 | if os.path.exists(os.path.expanduser(homedir)) is True: 46 | c.home_dir = os.path.expanduser(homedir) 47 | else: 48 | pass 49 | elif os.path.exists(homedir) is True: 50 | c.home_dir = homedir 51 | else: 52 | pass 53 | 54 | fpr = "".join(fpr0.split()) 55 | 56 | if uid_cmnt: 57 | userid = "{0} ({1}) <{2}>".format(uid_name, uid_cmnt, uid_email) 58 | else: 59 | userid = "{0} <{2}>".format(uid_name, uid_email) 60 | 61 | key = c.get_key(fpr, secret=True) 62 | c.key_revoke_uid(key, userid) 63 | -------------------------------------------------------------------------------- /doc/Makefile.am: -------------------------------------------------------------------------------- 1 | # Makefile.am for the Python bindings. 2 | # Copyright (C) 2019 g10 Code GmbH 3 | # 4 | # This file is part of GPGME. 5 | # 6 | # GPGME is free software; you can redistribute it and/or modify it 7 | # under the terms of the GNU Lesser General Public License as 8 | # published by the Free Software Foundation; either version 2.1 of the 9 | # License, or (at your option) any later version. 10 | # 11 | # GPGME is distributed in the hope that it will be useful, but WITHOUT 12 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 13 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 14 | # Public License for more details. 15 | # 16 | # You should have received a copy of the GNU Lesser General Public 17 | # License along with this program; if not, see . 18 | # SPDX-License-Identifier: LGPL-2.1-or-later 19 | 20 | EXTRA_DIST = README rst src texinfo 21 | 22 | if MAINTAINER_MODE 23 | 24 | ORGSRCS = index.org gpgme-python-howto.org maintenance-mode.org \ 25 | short-history.org what-is-new.org what-was-new.org 26 | 27 | # Make sure we have 'rst' and 'texinfo' dirs in build directory 28 | .PHONY: the_doc_dirs gen_rst gen_texi 29 | 30 | the_doc_dirs: 31 | @if test ! -d rst; then echo $(MKDIR_P) rst; $(MKDIR_P) rst; fi 32 | @if test ! -d texinfo; then echo $(MKDIR_P) texinfo; $(MKDIR_P) texinfo; fi 33 | 34 | # Generate RST files from ORG 35 | gen_rst: 36 | @for f in $(ORGSRCS); do if test ! -e rst/$${f%.org}.rst \ 37 | -o rst/$${f%.org}.rst -ot $(srcdir)/src/$$f; then \ 38 | echo pandoc -f org -t rst $(srcdir)/src/$$f -o rst/$${f%.org}.rst; \ 39 | pandoc -f org -t rst $(srcdir)/src/$$f -o rst/$${f%.org}.rst; \ 40 | fi; \ 41 | done 42 | 43 | # Generate Texinfo files from ORG 44 | gen_texi: 45 | @for f in $(ORGSRCS); do if test ! -e texinfo/$${f%.org}.texi \ 46 | -o texinfo/$${f%.org}.texi -ot $(srcdir)/src/$$f; then \ 47 | echo pandoc -f org -t texinfo $(srcdir)/src/$$f -o texinfo/$${f%.org}.texi; \ 48 | pandoc -f org -t texinfo $(srcdir)/src/$$f -o texinfo/$${f%.org}.texi; \ 49 | fi; \ 50 | done 51 | 52 | all-local: gen_rst gen_texi 53 | 54 | gen_rst gen_texi: the_doc_dirs 55 | 56 | maintainer-clean-local: 57 | @for f in $(ORGSRCS); do \ 58 | echo rm -f rst/$${f%.org}.rst texinfo/$${f%.org}.texi; \ 59 | rm -f rst/$${f%.org}.rst texinfo/$${f%.org}.texi; \ 60 | done 61 | endif 62 | -------------------------------------------------------------------------------- /examples/howto/sign-key.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | from __future__ import absolute_import, division, unicode_literals 5 | 6 | # Copyright (C) 2018 Ben McGinnes 7 | # 8 | # This program is free software; you can redistribute it and/or modify it under 9 | # the terms of the GNU General Public License as published by the Free Software 10 | # Foundation; either version 2 of the License, or (at your option) any later 11 | # version. 12 | # 13 | # This program is free software; you can redistribute it and/or modify it under 14 | # the terms of the GNU Lesser General Public License as published by the Free 15 | # Software Foundation; either version 2.1 of the License, or (at your option) 16 | # any later version. 17 | # 18 | # This program is distributed in the hope that it will be useful, but WITHOUT 19 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 20 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License and the GNU 21 | # Lesser General Public License for more details. 22 | # 23 | # You should have received a copy of the GNU General Public License and the GNU 24 | # Lesser General Public License along with this program; if not, see 25 | # . 26 | 27 | import gpg 28 | import os.path 29 | 30 | print(""" 31 | This script signs or certifies a key. 32 | 33 | The gpg-agent and pinentry are invoked to enter the passphrase. 34 | """) 35 | 36 | c = gpg.Context() 37 | 38 | homedir = input("Enter the GPG configuration directory path (optional): ") 39 | fpr0 = input("Enter the fingerprint of the key to sign: ") 40 | userid = input("Enter the UID to sign (case sensitive, optional): ") 41 | sig_type = input("Enter the certification type (local or normal): ") 42 | 43 | if homedir.startswith("~"): 44 | if os.path.exists(os.path.expanduser(homedir)) is True: 45 | c.home_dir = os.path.expanduser(homedir) 46 | else: 47 | pass 48 | elif os.path.exists(homedir) is True: 49 | c.home_dir = homedir 50 | else: 51 | pass 52 | 53 | fpr = "".join(fpr0.split()) 54 | key = c.get_key(fpr, secret=False) 55 | 56 | if userid and sig_type.lower() == "local": 57 | c.key_sign(key, uids=userid, local=True) 58 | elif userid and sig_type.lower() != "local": 59 | c.key_sign(key, uids=userid) 60 | elif not userid and sig_type.lower() == "local": 61 | c.key_sign(key, local=True) 62 | else: 63 | c.key_sign(key) 64 | -------------------------------------------------------------------------------- /README.GIT: -------------------------------------------------------------------------------- 1 | If you are building from GIT, run the script 2 | 3 | ./autogen.sh 4 | 5 | first, to make sure that you have all the necessary maintainer tools 6 | are installed and to build the actual configuration files. If you 7 | have just checked out from GIT, you should add the option "--force" to 8 | autogen.sh so that meta data is noticed by autom4te.cache. Then run 9 | 10 | ./configure --enable-maintainer-mode 11 | 12 | followed by the usual make. 13 | 14 | If autogen.sh complains about insufficient versions of the required 15 | tools, or the tools are not installed, you may use environment 16 | variables to override the default tool names: 17 | 18 | AUTOMAKE_SUFFIX is used as a suffix for all tools from the automake 19 | package. For example 20 | AUTOMAKE_SUFFIX="-1.7" ./autogen.sh 21 | uses "automake-1.7" and "aclocal-1.7. 22 | AUTOMAKE_PREFIX is used as a prefix for all tools from the automake 23 | page and may be combined with AUTOMAKE_SUFFIX. e.g.: 24 | AUTOMAKE_PREFIX=/usr/foo/bin ./autogen.sh 25 | uses "automake" and "aclocal" in the /usr/foo/bin 26 | directory. 27 | AUTOCONF_SUFFIX is used as a suffix for all tools from the automake 28 | package 29 | AUTOCONF_PREFIX is used as a prefix for all tools from the automake 30 | package 31 | GETTEXT_SUFFIX is used as a suffix for all tools from the gettext 32 | package 33 | GETTEXT_PREFIX is used as a prefix for all tools from the gettext 34 | package 35 | 36 | It is also possible to use the variable name AUTOMAKE, AUTOCONF, 37 | ACLOCAL, AUTOHEADER, GETTEXT and MSGMERGE to directly specify the name 38 | of the programs to run. It is however better to use the suffix and 39 | prefix forms as described above because that does not require 40 | knowledge about the actual tools used by autogen.sh. 41 | 42 | 43 | Please don't use autopoint, libtoolize or autoreconf unless you are 44 | the current maintainer and want to update the standard configuration 45 | files. All those files should be in GIT and only updated manually 46 | if the maintainer decides that newer versions are required. The 47 | maintainer should also make sure that the required version of automake 48 | et al. are properly indicated at the top of configure.ac and take care 49 | to copy the files and not merely use symlinks. 50 | -------------------------------------------------------------------------------- /doc/src/what-is-new.org: -------------------------------------------------------------------------------- 1 | # -*- mode: org -*- 2 | #+TITLE: What's New in the GPGME Python Bindings and Documentation 3 | #+AUTHOR: Ben McGinnes 4 | #+LATEX_COMPILER: xelatex 5 | #+LATEX_CLASS: article 6 | #+LATEX_CLASS_OPTIONS: [12pt] 7 | #+LATEX_HEADER: \usepackage{xltxtra} 8 | #+LATEX_HEADER: \usepackage[margin=1in]{geometry} 9 | #+LATEX_HEADER: \setmainfont[Ligatures={Common}]{Times New Roman} 10 | #+LATEX_HEADER: \author{Ben McGinnes } 11 | 12 | 13 | * What's New 14 | :PROPERTIES: 15 | :CUSTOM_ID: new-stuff 16 | :END: 17 | 18 | | Version: | 0.0.1 | 19 | | GPGME Version: | 1.13.0 | 20 | | Author: | Ben McGinnes | 21 | | Author GPG Key: | DB4724E6FA4286C92B4E55C4321E4E2373590E5D | 22 | | Language: | Australian English, British English | 23 | | xml:lang: | en-AU, en-GB, en | 24 | 25 | Last time the most obviously new thing was adding the /What's New/ 26 | section to the HOWTO. Now it's moving it out of the HOWTO. 27 | 28 | 29 | ** New in GPGME 1·13·0 30 | :PROPERTIES: 31 | :CUSTOM_ID: new-stuff-1-13-0 32 | :END: 33 | 34 | Additions since GPGME 1.12.0 include: 35 | 36 | - Moving the /What's New/ section out of the basic [[file:gpgme-python-howto.org][HOWTO]] document and 37 | into its own file so as to more readily include other documents 38 | beyond that HOWTO. 39 | - Moving the preceding, archival, segments into [[file:what-was-new.org][another file]]. 40 | - Added =gpg.version.versionintlist= to make it easier for Python 41 | developers to check for a specific version number, even with beta 42 | versions (it will drop the "-betaN" part). 43 | - Added expanded detail on issues pertaining to installing for Windows 44 | users. 45 | - Bindings enter [[file:maintenance-mode][maintenance mode]] from January, 2019. 46 | - Added documentation on maintenance mode and what changes can be made 47 | to the code when in that status. Essentially that boils down to bug 48 | fixes only and no feature requests. 49 | - The import-keys-hkp.py example script, which uses the =hkp4py= 50 | module to search the SKS servers for a key, has been tightened up to 51 | search for both hexadecimal key IDs and user ID strings with reduced 52 | chance of unnecessary repitition. There may still be some 53 | repetition if a key includes a user ID matching the hexadecimal 54 | value of a key ID. 55 | -------------------------------------------------------------------------------- /README.org: -------------------------------------------------------------------------------- 1 | #+TITLE: gpg - GPGME bindings for Python 2 | #+OPTIONS: author:nil 3 | 4 | The "gpg" module is a python interface to the GPGME library: 5 | [[https://www.gnupg.org/software/gpgme/][https://www.gnupg.org/software/gpgme/]] 6 | 7 | "gpg" offers two interfaces, one is a high-level, curated, and 8 | idiomatic interface that is implemented as a shim on top of the 9 | low-level interface automatically created using SWIG. 10 | 11 | This way we make simple things easy, while still providing the entire 12 | functionality of the underlying library. 13 | 14 | * Mailing List 15 | 16 | For general discussion and help see the gnupg-users mailing list: 17 | [[https://lists.gnupg.org/mailman/listinfo/gnupg-users][gnupg-users]] 18 | 19 | For development see the gnupg-devel mailing list: 20 | [[https://lists.gnupg.org/mailman/listinfo/gnupg-devel][gnupg-devel]] 21 | 22 | * Bugs 23 | 24 | Please report bugs using our bug tracker 25 | [[https://bugs.gnupg.org][bugs.gnupg.org]] with tag (aka project) 'gpgme'. 26 | 27 | * Authors 28 | 29 | PyME was created by John Goerzen, and maintained, developed, and 30 | cherished by Igor Belyi, Martin Albrecht, Ben McGinnes, Justus Winter, 31 | and everyone who contributed to it in any way. 32 | 33 | In 2016 we merged a port of PyME to into the GPGME repository, and 34 | development will continue there. Please see the VCS history for the 35 | list of contributors, and if you do find bugs, or want to contribute, 36 | please get in touch and help maintain the python gpg bindings. 37 | 38 | Please see the section 'History' further down this document for 39 | references to previous versions. 40 | 41 | * History 42 | 43 | - The python bindings were renamed from PyME to "gpg" in 2016. 44 | 45 | - The bindings have been merged into the GPGME repository in 2016. 46 | 47 | - The latest version of PyME for Python 3.2 and above (as of 48 | May, 2015) is v0.9.1. 49 | [[https://git.gnupg.org/gpgme.git/lang/py3-pyme][Python 3 PyME]] 50 | 51 | - The latest version of PyME for Python 2.6 and 2.7 (as of this 52 | writing) is v0.9.0. [[https://bitbucket.org/malb/pyme][PyME 0.9.0]] 53 | 54 | - A previous version of PyME v0.8.0 can be found on sourceforge: 55 | [[http://pyme.sourceforge.net/][PyME 0.8.0]] 56 | 57 | - A previous version of PyME v0.5.1 which works with GPGME v0.3.15 58 | can be found on John Goerzen's PyME page: 59 | [[http://quux.org/devel/pyme/][PyME 0.3.15]] 60 | [[https://www.complete.org/JohnGoerzen][John Goerzen]] 61 | -------------------------------------------------------------------------------- /examples/howto/symcrypt-file.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | from __future__ import absolute_import, division, unicode_literals 5 | 6 | import gpg 7 | import sys 8 | 9 | # Copyright (C) 2018 Ben McGinnes 10 | # 11 | # This program is free software; you can redistribute it and/or modify it under 12 | # the terms of the GNU General Public License as published by the Free Software 13 | # Foundation; either version 2 of the License, or (at your option) any later 14 | # version. 15 | # 16 | # This program is free software; you can redistribute it and/or modify it under 17 | # the terms of the GNU Lesser General Public License as published by the Free 18 | # Software Foundation; either version 2.1 of the License, or (at your option) 19 | # any later version. 20 | # 21 | # This program is distributed in the hope that it will be useful, but WITHOUT 22 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 23 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License and the GNU 24 | # Lesser General Public License for more details. 25 | # 26 | # You should have received a copy of the GNU General Public License and the GNU 27 | # Lesser General Public License along with this program; if not, see 28 | # . 29 | 30 | """ 31 | Symmetrically encrypts a file. Passphrase will be prompted for via Pinentry. 32 | 33 | Will produce both an ASCII armoured and GPG binary format copy of the encrypted 34 | file. 35 | """ 36 | 37 | if len(sys.argv) > 2: 38 | filename = " ".join(sys.argv[1:]) 39 | elif len(sys.argv) == 2: 40 | filename = sys.argv[1] 41 | else: 42 | filename = input("Enter the path and filename to encrypt: ") 43 | 44 | with open(filename, "rb") as f: 45 | text = f.read() 46 | 47 | with gpg.Context(armor=True) as ca: 48 | try: 49 | ciphertext, result, sign_result = ca.encrypt(text, passphrase=None, 50 | sign=False) 51 | with open("{0}.asc".format(filename), "wb") as fa: 52 | fa.write(ciphertext) 53 | except gpg.errors.GPGMEError as e: 54 | print(e) 55 | 56 | with gpg.Context() as cg: 57 | try: 58 | ciphertext, result, sign_result = cg.encrypt(text, passphrase=None, 59 | sign=False) 60 | with open("{0}.gpg".format(filename), "wb") as fg: 61 | fg.write(ciphertext) 62 | except gpg.errors.GPGMEError as e: 63 | print(e) 64 | -------------------------------------------------------------------------------- /tests/start-stop-agent: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright (C) 2013 g10 Code GmbH 3 | # 4 | # This file is free software; as a special exception the author gives 5 | # unlimited permission to copy and/or distribute it, with or without 6 | # modifications, as long as this notice is preserved. This file is 7 | # distributed in the hope that it will be useful, but WITHOUT ANY 8 | # WARRANTY, to the extent permitted by law; without even the implied 9 | # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 10 | 11 | if [ -z "$(command -v gpg-connect-agent)" ]; then 12 | echo "gpg-agent not installed and thus not started" >&2 13 | exit 0; 14 | fi 15 | 16 | GPG_AGENT_INFO= 17 | export GPG_AGENT_INFO 18 | GPG_AGENT=$(which gpg-agent) 19 | 20 | token=$(echo "gpgme-$(pwd)" | tr ' ' '_') 21 | 22 | if [ "$1" = "--stop" ]; then 23 | if [ "$(gpg-connect-agent --no-autostart getval\ $token /bye 2>/dev/null | head -1)" \ 24 | != "D set" ]; then 25 | echo "gpg-agent not running" >&2 26 | exit 0 27 | fi 28 | echo "stopping gpg-agent " >&2 29 | gpg-connect-agent KILLAGENT /bye >/dev/null 2>&1 30 | exit 0 31 | fi 32 | 33 | # Update 'agent-program' in the configuration files to make sure we 34 | # will always start exactly this agent again if we ever need to. 35 | for F in gpg.conf gpgsm.conf 36 | do 37 | if test -f "$GNUPGHOME/$F" 38 | then 39 | cat "$GNUPGHOME/$F" > "$GNUPGHOME/$F~" 40 | sed -e "s#^agent-program.*#agent-program ${GPG_AGENT}|--debug-quick-random#" \ 41 | >"$GNUPGHOME/$F" <"$GNUPGHOME/$F~" 42 | rm -f "$GNUPGHOME/$F~" 43 | fi 44 | done 45 | 46 | if [ "$(gpg-connect-agent --no-autostart getval\ $token /bye 2>/dev/null | head -1)" \ 47 | = "D set" ]; then 48 | echo "gpg-agent already running" >&2 49 | exit 0 50 | fi 51 | 52 | echo "starting gpg-agent.." >&2 53 | 54 | # GnuPG prior to 2.1.12 needs --allow-loopback-pinentry for the 55 | # loopback entry to work. Old versions do not understand this though, 56 | # so we need to be careful. 57 | if "$GPG_AGENT" --gpgconf-test --allow-loopback-pinentry && 58 | test -f "$GNUPGHOME/gpg-agent.conf" && 59 | ! grep -q allow-loopback-pinentry "$GNUPGHOME/gpg-agent.conf"; then 60 | echo allow-loopback-pinentry >> "$GNUPGHOME/gpg-agent.conf" 61 | fi 62 | 63 | gpg-connect-agent --agent-program="${GPG_AGENT}|--debug-quick-random" putval\ $token\ set /bye 64 | if [ $? -ne 0 -o "$(gpg-connect-agent getval\ $token /bye 2>/dev/null | head -1)" \ 65 | != "D set" ]; then 66 | echo "error starting gpg-agent" >&2 67 | exit 1 68 | fi 69 | exit 0 70 | -------------------------------------------------------------------------------- /examples/howto/sign-file.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | from __future__ import absolute_import, division, unicode_literals 5 | 6 | # Copyright (C) 2018 Ben McGinnes 7 | # 8 | # This program is free software; you can redistribute it and/or modify it under 9 | # the terms of the GNU General Public License as published by the Free Software 10 | # Foundation; either version 2 of the License, or (at your option) any later 11 | # version. 12 | # 13 | # This program is free software; you can redistribute it and/or modify it under 14 | # the terms of the GNU Lesser General Public License as published by the Free 15 | # Software Foundation; either version 2.1 of the License, or (at your option) 16 | # any later version. 17 | # 18 | # This program is distributed in the hope that it will be useful, but WITHOUT 19 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 20 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License and the GNU 21 | # Lesser General Public License for more details. 22 | # 23 | # You should have received a copy of the GNU General Public License and the GNU 24 | # Lesser General Public License along with this program; if not, see 25 | # . 26 | 27 | import gpg 28 | import sys 29 | 30 | """ 31 | Signs a file with a specified key. If entering both the key and the filename 32 | on the command line, the key must be entered first. 33 | 34 | Will produce both an ASCII armoured and GPG binary format copy of the signed 35 | file. 36 | """ 37 | 38 | if len(sys.argv) > 3: 39 | logrus = sys.argv[1] 40 | filename = " ".join(sys.argv[2:]) 41 | elif len(sys.argv) == 3: 42 | logrus = sys.argv[1] 43 | filename = sys.argv[2] 44 | elif len(sys.argv) == 2: 45 | logrus = sys.argv[1] 46 | filename = input("Enter the path and filename to sign: ") 47 | else: 48 | logrus = input("Enter the fingerprint or key ID to sign with: ") 49 | filename = input("Enter the path and filename to sign: ") 50 | 51 | with open(filename, "rb") as f: 52 | text = f.read() 53 | 54 | key = list(gpg.Context().keylist(pattern=logrus)) 55 | 56 | with gpg.Context(armor=True, signers=key) as ca: 57 | signed_data, result = ca.sign(text, mode=gpg.constants.sig.mode.NORMAL) 58 | with open("{0}.asc".format(filename), "wb") as fa: 59 | fa.write(signed_data) 60 | 61 | with gpg.Context(signers=key) as cg: 62 | signed_data, result = cg.sign(text, mode=gpg.constants.sig.mode.NORMAL) 63 | with open("{0}.gpg".format(filename), "wb") as fg: 64 | fg.write(signed_data) 65 | -------------------------------------------------------------------------------- /tests/t-edit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright (C) 2005 Igor Belyi 4 | # Copyright (C) 2016 g10 Code GmbH 5 | # 6 | # This file is part of GPGME. 7 | # 8 | # GPGME is free software; you can redistribute it and/or modify it 9 | # under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation; either version 2 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # GPGME is distributed in the hope that it will be useful, but WITHOUT 14 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 16 | # Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public 19 | # License along with this program; if not, see . 20 | 21 | from __future__ import absolute_import, print_function, unicode_literals 22 | 23 | import sys 24 | import os 25 | import gpg 26 | import support 27 | _ = support # to appease pyflakes. 28 | 29 | del absolute_import, print_function, unicode_literals 30 | 31 | 32 | class KeyEditor(object): 33 | def __init__(self): 34 | self.steps = ["fpr", "expire", "1", "primary", "quit"] 35 | self.step = 0 36 | self.done = False 37 | self.verbose = int(os.environ.get('verbose', 0)) > 1 38 | 39 | def edit_fnc(self, status, args, out=None): 40 | if args == "keyedit.prompt": 41 | result = self.steps[self.step] 42 | self.step += 1 43 | elif args == "keyedit.save.okay": 44 | result = "Y" 45 | self.done = self.step == len(self.steps) 46 | elif args == "keygen.valid": 47 | result = "0" 48 | else: 49 | result = None 50 | 51 | if self.verbose: 52 | sys.stderr.write("Code: {}, args: {!r}, Returning: {!r}\n".format( 53 | status, args, result)) 54 | 55 | return result 56 | 57 | 58 | c = gpg.Context() 59 | c.set_pinentry_mode(gpg.constants.PINENTRY_MODE_LOOPBACK) 60 | c.set_passphrase_cb(lambda *args: "abc") 61 | c.set_armor(True) 62 | 63 | # The deprecated interface. 64 | editor = KeyEditor() 65 | c.interact( 66 | c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False), 67 | editor.edit_fnc) 68 | assert editor.done 69 | 70 | # The deprecated interface. 71 | sink = gpg.Data() 72 | editor = KeyEditor() 73 | c.op_edit( 74 | c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False), 75 | editor.edit_fnc, sink, sink) 76 | assert editor.done 77 | -------------------------------------------------------------------------------- /examples/howto/detach-sign-file.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | from __future__ import absolute_import, division, unicode_literals 5 | 6 | # Copyright (C) 2018 Ben McGinnes 7 | # 8 | # This program is free software; you can redistribute it and/or modify it under 9 | # the terms of the GNU General Public License as published by the Free Software 10 | # Foundation; either version 2 of the License, or (at your option) any later 11 | # version. 12 | # 13 | # This program is free software; you can redistribute it and/or modify it under 14 | # the terms of the GNU Lesser General Public License as published by the Free 15 | # Software Foundation; either version 2.1 of the License, or (at your option) 16 | # any later version. 17 | # 18 | # This program is distributed in the hope that it will be useful, but WITHOUT 19 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 20 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License and the GNU 21 | # Lesser General Public License for more details. 22 | # 23 | # You should have received a copy of the GNU General Public License and the GNU 24 | # Lesser General Public License along with this program; if not, see 25 | # . 26 | 27 | import gpg 28 | import sys 29 | 30 | """ 31 | Signs a file with a specified key. If entering both the key and the filename 32 | on the command line, the key must be entered first. 33 | 34 | Will produce both an ASCII armoured and GPG binary format copy of the detached 35 | signature file. 36 | """ 37 | 38 | if len(sys.argv) > 3: 39 | logrus = sys.argv[1] 40 | filename = " ".join(sys.argv[2:]) 41 | elif len(sys.argv) == 3: 42 | logrus = sys.argv[1] 43 | filename = sys.argv[2] 44 | elif len(sys.argv) == 2: 45 | logrus = sys.argv[1] 46 | filename = input("Enter the path and filename to sign: ") 47 | else: 48 | logrus = input("Enter the fingerprint or key ID to sign with: ") 49 | filename = input("Enter the path and filename to sign: ") 50 | 51 | with open(filename, "rb") as f: 52 | text = f.read() 53 | 54 | key = list(gpg.Context().keylist(pattern=logrus)) 55 | 56 | with gpg.Context(armor=True, signers=key) as ca: 57 | signed_data, result = ca.sign(text, mode=gpg.constants.sig.mode.DETACH) 58 | with open("{0}.asc".format(filename), "wb") as fa: 59 | fa.write(signed_data) 60 | 61 | with gpg.Context(signers=key) as cb: 62 | signed_data, result = cb.sign(text, mode=gpg.constants.sig.mode.DETACH) 63 | with open("{0}.sig".format(filename), "wb") as fb: 64 | fb.write(signed_data) 65 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2 | GPG - GPGME BINDINGS FOR PYTHON 3 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4 | 5 | 6 | Table of Contents 7 | ───────────────── 8 | 9 | 1 Mailing List 10 | 2 Bugs 11 | 3 Authors 12 | 4 History 13 | 14 | 15 | The "gpg" module is a python interface to the GPGME library: 16 | 17 | 18 | "gpg" offers two interfaces, one is a high-level, curated, and idiomatic 19 | interface that is implemented as a shim on top of the low-level 20 | interface automatically created using SWIG. 21 | 22 | This way we make simple things easy, while still providing the entire 23 | functionality of the underlying library. 24 | 25 | 26 | 1 Mailing List 27 | ══════════════ 28 | 29 | For general discussion and help see the gnupg-users mailing list: 30 | 31 | 32 | For development see the gnupg-devel mailing list: 33 | 34 | 35 | 36 | 2 Bugs 37 | ══════ 38 | 39 | Please report bugs using our bug tracker with 40 | tag (aka project) 'gpgme'. 41 | 42 | 43 | 3 Authors 44 | ═════════ 45 | 46 | PyME was created by John Goerzen, and maintained, developed, and 47 | cherished by Igor Belyi, Martin Albrecht, Ben McGinnes, Justus 48 | Winter, and everyone who contributed to it in any way. 49 | 50 | In 2016 we merged a port of PyME to into the GPGME repository, and 51 | development will continue there. Please see the VCS history for the 52 | list of contributors, and if you do find bugs, or want to contribute, 53 | please get in touch and help maintain the python gpg bindings. 54 | 55 | Please see the section 'History' further down this document for 56 | references to previous versions. 57 | 58 | 59 | 4 History 60 | ═════════ 61 | 62 | • The python bindings were renamed from PyME to "gpg" in 2016. 63 | 64 | • The bindings have been merged into the GPGME repository in 2016. 65 | 66 | • The latest version of PyME for Python 3.2 and above (as of May, 67 | 2015) is v0.9.1. 68 | 69 | • The latest version of PyME for Python 2.6 and 2.7 (as of this 70 | writing) is v0.9.0. 71 | 72 | • A previous version of PyME v0.8.0 can be found on sourceforge: 73 | 74 | 75 | • A previous version of PyME v0.5.1 which works with GPGME v0.3.15 can 76 | be found on John Goerzen's PyME page: 77 | 78 | -------------------------------------------------------------------------------- /examples/howto/mutt-groups.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | from __future__ import absolute_import, division, unicode_literals 5 | 6 | # Copyright (C) 2018 Ben McGinnes 7 | # 8 | # This program is free software; you can redistribute it and/or modify it under 9 | # the terms of the GNU General Public License as published by the Free Software 10 | # Foundation; either version 2 of the License, or (at your option) any later 11 | # version. 12 | # 13 | # This program is free software; you can redistribute it and/or modify it under 14 | # the terms of the GNU Lesser General Public License as published by the Free 15 | # Software Foundation; either version 2.1 of the License, or (at your option) 16 | # any later version. 17 | # 18 | # This program is distributed in the hope that it will be useful, but WITHOUT 19 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 20 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License and the GNU 21 | # Lesser General Public License for more details. 22 | # 23 | # You should have received a copy of the GNU General Public License and the GNU 24 | # Lesser General Public License along with this program; if not, see 25 | # . 26 | 27 | import sys 28 | from groups import group_lists 29 | 30 | """ 31 | Uses the groups module to generate Mutt crypt-hooks from gpg.conf. 32 | 33 | """ 34 | 35 | if len(sys.argv) >= 2: 36 | hook_file = sys.argv[1] 37 | else: 38 | hook_file = input("Enter the filename to save the crypt-hooks in: ") 39 | 40 | with open(hook_file, "w") as f: 41 | f.write("""# Change settings based upon message recipient 42 | # 43 | # send-hook [!] 44 | # 45 | # is executed when sending mail to an address matching 46 | # 47 | # crypt-hook regexp key-id 48 | # The crypt-hook command provides a method by which you can 49 | # specify the ID of the public key to be used when encrypting 50 | # messages to a certain recipient. The meaning of "key ID" is to 51 | # be taken broadly: This can be a different e-mail address, a 52 | # numerical key ID, or even just an arbitrary search string. You 53 | # may use multiple crypt-hooks with the same regexp; multiple 54 | # matching crypt-hooks result in the use of multiple key-ids for a 55 | # recipient. 56 | """) 57 | 58 | for n in range(len(group_lists)): 59 | rule = group_lists[n][0].replace(".", "\\\\.") 60 | with open(hook_file, "a") as f: 61 | f.write("\n") 62 | f.write("# {0}\n".format(group_lists[n][0])) 63 | for i in range(len(group_lists[n][1])): 64 | f.write("crypt-hook {0} {1}\n".format(rule, group_lists[n][1][i])) 65 | -------------------------------------------------------------------------------- /examples/howto/import-keys.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | from __future__ import absolute_import, division, unicode_literals 5 | 6 | import gpg 7 | import os.path 8 | import requests 9 | 10 | # Copyright (C) 2018 Ben McGinnes 11 | # 12 | # This program is free software; you can redistribute it and/or modify it under 13 | # the terms of the GNU General Public License as published by the Free Software 14 | # Foundation; either version 2 of the License, or (at your option) any later 15 | # version. 16 | # 17 | # This program is free software; you can redistribute it and/or modify it under 18 | # the terms of the GNU Lesser General Public License as published by the Free 19 | # Software Foundation; either version 2.1 of the License, or (at your option) 20 | # any later version. 21 | # 22 | # This program is distributed in the hope that it will be useful, but WITHOUT 23 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 24 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License and the GNU 25 | # Lesser General Public License for more details. 26 | # 27 | # You should have received a copy of the GNU General Public License and the GNU 28 | # Lesser General Public License along with this program; if not, see 29 | # . 30 | 31 | print(""" 32 | This script imports one or more public keys from the SKS keyservers. 33 | """) 34 | 35 | c = gpg.Context() 36 | url = "https://sks-keyservers.net/pks/lookup" 37 | pattern = input("Enter the pattern to search for key or user IDs: ") 38 | payload = {"op": "get", "search": pattern} 39 | 40 | r = requests.get(url, verify=True, params=payload) 41 | result = c.key_import(r.content) 42 | 43 | if result is not None and hasattr(result, "considered") is False: 44 | print(result) 45 | elif result is not None and hasattr(result, "considered") is True: 46 | num_keys = len(result.imports) 47 | new_revs = result.new_revocations 48 | new_sigs = result.new_signatures 49 | new_subs = result.new_sub_keys 50 | new_uids = result.new_user_ids 51 | new_scrt = result.secret_imported 52 | nochange = result.unchanged 53 | print(""" 54 | The total number of keys considered for import was: {0} 55 | 56 | Number of keys revoked: {1} 57 | Number of new signatures: {2} 58 | Number of new subkeys: {3} 59 | Number of new user IDs: {4} 60 | Number of new secret keys: {5} 61 | Number of unchanged keys: {6} 62 | 63 | The key IDs for all considered keys were: 64 | """.format(num_keys, new_revs, new_sigs, new_subs, new_uids, new_scrt, 65 | nochange)) 66 | for i in range(num_keys): 67 | print(result.imports[i].fpr) 68 | print("") 69 | else: 70 | pass 71 | -------------------------------------------------------------------------------- /tests/t-protocol-assuan.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright (C) 2016 g10 Code GmbH 4 | # 5 | # This file is part of GPGME. 6 | # 7 | # GPGME is free software; you can redistribute it and/or modify it 8 | # under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # GPGME is distributed in the hope that it will be useful, but WITHOUT 13 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 15 | # Public License for more details. 16 | # 17 | # You should have received a copy of the GNU Lesser General Public 18 | # License along with this program; if not, see . 19 | 20 | from __future__ import absolute_import, print_function, unicode_literals 21 | 22 | import gpg 23 | import support 24 | _ = support # to appease pyflakes. 25 | 26 | del absolute_import, print_function, unicode_literals 27 | 28 | with gpg.Context(protocol=gpg.constants.protocol.ASSUAN) as c: 29 | # Do nothing. 30 | err = c.assuan_transact('nop') 31 | assert err is None 32 | err = c.assuan_transact(b'NOP') 33 | assert err is None 34 | err = c.assuan_transact(['NOP']) 35 | assert err is None 36 | 37 | err = c.assuan_transact('idontexist') 38 | assert err.getsource() == gpg.errors.SOURCE_GPGAGENT 39 | assert err.getcode() == gpg.errors.ASS_UNKNOWN_CMD 40 | 41 | # Invoke the pinentry to get a confirmation. 42 | c.assuan_transact(['GET_CONFIRMATION', 'Hello there']) 43 | 44 | data = [] 45 | 46 | def data_cb(line): 47 | data.append(line) 48 | 49 | err = c.assuan_transact(['GETINFO', 'version'], data_cb=data_cb) 50 | assert not err 51 | assert len(data) == 1 52 | 53 | data = [] 54 | err = c.assuan_transact(['GETINFO', 's2k_count'], data_cb=data_cb) 55 | if not err: 56 | assert len(data) == 1 57 | assert int(data[0]) > 0 58 | 59 | # XXX HELP sends status lines if we could use ASSUAN_CONVEY_COMMENTS. 60 | 61 | status = [] 62 | 63 | def status_cb(line, args): 64 | status.append((line, args)) 65 | 66 | alphas_grip = '76F7E2B35832976B50A27A282D9B87E44577EB66' 67 | err = c.assuan_transact(['KEYINFO', alphas_grip], status_cb=status_cb) 68 | if not err: 69 | assert len(status) == 1 70 | line, args = status[0] 71 | assert line.startswith('KEYINFO') 72 | assert args.startswith(alphas_grip) 73 | 74 | # XXX: test these callbacks, e.g. using PRESET_PASSPHRASE 75 | # XXX: once issue2428 is resolved 76 | def inq_cb(name, args): 77 | print("inq_cb", name, args) 78 | -------------------------------------------------------------------------------- /examples/howto/encrypt-file.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | from __future__ import absolute_import, division, unicode_literals 5 | 6 | import gpg 7 | import sys 8 | 9 | # Copyright (C) 2018 Ben McGinnes 10 | # 11 | # This program is free software; you can redistribute it and/or modify it under 12 | # the terms of the GNU General Public License as published by the Free Software 13 | # Foundation; either version 2 of the License, or (at your option) any later 14 | # version. 15 | # 16 | # This program is free software; you can redistribute it and/or modify it under 17 | # the terms of the GNU Lesser General Public License as published by the Free 18 | # Software Foundation; either version 2.1 of the License, or (at your option) 19 | # any later version. 20 | # 21 | # This program is distributed in the hope that it will be useful, but WITHOUT 22 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 23 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License and the GNU 24 | # Lesser General Public License for more details. 25 | # 26 | # You should have received a copy of the GNU General Public License and the GNU 27 | # Lesser General Public License along with this program; if not, see 28 | # . 29 | 30 | """ 31 | Encrypts a file to a specified key. If entering both the key and the filename 32 | on the command line, the key must be entered first. 33 | 34 | Will produce both an ASCII armoured and GPG binary format copy of the encrypted 35 | file. 36 | """ 37 | 38 | if len(sys.argv) > 3: 39 | a_key = sys.argv[1] 40 | filename = " ".join(sys.argv[2:]) 41 | elif len(sys.argv) == 3: 42 | a_key = sys.argv[1] 43 | filename = sys.argv[2] 44 | elif len(sys.argv) == 2: 45 | a_key = sys.argv[1] 46 | filename = input("Enter the path and filename to encrypt: ") 47 | else: 48 | a_key = input("Enter the fingerprint or key ID to encrypt to: ") 49 | filename = input("Enter the path and filename to encrypt: ") 50 | 51 | rkey = list(gpg.Context().keylist(pattern=a_key, secret=False)) 52 | with open(filename, "rb") as f: 53 | text = f.read() 54 | 55 | with gpg.Context(armor=True) as ca: 56 | try: 57 | ciphertext, result, sign_result = ca.encrypt(text, recipients=rkey, 58 | sign=False) 59 | with open("{0}.asc".format(filename), "wb") as fa: 60 | fa.write(ciphertext) 61 | except gpg.errors.InvalidRecipients as e: 62 | print(e) 63 | 64 | with gpg.Context() as cg: 65 | try: 66 | ciphertext, result, sign_result = cg.encrypt(text, recipients=rkey, 67 | sign=False) 68 | with open("{0}.gpg".format(filename), "wb") as fg: 69 | fg.write(ciphertext) 70 | except gpg.errors.InvalidRecipients as e: 71 | print(e) 72 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "gpg" 3 | 4 | # The version is written into the setup.py file by configure. 5 | dynamic = ["version"] 6 | 7 | # Note: description appears as Summary in egg-info file. 8 | description = "Python bindings to the GPGME API of the GnuPG cryptography library." 9 | 10 | license = {text = "LGPL2.1+ (the library), GPL2+ (tests and examples)"} 11 | authors = [{name = "The GnuPG hackers", email = "gnupg-devel@gnupg.org"}] 12 | 13 | classifiers = [ 14 | "Development Status :: 4 - Beta", 15 | "Intended Audience :: Developers", 16 | "License :: OSI Approved :: GNU Lesser General Public License v2 or later (LGPLv2+)", 17 | "Programming Language :: Python :: 3", 18 | "Programming Language :: Python :: 3.6", 19 | "Programming Language :: Python :: 3.9", 20 | "Programming Language :: Python :: 3.10", 21 | "Programming Language :: Python :: 3.11", 22 | "Programming Language :: Python :: 3.12", 23 | "Programming Language :: Python :: 3.13", 24 | "Operating System :: POSIX", 25 | "Operating System :: Microsoft :: Windows", 26 | "Topic :: Communications :: Email", 27 | "Topic :: Security :: Cryptography", 28 | ] 29 | urls = {homepage = "https://www.gnupg.org"} 30 | 31 | # Which versions should be supported? https://devguide.python.org/versions/ 32 | requires-python = ">= 3.6" 33 | 34 | [project.readme] 35 | # Note: long-description appears as Description in egg-info file. 36 | text = """Dynamically generated bindings to the C API of the GNU Privacy Guard. 37 | 38 | The GPG Made Easy (GPGME) library provides a high-level API in C to all the 39 | component software and libraries in the GnuPG Project, including GPG itself 40 | (the GnuPG OpenPGP implementation), libgcrypt, libgpg-error, libassuan and 41 | more. 42 | 43 | The official CPython bindings to GPGME are generated during the compiling 44 | process of GPGME itself and built for the specific C header and include files 45 | produced when GPGME is compiled using SWIG. This provides access to over two 46 | thousand functions, methods and values via both the lower level dynamically 47 | generated bindings and a more intuitively pythonic higher level layer. 48 | 49 | While the lower level, dynamically generated bindings provide access to 50 | everything which GPGME itself provides; the higher level layer is easier to use 51 | by Python developers, provides access to the vast majority of functionality 52 | developers would want from GnuPG and is extensively documented. 53 | 54 | GPGME and these bindings is available here: 55 | 56 | [GPGME](https://gnupg.org/software/gpgme/index.html) 57 | 58 | Code examples for the bindings are located here: 59 | 60 | [Examples](https://git.gnupg.org/cgi-bin/gitweb.cgi?p=gpgmepy.git;a=tree;f=examples;hb=HEAD) 61 | """ 62 | content-type = "text/markdown" 63 | 64 | [build-system] 65 | # Minimum requirements for the build system to execute. 66 | requires = ["setuptools>=65.2.0", "swig"] 67 | build-backend = "setuptools.build_meta" 68 | -------------------------------------------------------------------------------- /examples/howto/encrypt-to-group-gullible.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | from __future__ import absolute_import, division, unicode_literals 5 | 6 | import gpg 7 | import sys 8 | from groups import group_lists 9 | 10 | # Copyright (C) 2018 Ben McGinnes 11 | # 12 | # This program is free software; you can redistribute it and/or modify it under 13 | # the terms of the GNU General Public License as published by the Free Software 14 | # Foundation; either version 2 of the License, or (at your option) any later 15 | # version. 16 | # 17 | # This program is free software; you can redistribute it and/or modify it under 18 | # the terms of the GNU Lesser General Public License as published by the Free 19 | # Software Foundation; either version 2.1 of the License, or (at your option) 20 | # any later version. 21 | # 22 | # This program is distributed in the hope that it will be useful, but WITHOUT 23 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 24 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License and the GNU 25 | # Lesser General Public License for more details. 26 | # 27 | # You should have received a copy of the GNU General Public License and the GNU 28 | # Lesser General Public License along with this program; if not, see 29 | # . 30 | 31 | """ 32 | Uses the groups module to encrypt to multiple recipients. 33 | 34 | """ 35 | 36 | c = gpg.Context(armor=True) 37 | 38 | if len(sys.argv) > 3: 39 | group_id = sys.argv[1] 40 | filepath = sys.argv[2:] 41 | elif len(sys.argv) == 3: 42 | group_id = sys.argv[1] 43 | filepath = sys.argv[2] 44 | elif len(sys.argv) == 2: 45 | group_id = sys.argv[1] 46 | filepath = input("Enter the filename to encrypt: ") 47 | else: 48 | group_id = input("Enter the group name to encrypt to: ") 49 | filepath = input("Enter the filename to encrypt: ") 50 | 51 | with open(filepath, "rb") as f: 52 | text = f.read() 53 | 54 | for i in range(len(group_lists)): 55 | if group_lists[i][0] == group_id: 56 | klist = group_lists[i][1] 57 | else: 58 | klist = None 59 | 60 | logrus = [] 61 | 62 | if klist is not None: 63 | for i in range(len(klist)): 64 | apattern = list(c.keylist(pattern=klist[i], secret=False)) 65 | if apattern[0].can_encrypt == 1: 66 | logrus.append(apattern[0]) 67 | else: 68 | pass 69 | try: 70 | ciphertext, result, sign_result = c.encrypt(text, recipients=logrus, 71 | add_encrypt_to=True) 72 | except: 73 | ciphertext, result, sign_result = c.encrypt(text, recipients=logrus, 74 | add_encrypt_to=True, 75 | always_trust=True) 76 | with open("{0}.asc".format(filepath), "wb") as f: 77 | f.write(ciphertext) 78 | else: 79 | pass 80 | 81 | # EOF 82 | -------------------------------------------------------------------------------- /tests/t-encrypt.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright (C) 2016 g10 Code GmbH 4 | # 5 | # This file is part of GPGME. 6 | # 7 | # GPGME is free software; you can redistribute it and/or modify it 8 | # under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # GPGME is distributed in the hope that it will be useful, but WITHOUT 13 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 15 | # Public License for more details. 16 | # 17 | # You should have received a copy of the GNU Lesser General Public 18 | # License along with this program; if not, see . 19 | 20 | from __future__ import absolute_import, print_function, unicode_literals 21 | 22 | import gpg 23 | import support 24 | 25 | del absolute_import, print_function, unicode_literals 26 | 27 | c = gpg.Context() 28 | c.set_armor(True) 29 | 30 | source = gpg.Data("Hallo Leute\n") 31 | sink = gpg.Data() 32 | 33 | keys = [] 34 | keys.append(c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False)) 35 | keys.append(c.get_key("D695676BDCEDCC2CDD6152BCFE180B1DA9E3B0B2", False)) 36 | 37 | c.op_encrypt(keys, gpg.constants.ENCRYPT_ALWAYS_TRUST, source, sink) 38 | result = c.op_encrypt_result() 39 | assert not result.invalid_recipients, \ 40 | "Invalid recipients: {}".format(", ".join(r.fpr for r in result.recipients)) 41 | support.print_data(sink) 42 | 43 | # Idiomatic interface. 44 | with gpg.Context(armor=True) as c: 45 | ciphertext, _, _ = c.encrypt( 46 | "Hallo Leute\n".encode(), 47 | recipients=keys, 48 | sign=False, 49 | always_trust=True) 50 | assert len(ciphertext) > 0 51 | assert ciphertext.find(b'BEGIN PGP MESSAGE') > 0, 'Marker not found' 52 | 53 | c.encrypt( 54 | "Hallo Leute\n".encode(), 55 | recipients=[c.get_key(support.encrypt_only, False)], 56 | sign=False, 57 | always_trust=True) 58 | 59 | try: 60 | c.encrypt( 61 | "Hallo Leute\n".encode(), 62 | recipients=[c.get_key(support.sign_only, False)], 63 | sign=False, 64 | always_trust=True) 65 | except gpg.errors.InvalidRecipients as e: 66 | assert len(e.recipients) == 1 67 | assert support.sign_only.endswith(e.recipients[0].fpr) 68 | else: 69 | assert False, "Expected an InvalidRecipients error, got none" 70 | 71 | try: 72 | # People might be tempted to provide strings. 73 | # We should raise something useful. 74 | ciphertext, _, _ = c.encrypt( 75 | "Hallo Leute\n", recipients=keys, sign=False, always_trust=True) 76 | except TypeError as e: 77 | # This test is a bit fragile, because the message 78 | # may very well change. So if the behaviour will change 79 | # this test can easily be deleted. 80 | assert "encode" in str(e) 81 | -------------------------------------------------------------------------------- /tests/t-sig-notation.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright (C) 2016 g10 Code GmbH 4 | # 5 | # This file is part of GPGME. 6 | # 7 | # GPGME is free software; you can redistribute it and/or modify it 8 | # under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # GPGME is distributed in the hope that it will be useful, but WITHOUT 13 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 15 | # Public License for more details. 16 | # 17 | # You should have received a copy of the GNU Lesser General Public 18 | # License along with this program; if not, see . 19 | 20 | from __future__ import absolute_import, print_function, unicode_literals 21 | 22 | import os 23 | import gpg 24 | import support 25 | _ = support # to appease pyflakes. 26 | 27 | del absolute_import, print_function, unicode_literals 28 | 29 | expected_notations = { 30 | "laughing@me": ("Just Squeeze Me", 31 | gpg.constants.sig.notation.HUMAN_READABLE), 32 | "preferred-email-encoding@pgp.com": 33 | ("pgpmime", gpg.constants.sig.notation.HUMAN_READABLE | 34 | gpg.constants.sig.notation.CRITICAL), 35 | None: ("https://www.gnu.org/policy/", 0), 36 | } 37 | 38 | # GnuPG prior to 2.1.13 did not report the critical flag correctly. 39 | with gpg.Context() as c: 40 | version = c.engine_info.version 41 | have_correct_sig_data = not ( 42 | version.startswith("1.") or version.startswith("2.0.") or 43 | (version.startswith("2.1.") and int(version[4:]) < 13)) 44 | 45 | 46 | def check_result(result): 47 | assert len(result.signatures) == 1, "Unexpected number of signatures" 48 | sig = result.signatures[0] 49 | assert len(sig.notations) == len(expected_notations) 50 | 51 | for r in sig.notations: 52 | assert 'name_len' not in dir(r) 53 | assert 'value_len' not in dir(r) 54 | assert r.name in expected_notations 55 | value, flags = expected_notations.pop(r.name) 56 | 57 | assert r.value == value, \ 58 | "Expected {!r}, got {!r}".format(value, r.value) 59 | assert r.human_readable \ 60 | == bool(flags & gpg.constants.sig.notation.HUMAN_READABLE) 61 | assert r.critical \ 62 | == (bool(flags & gpg.constants.sig.notation.CRITICAL) 63 | if have_correct_sig_data else False) 64 | 65 | assert len(expected_notations) == 0 66 | 67 | 68 | source = gpg.Data("Hallo Leute\n") 69 | signed = gpg.Data() 70 | 71 | c = gpg.Context() 72 | for name, (value, flags) in expected_notations.items(): 73 | c.sig_notation_add(name, value, flags) 74 | 75 | c.op_sign(source, signed, gpg.constants.sig.mode.NORMAL) 76 | 77 | signed.seek(0, os.SEEK_SET) 78 | sink = gpg.Data() 79 | c.op_verify(signed, None, sink) 80 | result = c.op_verify_result() 81 | check_result(result) 82 | -------------------------------------------------------------------------------- /examples/howto/encrypt-sign-file.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | from __future__ import absolute_import, division, unicode_literals 5 | 6 | import gpg 7 | import sys 8 | 9 | # Copyright (C) 2018 Ben McGinnes 10 | # 11 | # This program is free software; you can redistribute it and/or modify it under 12 | # the terms of the GNU General Public License as published by the Free Software 13 | # Foundation; either version 2 of the License, or (at your option) any later 14 | # version. 15 | # 16 | # This program is free software; you can redistribute it and/or modify it under 17 | # the terms of the GNU Lesser General Public License as published by the Free 18 | # Software Foundation; either version 2.1 of the License, or (at your option) 19 | # any later version. 20 | # 21 | # This program is distributed in the hope that it will be useful, but WITHOUT 22 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 23 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License and the GNU 24 | # Lesser General Public License for more details. 25 | # 26 | # You should have received a copy of the GNU General Public License and the GNU 27 | # Lesser General Public License along with this program; if not, see 28 | # . 29 | 30 | """ 31 | Signs and encrypts a file to a specified key. If entering both the key and the 32 | filename on the command line, the key must be entered first. 33 | 34 | Signs with and also encrypts to the default key of the user invoking the 35 | script. Will treat all recipients as trusted to permit encryption. 36 | 37 | Will produce both an ASCII armoured and GPG binary format copy of the signed 38 | and encrypted file. 39 | """ 40 | 41 | if len(sys.argv) > 3: 42 | a_key = sys.argv[1] 43 | filename = " ".join(sys.argv[2:]) 44 | elif len(sys.argv) == 3: 45 | a_key = sys.argv[1] 46 | filename = sys.argv[2] 47 | elif len(sys.argv) == 2: 48 | a_key = sys.argv[1] 49 | filename = input("Enter the path and filename to encrypt: ") 50 | else: 51 | a_key = input("Enter the fingerprint or key ID to encrypt to: ") 52 | filename = input("Enter the path and filename to encrypt: ") 53 | 54 | rkey = list(gpg.Context().keylist(pattern=a_key, secret=False)) 55 | with open(filename, "rb") as f: 56 | text = f.read() 57 | 58 | with gpg.Context(armor=True) as ca: 59 | ciphertext, result, sign_result = ca.encrypt(text, recipients=rkey, 60 | always_trust=True, 61 | add_encrypt_to=True) 62 | with open("{0}.asc".format(filename), "wb") as fa: 63 | fa.write(ciphertext) 64 | 65 | with gpg.Context() as cg: 66 | ciphertext, result, sign_result = cg.encrypt(text, recipients=rkey, 67 | always_trust=True, 68 | add_encrypt_to=True) 69 | with open("{0}.gpg".format(filename), "wb") as fg: 70 | fg.write(ciphertext) 71 | -------------------------------------------------------------------------------- /examples/howto/import-keybasekey.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | from __future__ import absolute_import, division, unicode_literals 5 | 6 | import gpg 7 | import requests 8 | import sys 9 | 10 | # Copyright (C) 2018 Ben McGinnes 11 | # 12 | # This program is free software; you can redistribute it and/or modify it under 13 | # the terms of the GNU General Public License as published by the Free Software 14 | # Foundation; either version 2 of the License, or (at your option) any later 15 | # version. 16 | # 17 | # This program is free software; you can redistribute it and/or modify it under 18 | # the terms of the GNU Lesser General Public License as published by the Free 19 | # Software Foundation; either version 2.1 of the License, or (at your option) 20 | # any later version. 21 | # 22 | # This program is distributed in the hope that it will be useful, but WITHOUT 23 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 24 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License and the GNU 25 | # Lesser General Public License for more details. 26 | # 27 | # You should have received a copy of the GNU General Public License and the GNU 28 | # Lesser General Public License along with this program; if not, see 29 | # . 30 | 31 | print(""" 32 | This script imports one or more public keys from keybase.io with the username 33 | of a keybase.io user. 34 | 35 | Multiple usernames may be provided, separated by spaces. 36 | """) 37 | 38 | c = gpg.Context() 39 | # https://keybase.io//pgp_keys.asc 40 | results = [] 41 | 42 | if len(sys.argv) >= 2: 43 | keys = sys.argv[1:] 44 | else: 45 | keys = input("Enter the username(s) to get keys for: ") 46 | 47 | for key in keys: 48 | r = requests.get("https://keybase.io/{0}/pgp_keys.asc".format(key)) 49 | import_result = c.key_import(r.content) 50 | results.append(import_result) 51 | 52 | for result in results: 53 | if result is not None and hasattr(result, "considered") is False: 54 | print(result) 55 | elif result is not None and hasattr(result, "considered") is True: 56 | num_keys = len(result.imports) 57 | new_revs = result.new_revocations 58 | new_sigs = result.new_signatures 59 | new_subs = result.new_sub_keys 60 | new_uids = result.new_user_ids 61 | new_scrt = result.secret_imported 62 | nochange = result.unchanged 63 | print(""" 64 | The total number of keys considered for import was: {0} 65 | 66 | Number of keys revoked: {1} 67 | Number of new signatures: {2} 68 | Number of new subkeys: {3} 69 | Number of new user IDs: {4} 70 | Number of new secret keys: {5} 71 | Number of unchanged keys: {6} 72 | 73 | The key IDs for all considered keys were: 74 | """.format(num_keys, new_revs, new_sigs, new_subs, new_uids, new_scrt, 75 | nochange)) 76 | for i in range(num_keys): 77 | print(result.imports[i].fpr) 78 | print("") 79 | else: 80 | print("No keys were imported or found.") 81 | -------------------------------------------------------------------------------- /examples/howto/export-key.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | from __future__ import absolute_import, division, unicode_literals 5 | 6 | import gpg 7 | import os.path 8 | import sys 9 | 10 | # Copyright (C) 2018 Ben McGinnes 11 | # 12 | # This program is free software; you can redistribute it and/or modify it under 13 | # the terms of the GNU General Public License as published by the Free Software 14 | # Foundation; either version 2 of the License, or (at your option) any later 15 | # version. 16 | # 17 | # This program is free software; you can redistribute it and/or modify it under 18 | # the terms of the GNU Lesser General Public License as published by the Free 19 | # Software Foundation; either version 2.1 of the License, or (at your option) 20 | # any later version. 21 | # 22 | # This program is distributed in the hope that it will be useful, but WITHOUT 23 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 24 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License and the GNU 25 | # Lesser General Public License for more details. 26 | # 27 | # You should have received a copy of the GNU General Public License and the GNU 28 | # Lesser General Public License along with this program; if not, see 29 | # . 30 | 31 | print(""" 32 | This script exports one or more public keys. 33 | """) 34 | 35 | c = gpg.Context(armor=True) 36 | 37 | if len(sys.argv) >= 4: 38 | keyfile = sys.argv[1] 39 | logrus = sys.argv[2] 40 | homedir = sys.argv[3] 41 | elif len(sys.argv) == 3: 42 | keyfile = sys.argv[1] 43 | logrus = sys.argv[2] 44 | homedir = input("Enter the GPG configuration directory path (optional): ") 45 | elif len(sys.argv) == 2: 46 | keyfile = sys.argv[1] 47 | logrus = input("Enter the UID matching the key(s) to export: ") 48 | homedir = input("Enter the GPG configuration directory path (optional): ") 49 | else: 50 | keyfile = input("Enter the path and filename to save the key(s) to: ") 51 | logrus = input("Enter the UID matching the key(s) to export: ") 52 | homedir = input("Enter the GPG configuration directory path (optional): ") 53 | 54 | if len(homedir) == 0: 55 | homedir = None 56 | elif homedir.startswith("~"): 57 | userdir = os.path.expanduser(homedir) 58 | if os.path.exists(userdir) is True: 59 | homedir = os.path.realpath(userdir) 60 | else: 61 | homedir = None 62 | else: 63 | homedir = os.path.realpath(homedir) 64 | 65 | if homedir is not None and os.path.exists(homedir) is False: 66 | homedir = None 67 | elif homedir is not None and os.path.exists(homedir) is True: 68 | if os.path.isdir(homedir) is False: 69 | homedir = None 70 | else: 71 | pass 72 | 73 | if homedir is not None: 74 | c.home_dir = homedir 75 | else: 76 | pass 77 | 78 | try: 79 | result = c.key_export(pattern=logrus) 80 | except: 81 | result = c.key_export(pattern=None) 82 | 83 | if result is not None: 84 | with open(keyfile, "wb") as f: 85 | f.write(result) 86 | else: 87 | pass 88 | -------------------------------------------------------------------------------- /examples/verifydetails.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright (C) 2016 g10 Code GmbH 4 | # Copyright (C) 2004,2008 Igor Belyi 5 | # Copyright (c) 2008 Bernhard Reiter 6 | # 7 | # This program is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, but 13 | # WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | # General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program; if not, see . 19 | 20 | from __future__ import absolute_import, print_function, unicode_literals 21 | 22 | import sys 23 | import gpg 24 | 25 | del absolute_import, print_function, unicode_literals 26 | 27 | 28 | def print_engine_infos(): 29 | print("gpgme version:", gpg.core.check_version(None)) 30 | print("engines:") 31 | 32 | for engine in gpg.core.get_engine_info(): 33 | print(engine.file_name, engine.version) 34 | 35 | for proto in [gpg.constants.protocol.OpenPGP, gpg.constants.protocol.CMS]: 36 | print("Have {}? {}".format( 37 | gpg.core.get_protocol_name(proto), 38 | gpg.core.engine_check_version(proto))) 39 | 40 | 41 | def verifyprintdetails(filename, detached_sig_filename=None): 42 | """Verify a signature, print a lot of details.""" 43 | with gpg.Context() as c: 44 | 45 | # Verify. 46 | data, result = c.verify( 47 | open(filename), 48 | open(detached_sig_filename) if detached_sig_filename else None) 49 | 50 | # List results for all signatures. Status equal 0 means "Ok". 51 | for index, sign in enumerate(result.signatures): 52 | print("signature", index, ":") 53 | print(" summary: %#0x" % (sign.summary)) 54 | print(" status: %#0x" % (sign.status)) 55 | print(" timestamp: ", sign.timestamp) 56 | print(" fingerprint:", sign.fpr) 57 | print(" uid: ", c.get_key(sign.fpr).uids[0].uid) 58 | 59 | # Print "unsigned" text if inline signature 60 | if data: 61 | sys.stdout.buffer.write(data) 62 | 63 | 64 | def main(): 65 | print_engine_infos() 66 | print() 67 | 68 | argc = len(sys.argv) 69 | if argc < 2 or argc > 3: 70 | sys.exit("Usage: {} [ ]".format( 71 | sys.argv[0])) 72 | 73 | if argc == 2: 74 | print("trying to verify file {}.".format(sys.argv[1])) 75 | verifyprintdetails(sys.argv[1]) 76 | if argc == 3: 77 | print("trying to verify signature {1} for file {0}.".format(*sys.argv)) 78 | verifyprintdetails(sys.argv[1], sys.argv[2]) 79 | 80 | 81 | if __name__ == "__main__": 82 | main() 83 | -------------------------------------------------------------------------------- /examples/howto/export-minimised-key.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | from __future__ import absolute_import, division, unicode_literals 5 | 6 | import gpg 7 | import os.path 8 | import sys 9 | 10 | # Copyright (C) 2018 Ben McGinnes 11 | # 12 | # This program is free software; you can redistribute it and/or modify it under 13 | # the terms of the GNU General Public License as published by the Free Software 14 | # Foundation; either version 2 of the License, or (at your option) any later 15 | # version. 16 | # 17 | # This program is free software; you can redistribute it and/or modify it under 18 | # the terms of the GNU Lesser General Public License as published by the Free 19 | # Software Foundation; either version 2.1 of the License, or (at your option) 20 | # any later version. 21 | # 22 | # This program is distributed in the hope that it will be useful, but WITHOUT 23 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 24 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License and the GNU 25 | # Lesser General Public License for more details. 26 | # 27 | # You should have received a copy of the GNU General Public License and the GNU 28 | # Lesser General Public License along with this program; if not, see 29 | # . 30 | 31 | print(""" 32 | This script exports one or more public keys in minimised form. 33 | """) 34 | 35 | c = gpg.Context(armor=True) 36 | 37 | if len(sys.argv) >= 4: 38 | keyfile = sys.argv[1] 39 | logrus = sys.argv[2] 40 | homedir = sys.argv[3] 41 | elif len(sys.argv) == 3: 42 | keyfile = sys.argv[1] 43 | logrus = sys.argv[2] 44 | homedir = input("Enter the GPG configuration directory path (optional): ") 45 | elif len(sys.argv) == 2: 46 | keyfile = sys.argv[1] 47 | logrus = input("Enter the UID matching the key(s) to export: ") 48 | homedir = input("Enter the GPG configuration directory path (optional): ") 49 | else: 50 | keyfile = input("Enter the path and filename to save the key(s) to: ") 51 | logrus = input("Enter the UID matching the key(s) to export: ") 52 | homedir = input("Enter the GPG configuration directory path (optional): ") 53 | 54 | if len(homedir) == 0: 55 | homedir = None 56 | elif homedir.startswith("~"): 57 | userdir = os.path.expanduser(homedir) 58 | if os.path.exists(userdir) is True: 59 | homedir = os.path.realpath(userdir) 60 | else: 61 | homedir = None 62 | else: 63 | homedir = os.path.realpath(homedir) 64 | 65 | if homedir is not None and os.path.exists(homedir) is False: 66 | homedir = None 67 | elif homedir is not None and os.path.exists(homedir) is True: 68 | if os.path.isdir(homedir) is False: 69 | homedir = None 70 | else: 71 | pass 72 | 73 | if homedir is not None: 74 | c.home_dir = homedir 75 | else: 76 | pass 77 | 78 | try: 79 | result = c.key_export_minimal(pattern=logrus) 80 | except: 81 | result = c.key_export_minimal(pattern=None) 82 | 83 | if result is not None: 84 | with open(keyfile, "wb") as f: 85 | f.write(result) 86 | else: 87 | pass 88 | -------------------------------------------------------------------------------- /examples/Makefile.am: -------------------------------------------------------------------------------- 1 | # Makefile.am for the Python bindings. 2 | # Copyright (C) 2019 g10 Code GmbH 3 | # 4 | # This file is part of GPGME. 5 | # 6 | # GPGME is free software; you can redistribute it and/or modify it 7 | # under the terms of the GNU Lesser General Public License as 8 | # published by the Free Software Foundation; either version 2.1 of the 9 | # License, or (at your option) any later version. 10 | # 11 | # GPGME is distributed in the hope that it will be useful, but WITHOUT 12 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 13 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 14 | # Public License for more details. 15 | # 16 | # You should have received a copy of the GNU Lesser General Public 17 | # License along with this program; if not, see . 18 | # SPDX-License-Identifier: LGPL-2.1-or-later 19 | 20 | # Created by: 21 | # find . -type f -print | sed 's/^.\// /;$q;s/$/ \\/' | sort 22 | EXTRA_DIST = assuan.py \ 23 | decryption-filter.py \ 24 | delkey.py \ 25 | exportimport.py \ 26 | genkey.py \ 27 | howto/add-userid.py \ 28 | howto/advanced/cython/keycount.pyx \ 29 | howto/advanced/cython/requirements.txt \ 30 | howto/advanced/cython/setup.py \ 31 | howto/clear-sign-file.py \ 32 | howto/create-key.py \ 33 | howto/decrypt-file.py \ 34 | howto/detach-sign-file.py \ 35 | howto/encrypt-file.py \ 36 | howto/encrypt-sign-file.py \ 37 | howto/encrypt-to-group-gullible.py \ 38 | howto/encrypt-to-group.py \ 39 | howto/encrypt-to-group-trustno1.py \ 40 | howto/export-key.py \ 41 | howto/export-minimised-key.py \ 42 | howto/export-secret-key.py \ 43 | howto/export-secret-keys.py \ 44 | howto/groups.py \ 45 | howto/import-keybasekey.py \ 46 | howto/import-key.py \ 47 | howto/import-keys-hkp.py \ 48 | howto/import-keys.py \ 49 | howto/import-mailvelope-keys.py \ 50 | howto/keycount.py \ 51 | howto/local-sign-group.py \ 52 | howto/mutt-groups.py \ 53 | howto/pmkey-import-alt.py \ 54 | howto/pmkey-import-hkp-alt.py \ 55 | howto/pmkey-import-hkp.py \ 56 | howto/pmkey-import.py \ 57 | howto/post_installer.py \ 58 | howto/README.org \ 59 | howto/requirements.txt \ 60 | howto/revoke-userid.py \ 61 | howto/send-key-to-keyserver.py \ 62 | howto/sign-file.py \ 63 | howto/sign-key.py \ 64 | howto/symcrypt-file.py \ 65 | howto/temp-homedir-config.py \ 66 | howto/verify-signatures.py \ 67 | howto/verify-signed-file.py \ 68 | inter-edit.py \ 69 | low_level-encrypt_to_all.py \ 70 | sign.py \ 71 | signverify.py \ 72 | simple.py \ 73 | testCMSgetkey.py \ 74 | verifydetails.py 75 | -------------------------------------------------------------------------------- /tests/t-idiomatic.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright (C) 2016 g10 Code GmbH 4 | # 5 | # This file is part of GPGME. 6 | # 7 | # GPGME is free software; you can redistribute it and/or modify it 8 | # under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # GPGME is distributed in the hope that it will be useful, but WITHOUT 13 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 15 | # Public License for more details. 16 | # 17 | # You should have received a copy of the GNU Lesser General Public 18 | # License along with this program; if not, see . 19 | 20 | from __future__ import absolute_import, print_function, unicode_literals 21 | 22 | import sys 23 | import io 24 | import os 25 | import tempfile 26 | import gpg 27 | import support 28 | _ = support # to appease pyflakes. 29 | 30 | del absolute_import, print_function, unicode_literals 31 | 32 | # Both Context and Data can be used as context manager: 33 | with gpg.Context() as c, gpg.Data() as d: 34 | c.get_engine_info() 35 | d.write(b"Halloechen") 36 | leak_c = c 37 | leak_d = d 38 | 39 | leak_c.__del__() 40 | leak_d.__del__() 41 | assert leak_c.wrapped is None 42 | assert leak_d.wrapped is None 43 | 44 | 45 | def sign_and_verify(source, signed, sink): 46 | with gpg.Context() as c: 47 | c.op_sign(source, signed, gpg.constants.sig.mode.NORMAL) 48 | signed.seek(0, os.SEEK_SET) 49 | c.op_verify(signed, None, sink) 50 | result = c.op_verify_result() 51 | 52 | assert len(result.signatures) == 1, "Unexpected number of signatures" 53 | sig = result.signatures[0] 54 | assert sig.summary == (gpg.constants.sigsum.VALID | 55 | gpg.constants.sigsum.GREEN) 56 | assert gpg.errors.GPGMEError(sig.status).getcode() == gpg.errors.NO_ERROR 57 | 58 | sink.seek(0, os.SEEK_SET) 59 | assert sink.read() == b"Hallo Leute\n" 60 | 61 | 62 | # Demonstrate automatic wrapping of file-like objects with 'fileno' 63 | # method. 64 | with tempfile.TemporaryFile() as source, \ 65 | tempfile.TemporaryFile() as signed, \ 66 | tempfile.TemporaryFile() as sink: 67 | source.write(b"Hallo Leute\n") 68 | source.seek(0, os.SEEK_SET) 69 | 70 | sign_and_verify(source, signed, sink) 71 | 72 | if sys.version_info[0] == 3: 73 | # Python2's io.BytesIO does not implement the buffer interface, 74 | # hence we cannot use it as sink. 75 | 76 | # XXX: Python's io.BytesIo.truncate does not work as advertised. 77 | # https://bugs.python.org/issue27261 78 | bio = io.BytesIO() 79 | bio.truncate(1) 80 | if len(bio.getvalue()) != 1: 81 | # This version of Python is affected, preallocate buffer. 82 | preallocate = 128 * b'\x00' 83 | else: 84 | preallocate = b'' 85 | 86 | # Demonstrate automatic wrapping of objects implementing the buffer 87 | # interface, and the use of data objects with the 'with' statement. 88 | with io.BytesIO(preallocate) as signed, gpg.Data() as sink: 89 | sign_and_verify(b"Hallo Leute\n", signed, sink) 90 | -------------------------------------------------------------------------------- /examples/howto/encrypt-to-group-trustno1.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | from __future__ import absolute_import, division, unicode_literals 5 | 6 | import gpg 7 | import sys 8 | from groups import group_lists 9 | 10 | # Copyright (C) 2018 Ben McGinnes 11 | # 12 | # This program is free software; you can redistribute it and/or modify it under 13 | # the terms of the GNU General Public License as published by the Free Software 14 | # Foundation; either version 2 of the License, or (at your option) any later 15 | # version. 16 | # 17 | # This program is free software; you can redistribute it and/or modify it under 18 | # the terms of the GNU Lesser General Public License as published by the Free 19 | # Software Foundation; either version 2.1 of the License, or (at your option) 20 | # any later version. 21 | # 22 | # This program is distributed in the hope that it will be useful, but WITHOUT 23 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 24 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License and the GNU 25 | # Lesser General Public License for more details. 26 | # 27 | # You should have received a copy of the GNU General Public License and the GNU 28 | # Lesser General Public License along with this program; if not, see 29 | # . 30 | 31 | """ 32 | Uses the groups module to encrypt to multiple recipients. 33 | 34 | """ 35 | 36 | c = gpg.Context(armor=True) 37 | 38 | if len(sys.argv) > 3: 39 | group_id = sys.argv[1] 40 | filepath = sys.argv[2:] 41 | elif len(sys.argv) == 3: 42 | group_id = sys.argv[1] 43 | filepath = sys.argv[2] 44 | elif len(sys.argv) == 2: 45 | group_id = sys.argv[1] 46 | filepath = input("Enter the filename to encrypt: ") 47 | else: 48 | group_id = input("Enter the group name to encrypt to: ") 49 | filepath = input("Enter the filename to encrypt: ") 50 | 51 | with open(filepath, "rb") as f: 52 | text = f.read() 53 | 54 | for i in range(len(group_lists)): 55 | if group_lists[i][0] == group_id: 56 | klist = group_lists[i][1] 57 | else: 58 | klist = None 59 | 60 | logrus = [] 61 | 62 | if klist is not None: 63 | for i in range(len(klist)): 64 | apattern = list(c.keylist(pattern=klist[i], secret=False)) 65 | if apattern[0].can_encrypt == 1: 66 | logrus.append(apattern[0]) 67 | else: 68 | pass 69 | try: 70 | ciphertext, result, sign_result = c.encrypt(text, recipients=logrus, 71 | add_encrypt_to=True) 72 | except gpg.errors.InvalidRecipients as e: 73 | for i in range(len(e.recipients)): 74 | for n in range(len(logrus)): 75 | if logrus[n].fpr == e.recipients[i].fpr: 76 | logrus.remove(logrus[n]) 77 | else: 78 | pass 79 | try: 80 | ciphertext, result, sign_result = c.encrypt(text, 81 | recipients=logrus, 82 | add_encrypt_to=True) 83 | except: 84 | pass 85 | with open("{0}.asc".format(filepath), "wb") as f: 86 | f.write(ciphertext) 87 | else: 88 | pass 89 | 90 | # EOF 91 | -------------------------------------------------------------------------------- /examples/howto/export-secret-key.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | from __future__ import absolute_import, division, unicode_literals 5 | 6 | import gpg 7 | import os 8 | import os.path 9 | import sys 10 | 11 | # Copyright (C) 2018 Ben McGinnes 12 | # 13 | # This program is free software; you can redistribute it and/or modify it under 14 | # the terms of the GNU General Public License as published by the Free Software 15 | # Foundation; either version 2 of the License, or (at your option) any later 16 | # version. 17 | # 18 | # This program is free software; you can redistribute it and/or modify it under 19 | # the terms of the GNU Lesser General Public License as published by the Free 20 | # Software Foundation; either version 2.1 of the License, or (at your option) 21 | # any later version. 22 | # 23 | # This program is distributed in the hope that it will be useful, but WITHOUT 24 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 25 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License and the GNU 26 | # Lesser General Public License for more details. 27 | # 28 | # You should have received a copy of the GNU General Public License and the GNU 29 | # Lesser General Public License along with this program; if not, see 30 | # . 31 | 32 | print(""" 33 | This script exports one or more secret keys. 34 | 35 | The gpg-agent and pinentry are invoked to authorise the export. 36 | """) 37 | 38 | def open_0o600(path, flags): 39 | return os.open(path, flags, mode=0o600) 40 | 41 | c = gpg.Context(armor=True) 42 | 43 | if len(sys.argv) >= 4: 44 | keyfile = sys.argv[1] 45 | logrus = sys.argv[2] 46 | homedir = sys.argv[3] 47 | elif len(sys.argv) == 3: 48 | keyfile = sys.argv[1] 49 | logrus = sys.argv[2] 50 | homedir = input("Enter the GPG configuration directory path (optional): ") 51 | elif len(sys.argv) == 2: 52 | keyfile = sys.argv[1] 53 | logrus = input("Enter the UID matching the secret key(s) to export: ") 54 | homedir = input("Enter the GPG configuration directory path (optional): ") 55 | else: 56 | keyfile = input("Enter the path and filename to save the secret key to: ") 57 | logrus = input("Enter the UID matching the secret key(s) to export: ") 58 | homedir = input("Enter the GPG configuration directory path (optional): ") 59 | 60 | if len(homedir) == 0: 61 | homedir = None 62 | elif homedir.startswith("~"): 63 | userdir = os.path.expanduser(homedir) 64 | if os.path.exists(userdir) is True: 65 | homedir = os.path.realpath(userdir) 66 | else: 67 | homedir = None 68 | else: 69 | homedir = os.path.realpath(homedir) 70 | 71 | if homedir is not None and os.path.exists(homedir) is False: 72 | homedir = None 73 | elif homedir is not None and os.path.exists(homedir) is True: 74 | if os.path.isdir(homedir) is False: 75 | homedir = None 76 | else: 77 | pass 78 | 79 | if homedir is not None: 80 | c.home_dir = homedir 81 | else: 82 | pass 83 | 84 | try: 85 | result = c.key_export_secret(pattern=logrus) 86 | except: 87 | result = c.key_export_secret(pattern=None) 88 | 89 | if result is not None: 90 | with open(keyfile, "wb", opener=open_0o600) as f: 91 | f.write(result) 92 | else: 93 | pass 94 | -------------------------------------------------------------------------------- /examples/howto/encrypt-to-group.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | from __future__ import absolute_import, division, unicode_literals 5 | 6 | import gpg 7 | import sys 8 | from groups import group_lists 9 | 10 | # Copyright (C) 2018 Ben McGinnes 11 | # 12 | # This program is free software; you can redistribute it and/or modify it under 13 | # the terms of the GNU General Public License as published by the Free Software 14 | # Foundation; either version 2 of the License, or (at your option) any later 15 | # version. 16 | # 17 | # This program is free software; you can redistribute it and/or modify it under 18 | # the terms of the GNU Lesser General Public License as published by the Free 19 | # Software Foundation; either version 2.1 of the License, or (at your option) 20 | # any later version. 21 | # 22 | # This program is distributed in the hope that it will be useful, but WITHOUT 23 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 24 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License and the GNU 25 | # Lesser General Public License for more details. 26 | # 27 | # You should have received a copy of the GNU General Public License and the GNU 28 | # Lesser General Public License along with this program; if not, see 29 | # . 30 | 31 | """ 32 | Uses the groups module to encrypt to multiple recipients. 33 | 34 | """ 35 | 36 | c = gpg.Context(armor=True) 37 | 38 | if len(sys.argv) > 3: 39 | group_id = sys.argv[1] 40 | filepath = sys.argv[2:] 41 | elif len(sys.argv) == 3: 42 | group_id = sys.argv[1] 43 | filepath = sys.argv[2] 44 | elif len(sys.argv) == 2: 45 | group_id = sys.argv[1] 46 | filepath = input("Enter the filename to encrypt: ") 47 | else: 48 | group_id = input("Enter the group name to encrypt to: ") 49 | filepath = input("Enter the filename to encrypt: ") 50 | 51 | with open(filepath, "rb") as f: 52 | text = f.read() 53 | 54 | for i in range(len(group_lists)): 55 | if group_lists[i][0] == group_id: 56 | klist = group_lists[i][1] 57 | else: 58 | klist = None 59 | 60 | logrus = [] 61 | 62 | if klist is not None: 63 | for i in range(len(klist)): 64 | apattern = list(c.keylist(pattern=klist[i], secret=False)) 65 | if apattern[0].can_encrypt == 1: 66 | logrus.append(apattern[0]) 67 | else: 68 | pass 69 | try: 70 | ciphertext, result, sign_result = c.encrypt(text, recipients=logrus, 71 | add_encrypt_to=True) 72 | except gpg.errors.InvalidRecipients as e: 73 | for i in range(len(e.recipients)): 74 | for n in range(len(logrus)): 75 | if logrus[n].fpr == e.recipients[i].fpr: 76 | logrus.remove(logrus[n]) 77 | else: 78 | pass 79 | try: 80 | ciphertext, result, sign_result = c.encrypt(text, 81 | recipients=logrus, 82 | add_encrypt_to=True, 83 | always_trust=True) 84 | except: 85 | pass 86 | with open("{0}.asc".format(filepath), "wb") as f: 87 | f.write(ciphertext) 88 | else: 89 | pass 90 | 91 | # EOF 92 | -------------------------------------------------------------------------------- /examples/howto/send-key-to-keyserver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | from __future__ import absolute_import, division, unicode_literals 5 | 6 | import gpg 7 | import hkp4py 8 | import os.path 9 | import sys 10 | 11 | # Copyright (C) 2018 Ben McGinnes 12 | # 13 | # This program is free software; you can redistribute it and/or modify it under 14 | # the terms of the GNU General Public License as published by the Free Software 15 | # Foundation; either version 2 of the License, or (at your option) any later 16 | # version. 17 | # 18 | # This program is free software; you can redistribute it and/or modify it under 19 | # the terms of the GNU Lesser General Public License as published by the Free 20 | # Software Foundation; either version 2.1 of the License, or (at your option) 21 | # any later version. 22 | # 23 | # This program is distributed in the hope that it will be useful, but WITHOUT 24 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 25 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License and the GNU 26 | # Lesser General Public License for more details. 27 | # 28 | # You should have received a copy of the GNU General Public License and the GNU 29 | # Lesser General Public License along with this program; if not, see 30 | # . 31 | 32 | print(""" 33 | This script sends one or more public keys to the SKS keyservers and is 34 | essentially a slight variation on the export-key.py script. 35 | 36 | The default is to send all keys if there is no pattern or search term. 37 | """) 38 | 39 | c = gpg.Context(armor=True) 40 | server = hkp4py.KeyServer("hkps://hkps.pool.sks-keyservers.net") 41 | 42 | if len(sys.argv) >= 3: 43 | logrus = sys.argv[1] 44 | homedir = sys.argv[2] 45 | elif len(sys.argv) == 2: 46 | logrus = sys.argv[1] 47 | homedir = input("Enter the GPG configuration directory path (optional): ") 48 | else: 49 | logrus = input("Enter the UID matching the key(s) to export: ") 50 | homedir = input("Enter the GPG configuration directory path (optional): ") 51 | 52 | if not homedir: 53 | homedir = None 54 | elif homedir.startswith("~"): 55 | userdir = os.path.expanduser(homedir) 56 | if os.path.exists(userdir) is True: 57 | homedir = os.path.realpath(userdir) 58 | else: 59 | homedir = None 60 | else: 61 | homedir = os.path.realpath(homedir) 62 | 63 | if homedir is not None and os.path.exists(homedir) is False: 64 | homedir = None 65 | elif homedir is not None and os.path.exists(homedir) is True: 66 | if os.path.isdir(homedir) is False: 67 | homedir = None 68 | else: 69 | pass 70 | 71 | if homedir is not None: 72 | c.home_dir = homedir 73 | else: 74 | pass 75 | 76 | if logrus: 77 | try: 78 | export_result = c.key_export(pattern=logrus) 79 | except Exception as e: 80 | print(e) 81 | export_result = None 82 | else: 83 | export_result = c.key_export(pattern=None) 84 | 85 | if export_result is not None: 86 | try: 87 | try: 88 | send_result = server.add(export_result) 89 | except: 90 | send_result = server.add(export_result.decode()) 91 | if send_result is not None: 92 | print(send_result) 93 | else: 94 | pass 95 | except Exception as e: 96 | print(e) 97 | else: 98 | pass 99 | -------------------------------------------------------------------------------- /examples/howto/create-key.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | from __future__ import absolute_import, division, unicode_literals 5 | 6 | # Copyright (C) 2018 Ben McGinnes 7 | # 8 | # This program is free software; you can redistribute it and/or modify it under 9 | # the terms of the GNU General Public License as published by the Free Software 10 | # Foundation; either version 2 of the License, or (at your option) any later 11 | # version. 12 | # 13 | # This program is free software; you can redistribute it and/or modify it under 14 | # the terms of the GNU Lesser General Public License as published by the Free 15 | # Software Foundation; either version 2.1 of the License, or (at your option) 16 | # any later version. 17 | # 18 | # This program is distributed in the hope that it will be useful, but WITHOUT 19 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 20 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License and the GNU 21 | # Lesser General Public License for more details. 22 | # 23 | # You should have received a copy of the GNU General Public License and the GNU 24 | # Lesser General Public License along with this program; if not, see 25 | # . 26 | 27 | import gpg 28 | import os.path 29 | 30 | print(""" 31 | This script generates a new key which does not expire. 32 | 33 | The gpg-agent and pinentry are invoked to set the passphrase. 34 | """) 35 | 36 | c = gpg.Context() 37 | 38 | homedir = input("Enter the GPG configuration directory path (optional): ") 39 | uid_name = input("Enter the name of the user ID: ") 40 | uid_email = input("Enter the email address of the user ID: ") 41 | uid_cmnt = input("Enter a comment to include (optional): ") 42 | key_algo = input("Enter the key algorithm, RSA or DSA (default is RSA): ") 43 | key_size = input("Enter the key size (2048-4096, default is 2048): ") 44 | 45 | if homedir.startswith("~"): 46 | if os.path.exists(os.path.expanduser(homedir)) is True: 47 | c.home_dir = os.path.expanduser(homedir) 48 | else: 49 | pass 50 | elif os.path.exists(homedir) is True: 51 | c.home_dir = homedir 52 | else: 53 | pass 54 | 55 | if uid_cmnt: 56 | userid = "{0} ({1}) <{2}>".format(uid_name, uid_cmnt, uid_email) 57 | else: 58 | userid = "{0} <{2}>".format(uid_name, uid_email) 59 | 60 | if key_algo.lower() == "dsa": 61 | ka = "dsa" 62 | else: 63 | ka = "rsa" 64 | 65 | if len(key_size) == 4: 66 | try: 67 | ks0 = int(key_size) 68 | except ValueError: 69 | ks0 = None 70 | if ks0 is None: 71 | ks = "2048" 72 | else: 73 | if ks0 < 2048: 74 | ks = "2048" 75 | elif ka == "dsa" and ks0 > 3072: 76 | ks = "3072" 77 | elif ka == "rsa" and ks0 > 4096: 78 | ks = "4096" 79 | else: 80 | ks = key_size 81 | else: 82 | ks = "2048" 83 | 84 | keyalgo = "{0}{1}".format(ka, ks) 85 | 86 | newkey = c.create_key(userid, algorithm=keyalgo, expires=False, 87 | passphrase=True, certify=True) 88 | key = c.get_key(newkey.fpr, secret=True) 89 | 90 | if ka == "rsa": 91 | newsub = c.create_subkey(key, algorithm=keyalgo, expires=False, 92 | passphrase=True, encrypt=True) 93 | else: 94 | newsub = c.create_subkey(key, expires=False, passphrase=True, 95 | encrypt=True) 96 | -------------------------------------------------------------------------------- /examples/howto/import-key.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | from __future__ import absolute_import, division, unicode_literals 5 | 6 | import gpg 7 | import os.path 8 | import sys 9 | 10 | del absolute_import, division, unicode_literals 11 | 12 | # Copyright (C) 2018 Ben McGinnes 13 | # 14 | # This program is free software; you can redistribute it and/or modify it under 15 | # the terms of the GNU General Public License as published by the Free Software 16 | # Foundation; either version 2 of the License, or (at your option) any later 17 | # version. 18 | # 19 | # This program is free software; you can redistribute it and/or modify it under 20 | # the terms of the GNU Lesser General Public License as published by the Free 21 | # Software Foundation; either version 2.1 of the License, or (at your option) 22 | # any later version. 23 | # 24 | # This program is distributed in the hope that it will be useful, but WITHOUT 25 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 26 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License and the GNU 27 | # Lesser General Public License for more details. 28 | # 29 | # You should have received a copy of the GNU General Public License and the GNU 30 | # Lesser General Public License along with this program; if not, see 31 | # . 32 | 33 | print(""" 34 | This script imports one or more public keys from a single file. 35 | """) 36 | 37 | c = gpg.Context(armor=True) 38 | 39 | if len(sys.argv) >= 3: 40 | keyfile = sys.argv[1] 41 | homedir = sys.argv[2] 42 | elif len(sys.argv) == 2: 43 | keyfile = sys.argv[1] 44 | homedir = input("Enter the GPG configuration directory path (optional): ") 45 | else: 46 | keyfile = input("Enter the path and filename to import the key(s) from: ") 47 | homedir = input("Enter the GPG configuration directory path (optional): ") 48 | 49 | if homedir.startswith("~"): 50 | if os.path.exists(os.path.expanduser(homedir)) is True: 51 | c.home_dir = os.path.expanduser(homedir) 52 | else: 53 | pass 54 | elif os.path.exists(homedir) is True: 55 | c.home_dir = homedir 56 | else: 57 | pass 58 | 59 | if os.path.isfile(keyfile) is True: 60 | with open(keyfile, "rb") as f: 61 | incoming = f.read() 62 | result = c.key_import(incoming) 63 | else: 64 | result = None 65 | 66 | if result is not None and hasattr(result, "considered") is False: 67 | print(result) 68 | elif result is not None and hasattr(result, "considered") is True: 69 | num_keys = len(result.imports) 70 | new_revs = result.new_revocations 71 | new_sigs = result.new_signatures 72 | new_subs = result.new_sub_keys 73 | new_uids = result.new_user_ids 74 | new_scrt = result.secret_imported 75 | nochange = result.unchanged 76 | print(""" 77 | The total number of keys considered for import was: {0} 78 | 79 | Number of keys revoked: {1} 80 | Number of new signatures: {2} 81 | Number of new subkeys: {3} 82 | Number of new user IDs: {4} 83 | Number of new secret keys: {5} 84 | Number of unchanged keys: {6} 85 | 86 | The key IDs for all considered keys were: 87 | """.format(num_keys, new_revs, new_sigs, new_subs, new_uids, new_scrt, 88 | nochange)) 89 | for i in range(num_keys): 90 | print(result.imports[i].fpr) 91 | print("") 92 | elif result is None: 93 | print("You must specify a key file to import.") 94 | -------------------------------------------------------------------------------- /version.py.in: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Copyright (C) 2016-2018 g10 Code GmbH 4 | # Copyright (C) 2015 Ben McGinnes 5 | # Copyright (C) 2004 Igor Belyi 6 | # 7 | # This library is free software; you can redistribute it and/or 8 | # modify it under the terms of the GNU Lesser General Public 9 | # License as published by the Free Software Foundation; either 10 | # version 2.1 of the License, or (at your option) any later version. 11 | # 12 | # This library is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | # Lesser General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU Lesser General Public 18 | # License along with this library; if not, write to the Free Software 19 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 | 21 | from __future__ import absolute_import, print_function 22 | 23 | from . import gpgme 24 | 25 | del absolute_import, print_function 26 | 27 | productname = 'gpg' 28 | versionstr = "@VERSION@" 29 | gpgme_versionstr = gpgme.GPGME_VERSION 30 | in_tree_build = bool(gpgme.cvar.gpg_in_tree_build) 31 | is_beta = False 32 | 33 | versionlist = versionstr.split(".") 34 | major = versionlist[0] 35 | minor = versionlist[1] 36 | patch = versionlist[2] 37 | 38 | versionintlist = [] 39 | versionintlist.append(int(major)) 40 | versionintlist.append(int(minor)) 41 | 42 | try: 43 | int(patch) 44 | except ValueError as e: 45 | is_beta = True 46 | 47 | if is_beta is False: 48 | versionintlist.append(int(patch)) 49 | else: 50 | try: 51 | beta_patch = patch.split("-") 52 | versionintlist.append(int(beta_patch[0])) 53 | except Exception as e: 54 | # This should never happen, if it does then lodge a bug report. 55 | versionintlist.append(-1) 56 | 57 | copyright = """\ 58 | Copyright (C) 2016-2018 g10 Code GmbH 59 | Copyright (C) 2015 Benjamin D. McGinnes 60 | Copyright (C) 2014-2015 Martin Albrecht 61 | Copyright (C) 2004-2008 Igor Belyi 62 | Copyright (C) 2002 John Goerzen""" 63 | 64 | author = "The GnuPG hackers" 65 | author_email = "gnupg-devel@gnupg.org" 66 | 67 | description = "Python support for GPGME GnuPG cryptography library" 68 | homepage = "https://gnupg.org" 69 | 70 | license = """Copyright (C) 2016-2018 g10 Code GmbH 71 | Copyright (C) 2015 Benjamin D. McGinnes 72 | Copyright (C) 2014, 2015 Martin Albrecht 73 | Copyright (C) 2004, 2008 Igor Belyi 74 | Copyright (C) 2002 John Goerzen 75 | 76 | This library is free software; you can redistribute it and/or 77 | modify it under the terms of the GNU Lesser General Public 78 | License as published by the Free Software Foundation; either 79 | version 2.1 of the License, or (at your option) any later version. 80 | 81 | This library is distributed in the hope that it will be useful, 82 | but WITHOUT ANY WARRANTY; without even the implied warranty of 83 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 84 | Lesser General Public License for more details. 85 | 86 | You should have received a copy of the GNU Lesser General Public 87 | License along with this library; if not, write to the Free Software 88 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA""" 89 | 90 | # Interface hygiene. Keep this at the end. 91 | del gpgme 92 | -------------------------------------------------------------------------------- /tests/t-encrypt-sym.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright (C) 2016 g10 Code GmbH 4 | # 5 | # This file is part of GPGME. 6 | # 7 | # GPGME is free software; you can redistribute it and/or modify it 8 | # under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # GPGME is distributed in the hope that it will be useful, but WITHOUT 13 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 15 | # Public License for more details. 16 | # 17 | # You should have received a copy of the GNU Lesser General Public 18 | # License along with this program; if not, see . 19 | 20 | from __future__ import absolute_import, print_function, unicode_literals 21 | 22 | import os 23 | import gpg 24 | import support 25 | _ = support # to appease pyflakes. 26 | 27 | del absolute_import, print_function, unicode_literals 28 | 29 | for passphrase in ("abc", b"abc"): 30 | c = gpg.Context() 31 | c.set_armor(True) 32 | c.set_pinentry_mode(gpg.constants.PINENTRY_MODE_LOOPBACK) 33 | 34 | source = gpg.Data("Hallo Leute\n") 35 | cipher = gpg.Data() 36 | 37 | passphrase_cb_called = 0 38 | 39 | def passphrase_cb(hint, desc, prev_bad, hook=None): 40 | global passphrase_cb_called 41 | passphrase_cb_called += 1 42 | return passphrase 43 | 44 | c.set_passphrase_cb(passphrase_cb, None) 45 | 46 | c.op_encrypt([], 0, source, cipher) 47 | # gpg 2.2.21 has a bug in that for a new passphrase the callback 48 | # is called twice. This is fixed in 2.2.22 but a patch was also 49 | # distributed so that we allow both. 50 | if support.is_gpg_version((2,2,21)): 51 | print("Enabling GnuPG 2.2.21 bug 4991 test workaround.") 52 | assert passphrase_cb_called == 1 or passphrase_cb_called == 2, \ 53 | "Callback called {} times".format(passphrase_cb_called) 54 | else: 55 | assert passphrase_cb_called == 1, \ 56 | "Callback called {} times".format(passphrase_cb_called) 57 | support.print_data(cipher) 58 | 59 | c = gpg.Context() 60 | c.set_armor(True) 61 | c.set_pinentry_mode(gpg.constants.PINENTRY_MODE_LOOPBACK) 62 | c.set_passphrase_cb(passphrase_cb, None) 63 | plain = gpg.Data() 64 | cipher.seek(0, os.SEEK_SET) 65 | 66 | c.op_decrypt(cipher, plain) 67 | # Seems like the passphrase is cached. 68 | # assert passphrase_cb_called == 2, \ 69 | # "Callback called {} times".format(passphrase_cb_called) 70 | support.print_data(plain) 71 | 72 | plain.seek(0, os.SEEK_SET) 73 | plaintext = plain.read() 74 | assert plaintext == b"Hallo Leute\n", \ 75 | "Wrong plaintext {!r}".format(plaintext) 76 | 77 | # Idiomatic interface. 78 | for passphrase in ("abc", b"abc"): 79 | with gpg.Context(armor=True) as c: 80 | # Check that the passphrase callback is not altered. 81 | def f(*args): 82 | assert False 83 | 84 | c.set_passphrase_cb(f) 85 | 86 | message = "Hallo Leute\n".encode() 87 | ciphertext, _, _ = c.encrypt( 88 | message, passphrase=passphrase, sign=False) 89 | assert ciphertext.find(b'BEGIN PGP MESSAGE') > 0, 'Marker not found' 90 | 91 | plaintext, _, _ = c.decrypt(ciphertext, passphrase=passphrase) 92 | assert plaintext == message, 'Message body not recovered' 93 | 94 | assert c._passphrase_cb[1] == f, "Passphrase callback not restored" 95 | -------------------------------------------------------------------------------- /tests/t-decrypt-verify.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright (C) 2016 g10 Code GmbH 4 | # 5 | # This file is part of GPGME. 6 | # 7 | # GPGME is free software; you can redistribute it and/or modify it 8 | # under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # GPGME is distributed in the hope that it will be useful, but WITHOUT 13 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 15 | # Public License for more details. 16 | # 17 | # You should have received a copy of the GNU Lesser General Public 18 | # License along with this program; if not, see . 19 | 20 | from __future__ import absolute_import, print_function, unicode_literals 21 | 22 | import gpg 23 | import support 24 | 25 | del absolute_import, print_function, unicode_literals 26 | 27 | 28 | def check_verify_result(result, summary, fpr, status): 29 | assert len(result.signatures) == 1, "Unexpected number of signatures" 30 | sig = result.signatures[0] 31 | assert sig.summary == summary, "Unexpected signature summary" 32 | assert sig.fpr == fpr 33 | assert gpg.errors.GPGMEError(sig.status).getcode() == status 34 | assert len(sig.notations) == 0 35 | assert not sig.wrong_key_usage 36 | assert sig.validity == gpg.constants.validity.FULL 37 | assert gpg.errors.GPGMEError( 38 | sig.validity_reason).getcode() == gpg.errors.NO_ERROR 39 | 40 | 41 | c = gpg.Context() 42 | 43 | source = gpg.Data(file=support.make_filename("cipher-2.asc")) 44 | sink = gpg.Data() 45 | 46 | c.op_decrypt_verify(source, sink) 47 | result = c.op_decrypt_result() 48 | assert not result.unsupported_algorithm, \ 49 | "Unsupported algorithm: {}".format(result.unsupported_algorithm) 50 | 51 | support.print_data(sink) 52 | 53 | verify_result = c.op_verify_result() 54 | check_verify_result( 55 | verify_result, gpg.constants.sigsum.VALID | gpg.constants.sigsum.GREEN, 56 | "A0FF4590BB6122EDEF6E3C542D727CC768697734", gpg.errors.NO_ERROR) 57 | 58 | # Idiomatic interface. 59 | with gpg.Context() as c: 60 | alpha = c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False) 61 | bob = c.get_key("D695676BDCEDCC2CDD6152BCFE180B1DA9E3B0B2", False) 62 | plaintext, _, verify_result = \ 63 | c.decrypt(open(support.make_filename("cipher-2.asc")), verify=[alpha]) 64 | assert plaintext.find(b'Wenn Sie dies lesen k') >= 0, \ 65 | 'Plaintext not found' 66 | check_verify_result( 67 | verify_result, gpg.constants.sigsum.VALID | gpg.constants.sigsum.GREEN, 68 | "A0FF4590BB6122EDEF6E3C542D727CC768697734", gpg.errors.NO_ERROR) 69 | 70 | try: 71 | c.decrypt( 72 | open(support.make_filename("cipher-2.asc")), verify=[alpha, bob]) 73 | except Exception as e: 74 | assert len(e.missing) == 1 75 | assert e.missing[0] == bob 76 | else: 77 | assert False, "Expected an error, got none" 78 | 79 | # plaintext, _, verify_result = c.decrypt(open(support.make_filename("cipher-no-sig.asc"))) 80 | # assert len(plaintext) > 0 81 | # assert len(verify_result.signatures) == 0 82 | # assert plaintext.find(b'Viscosity Dispersal Thimble Saturday Flaxseed Deflected') >= 0, \ 83 | # 'unsigned Plaintext was not found' 84 | # 85 | # plaintext, _, verify_result = c.decrypt(open(support.make_filename("cipher-3.asc"))) 86 | # assert len(plaintext) > 0 87 | # assert len(verify_result.signatures) == 1 88 | # assert plaintext.find(b'Reenact Studied Thermos Bonehead Unclasp Opposing') >= 0, \ 89 | # 'second Plaintext not found' 90 | -------------------------------------------------------------------------------- /tests/t-import.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright (C) 2016 Tobias Mueller 4 | # 5 | # This file is part of GPGME. 6 | # 7 | # GPGME is free software; you can redistribute it and/or modify it 8 | # under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # GPGME is distributed in the hope that it will be useful, but WITHOUT 13 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 15 | # Public License for more details. 16 | # 17 | # You should have received a copy of the GNU Lesser General Public 18 | # License along with this program; if not, see . 19 | 20 | from __future__ import absolute_import, print_function, unicode_literals 21 | 22 | import gpg 23 | import support 24 | 25 | del absolute_import, print_function, unicode_literals 26 | 27 | 28 | def check_result(result, fpr, secret): 29 | assert result.considered == 1 or (secret and result.considered == 3) 30 | assert result.no_user_id == 0 31 | assert not ((secret and result.imported != 0) or 32 | (not secret and 33 | (result.imported != 0 and result.imported != 1))) 34 | assert result.imported_rsa == 0 35 | assert not ((secret and 36 | (result.unchanged != 0 and result.unchanged != 1)) or 37 | (not secret and 38 | ((result.imported == 0 and result.unchanged != 1) or 39 | (result.imported == 1 and result.unchanged != 0)))) 40 | assert result.new_user_ids == 0 41 | assert result.new_sub_keys == 0 42 | assert not ((secret and ( 43 | (result.secret_imported == 0 and result.new_signatures != 0) or 44 | (result.secret_imported == 1 and result.new_signatures > 1))) or 45 | (not secret and result.new_signatures != 0)) 46 | assert result.new_revocations == 0 47 | assert not ( 48 | (secret and result.secret_read != 1 and result.secret_read != 3) or 49 | (not secret and result.secret_read != 0)) 50 | assert not ( 51 | (secret and result.secret_imported != 0 and result. 52 | secret_imported != 1 and result. 53 | secret_imported != 2) or (not secret and result. 54 | secret_imported != 0)) 55 | assert not ((secret and 56 | ((result.secret_imported == 0 and result. 57 | secret_unchanged != 1 and result. 58 | secret_unchanged != 2) or (result. 59 | secret_imported == 1 and result. 60 | secret_unchanged != 0))) or 61 | (not secret and result.secret_unchanged != 0)) 62 | assert result.not_imported == 0 63 | if secret: 64 | assert not (len(result.imports) in (0, 3)) 65 | else: 66 | assert not (len(result.imports) in (0, 2)) 67 | 68 | assert fpr == result.imports[0].fpr 69 | assert len(result.imports) == 1 or fpr == result.imports[1].fpr 70 | assert result.imports[0].result == 0 71 | 72 | 73 | c = gpg.Context() 74 | 75 | result = c.key_import(open(support.make_filename("pubkey-1.asc"), 'rb').read()) 76 | check_result(result, "ADAB7FCC1F4DE2616ECFA402AF82244F9CD9FD55", False) 77 | 78 | result = c.key_import(open(support.make_filename("seckey-1.asc"), 'rb').read()) 79 | check_result(result, "ADAB7FCC1F4DE2616ECFA402AF82244F9CD9FD55", True) 80 | 81 | try: 82 | result = c.key_import(b"thisisnotakey") 83 | except ValueError: 84 | pass 85 | assert result == "IMPORT_PROBLEM" 86 | -------------------------------------------------------------------------------- /tests/t-signers.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright (C) 2016 g10 Code GmbH 4 | # 5 | # This file is part of GPGME. 6 | # 7 | # GPGME is free software; you can redistribute it and/or modify it 8 | # under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # GPGME is distributed in the hope that it will be useful, but WITHOUT 13 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 15 | # Public License for more details. 16 | # 17 | # You should have received a copy of the GNU Lesser General Public 18 | # License along with this program; if not, see . 19 | 20 | from __future__ import absolute_import, print_function, unicode_literals 21 | 22 | import gpg 23 | import support 24 | 25 | del absolute_import, print_function, unicode_literals 26 | 27 | 28 | def fail(msg): 29 | raise RuntimeError(msg) 30 | 31 | 32 | def check_result(r, typ): 33 | if r.invalid_signers: 34 | fail("Invalid signer found: {}".format(r.invalid_signers.fpr)) 35 | 36 | if len(r.signatures) != 2: 37 | fail("Unexpected number of signatures created") 38 | 39 | for signature in r.signatures: 40 | if signature.type != typ: 41 | fail("Wrong type of signature created") 42 | 43 | if signature.pubkey_algo != gpg.constants.pk.DSA: 44 | fail("Wrong pubkey algorithm reported: {}".format( 45 | signature.pubkey_algo)) 46 | 47 | if signature.hash_algo != gpg.constants.md.SHA1: 48 | fail("Wrong hash algorithm reported: {}".format( 49 | signature.hash_algo)) 50 | 51 | if signature.sig_class != 1: 52 | fail("Wrong signature class reported: got {}, want {}".format( 53 | signature.sig_class, 1)) 54 | 55 | if signature.fpr not in ("A0FF4590BB6122EDEF6E3C542D727CC768697734", 56 | "23FD347A419429BACCD5E72D6BC4778054ACD246"): 57 | fail("Wrong fingerprint reported: {}".format(signature.fpr)) 58 | 59 | 60 | c = gpg.Context() 61 | c.set_textmode(True) 62 | c.set_armor(True) 63 | 64 | keys = [] 65 | c.op_keylist_start('', True) 66 | keys.append(c.op_keylist_next()) 67 | keys.append(c.op_keylist_next()) 68 | c.op_keylist_end() 69 | 70 | c.signers_add(keys[0]) 71 | c.signers_add(keys[1]) 72 | 73 | for mode in (gpg.constants.sig.mode.NORMAL, gpg.constants.sig.mode.DETACH, 74 | gpg.constants.sig.mode.CLEAR): 75 | source = gpg.Data("Hallo Leute\n") 76 | sink = gpg.Data() 77 | 78 | c.op_sign(source, sink, mode) 79 | 80 | result = c.op_sign_result() 81 | check_result(result, mode) 82 | support.print_data(sink) 83 | 84 | # Idiomatic interface. 85 | with gpg.Context(armor=True, textmode=True, signers=keys) as c: 86 | message = "Hallo Leute\n".encode() 87 | signed, result = c.sign(message) 88 | check_result(result, gpg.constants.sig.mode.NORMAL) 89 | assert signed.find(b'BEGIN PGP MESSAGE') > 0, 'Message not found' 90 | 91 | signed, result = c.sign(message, mode=gpg.constants.sig.mode.DETACH) 92 | check_result(result, gpg.constants.sig.mode.DETACH) 93 | assert signed.find(b'BEGIN PGP SIGNATURE') > 0, 'Signature not found' 94 | 95 | signed, result = c.sign(message, mode=gpg.constants.sig.mode.CLEAR) 96 | check_result(result, gpg.constants.sig.mode.CLEAR) 97 | assert signed.find(b'BEGIN PGP SIGNED MESSAGE') > 0, 'Message not found' 98 | assert signed.find(message) > 0, 'Message content not found' 99 | assert signed.find(b'BEGIN PGP SIGNATURE') > 0, 'Signature not found' 100 | -------------------------------------------------------------------------------- /tests/t-encrypt-sign.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright (C) 2016 g10 Code GmbH 4 | # 5 | # This file is part of GPGME. 6 | # 7 | # GPGME is free software; you can redistribute it and/or modify it 8 | # under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # GPGME is distributed in the hope that it will be useful, but WITHOUT 13 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 15 | # Public License for more details. 16 | # 17 | # You should have received a copy of the GNU Lesser General Public 18 | # License along with this program; if not, see . 19 | 20 | from __future__ import absolute_import, print_function, unicode_literals 21 | 22 | import sys 23 | import gpg 24 | import support 25 | 26 | del absolute_import, print_function, unicode_literals 27 | 28 | c = gpg.Context() 29 | c.set_armor(True) 30 | 31 | 32 | def check_result(r, typ): 33 | if r.invalid_signers: 34 | sys.exit("Invalid signer found: {}".format(r.invalid_signers.fpr)) 35 | 36 | if len(r.signatures) != 1: 37 | sys.exit("Unexpected number of signatures created") 38 | 39 | signature = r.signatures[0] 40 | if signature.type != typ: 41 | sys.exit("Wrong type of signature created") 42 | 43 | if signature.pubkey_algo != gpg.constants.pk.DSA: 44 | sys.exit("Wrong pubkey algorithm reported: {}".format( 45 | signature.pubkey_algo)) 46 | 47 | if signature.hash_algo not in (gpg.constants.md.SHA1, 48 | gpg.constants.md.RMD160): 49 | sys.exit("Wrong hash algorithm reported: {}".format( 50 | signature.hash_algo)) 51 | 52 | if signature.sig_class != 0: 53 | sys.exit("Wrong signature class reported: {}".format( 54 | signature.sig_class)) 55 | 56 | if signature.fpr != "A0FF4590BB6122EDEF6E3C542D727CC768697734": 57 | sys.exit("Wrong fingerprint reported: {}".format(signature.fpr)) 58 | 59 | 60 | keys = [] 61 | keys.append(c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False)) 62 | keys.append(c.get_key("D695676BDCEDCC2CDD6152BCFE180B1DA9E3B0B2", False)) 63 | 64 | for recipients in (keys, []): 65 | source = gpg.Data("Hallo Leute\n") 66 | sink = gpg.Data() 67 | 68 | c.op_encrypt_sign(recipients, gpg.constants.ENCRYPT_ALWAYS_TRUST, source, 69 | sink) 70 | result = c.op_encrypt_result() 71 | assert not result.invalid_recipients, \ 72 | "Invalid recipient encountered: {}".format( 73 | result.invalid_recipients.fpr) 74 | 75 | result = c.op_sign_result() 76 | check_result(result, gpg.constants.sig.mode.NORMAL) 77 | 78 | support.print_data(sink) 79 | 80 | # Idiomatic interface. 81 | with gpg.Context(armor=True) as c: 82 | message = "Hallo Leute\n".encode() 83 | ciphertext, _, sig_result = c.encrypt( 84 | message, recipients=keys, always_trust=True) 85 | assert len(ciphertext) > 0 86 | assert ciphertext.find(b'BEGIN PGP MESSAGE') > 0, 'Marker not found' 87 | check_result(sig_result, gpg.constants.sig.mode.NORMAL) 88 | 89 | c.signers = [c.get_key(support.sign_only, True)] 90 | c.encrypt(message, recipients=keys, always_trust=True) 91 | 92 | c.signers = [c.get_key(support.encrypt_only, True)] 93 | try: 94 | c.encrypt(message, recipients=keys, always_trust=True) 95 | except gpg.errors.InvalidSigners as e: 96 | assert len(e.signers) == 1 97 | assert support.encrypt_only.endswith(e.signers[0].fpr) 98 | else: 99 | assert False, "Expected an InvalidSigners error, got none" 100 | -------------------------------------------------------------------------------- /tests/secdemo.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP PRIVATE KEY BLOCK----- 2 | Version: GnuPG v2.1.0-gitb3c71eb (GNU/Linux) 3 | 4 | lQHpBDbjjp4RBAC2ZbFDX0wmJI8yLDYQdIiZeAuHLmfyHsqXaLGUMZtWiAvn/hNp 5 | ctwahmzKm5oXinHUvUkLOQ0s8rOlu15nhw4azc30rTP1LsIkn5zORNnFdgYC6RKy 6 | hOeim/63+/yGtdnTm49lVfaCqwsEmBCEkXaeWDGq+ie1b89J89T6n/JquwCgoQkj 7 | VeVGG+B/SzJ6+yifdHWQVkcD/RXDyLXX4+WHGP2aet51XlKojWGwsZmc9LPPYhwU 8 | /RcUO7ce1QQb0XFlUVFBhY0JQpM/ty/kNi+aGWFzigbQ+HAWZkUvA8+VIAVneN+p 9 | +SHhGIyLTXKpAYTq46AwvllZ5Cpvf02Cp/+W1aVyA0qnBWMyeIxXmR9HOi6lxxn5 10 | cjajA/9VZufOXWqCXkBvz4Oy3Q5FbjQQ0/+ty8rDn8OTaiPi41FyUnEi6LO+qyBS 11 | 09FjnZj++PkcRcXW99SNxmEJRY7MuNHt5wIvEH2jNEOJ9lszzZFBDbuwsjXHK35+ 12 | lPbGEy69xCP26iEafysKKbRXJhE1C+tk8SnK+Gm62sivmK/5av4HAwJXxtv1ynxO 13 | DtS0nVDdzgGHGC3F520qQpUb+rrWSMvo4f2/ODb6HbQt8FB2G0zFxN9DurBh1Rq1 14 | ILvFIIs0T5K/YZ29tClBbHBoYSBUZXN0IChkZW1vIGtleSkgPGFscGhhQGV4YW1w 15 | bGUubmV0PohVBBMRAgAVBQI2446eAwsKAwMVAwIDFgIBAheAAAoJEC1yfMdoaXc0 16 | OXgAoIEuZGmW//xl9Kp6nkiOoQC5pe9bAKCXo0TNP79Z7A9MZzBlj6kuTJwu/YhV 17 | BBMRAgAVBQI2446eAwsKAwMVAwIDFgIBAheAAAoJEC1yfMdoaXc0OXgAniui4cH4 18 | ukKQ2LkLn2McRrWRsA3MAKCZ122s1KPXI/JMLBTBGCE9SiYQJLQQQWxpY2UgKGRl 19 | bW8ga2V5KYhVBBMRAgAVBQI247arAwsKAwMVAwIDFgIBAheAAAoJEC1yfMdoaXc0 20 | J4wAn0x5RWtqCjklzo93B143k4zBvLftAKCFbrlxlNCUPVsGUir9AzxvP0A3gbQn 21 | QWxmYSBUZXN0IChkZW1vIGtleSkgPGFsZmFAZXhhbXBsZS5uZXQ+iFUEExECABUF 22 | AjbjuFgDCwoDAxUDAgMWAgECF4AACgkQLXJ8x2hpdzS3wgCgk/BrqP5WblWLc2+6 23 | jwlmuLg8n8MAn12puZol0HwV0mcd8aHWtcrfL8lynQHABDbjjw8QBACcjdcfV/S7 24 | I319mfDvbOwczDvTqDsRbb2cPhQNAbg7NFlWJKtRrmff14jtCt9M77WZ5W+zTLwX 25 | 8+8Wy3mMfrys8ucZKtfPixOXVPhyinUUGSq68IArA8vLSUTuOO0LIi05LAg6jzGh 26 | N9jgkQReZyqxub4oe/3JhIX9grgJ/tsjNwADBwP9GeXmMrGi5wMD3qkPbzb1Mqws 27 | VBJq75eLLxu85JIN2XIAGw6Q0FJp4o7d4BAQqAMzt3ONU1OcCWlDQRDxj1nynE5Z 28 | gRBiVoyudEELgNnYhp3MSEuUg7PkFWn+N+GuvyhVUHApleyvP09kvP57hif6yJRS 29 | +V6L1ugP0vZmBI4dqQ/+BwMCZD+ecL2Wy7jUELEqiGi2L9T8zyQKP2d7/8YTIez/ 30 | HxRO6mMvs7YHx87imq1eAFFqXsxNOGbBOT0oUY8zkYV4R3pC/hNX2lsWq/TbfaUS 31 | i+qK5yKNm7ccniHUgFoCeA3esILIUh73TuaBpk2eWy7RLXHr+BvkbkC1gZ4HzWlx 32 | QLjzovsYVpbq3/cofktJN0O+4UjKcVEYmUtunmBV9+6FJuAsz/sYSVi3RTgqI0+g 33 | YYhGBBgRAgAGBQI2448PAAoJEC1yfMdoaXc0IKkAn3A15g/LjVXSoPwvb6iNyUp3 34 | apJ7AJ0cc1Xh4v4ie9zgirbxax21fRqIKpUB6QQ247XLEQQAgQyThl/Qv8cQlWTT 35 | +jh8+nC+bzNz4plAIVfvRwFVT0FYk5xSq5GD0kMkX1s4zlPETtU6eQh8++O6Dm+o 36 | /T++Mh9bsu/MhYOFLoVwVop4bgiiquCCFsCZAigRa9VPH7vGumOjXI6ogwNCphkS 37 | azD5l3p15CaRRhxu/K1LzYvSDH8AoLoMzSC4f912QmVPgVD2Hly/p1ABBACA12YY 38 | 9bxVx4IvZZooyg4yaHBAaGpjf7WkMujsdUUQ+h7XwD2OUxEdZ+8ZvYTMxPjr9SCq 39 | R/xPO9kYWtartb+3jmunk7jVhdDb5kkfeeX63kbDbkfCTSG+krSNhEfacwVH48pA 40 | vaYNsD3gu8KUCSBfUxfiWtQbxtiPoWtsSe/OgAP7BxFLwDrHOfGGz5WyD8qdiXRB 41 | 7100U9jSElUbkzELIPL1ffZzGEdglIdu9Lj8stsWWg/5GHCff9Z4GOwvaW2zVqFe 42 | 9D5BDDv6o+uziFYllT81ISHVEaK26RobnN6Ac1MToImpeyGyEj0SLQ4INqGaGOIa 43 | skDcfAo9mWQMw6TNrwr+BwMCQUUVllgNCNzUZi7YINDlwhj1tLE8IdDJ14WJ29TS 44 | 5BgjrBaMLDetvYvnYPwrpwh/ZIRUm0bg5/K2DQXYQLbuBE02u7QnWnVsdSBUZXN0 45 | IChkZW1vIGtleSkgPHp1bHVAZXhhbXBsZS5uZXQ+iFUEExECABUFAjbjtcsDCwoD 46 | AxUDAgMWAgECF4AACgkQa8R3gFSs0kZA6wCeJUyRzuFbsZ0uQulvpgOIRTLTKscA 47 | oLd3InVEj20peTUQ5b2NOimSXnKxiFUEExECABUFAjbjtcsDCwoDAxUDAgMWAgEC 48 | F4AACgkQa8R3gFSs0kZA6wCeOBSNOP3/J4LLMGDC7YWzVnYcH1oAoJh1THc6xw3d 49 | CapVWt7enBljkaZInQHABDbjtfIQBADMfPDBQoMzv52Mmjb8SdaYKKNzqDd9K1oY 50 | 2hcMSi+LcHag+KJFOyKBf3SoHmcU/vCEN+LyTgljYSKDmEf4wZ2+eLfqFgSdBJp2 51 | xm55ih+9CHXg3dXx9SbHiGJCIxfJaIsnNz3VmJGPDDjBlaf/hjl/7SZvR+MJpVLF 52 | PGjj7uOhTwADBQP/Sgv0abeCXVdVXwGEmhdV0VDo833IQRdRu1yt+QLnWRMGTY1o 53 | QapsH6QLwYSZfDJlxbsBA3tfqKStpRSbdGNNTsK+RIehsGddi3sWGplRGm5Xt5Kp 54 | kY/mc/tLFaYJNMqAgfWQcKlZHBp7EoWMgiRiDJUWq0TH1wRDoPaRc+H5Gdr+BwMC 55 | RQr6jr/dSR7UxBJhvbow5H8f24gW0461q02MigdIzk00fAjc8xNZI9dN0HaICqif 56 | tbbPCezutLGtXEb4rOhAttuMVswdGF8aerhA6lwVF8lbvLTOyf2HbLAgVs/zvEgy 57 | LVHmXwNhoaLMcytlRL7ZpLA59C6mywH83OMYF+NHLsMRu5VwSF0ZHE3VMLb6APdI 58 | J1qfpeQesrudHES5wb5OgX8TosiEeJ0RmEB8oU+/MIhGBBgRAgAGBQI247XyAAoJ 59 | EGvEd4BUrNJGfWMAoLkanmwcz2xZ1l4zqp+7ngXY7AxAAJ9ONhd+kwCkBE4+SOGE 60 | U2ofR3zHkQ== 61 | =c9V4 62 | -----END PGP PRIVATE KEY BLOCK----- 63 | --------------------------------------------------------------------------------