Compare commits
8 Commits
master
...
ben/export
Author | SHA1 | Date | |
---|---|---|---|
|
fa1a4e0b25 | ||
|
6573eb339a | ||
|
248c42788f | ||
|
4bbe247c84 | ||
|
483de0330d | ||
|
cd03423b8f | ||
|
14cbbb3d70 | ||
|
870c317120 |
@ -454,6 +454,364 @@
|
|||||||
literals with the fingerprint when getting a key in this way.
|
literals with the fingerprint when getting a key in this way.
|
||||||
|
|
||||||
|
|
||||||
|
** Importing keys
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: howto-import-key
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Importing keys is possible with the =key_import()= method and takes
|
||||||
|
one argument which is a bytes literal object containing either the
|
||||||
|
binary or ASCII armoured key data for one or more keys.
|
||||||
|
|
||||||
|
The following example retrieves one or more keys from the SKS
|
||||||
|
keyservers via the web using the requests module. Since requests
|
||||||
|
returns the content as a bytes literal object, we can then use that
|
||||||
|
directly to import the resulting data into our keybox.
|
||||||
|
|
||||||
|
#+begin_src python
|
||||||
|
import gpg
|
||||||
|
import os.path
|
||||||
|
import requests
|
||||||
|
|
||||||
|
c = gpg.Context()
|
||||||
|
url = "https://sks-keyservers.net/pks/lookup"
|
||||||
|
pattern = input("Enter the pattern to search for key or user IDs: ")
|
||||||
|
payload = { "op": "get", "search": pattern }
|
||||||
|
|
||||||
|
r = requests.get(url, verify=True, params=payload)
|
||||||
|
result = c.key_import(r.content)
|
||||||
|
|
||||||
|
if result is not None and hasattr(result, "considered") is False:
|
||||||
|
print(result)
|
||||||
|
elif result is not None and hasattr(result, "considered") is True:
|
||||||
|
num_keys = len(result.imports)
|
||||||
|
new_revs = result.new_revocations
|
||||||
|
new_sigs = result.new_signatures
|
||||||
|
new_subs = result.new_sub_keys
|
||||||
|
new_uids = result.new_user_ids
|
||||||
|
new_scrt = result.secret_imported
|
||||||
|
nochange = result.unchanged
|
||||||
|
print("""
|
||||||
|
The total number of keys considered for import was: {0}
|
||||||
|
|
||||||
|
Number of keys revoked: {1}
|
||||||
|
Number of new signatures: {2}
|
||||||
|
Number of new subkeys: {3}
|
||||||
|
Number of new user IDs: {4}
|
||||||
|
Number of new secret keys: {5}
|
||||||
|
Number of unchanged keys: {6}
|
||||||
|
|
||||||
|
The key IDs for all considered keys were:
|
||||||
|
""".format(num_keys, new_revs, new_sigs, new_subs, new_uids, new_scrt,
|
||||||
|
nochange))
|
||||||
|
for i in range(num_keys):
|
||||||
|
print(result.imports[i].fpr)
|
||||||
|
print("")
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
*NOTE:* When searching for a key ID of any length or a fingerprint
|
||||||
|
(without spaces), the SKS servers require the the leading =0x=
|
||||||
|
indicative of hexadecimal be included. Also note that the old short
|
||||||
|
key IDs (e.g. =0xDEADBEEF=) should no longer be used due to the
|
||||||
|
relative ease by which such key IDs can be reproduced, as
|
||||||
|
demonstrated by the Evil32 Project in 2014 (which was subsequently
|
||||||
|
exploited in 2016).
|
||||||
|
|
||||||
|
|
||||||
|
** Exporting keys
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: howto-export-key
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Exporting keys remains a reasonably simple task, but has been
|
||||||
|
separated into three different functions for the OpenPGP
|
||||||
|
cryptographic engine. Two of those functions are for exporting
|
||||||
|
public keys and the third is for exporting secret keys.
|
||||||
|
|
||||||
|
|
||||||
|
*** Exporting public keys
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: howto-export-public-key
|
||||||
|
:END:
|
||||||
|
|
||||||
|
There are two methods of exporting public keys, both of which are
|
||||||
|
very similar to the other. The default method, =key_export()=,
|
||||||
|
will export a public key or keys matching a specified pattern as
|
||||||
|
normal. The alternative, the =key_export_minimal()= method, will
|
||||||
|
do the same thing except producing a minimised output with extra
|
||||||
|
signatures and third party signatures or certifications removed.
|
||||||
|
|
||||||
|
#+begin_src python
|
||||||
|
import gpg
|
||||||
|
import os.path
|
||||||
|
import sys
|
||||||
|
|
||||||
|
print("""
|
||||||
|
This script exports one or more public keys.
|
||||||
|
""")
|
||||||
|
|
||||||
|
c = gpg.Context(armor=True)
|
||||||
|
|
||||||
|
if len(sys.argv) >= 4:
|
||||||
|
keyfile = sys.argv[1]
|
||||||
|
logrus = sys.argv[2]
|
||||||
|
homedir = sys.argv[3]
|
||||||
|
elif len(sys.argv) == 3:
|
||||||
|
keyfile = sys.argv[1]
|
||||||
|
logrus = sys.argv[2]
|
||||||
|
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||||
|
elif len(sys.argv) == 2:
|
||||||
|
keyfile = sys.argv[1]
|
||||||
|
logrus = input("Enter the UID matching the key(s) to export: ")
|
||||||
|
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||||
|
else:
|
||||||
|
keyfile = input("Enter the path and filename to save the secret key to: ")
|
||||||
|
logrus = input("Enter the UID matching the key(s) to export: ")
|
||||||
|
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||||
|
|
||||||
|
if homedir.startswith("~"):
|
||||||
|
if os.path.exists(os.path.expanduser(homedir)) is True:
|
||||||
|
c.home_dir = os.path.expanduser(homedir)
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
elif os.path.exists(homedir) is True:
|
||||||
|
c.home_dir = homedir
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = c.key_export(pattern=logrus)
|
||||||
|
except:
|
||||||
|
result = c.key_export(pattern=None)
|
||||||
|
|
||||||
|
if result is not None:
|
||||||
|
with open(keyfile, "wb") as f:
|
||||||
|
f.write(result)
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
It is important to note that the result will only return =None=
|
||||||
|
when a pattern has been entered for =logrus=, but it has not
|
||||||
|
matched any keys. When the search pattern itself is set to =None=
|
||||||
|
this triggers the exporting of the entire public keybox.
|
||||||
|
|
||||||
|
#+begin_src python
|
||||||
|
import gpg
|
||||||
|
import os.path
|
||||||
|
import sys
|
||||||
|
|
||||||
|
print("""
|
||||||
|
This script exports one or more public keys in minimised form.
|
||||||
|
""")
|
||||||
|
|
||||||
|
c = gpg.Context(armor=True)
|
||||||
|
|
||||||
|
if len(sys.argv) >= 4:
|
||||||
|
keyfile = sys.argv[1]
|
||||||
|
logrus = sys.argv[2]
|
||||||
|
homedir = sys.argv[3]
|
||||||
|
elif len(sys.argv) == 3:
|
||||||
|
keyfile = sys.argv[1]
|
||||||
|
logrus = sys.argv[2]
|
||||||
|
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||||
|
elif len(sys.argv) == 2:
|
||||||
|
keyfile = sys.argv[1]
|
||||||
|
logrus = input("Enter the UID matching the key(s) to export: ")
|
||||||
|
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||||
|
else:
|
||||||
|
keyfile = input("Enter the path and filename to save the secret key to: ")
|
||||||
|
logrus = input("Enter the UID matching the key(s) to export: ")
|
||||||
|
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||||
|
|
||||||
|
if homedir.startswith("~"):
|
||||||
|
if os.path.exists(os.path.expanduser(homedir)) is True:
|
||||||
|
c.home_dir = os.path.expanduser(homedir)
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
elif os.path.exists(homedir) is True:
|
||||||
|
c.home_dir = homedir
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = c.key_export_minimal(pattern=logrus)
|
||||||
|
except:
|
||||||
|
result = c.key_export_minimal(pattern=None)
|
||||||
|
|
||||||
|
if result is not None:
|
||||||
|
with open(keyfile, "wb") as f:
|
||||||
|
f.write(result)
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*** Exporting secret keys
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: howto-export-secret-key
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Exporting secret keys is, functionally, very similar to exporting
|
||||||
|
public keys; save for the invocation of =pinentry= via =gpg-agent=
|
||||||
|
in order to securely enter the key's passphrase and authorise the
|
||||||
|
export.
|
||||||
|
|
||||||
|
The following example exports the secret key to a file which is
|
||||||
|
then set with the same permissions as the output files created by
|
||||||
|
the command line secret key export options.
|
||||||
|
|
||||||
|
#+begin_src python
|
||||||
|
import gpg
|
||||||
|
import os
|
||||||
|
import os.path
|
||||||
|
import sys
|
||||||
|
|
||||||
|
print("""
|
||||||
|
This script exports one or more secret keys.
|
||||||
|
|
||||||
|
The gpg-agent and pinentry are invoked to authorise the export.
|
||||||
|
""")
|
||||||
|
|
||||||
|
c = gpg.Context(armor=True)
|
||||||
|
|
||||||
|
if len(sys.argv) >= 4:
|
||||||
|
keyfile = sys.argv[1]
|
||||||
|
logrus = sys.argv[2]
|
||||||
|
homedir = sys.argv[3]
|
||||||
|
elif len(sys.argv) == 3:
|
||||||
|
keyfile = sys.argv[1]
|
||||||
|
logrus = sys.argv[2]
|
||||||
|
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||||
|
elif len(sys.argv) == 2:
|
||||||
|
keyfile = sys.argv[1]
|
||||||
|
logrus = input("Enter the UID matching the secret key(s) to export: ")
|
||||||
|
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||||
|
else:
|
||||||
|
keyfile = input("Enter the path and filename to save the secret key to: ")
|
||||||
|
logrus = input("Enter the UID matching the secret key(s) to export: ")
|
||||||
|
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||||
|
|
||||||
|
if homedir.startswith("~"):
|
||||||
|
if os.path.exists(os.path.expanduser(homedir)) is True:
|
||||||
|
c.home_dir = os.path.expanduser(homedir)
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
elif os.path.exists(homedir) is True:
|
||||||
|
c.home_dir = homedir
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = c.key_export_secret(pattern=logrus)
|
||||||
|
except:
|
||||||
|
result = c.key_export_secret(pattern=None)
|
||||||
|
|
||||||
|
if result is not None:
|
||||||
|
with open(keyfile, "wb") as f:
|
||||||
|
f.write(result)
|
||||||
|
os.chmod(keyfile, 0o600)
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
Alternatively the approach of the following script can be
|
||||||
|
used. This longer example saves the exported secret key(s) in
|
||||||
|
files in the GnuPG home directory, in addition to setting the file
|
||||||
|
permissions as only readable and writable by the user. It also
|
||||||
|
exports the secret key(s) twice in order to output both GPG binary
|
||||||
|
(=.gpg=) and ASCII armoured (=.asc=) files.
|
||||||
|
|
||||||
|
#+begin_src python
|
||||||
|
import gpg
|
||||||
|
import os
|
||||||
|
import os.path
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
print("""
|
||||||
|
This script exports one or more secret keys as both ASCII armored and binary
|
||||||
|
file formats, saved in files within the user's GPG home directory.
|
||||||
|
|
||||||
|
The gpg-agent and pinentry are invoked to authorise the export.
|
||||||
|
""")
|
||||||
|
|
||||||
|
if sys.platform == "win32":
|
||||||
|
gpgconfcmd = "gpgconf.exe --list-dirs homedir"
|
||||||
|
else:
|
||||||
|
gpgconfcmd = "gpgconf --list-dirs homedir"
|
||||||
|
|
||||||
|
a = gpg.Context(armor=True)
|
||||||
|
b = gpg.Context()
|
||||||
|
c = gpg.Context()
|
||||||
|
|
||||||
|
if len(sys.argv) >= 4:
|
||||||
|
keyfile = sys.argv[1]
|
||||||
|
logrus = sys.argv[2]
|
||||||
|
homedir = sys.argv[3]
|
||||||
|
elif len(sys.argv) == 3:
|
||||||
|
keyfile = sys.argv[1]
|
||||||
|
logrus = sys.argv[2]
|
||||||
|
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||||
|
elif len(sys.argv) == 2:
|
||||||
|
keyfile = sys.argv[1]
|
||||||
|
logrus = input("Enter the UID matching the secret key(s) to export: ")
|
||||||
|
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||||
|
else:
|
||||||
|
keyfile = input("Enter the filename to save the secret key to: ")
|
||||||
|
logrus = input("Enter the UID matching the secret key(s) to export: ")
|
||||||
|
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||||
|
|
||||||
|
if homedir.startswith("~"):
|
||||||
|
if os.path.exists(os.path.expanduser(homedir)) is True:
|
||||||
|
c.home_dir = os.path.expanduser(homedir)
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
elif os.path.exists(homedir) is True:
|
||||||
|
c.home_dir = homedir
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if c.home_dir is not None:
|
||||||
|
if c.home_dir.endswith("/"):
|
||||||
|
gpgfile = "{0}{1}.gpg".format(c.home_dir, keyfile)
|
||||||
|
ascfile = "{0}{1}.asc".format(c.home_dir, keyfile)
|
||||||
|
else:
|
||||||
|
gpgfile = "{0}/{1}.gpg".format(c.home_dir, keyfile)
|
||||||
|
ascfile = "{0}/{1}.asc".format(c.home_dir, keyfile)
|
||||||
|
else:
|
||||||
|
if os.path.exists(os.environ["GNUPGHOME"]) is True:
|
||||||
|
hd = os.environ["GNUPGHOME"]
|
||||||
|
else:
|
||||||
|
hd = subprocess.getoutput(gpgconfcmd)
|
||||||
|
gpgfile = "{0}/{1}.gpg".format(hd, keyfile)
|
||||||
|
ascfile = "{0}/{1}.asc".format(hd, keyfile)
|
||||||
|
|
||||||
|
try:
|
||||||
|
a_result = a.key_export_secret(pattern=logrus)
|
||||||
|
b_result = b.key_export_secret(pattern=logrus)
|
||||||
|
except:
|
||||||
|
a_result = a.key_export_secret(pattern=None)
|
||||||
|
b_result = b.key_export_secret(pattern=None)
|
||||||
|
|
||||||
|
if a_result is not None:
|
||||||
|
with open(ascfile, "wb") as f:
|
||||||
|
f.write(a_result)
|
||||||
|
os.chmod(ascfile, 0o600)
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if b_result is not None:
|
||||||
|
with open(gpgfile, "wb") as f:
|
||||||
|
f.write(b_result)
|
||||||
|
os.chmod(gpgfile, 0o600)
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
* Basic Functions
|
* Basic Functions
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
:CUSTOM_ID: howto-the-basics
|
:CUSTOM_ID: howto-the-basics
|
||||||
|
73
lang/python/examples/howto/export-key.py
Executable file
73
lang/python/examples/howto/export-key.py
Executable file
@ -0,0 +1,73 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, unicode_literals
|
||||||
|
|
||||||
|
# Copyright (C) 2018 Ben McGinnes <ben@gnupg.org>
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU General Public License as published by the Free Software
|
||||||
|
# Foundation; either version 2 of the License, or (at your option) any later
|
||||||
|
# version.
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU Lesser General Public License as published by the Free
|
||||||
|
# Software Foundation; either version 2.1 of the License, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License and the GNU
|
||||||
|
# Lesser General Public Licensefor more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License and the GNU
|
||||||
|
# Lesser General Public along with this program; if not, see
|
||||||
|
# <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import gpg
|
||||||
|
import os.path
|
||||||
|
import sys
|
||||||
|
|
||||||
|
print("""
|
||||||
|
This script exports one or more public keys.
|
||||||
|
""")
|
||||||
|
|
||||||
|
c = gpg.Context(armor=True)
|
||||||
|
|
||||||
|
if len(sys.argv) >= 4:
|
||||||
|
keyfile = sys.argv[1]
|
||||||
|
logrus = sys.argv[2]
|
||||||
|
homedir = sys.argv[3]
|
||||||
|
elif len(sys.argv) == 3:
|
||||||
|
keyfile = sys.argv[1]
|
||||||
|
logrus = sys.argv[2]
|
||||||
|
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||||
|
elif len(sys.argv) == 2:
|
||||||
|
keyfile = sys.argv[1]
|
||||||
|
logrus = input("Enter the UID matching the key(s) to export: ")
|
||||||
|
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||||
|
else:
|
||||||
|
keyfile = input("Enter the path and filename to save the secret key to: ")
|
||||||
|
logrus = input("Enter the UID matching the key(s) to export: ")
|
||||||
|
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||||
|
|
||||||
|
if homedir.startswith("~"):
|
||||||
|
if os.path.exists(os.path.expanduser(homedir)) is True:
|
||||||
|
c.home_dir = os.path.expanduser(homedir)
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
elif os.path.exists(homedir) is True:
|
||||||
|
c.home_dir = homedir
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = c.key_export(pattern=logrus)
|
||||||
|
except:
|
||||||
|
result = c.key_export(pattern=None)
|
||||||
|
|
||||||
|
if result is not None:
|
||||||
|
with open(keyfile, "wb") as f:
|
||||||
|
f.write(result)
|
||||||
|
else:
|
||||||
|
pass
|
73
lang/python/examples/howto/export-minimised-key.py
Executable file
73
lang/python/examples/howto/export-minimised-key.py
Executable file
@ -0,0 +1,73 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, unicode_literals
|
||||||
|
|
||||||
|
# Copyright (C) 2018 Ben McGinnes <ben@gnupg.org>
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU General Public License as published by the Free Software
|
||||||
|
# Foundation; either version 2 of the License, or (at your option) any later
|
||||||
|
# version.
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU Lesser General Public License as published by the Free
|
||||||
|
# Software Foundation; either version 2.1 of the License, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License and the GNU
|
||||||
|
# Lesser General Public Licensefor more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License and the GNU
|
||||||
|
# Lesser General Public along with this program; if not, see
|
||||||
|
# <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import gpg
|
||||||
|
import os.path
|
||||||
|
import sys
|
||||||
|
|
||||||
|
print("""
|
||||||
|
This script exports one or more public keys in minimised form.
|
||||||
|
""")
|
||||||
|
|
||||||
|
c = gpg.Context(armor=True)
|
||||||
|
|
||||||
|
if len(sys.argv) >= 4:
|
||||||
|
keyfile = sys.argv[1]
|
||||||
|
logrus = sys.argv[2]
|
||||||
|
homedir = sys.argv[3]
|
||||||
|
elif len(sys.argv) == 3:
|
||||||
|
keyfile = sys.argv[1]
|
||||||
|
logrus = sys.argv[2]
|
||||||
|
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||||
|
elif len(sys.argv) == 2:
|
||||||
|
keyfile = sys.argv[1]
|
||||||
|
logrus = input("Enter the UID matching the key(s) to export: ")
|
||||||
|
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||||
|
else:
|
||||||
|
keyfile = input("Enter the path and filename to save the secret key to: ")
|
||||||
|
logrus = input("Enter the UID matching the key(s) to export: ")
|
||||||
|
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||||
|
|
||||||
|
if homedir.startswith("~"):
|
||||||
|
if os.path.exists(os.path.expanduser(homedir)) is True:
|
||||||
|
c.home_dir = os.path.expanduser(homedir)
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
elif os.path.exists(homedir) is True:
|
||||||
|
c.home_dir = homedir
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = c.key_export_minimal(pattern=logrus)
|
||||||
|
except:
|
||||||
|
result = c.key_export_minimal(pattern=None)
|
||||||
|
|
||||||
|
if result is not None:
|
||||||
|
with open(keyfile, "wb") as f:
|
||||||
|
f.write(result)
|
||||||
|
else:
|
||||||
|
pass
|
77
lang/python/examples/howto/export-secret-key.py
Executable file
77
lang/python/examples/howto/export-secret-key.py
Executable file
@ -0,0 +1,77 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, unicode_literals
|
||||||
|
|
||||||
|
# Copyright (C) 2018 Ben McGinnes <ben@gnupg.org>
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU General Public License as published by the Free Software
|
||||||
|
# Foundation; either version 2 of the License, or (at your option) any later
|
||||||
|
# version.
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU Lesser General Public License as published by the Free
|
||||||
|
# Software Foundation; either version 2.1 of the License, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License and the GNU
|
||||||
|
# Lesser General Public Licensefor more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License and the GNU
|
||||||
|
# Lesser General Public along with this program; if not, see
|
||||||
|
# <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import gpg
|
||||||
|
import os
|
||||||
|
import os.path
|
||||||
|
import sys
|
||||||
|
|
||||||
|
print("""
|
||||||
|
This script exports one or more secret keys.
|
||||||
|
|
||||||
|
The gpg-agent and pinentry are invoked to authorise the export.
|
||||||
|
""")
|
||||||
|
|
||||||
|
c = gpg.Context(armor=True)
|
||||||
|
|
||||||
|
if len(sys.argv) >= 4:
|
||||||
|
keyfile = sys.argv[1]
|
||||||
|
logrus = sys.argv[2]
|
||||||
|
homedir = sys.argv[3]
|
||||||
|
elif len(sys.argv) == 3:
|
||||||
|
keyfile = sys.argv[1]
|
||||||
|
logrus = sys.argv[2]
|
||||||
|
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||||
|
elif len(sys.argv) == 2:
|
||||||
|
keyfile = sys.argv[1]
|
||||||
|
logrus = input("Enter the UID matching the secret key(s) to export: ")
|
||||||
|
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||||
|
else:
|
||||||
|
keyfile = input("Enter the path and filename to save the secret key to: ")
|
||||||
|
logrus = input("Enter the UID matching the secret key(s) to export: ")
|
||||||
|
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||||
|
|
||||||
|
if homedir.startswith("~"):
|
||||||
|
if os.path.exists(os.path.expanduser(homedir)) is True:
|
||||||
|
c.home_dir = os.path.expanduser(homedir)
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
elif os.path.exists(homedir) is True:
|
||||||
|
c.home_dir = homedir
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = c.key_export_secret(pattern=logrus)
|
||||||
|
except:
|
||||||
|
result = c.key_export_secret(pattern=None)
|
||||||
|
|
||||||
|
if result is not None:
|
||||||
|
with open(keyfile, "wb") as f:
|
||||||
|
f.write(result)
|
||||||
|
os.chmod(keyfile, 0o600)
|
||||||
|
else:
|
||||||
|
pass
|
110
lang/python/examples/howto/export-secret-keys.py
Executable file
110
lang/python/examples/howto/export-secret-keys.py
Executable file
@ -0,0 +1,110 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, unicode_literals
|
||||||
|
|
||||||
|
# Copyright (C) 2018 Ben McGinnes <ben@gnupg.org>
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU General Public License as published by the Free Software
|
||||||
|
# Foundation; either version 2 of the License, or (at your option) any later
|
||||||
|
# version.
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU Lesser General Public License as published by the Free
|
||||||
|
# Software Foundation; either version 2.1 of the License, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License and the GNU
|
||||||
|
# Lesser General Public Licensefor more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License and the GNU
|
||||||
|
# Lesser General Public along with this program; if not, see
|
||||||
|
# <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import gpg
|
||||||
|
import os
|
||||||
|
import os.path
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
print("""
|
||||||
|
This script exports one or more secret keys as both ASCII armored and binary
|
||||||
|
file formats, saved in files within the user's GPG home directory.
|
||||||
|
|
||||||
|
The gpg-agent and pinentry are invoked to authorise the export.
|
||||||
|
""")
|
||||||
|
|
||||||
|
if sys.platform == "win32":
|
||||||
|
gpgconfcmd = "gpgconf.exe --list-dirs homedir"
|
||||||
|
else:
|
||||||
|
gpgconfcmd = "gpgconf --list-dirs homedir"
|
||||||
|
|
||||||
|
a = gpg.Context(armor=True)
|
||||||
|
b = gpg.Context()
|
||||||
|
c = gpg.Context()
|
||||||
|
|
||||||
|
if len(sys.argv) >= 4:
|
||||||
|
keyfile = sys.argv[1]
|
||||||
|
logrus = sys.argv[2]
|
||||||
|
homedir = sys.argv[3]
|
||||||
|
elif len(sys.argv) == 3:
|
||||||
|
keyfile = sys.argv[1]
|
||||||
|
logrus = sys.argv[2]
|
||||||
|
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||||
|
elif len(sys.argv) == 2:
|
||||||
|
keyfile = sys.argv[1]
|
||||||
|
logrus = input("Enter the UID matching the secret key(s) to export: ")
|
||||||
|
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||||
|
else:
|
||||||
|
keyfile = input("Enter the filename to save the secret key to: ")
|
||||||
|
logrus = input("Enter the UID matching the secret key(s) to export: ")
|
||||||
|
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||||
|
|
||||||
|
if homedir.startswith("~"):
|
||||||
|
if os.path.exists(os.path.expanduser(homedir)) is True:
|
||||||
|
c.home_dir = os.path.expanduser(homedir)
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
elif os.path.exists(homedir) is True:
|
||||||
|
c.home_dir = homedir
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if c.home_dir is not None:
|
||||||
|
if c.home_dir.endswith("/"):
|
||||||
|
gpgfile = "{0}{1}.gpg".format(c.home_dir, keyfile)
|
||||||
|
ascfile = "{0}{1}.asc".format(c.home_dir, keyfile)
|
||||||
|
else:
|
||||||
|
gpgfile = "{0}/{1}.gpg".format(c.home_dir, keyfile)
|
||||||
|
ascfile = "{0}/{1}.asc".format(c.home_dir, keyfile)
|
||||||
|
else:
|
||||||
|
if os.path.exists(os.environ["GNUPGHOME"]) is True:
|
||||||
|
hd = os.environ["GNUPGHOME"]
|
||||||
|
else:
|
||||||
|
hd = subprocess.getoutput(gpgconfcmd)
|
||||||
|
gpgfile = "{0}/{1}.gpg".format(hd, keyfile)
|
||||||
|
ascfile = "{0}/{1}.asc".format(hd, keyfile)
|
||||||
|
|
||||||
|
try:
|
||||||
|
a_result = a.key_export_secret(pattern=logrus)
|
||||||
|
b_result = b.key_export_secret(pattern=logrus)
|
||||||
|
except:
|
||||||
|
a_result = a.key_export_secret(pattern=None)
|
||||||
|
b_result = b.key_export_secret(pattern=None)
|
||||||
|
|
||||||
|
if a_result is not None:
|
||||||
|
with open(ascfile, "wb") as f:
|
||||||
|
f.write(a_result)
|
||||||
|
os.chmod(ascfile, 0o600)
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if b_result is not None:
|
||||||
|
with open(gpgfile, "wb") as f:
|
||||||
|
f.write(b_result)
|
||||||
|
os.chmod(gpgfile, 0o600)
|
||||||
|
else:
|
||||||
|
pass
|
91
lang/python/examples/howto/import-key.py
Executable file
91
lang/python/examples/howto/import-key.py
Executable file
@ -0,0 +1,91 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, unicode_literals
|
||||||
|
|
||||||
|
# Copyright (C) 2018 Ben McGinnes <ben@gnupg.org>
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU General Public License as published by the Free Software
|
||||||
|
# Foundation; either version 2 of the License, or (at your option) any later
|
||||||
|
# version.
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU Lesser General Public License as published by the Free
|
||||||
|
# Software Foundation; either version 2.1 of the License, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License and the GNU
|
||||||
|
# Lesser General Public Licensefor more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License and the GNU
|
||||||
|
# Lesser General Public along with this program; if not, see
|
||||||
|
# <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import gpg
|
||||||
|
import os.path
|
||||||
|
import sys
|
||||||
|
|
||||||
|
print("""
|
||||||
|
This script exports one or more public keys.
|
||||||
|
""")
|
||||||
|
|
||||||
|
c = gpg.Context(armor=True)
|
||||||
|
|
||||||
|
if len(sys.argv) >= 3:
|
||||||
|
keyfile = sys.argv[1]
|
||||||
|
homedir = sys.argv[2]
|
||||||
|
elif len(sys.argv) == 2:
|
||||||
|
keyfile = sys.argv[1]
|
||||||
|
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||||
|
else:
|
||||||
|
keyfile = input("Enter the path and filename to import the key(s) from: ")
|
||||||
|
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||||
|
|
||||||
|
if homedir.startswith("~"):
|
||||||
|
if os.path.exists(os.path.expanduser(homedir)) is True:
|
||||||
|
c.home_dir = os.path.expanduser(homedir)
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
elif os.path.exists(homedir) is True:
|
||||||
|
c.home_dir = homedir
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if os.path.isfile(keyfile) is True:
|
||||||
|
with open(keyfile, "rb") as f:
|
||||||
|
incoming = f.read()
|
||||||
|
result = c.key_import(incoming)
|
||||||
|
else:
|
||||||
|
result = None
|
||||||
|
|
||||||
|
if result is not None and hasattr(result, "considered") is False:
|
||||||
|
print(result)
|
||||||
|
elif result is not None and hasattr(result, "considered") is True:
|
||||||
|
num_keys = len(result.imports)
|
||||||
|
new_revs = result.new_revocations
|
||||||
|
new_sigs = result.new_signatures
|
||||||
|
new_subs = result.new_sub_keys
|
||||||
|
new_uids = result.new_user_ids
|
||||||
|
new_scrt = result.secret_imported
|
||||||
|
nochange = result.unchanged
|
||||||
|
print("""
|
||||||
|
The total number of keys considered for import was: {0}
|
||||||
|
|
||||||
|
Number of keys revoked: {1}
|
||||||
|
Number of new signatures: {2}
|
||||||
|
Number of new subkeys: {3}
|
||||||
|
Number of new user IDs: {4}
|
||||||
|
Number of new secret keys: {5}
|
||||||
|
Number of unchanged keys: {6}
|
||||||
|
|
||||||
|
The key IDs for all considered keys were:
|
||||||
|
""".format(num_keys, new_revs, new_sigs, new_subs, new_uids, new_scrt,
|
||||||
|
nochange))
|
||||||
|
for i in range(num_keys):
|
||||||
|
print(result.imports[i].fpr)
|
||||||
|
print("")
|
||||||
|
elif result is None:
|
||||||
|
print("You must specify a key file to import.")
|
73
lang/python/examples/howto/import-keys.py
Executable file
73
lang/python/examples/howto/import-keys.py
Executable file
@ -0,0 +1,73 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, unicode_literals
|
||||||
|
|
||||||
|
# Copyright (C) 2018 Ben McGinnes <ben@gnupg.org>
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU General Public License as published by the Free Software
|
||||||
|
# Foundation; either version 2 of the License, or (at your option) any later
|
||||||
|
# version.
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU Lesser General Public License as published by the Free
|
||||||
|
# Software Foundation; either version 2.1 of the License, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License and the GNU
|
||||||
|
# Lesser General Public Licensefor more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License and the GNU
|
||||||
|
# Lesser General Public along with this program; if not, see
|
||||||
|
# <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import gpg
|
||||||
|
import os.path
|
||||||
|
import requests
|
||||||
|
|
||||||
|
print("""
|
||||||
|
This script imports one or more public keys from the SKS keyservers.
|
||||||
|
""")
|
||||||
|
|
||||||
|
import gpg
|
||||||
|
import requests
|
||||||
|
|
||||||
|
c = gpg.Context()
|
||||||
|
url = "https://sks-keyservers.net/pks/lookup"
|
||||||
|
pattern = input("Enter the pattern to search for key or user IDs: ")
|
||||||
|
payload = { "op": "get", "search": pattern }
|
||||||
|
|
||||||
|
r = requests.get(url, verify=True, params=payload)
|
||||||
|
result = c.key_import(r.content)
|
||||||
|
|
||||||
|
if result is not None and hasattr(result, "considered") is False:
|
||||||
|
print(result)
|
||||||
|
elif result is not None and hasattr(result, "considered") is True:
|
||||||
|
num_keys = len(result.imports)
|
||||||
|
new_revs = result.new_revocations
|
||||||
|
new_sigs = result.new_signatures
|
||||||
|
new_subs = result.new_sub_keys
|
||||||
|
new_uids = result.new_user_ids
|
||||||
|
new_scrt = result.secret_imported
|
||||||
|
nochange = result.unchanged
|
||||||
|
print("""
|
||||||
|
The total number of keys considered for import was: {0}
|
||||||
|
|
||||||
|
Number of keys revoked: {1}
|
||||||
|
Number of new signatures: {2}
|
||||||
|
Number of new subkeys: {3}
|
||||||
|
Number of new user IDs: {4}
|
||||||
|
Number of new secret keys: {5}
|
||||||
|
Number of unchanged keys: {6}
|
||||||
|
|
||||||
|
The key IDs for all considered keys were:
|
||||||
|
""".format(num_keys, new_revs, new_sigs, new_subs, new_uids, new_scrt,
|
||||||
|
nochange))
|
||||||
|
for i in range(num_keys):
|
||||||
|
print(result.imports[i].fpr)
|
||||||
|
print("")
|
||||||
|
else:
|
||||||
|
pass
|
@ -537,7 +537,7 @@ class Context(GpgmeWrapper):
|
|||||||
managed to run the function without any
|
managed to run the function without any
|
||||||
arguments, while an argument of None triggers
|
arguments, while an argument of None triggers
|
||||||
the first NODATA of errors.GPGME in the
|
the first NODATA of errors.GPGME in the
|
||||||
exception.
|
exception.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
self.op_import(data)
|
self.op_import(data)
|
||||||
@ -566,6 +566,116 @@ class Context(GpgmeWrapper):
|
|||||||
|
|
||||||
return import_result
|
return import_result
|
||||||
|
|
||||||
|
def key_export(self, pattern=None):
|
||||||
|
"""Export keys.
|
||||||
|
|
||||||
|
Exports public keys matching the pattern specified. If no
|
||||||
|
pattern is specified then exports all available keys.
|
||||||
|
|
||||||
|
Keyword arguments:
|
||||||
|
pattern -- return keys matching pattern (default: all keys)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
-- A key block containing one or more OpenPGP keys in
|
||||||
|
either ASCII armoured or binary format as determined
|
||||||
|
by the Context(). If there are no matching keys it
|
||||||
|
returns None.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
GPGMEError -- as signaled by the underlying library.
|
||||||
|
"""
|
||||||
|
data = Data()
|
||||||
|
mode = 0
|
||||||
|
try:
|
||||||
|
self.op_export(pattern, mode, data)
|
||||||
|
data.seek(0, os.SEEK_SET)
|
||||||
|
pk_result = data.read()
|
||||||
|
except GPGMEError as e:
|
||||||
|
pk_result = e
|
||||||
|
|
||||||
|
if len(pk_result) > 0:
|
||||||
|
result = pk_result
|
||||||
|
else:
|
||||||
|
result = None
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def key_export_minimal(self, pattern=None):
|
||||||
|
"""Export keys.
|
||||||
|
|
||||||
|
Exports public keys matching the pattern specified in a
|
||||||
|
minimised format. If no pattern is specified then exports all
|
||||||
|
available keys.
|
||||||
|
|
||||||
|
Keyword arguments:
|
||||||
|
pattern -- return keys matching pattern (default: all keys)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
-- A key block containing one or more minimised OpenPGP
|
||||||
|
keys in either ASCII armoured or binary format as
|
||||||
|
determined by the Context(). If there are no matching
|
||||||
|
keys it returns None.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
GPGMEError -- as signaled by the underlying library.
|
||||||
|
"""
|
||||||
|
data = Data()
|
||||||
|
mode = gpgme.GPGME_EXPORT_MODE_MINIMAL
|
||||||
|
try:
|
||||||
|
self.op_export(pattern, mode, data)
|
||||||
|
data.seek(0, os.SEEK_SET)
|
||||||
|
pk_result = data.read()
|
||||||
|
except GPGMEError as e:
|
||||||
|
pk_result = e
|
||||||
|
|
||||||
|
if len(pk_result) > 0:
|
||||||
|
result = pk_result
|
||||||
|
else:
|
||||||
|
result = None
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def key_export_secret(self, pattern=None):
|
||||||
|
"""Export secret keys.
|
||||||
|
|
||||||
|
Exports secret keys matching the pattern specified. If no
|
||||||
|
pattern is specified then exports or attempts to export all
|
||||||
|
available secret keys.
|
||||||
|
|
||||||
|
IMPORTANT: Each secret key to be exported will prompt for its
|
||||||
|
passphrase via an invocation of pinentry and gpg-agent. If the
|
||||||
|
passphrase is not entered or does not match then no data will be
|
||||||
|
exported. This is the same result as when specifying a pattern
|
||||||
|
that is not matched by the available keys.
|
||||||
|
|
||||||
|
Keyword arguments:
|
||||||
|
pattern -- return keys matching pattern (default: all keys)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
-- On success a key block containing one or more OpenPGP
|
||||||
|
secret keys in either ASCII armoured or binary format
|
||||||
|
as determined by the Context().
|
||||||
|
-- On failure while not raising an exception, returns None.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
GPGMEError -- as signaled by the underlying library.
|
||||||
|
"""
|
||||||
|
data = Data()
|
||||||
|
mode = gpgme.GPGME_EXPORT_MODE_SECRET
|
||||||
|
try:
|
||||||
|
self.op_export(pattern, mode, data)
|
||||||
|
data.seek(0, os.SEEK_SET)
|
||||||
|
sk_result = data.read()
|
||||||
|
except GPGMEError as e:
|
||||||
|
sk_result = e
|
||||||
|
|
||||||
|
if len(sk_result) > 0:
|
||||||
|
result = sk_result
|
||||||
|
else:
|
||||||
|
result = None
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
def keylist(self, pattern=None, secret=False,
|
def keylist(self, pattern=None, secret=False,
|
||||||
mode=constants.keylist.mode.LOCAL,
|
mode=constants.keylist.mode.LOCAL,
|
||||||
source=None):
|
source=None):
|
||||||
|
Loading…
Reference in New Issue
Block a user