[git] GPGME - branch, master, updated. gpgme-1.11.1-72-g48174b2

by Ben McGinnes cvs at cvs.gnupg.org
Thu Jun 28 10:52:48 CEST 2018


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GnuPG Made Easy".

The branch, master has been updated
       via  48174b2bcc319e4542aefd0cc3aae02c4083784e (commit)
       via  6aec7d6e4a5173f54a079719020704a0098b8f0a (commit)
       via  a7ccdc51efd8c199b902eb942e9db7b3549e721f (commit)
       via  7fc7e80e54235c558051cbf72b51dd60b4ca485e (commit)
       via  0d163a7d121eacacc5f6da11a3dee3548f98f124 (commit)
       via  4251cae34da0d825a29f509ac828f7ecb90c1752 (commit)
       via  a5b91b21f561d7b13ddcb62fca3749ed92ea8720 (commit)
       via  7faef33d13fa8efce152ca7aa6e9d39030c1cf08 (commit)
       via  89c548efdf46bd7d9e6f0ca34a07efbbf420e821 (commit)
      from  d8beab30c44482fb7a3e445b92cec482792b2ca0 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 48174b2bcc319e4542aefd0cc3aae02c4083784e
Author: Ben McGinnes <ben at adversary.org>
Date:   Thu Jun 28 18:46:31 2018 +1000

    whitespace police:
    
    * There's always one or, in this case, two.

diff --git a/lang/python/src/core.py b/lang/python/src/core.py
index f8e0c60..7003b25 100644
--- a/lang/python/src/core.py
+++ b/lang/python/src/core.py
@@ -610,9 +610,9 @@ class Context(GpgmeWrapper):
         Keyword arguments:
         pattern	-- return keys matching pattern (default: all keys)
 
-        Returns: 
+        Returns:
                 -- A key block containing one or more minimised OpenPGP
-                   keys in either ASCII armoured or binary format as 
+                   keys in either ASCII armoured or binary format as
                    determined by the Context().  If there are no matching
                    keys it returns None.
 

commit 6aec7d6e4a5173f54a079719020704a0098b8f0a
Author: Ben McGinnes <ben at adversary.org>
Date:   Thu Jun 28 18:33:51 2018 +1000

    docs: python bindings howto
    
    * Updated official doc (the org-mode file) with the instructions on
      importing and exporting both public and secret keys.

diff --git a/lang/python/docs/GPGMEpythonHOWTOen.org b/lang/python/docs/GPGMEpythonHOWTOen.org
index 3325c08..6a3f9db 100644
--- a/lang/python/docs/GPGMEpythonHOWTOen.org
+++ b/lang/python/docs/GPGMEpythonHOWTOen.org
@@ -454,6 +454,364 @@
    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
   :PROPERTIES:
   :CUSTOM_ID: howto-the-basics

commit a7ccdc51efd8c199b902eb942e9db7b3549e721f
Author: Ben McGinnes <ben at adversary.org>
Date:   Thu Jun 28 18:14:13 2018 +1000

    python bindings examples
    
    * Added a secret key export variant which saves output as both GPG
      binary and ASCII armoured, plus saves in $GNUPGHOME and uses
      multiple methods of determining what that location is.

diff --git a/lang/python/examples/howto/export-secret-keys.py b/lang/python/examples/howto/export-secret-keys.py
new file mode 100755
index 0000000..03037c9
--- /dev/null
+++ b/lang/python/examples/howto/export-secret-keys.py
@@ -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 at 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

commit 7fc7e80e54235c558051cbf72b51dd60b4ca485e
Author: Ben McGinnes <ben at adversary.org>
Date:   Thu Jun 28 03:28:07 2018 +1000

    python bindings examples
    
    * Added a key import variant which accesses the SKS keyservers in a
      RESTful fashion and then imports or attempts to import the response.

diff --git a/lang/python/examples/howto/import-keys.py b/lang/python/examples/howto/import-keys.py
new file mode 100755
index 0000000..8a3bb29
--- /dev/null
+++ b/lang/python/examples/howto/import-keys.py
@@ -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 at 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

commit 0d163a7d121eacacc5f6da11a3dee3548f98f124
Author: Ben McGinnes <ben at adversary.org>
Date:   Wed Jun 27 20:12:27 2018 +1000

    python bindings examples: three export scripts
    
    * Example of default exporting keys.
    * Example of exporting minimised keys.
    * Example of exporting secret keys to a file with correct permissions.
    
    Signed-off-by: Ben McGinnes <ben at adversary.org>

diff --git a/lang/python/examples/howto/export-key.py b/lang/python/examples/howto/export-key.py
new file mode 100755
index 0000000..41be64f
--- /dev/null
+++ b/lang/python/examples/howto/export-key.py
@@ -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 at 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
diff --git a/lang/python/examples/howto/export-minimised-key.py b/lang/python/examples/howto/export-minimised-key.py
new file mode 100755
index 0000000..d28b1cb
--- /dev/null
+++ b/lang/python/examples/howto/export-minimised-key.py
@@ -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 at 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
diff --git a/lang/python/examples/howto/export-secret-key.py b/lang/python/examples/howto/export-secret-key.py
new file mode 100755
index 0000000..8bbe409
--- /dev/null
+++ b/lang/python/examples/howto/export-secret-key.py
@@ -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 at 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

commit 4251cae34da0d825a29f509ac828f7ecb90c1752
Author: Ben McGinnes <ben at adversary.org>
Date:   Thu Jun 28 01:50:56 2018 +1000

    python bindings: import example
    
    * Added an example script for importing a key from a file (either
      ASCII armoured or not).

diff --git a/lang/python/examples/howto/import-key.py b/lang/python/examples/howto/import-key.py
new file mode 100755
index 0000000..56cfe25
--- /dev/null
+++ b/lang/python/examples/howto/import-key.py
@@ -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 at 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.")

commit a5b91b21f561d7b13ddcb62fca3749ed92ea8720
Author: Ben McGinnes <ben at adversary.org>
Date:   Wed Jun 27 19:16:29 2018 +1000

    python bindings: export secret keys
    
    * The holy grail: a function to export secret keys.
    * GPGME will still invoke pinentry and gpg-agent as usual to authorise
      the export.
    * Mostly similar to the two previous export functions for public keys
      except that it will return None if the result had a length of zero
      bytes.  Meaning that the difference between the specified pattern
      (if any) not matching available keys and an incorrect passphrase is
      not able to be determined from this function (or the underlying one
      for that matter).
    
    Signed-off-by: Ben McGinnes <ben at adversary.org>

diff --git a/lang/python/src/core.py b/lang/python/src/core.py
index d7db7de..f8e0c60 100644
--- a/lang/python/src/core.py
+++ b/lang/python/src/core.py
@@ -618,7 +618,7 @@ class Context(GpgmeWrapper):
 
         Raises:
         GPGMEError     -- as signaled by the underlying library.
-"""
+        """
         data = Data()
         mode = gpgme.GPGME_EXPORT_MODE_MINIMAL
         try:
@@ -635,6 +635,47 @@ class Context(GpgmeWrapper):
 
         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,
                 mode=constants.keylist.mode.LOCAL,
                 source=None):

commit 7faef33d13fa8efce152ca7aa6e9d39030c1cf08
Author: Ben McGinnes <ben at adversary.org>
Date:   Thu Jun 28 00:57:37 2018 +1000

    python bindings: export public keys
    
    * Updated key_export and key_export_minimal to return None where a
      pattern matched no keys in a manner simnilar to the possible result
      of key_export_secret.

diff --git a/lang/python/src/core.py b/lang/python/src/core.py
index 86a62b5..d7db7de 100644
--- a/lang/python/src/core.py
+++ b/lang/python/src/core.py
@@ -578,7 +578,8 @@ class Context(GpgmeWrapper):
         Returns:
                 -- A key block containing one or more OpenPGP keys in
                    either ASCII armoured or binary format as determined
-                   by the Context().
+                   by the Context().  If there are no matching keys it
+                   returns None.
 
         Raises:
         GPGMEError     -- as signaled by the underlying library.
@@ -588,9 +589,14 @@ class Context(GpgmeWrapper):
         try:
             self.op_export(pattern, mode, data)
             data.seek(0, os.SEEK_SET)
-            result = data.read()
+            pk_result = data.read()
         except GPGMEError as e:
-            result = e
+            pk_result = e
+
+        if len(pk_result) > 0:
+            result = pk_result
+        else:
+            result = None
 
         return result
 
@@ -607,7 +613,8 @@ class Context(GpgmeWrapper):
         Returns: 
                 -- A key block containing one or more minimised OpenPGP
                    keys in either ASCII armoured or binary format as 
-                   determined by the Context().
+                   determined by the Context().  If there are no matching
+                   keys it returns None.
 
         Raises:
         GPGMEError     -- as signaled by the underlying library.
@@ -617,9 +624,14 @@ class Context(GpgmeWrapper):
         try:
             self.op_export(pattern, mode, data)
             data.seek(0, os.SEEK_SET)
-            result = data.read()
+            pk_result = data.read()
         except GPGMEError as e:
-            result = e
+            pk_result = e
+
+        if len(pk_result) > 0:
+            result = pk_result
+        else:
+            result = None
 
         return result
 

commit 89c548efdf46bd7d9e6f0ca34a07efbbf420e821
Author: Ben McGinnes <ben at adversary.org>
Date:   Wed Jun 27 18:51:09 2018 +1000

    python bindings: export public keys
    
    * Added functions for exporting public keys to gpg.core in both
      complete form and in minimised form.
    * Rather than letting people need to worry about the export modes we
      are simply separating the functions as people would be more familiar
      with from the command line usage anyway.
    * Functions added for Context are: ctx.key_export_minimal and
      ctx.key_export as the default or full export.
    
    Signed-off-by: Ben McGinnes <ben at adversary.org>

diff --git a/lang/python/src/core.py b/lang/python/src/core.py
index 8f2e9d8..86a62b5 100644
--- a/lang/python/src/core.py
+++ b/lang/python/src/core.py
@@ -537,7 +537,7 @@ class Context(GpgmeWrapper):
                           managed to run the function without any
                           arguments, while an argument of None triggers
                           the first NODATA of errors.GPGME in the
-                           exception.
+                          exception.
         """
         try:
             self.op_import(data)
@@ -566,6 +566,63 @@ class Context(GpgmeWrapper):
 
         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().
+
+        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)
+            result = data.read()
+        except GPGMEError as e:
+            result = e
+
+        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().
+
+        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)
+            result = data.read()
+        except GPGMEError as e:
+            result = e
+
+        return result
+
     def keylist(self, pattern=None, secret=False,
                 mode=constants.keylist.mode.LOCAL,
                 source=None):

-----------------------------------------------------------------------

Summary of changes:
 lang/python/docs/GPGMEpythonHOWTOen.org            | 358 +++++++++++++++++++++
 .../howto/{add-userid.py => export-key.py}         |  43 ++-
 .../{add-userid.py => export-minimised-key.py}     |  43 ++-
 .../{revoke-userid.py => export-secret-key.py}     |  45 ++-
 lang/python/examples/howto/export-secret-keys.py   | 110 +++++++
 lang/python/examples/howto/import-key.py           |  91 ++++++
 lang/python/examples/howto/import-keys.py          |  73 +++++
 lang/python/src/core.py                            | 112 ++++++-
 8 files changed, 827 insertions(+), 48 deletions(-)
 copy lang/python/examples/howto/{add-userid.py => export-key.py} (59%)
 copy lang/python/examples/howto/{add-userid.py => export-minimised-key.py} (59%)
 copy lang/python/examples/howto/{revoke-userid.py => export-secret-key.py} (56%)
 create mode 100755 lang/python/examples/howto/export-secret-keys.py
 create mode 100755 lang/python/examples/howto/import-key.py
 create mode 100755 lang/python/examples/howto/import-keys.py


hooks/post-receive
-- 
GnuPG Made Easy
http://git.gnupg.org




More information about the Gnupg-commits mailing list