diff options
author | Ben McGinnes <[email protected]> | 2018-07-22 14:21:05 +0000 |
---|---|---|
committer | Ben McGinnes <[email protected]> | 2018-07-22 15:35:12 +0000 |
commit | d7c5366d58d035d7b7119f955824e842d0b6bbe0 (patch) | |
tree | f0d7dcc1f9ae25a1d1f862166f8af63b4598f9a2 /lang/python/docs/GPGMEpythonHOWTOen.org | |
parent | doc: python bindings howto (diff) | |
download | gpgme-d7c5366d58d035d7b7119f955824e842d0b6bbe0.tar.gz gpgme-d7c5366d58d035d7b7119f955824e842d0b6bbe0.zip |
doc: python bindings howto
* Another retrofitting of the HOWTO Python example code, this time
following adjustments to python-mode configuration and having
trawled through the org-mode mailing lists for clues.
Diffstat (limited to 'lang/python/docs/GPGMEpythonHOWTOen.org')
-rw-r--r-- | lang/python/docs/GPGMEpythonHOWTOen.org | 1247 |
1 files changed, 623 insertions, 624 deletions
diff --git a/lang/python/docs/GPGMEpythonHOWTOen.org b/lang/python/docs/GPGMEpythonHOWTOen.org index df37226b..c40772f2 100644 --- a/lang/python/docs/GPGMEpythonHOWTOen.org +++ b/lang/python/docs/GPGMEpythonHOWTOen.org @@ -340,40 +340,40 @@ pattern is upper or lower case. So this is the best method: -#+begin_src python - import gpg +#+begin_src python -i +import gpg - k = gpg.Context().keylist(pattern="258E88DCBD3CD44D8E7AB43F6ECB6AF0DEADBEEF") - keys = list(k) +k = gpg.Context().keylist(pattern="258E88DCBD3CD44D8E7AB43F6ECB6AF0DEADBEEF") +keys = list(k) #+end_src This is passable and very likely to be common: -#+begin_src python - import gpg +#+begin_src python -i +import gpg - k = gpg.Context().keylist(pattern="0x6ECB6AF0DEADBEEF") - keys = list(k) +k = gpg.Context().keylist(pattern="0x6ECB6AF0DEADBEEF") +keys = list(k) #+end_src And this is a really bad idea: -#+begin_src python - import gpg +#+begin_src python -i +import gpg - k = gpg.Context().keylist(pattern="0xDEADBEEF") - keys = list(k) +k = gpg.Context().keylist(pattern="0xDEADBEEF") +keys = list(k) #+end_src Alternatively it may be that the intention is to create a list of keys which all match a particular search string. For instance all the addresses at a particular domain, like this: -#+begin_src python - import gpg +#+begin_src python -i +import gpg - ncsc = gpg.Context().keylist(pattern="ncsc.mil") - nsa = list(ncsc) +ncsc = gpg.Context().keylist(pattern="ncsc.mil") +nsa = list(ncsc) #+end_src @@ -386,23 +386,23 @@ Counting the number of keys in your public keybox (=pubring.kbx=), the format which has superseded the old keyring format (=pubring.gpg= and =secring.gpg=), or the number of secret keys is a very simple task. -#+begin_src python - import gpg +#+begin_src python -i +import gpg - c = gpg.Context() - seckeys = c.keylist(pattern=None, secret=True) - pubkeys = c.keylist(pattern=None, secret=False) +c = gpg.Context() +seckeys = c.keylist(pattern=None, secret=True) +pubkeys = c.keylist(pattern=None, secret=False) - seclist = list(seckeys) - secnum = len(seclist) +seclist = list(seckeys) +secnum = len(seclist) - publist = list(pubkeys) - pubnum = len(publist) +publist = list(pubkeys) +pubnum = len(publist) - print(""" +print(""" Number of secret keys: {0} Number of public keys: {1} - """.format(secnum, pubnum)) +""".format(secnum, pubnum)) #+end_src @@ -424,21 +424,21 @@ secret keys as well. This first example demonstrates selecting the current key of Werner Koch, which is due to expire at the end of 2018: -#+begin_src python - import gpg +#+begin_src python -i +import gpg - fingerprint = "80615870F5BAD690333686D0F2AD85AC1E42B367" - key = gpg.Context().get_key(fingerprint) +fingerprint = "80615870F5BAD690333686D0F2AD85AC1E42B367" +key = gpg.Context().get_key(fingerprint) #+end_src Whereas this example demonstrates selecting the author's current key with the =secret= key word argument set to =True=: -#+begin_src python - import gpg +#+begin_src python -i +import gpg - fingerprint = "DB4724E6FA4286C92B4E55C4321E4E2373590E5D" - key = gpg.Context().get_key(fingerprint, secret=True) +fingerprint = "DB4724E6FA4286C92B4E55C4321E4E2373590E5D" +key = gpg.Context().get_key(fingerprint, secret=True) #+end_src It is, of course, quite possible to select expired, disabled and @@ -463,30 +463,30 @@ 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(""" +#+begin_src python -i +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} @@ -497,13 +497,13 @@ directly to import the resulting data into our keybox. 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 +""".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 @@ -538,54 +538,54 @@ 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 +#+begin_src python -i +import gpg +import os.path +import sys - print(""" +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 +""") + +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 @@ -593,54 +593,54 @@ 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 +#+begin_src python -i +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 @@ -657,58 +657,58 @@ 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 +#+begin_src python -i +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 @@ -718,91 +718,91 @@ 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 +#+begin_src python -i +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 @@ -850,24 +850,23 @@ trust model settings for recipient keys (defaults to =False=); =expect_sign=, prepare for signing (defaults to =False=); =compress=, compresses the plaintext prior to encryption (defaults to =True=). -#+begin_src python - import gpg +#+begin_src python -i +import gpg - a_key = "0x12345678DEADBEEF" - text = b"""Some text to test with. +a_key = "0x12345678DEADBEEF" +text = b"""Some text to test with. - Since the text in this case must be bytes, it is most likely that - the input form will be a separate file which is opened with "rb" - as this is the simplest method of obtaining the correct data - format. - """ +Since the text in this case must be bytes, it is most likely that +the input form will be a separate file which is opened with "rb" +as this is the simplest method of obtaining the correct data format. +""" - c = gpg.Context(armor=True) - rkey = list(c.keylist(pattern=a_key, secret=False)) - ciphertext, result, sign_result = c.encrypt(text, recipients=rkey, sign=False) +c = gpg.Context(armor=True) +rkey = list(c.keylist(pattern=a_key, secret=False)) +ciphertext, result, sign_result = c.encrypt(text, recipients=rkey, sign=False) - with open("secret_plans.txt.asc", "wb") as afile: - afile.write(ciphertext) +with open("secret_plans.txt.asc", "wb") as afile: + afile.write(ciphertext) #+end_src Though this is even more likely to be used like this; with the @@ -875,22 +874,22 @@ plaintext input read from a file, the recipient keys used for encryption regardless of key trust status and the encrypted output also encrypted to any preconfigured keys set in the =gpg.conf= file: -#+begin_src python - import gpg +#+begin_src python -i +import gpg - a_key = "0x12345678DEADBEEF" +a_key = "0x12345678DEADBEEF" - with open("secret_plans.txt", "rb") as afile: - text = afile.read() +with open("secret_plans.txt", "rb") as afile: + text = afile.read() - c = gpg.Context(armor=True) - rkey = list(c.keylist(pattern=a_key, secret=False)) - ciphertext, result, sign_result = c.encrypt(text, recipients=rkey, sign=True, - always_trust=True, - add_encrypt_to=True) +c = gpg.Context(armor=True) +rkey = list(c.keylist(pattern=a_key, secret=False)) +ciphertext, result, sign_result = c.encrypt(text, recipients=rkey, sign=True, + always_trust=True, + add_encrypt_to=True) - with open("secret_plans.txt.asc", "wb") as afile: - afile.write(ciphertext) +with open("secret_plans.txt.asc", "wb") as afile: + afile.write(ciphertext) #+end_src If the =recipients= paramater is empty then the plaintext is encrypted @@ -912,45 +911,45 @@ email address on the =gnupg.org= domain,[fn:3] but does /not/ encrypt to a default key or other key which is configured to normally encrypt to. -#+begin_src python - import gpg +#+begin_src python -i +import gpg - text = b"""Oh look, another test message. +text = b"""Oh look, another test message. - The same rules apply as with the previous example and more likely - than not, the message will actually be drawn from reading the - contents of a file or, maybe, from entering data at an input() - prompt. +The same rules apply as with the previous example and more likely +than not, the message will actually be drawn from reading the +contents of a file or, maybe, from entering data at an input() +prompt. - Since the text in this case must be bytes, it is most likely that - the input form will be a separate file which is opened with "rb" - as this is the simplest method of obtaining the correct data - format. - """ +Since the text in this case must be bytes, it is most likely that +the input form will be a separate file which is opened with "rb" +as this is the simplest method of obtaining the correct data +format. +""" - c = gpg.Context(armor=True) - rpattern = list(c.keylist(pattern="@gnupg.org", secret=False)) - logrus = [] +c = gpg.Context(armor=True) +rpattern = list(c.keylist(pattern="@gnupg.org", secret=False)) +logrus = [] - for i in range(len(rpattern)): - if rpattern[i].can_encrypt == 1: - logrus.append(rpattern[i]) +for i in range(len(rpattern)): + if rpattern[i].can_encrypt == 1: + logrus.append(rpattern[i]) - ciphertext, result, sign_result = c.encrypt(text, recipients=logrus, - sign=False, always_trust=True) +ciphertext, result, sign_result = c.encrypt(text, recipients=logrus, + sign=False, always_trust=True) - with open("secret_plans.txt.asc", "wb") as afile: - afile.write(ciphertext) +with open("secret_plans.txt.asc", "wb") as afile: + afile.write(ciphertext) #+end_src All it would take to change the above example to sign the message and also encrypt the message to any configured default keys would be to change the =c.encrypt= line to this: -#+begin_src python - ciphertext, result, sign_result = c.encrypt(text, recipients=logrus, - always_trust=True, - add_encrypt_to=True) +#+begin_src python -i +ciphertext, result, sign_result = c.encrypt(text, recipients=logrus, + always_trust=True, + add_encrypt_to=True) #+end_src The only keyword arguments requiring modification are those for which @@ -963,38 +962,38 @@ are not trusted (e.g. not signed or locally signed) then the encryption will raise an error. It is possible to mitigate this somewhat with something more like this: -#+begin_src python - import gpg - - with open("secret_plans.txt.asc", "rb") as afile: - text = afile.read() - - c = gpg.Context(armor=True) - rpattern = list(c.keylist(pattern="@gnupg.org", secret=False)) - logrus = [] - - for i in range(len(rpattern)): - if rpattern[i].can_encrypt == 1: - logrus.append(rpattern[i]) - - try: - ciphertext, result, sign_result = c.encrypt(text, recipients=logrus, - add_encrypt_to=True) - except gpg.errors.InvalidRecipients as e: - for i in range(len(e.recipients)): - for n in range(len(logrus)): - if logrus[n].fpr == e.recipients[i].fpr: - logrus.remove(logrus[n]) - else: - pass - try: - ciphertext, result, sign_result = c.encrypt(text, - recipients=logrus, - add_encrypt_to=True) - with open("secret_plans.txt.asc", "wb") as afile: - afile.write(ciphertext) - except: - pass +#+begin_src python -i +import gpg + +with open("secret_plans.txt.asc", "rb") as afile: + text = afile.read() + +c = gpg.Context(armor=True) +rpattern = list(c.keylist(pattern="@gnupg.org", secret=False)) +logrus = [] + +for i in range(len(rpattern)): + if rpattern[i].can_encrypt == 1: + logrus.append(rpattern[i]) + + try: + ciphertext, result, sign_result = c.encrypt(text, recipients=logrus, + add_encrypt_to=True) + except gpg.errors.InvalidRecipients as e: + for i in range(len(e.recipients)): + for n in range(len(logrus)): + if logrus[n].fpr == e.recipients[i].fpr: + logrus.remove(logrus[n]) + else: + pass + try: + ciphertext, result, sign_result = c.encrypt(text, + recipients=logrus, + add_encrypt_to=True) + with open("secret_plans.txt.asc", "wb") as afile: + afile.write(ciphertext) + except: + pass #+end_src This will attempt to encrypt to all the keys searched for, then remove @@ -1015,24 +1014,24 @@ to modify the Context prior to conducting the decryption and since the Context is only used once, setting it to =c= simply adds lines for no gain. -#+begin_src python - import gpg +#+begin_src python -i +import gpg - ciphertext = input("Enter path and filename of encrypted file: ") - newfile = input("Enter path and filename of file to save decrypted data to: ") +ciphertext = input("Enter path and filename of encrypted file: ") +newfile = input("Enter path and filename of file to save decrypted data to: ") - with open(ciphertext, "rb") as cfile: - try: - plaintext, result, verify_result = gpg.Context().decrypt(cfile) - except gpg.errors.GPGMEError as e: - plaintext = None - print(e) +with open(ciphertext, "rb") as cfile: + try: + plaintext, result, verify_result = gpg.Context().decrypt(cfile) + except gpg.errors.GPGMEError as e: + plaintext = None + print(e) - if plaintext is not None: - with open(newfile, "wb") as nfile: - nfile.write(plaintext) - else: - pass + if plaintext is not None: + with open(newfile, "wb") as nfile: + nfile.write(plaintext) + else: + pass #+end_src The data available in =plaintext= in this example is the decrypted @@ -1060,12 +1059,12 @@ default key specified and there is more than one secret key available it may be necessary to specify the key or keys with which to sign messages and files. -#+begin_src python - import gpg +#+begin_src python -i +import gpg - logrus = input("Enter the email address or string to match signing keys to: ") - hancock = gpg.Context().keylist(pattern=logrus, secret=True) - sig_src = list(hancock) +logrus = input("Enter the email address or string to match signing keys to: ") +hancock = gpg.Context().keylist(pattern=logrus, secret=True) +sig_src = list(hancock) #+end_src The signing examples in the following sections include the explicitly @@ -1101,19 +1100,19 @@ multiple keys are involved; from the preferences saved into the key itself or by comparison with the preferences with all other keys involved. -#+begin_src python - import gpg +#+begin_src python -i +import gpg - text0 = """Declaration of ... something. +text0 = """Declaration of ... something. - """ - text = text0.encode() +""" +text = text0.encode() - c = gpg.Context(armor=True, signers=sig_src) - signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.NORMAL) +c = gpg.Context(armor=True, signers=sig_src) +signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.NORMAL) - with open("/path/to/statement.txt.asc", "w") as afile: - afile.write(signed_data.decode()) +with open("/path/to/statement.txt.asc", "w") as afile: + afile.write(signed_data.decode()) #+end_src Though everything in this example is accurate, it is more likely that @@ -1121,17 +1120,17 @@ reading the input data from another file and writing the result to a new file will be performed more like the way it is done in the next example. Even if the output format is ASCII armoured. -#+begin_src python - import gpg +#+begin_src python -i +import gpg - with open("/path/to/statement.txt", "rb") as tfile: - text = tfile.read() +with open("/path/to/statement.txt", "rb") as tfile: + text = tfile.read() - c = gpg.Context() - signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.NORMAL) +c = gpg.Context() +signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.NORMAL) - with open("/path/to/statement.txt.sig", "wb") as afile: - afile.write(signed_data) +with open("/path/to/statement.txt.sig", "wb") as afile: + afile.write(signed_data) #+end_src @@ -1144,35 +1143,35 @@ Detached signatures will often be needed in programmatic uses of GPGME, either for signing files (e.g. tarballs of code releases) or as a component of message signing (e.g. PGP/MIME encoded email). -#+begin_src python - import gpg +#+begin_src python -i +import gpg - text0 = """Declaration of ... something. +text0 = """Declaration of ... something. - """ - text = text0.encode() +""" +text = text0.encode() - c = gpg.Context(armor=True) - signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.DETACH) +c = gpg.Context(armor=True) +signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.DETACH) - with open("/path/to/statement.txt.asc", "w") as afile: - afile.write(signed_data.decode()) +with open("/path/to/statement.txt.asc", "w") as afile: + afile.write(signed_data.decode()) #+end_src As with normal signatures, detached signatures are best handled as byte literals, even when the output is ASCII armoured. -#+begin_src python - import gpg +#+begin_src python -i +import gpg - with open("/path/to/statement.txt", "rb") as tfile: - text = tfile.read() +with open("/path/to/statement.txt", "rb") as tfile: + text = tfile.read() - c = gpg.Context(signers=sig_src) - signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.DETACH) +c = gpg.Context(signers=sig_src) +signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.DETACH) - with open("/path/to/statement.txt.sig", "wb") as afile: - afile.write(signed_data) +with open("/path/to/statement.txt.sig", "wb") as afile: + afile.write(signed_data) #+end_src @@ -1185,35 +1184,35 @@ Though PGP/in-line messages are no longer encouraged in favour of PGP/MIME, there is still sometimes value in utilising in-line signatures. This is where clear-signed messages or text is of value. -#+begin_src python - import gpg +#+begin_src python -i +import gpg - text0 = """Declaration of ... something. +text0 = """Declaration of ... something. - """ - text = text0.encode() +""" +text = text0.encode() - c = gpg.Context() - signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.CLEAR) +c = gpg.Context() +signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.CLEAR) - with open("/path/to/statement.txt.asc", "w") as afile: - afile.write(signed_data.decode()) +with open("/path/to/statement.txt.asc", "w") as afile: + afile.write(signed_data.decode()) #+end_src In spite of the appearance of a clear-signed message, the data handled by GPGME in signing it must still be byte literals. -#+begin_src python - import gpg +#+begin_src python -i +import gpg - with open("/path/to/statement.txt", "rb") as tfile: - text = tfile.read() +with open("/path/to/statement.txt", "rb") as tfile: + text = tfile.read() - c = gpg.Context() - signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.CLEAR) +c = gpg.Context() +signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.CLEAR) - with open("/path/to/statement.txt.asc", "wb") as afile: - afile.write(signed_data) +with open("/path/to/statement.txt.asc", "wb") as afile: + afile.write(signed_data) #+end_src @@ -1230,79 +1229,79 @@ with files and data with detached signatures. The following example is intended for use with the default signing method where the file was not ASCII armoured: -#+begin_src python - import gpg - import time - - filename = "statement.txt" - gpg_file = "statement.txt.gpg" - - c = gpg.Context() - - try: - data, result = c.verify(open(gpg_file)) - verified = True - except gpg.errors.BadSignatures as e: - verified = False - print(e) - - if verified is True: - for i in range(len(result.signatures)): - sign = result.signatures[i] - print("""Good signature from: - {0} - with key {1} - made at {2} - """.format(c.get_key(sign.fpr).uids[0].uid, sign.fpr, - time.ctime(sign.timestamp))) - else: - pass +#+begin_src python -i +import gpg +import time + +filename = "statement.txt" +gpg_file = "statement.txt.gpg" + +c = gpg.Context() + +try: + data, result = c.verify(open(gpg_file)) + verified = True +except gpg.errors.BadSignatures as e: + verified = False + print(e) + +if verified is True: + for i in range(len(result.signatures)): + sign = result.signatures[i] + print("""Good signature from: +{0} +with key {1} +made at {2} +""".format(c.get_key(sign.fpr).uids[0].uid, sign.fpr, + time.ctime(sign.timestamp))) +else: + pass #+end_src Whereas this next example, which is almost identical would work with normal ASCII armoured files and with clear-signed files: -#+begin_src python - import gpg - import time - - filename = "statement.txt" - asc_file = "statement.txt.asc" - - c = gpg.Context() - - try: - data, result = c.verify(open(asc_file)) - verified = True - except gpg.errors.BadSignatures as e: - verified = False - print(e) - - if verified is True: - for i in range(len(result.signatures)): - sign = result.signatures[i] - print("""Good signature from: - {0} - with key {1} - made at {2} - """.format(c.get_key(sign.fpr).uids[0].uid, sign.fpr, - time.ctime(sign.timestamp))) - else: - pass +#+begin_src python -i +import gpg +import time + +filename = "statement.txt" +asc_file = "statement.txt.asc" + +c = gpg.Context() + +try: + data, result = c.verify(open(asc_file)) + verified = True +except gpg.errors.BadSignatures as e: + verified = False + print(e) + +if verified is True: + for i in range(len(result.signatures)): + sign = result.signatures[i] + print("""Good signature from: +{0} +with key {1} +made at {2} +""".format(c.get_key(sign.fpr).uids[0].uid, sign.fpr, + time.ctime(sign.timestamp))) +else: + pass #+end_src In both of the previous examples it is also possible to compare the original data that was signed against the signed data in =data= to see if it matches with something like this: -#+begin_src python - with open(filename, "rb") as afile: - text = afile.read() +#+begin_src python -i +with open(filename, "rb") as afile: + text = afile.read() - if text == data: - print("Good signature.") - else: - pass +if text == data: + print("Good signature.") +else: + pass #+end_src The following two examples, however, deal with detached signatures. @@ -1311,62 +1310,62 @@ returned since it is already being explicitly referenced in the first argument of =c.verify=. So =data= is =None= and only the information in =result= is available. -#+begin_src python - import gpg - import time - - filename = "statement.txt" - sig_file = "statement.txt.sig" - - c = gpg.Context() - - try: - data, result = c.verify(open(filename), open(sig_file)) - verified = True - except gpg.errors.BadSignatures as e: - verified = False - print(e) - - if verified is True: - for i in range(len(result.signatures)): - sign = result.signatures[i] - print("""Good signature from: - {0} - with key {1} - made at {2} - """.format(c.get_key(sign.fpr).uids[0].uid, sign.fpr, - time.ctime(sign.timestamp))) - else: - pass +#+begin_src python -i +import gpg +import time + +filename = "statement.txt" +sig_file = "statement.txt.sig" + +c = gpg.Context() + +try: + data, result = c.verify(open(filename), open(sig_file)) + verified = True +except gpg.errors.BadSignatures as e: + verified = False + print(e) + +if verified is True: + for i in range(len(result.signatures)): + sign = result.signatures[i] + print("""Good signature from: +{0} +with key {1} +made at {2} +""".format(c.get_key(sign.fpr).uids[0].uid, sign.fpr, + time.ctime(sign.timestamp))) +else: + pass #+end_src -#+begin_src python - import gpg - import time - - filename = "statement.txt" - asc_file = "statement.txt.asc" - - c = gpg.Context() - - try: - data, result = c.verify(open(filename), open(asc_file)) - verified = True - except gpg.errors.BadSignatures as e: - verified = False - print(e) - - if verified is True: - for i in range(len(result.signatures)): - sign = result.signatures[i] - print("""Good signature from: - {0} - with key {1} - made at {2} - """.format(c.get_key(sign.fpr).uids[0].uid, sign.fpr, - time.ctime(sign.timestamp))) - else: - pass +#+begin_src python -i +import gpg +import time + +filename = "statement.txt" +asc_file = "statement.txt.asc" + +c = gpg.Context() + +try: + data, result = c.verify(open(filename), open(asc_file)) + verified = True +except gpg.errors.BadSignatures as e: + verified = False + print(e) + +if verified is True: + for i in range(len(result.signatures)): + sign = result.signatures[i] + print("""Good signature from: +{0} +with key {1} +made at {2} +""".format(c.get_key(sign.fpr).uids[0].uid, sign.fpr, + time.ctime(sign.timestamp))) +else: + pass #+end_src @@ -1424,16 +1423,16 @@ be the passphrase and if =passphrase= is set to =True= then gpg-agent will launch pinentry to prompt for a passphrase. For the sake of convenience, these examples will keep =passphrase= set to =None=. -#+begin_src python - import gpg +#+begin_src python -i +import gpg - c = gpg.Context() +c = gpg.Context() - c.home_dir = "~/.gnupg-dm" - userid = "Danger Mouse <[email protected]>" +c.home_dir = "~/.gnupg-dm" +userid = "Danger Mouse <[email protected]>" - dmkey = c.create_key(userid, algorithm="rsa3072", expires_in=31536000, - sign=True, certify=True) +dmkey = c.create_key(userid, algorithm="rsa3072", expires_in=31536000, + sign=True, certify=True) #+end_src One thing to note here is the use of setting the =c.home_dir= @@ -1452,8 +1451,8 @@ already set and the correct directory and file permissions. The successful generation of the key can be confirmed via the returned =GenkeyResult= object, which includes the following data: -#+begin_src python - print(""" +#+begin_src python -i +print(""" Fingerprint: {0} Primary Key: {1} Public Key: {2} @@ -1519,21 +1518,21 @@ primary key. Since Danger Mouse is a security conscious secret agent, this subkey will only be valid for about six months, half the length of the primary key. -#+begin_src python - import gpg +#+begin_src python -i +import gpg - c = gpg.Context() - c.home_dir = "~/.gnupg-dm" +c = gpg.Context() +c.home_dir = "~/.gnupg-dm" - key = c.get_key(dmkey.fpr, secret=True) - dmsub = c.create_subkey(key, algorithm="rsa3072", expires_in=15768000, - encrypt=True) +key = c.get_key(dmkey.fpr, secret=True) +dmsub = c.create_subkey(key, algorithm="rsa3072", expires_in=15768000, + encrypt=True) #+end_src As with the primary key, the results here can be checked with: -#+begin_src python - print(""" +#+begin_src python -i +print(""" Fingerprint: {0} Primary Key: {1} Public Key: {2} @@ -1575,17 +1574,17 @@ ID to an existing key is much simpler. The method used to do this is =key_add_uid= and the only arguments it takes are for the =key= and the new =uid=. -#+begin_src python - import gpg +#+begin_src python -i +import gpg - c = gpg.Context() - c.home_dir = "~/.gnupg-dm" +c = gpg.Context() +c.home_dir = "~/.gnupg-dm" - dmfpr = "177B7C25DB99745EE2EE13ED026D2F19E99E63AA" - key = c.get_key(dmfpr, secret=True) - uid = "Danger Mouse <[email protected]>" +dmfpr = "177B7C25DB99745EE2EE13ED026D2F19E99E63AA" +key = c.get_key(dmfpr, secret=True) +uid = "Danger Mouse <[email protected]>" - c.key_add_uid(key, uid) +c.key_add_uid(key, uid) #+end_src Unsurprisingly the result of this is: @@ -1612,17 +1611,17 @@ Unsurprisingly the result of this is: Revoking a user ID is a fairly similar process, except that it uses the =key_revoke_uid= method. -#+begin_src python - import gpg +#+begin_src python -i +import gpg - c = gpg.Context() - c.home_dir = "~/.gnupg-dm" +c = gpg.Context() +c.home_dir = "~/.gnupg-dm" - dmfpr = "177B7C25DB99745EE2EE13ED026D2F19E99E63AA" - key = c.get_key(dmfpr, secret=True) - uid = "Danger Mouse <[email protected]>" +dmfpr = "177B7C25DB99745EE2EE13ED026D2F19E99E63AA" +key = c.get_key(dmfpr, secret=True) +uid = "Danger Mouse <[email protected]>" - c.key_revoke_uid(key, uid) +c.key_revoke_uid(key, uid) #+end_src @@ -1652,15 +1651,15 @@ it is case sensitive. To sign Danger Mouse's key for just the initial user ID with a signature which will last a little over a month, do this: -#+begin_src python - import gpg +#+begin_src python -i +import gpg - c = gpg.Context() - uid = "Danger Mouse <[email protected]>" +c = gpg.Context() +uid = "Danger Mouse <[email protected]>" - dmfpr = "177B7C25DB99745EE2EE13ED026D2F19E99E63AA" - key = c.get_key(dmfpr, secret=True) - c.key_sign(key, uids=uid, expires_in=2764800) +dmfpr = "177B7C25DB99745EE2EE13ED026D2F19E99E63AA" +key = c.get_key(dmfpr, secret=True) +c.key_sign(key, uids=uid, expires_in=2764800) #+end_src @@ -1683,28 +1682,28 @@ MUAs readily. The following code, however, provides a work-around for obtaining this information in Python. -#+begin_src python - import subprocess +#+begin_src python -i +import subprocess - lines = subprocess.getoutput("gpgconf --list-options gpg").splitlines() +lines = subprocess.getoutput("gpgconf --list-options gpg").splitlines() - for i in range(len(lines)): - if lines[i].startswith("group") is True: - line = lines[i] - else: - pass +for i in range(len(lines)): + if lines[i].startswith("group") is True: + line = lines[i] + else: + pass - groups = line.split(":")[-1].replace('"', '').split(',') +groups = line.split(":")[-1].replace('"', '').split(',') - group_lines = [] - group_lists = [] +group_lines = [] +group_lists = [] - for i in range(len(groups)): - group_lines.append(groups[i].split("=")) - group_lists.append(groups[i].split("=")) +for i in range(len(groups)): + group_lines.append(groups[i].split("=")) + group_lists.append(groups[i].split("=")) - for i in range(len(group_lists)): - group_lists[i][1] = group_lists[i][1].split() +for i in range(len(group_lists)): + group_lists[i][1] = group_lists[i][1].split() #+end_src The result of that code is that =group_lines= is a list of lists where |