diff options
| author | Ben McGinnes <[email protected]> | 2018-07-22 15:16:31 +0000 | 
|---|---|---|
| committer | Ben McGinnes <[email protected]> | 2018-07-22 15:35:12 +0000 | 
| commit | 4d1642b11ea64b8009a8720d9b59e89636d691d2 (patch) | |
| tree | 4ce2589863e8618b6bc495732d26c91271ea4db2 | |
| parent | doc: python bindings howto (diff) | |
| download | gpgme-4d1642b11ea64b8009a8720d9b59e89636d691d2.tar.gz gpgme-4d1642b11ea64b8009a8720d9b59e89636d691d2.zip | |
docs: python bindings howto
* Fixed and tested the changes necessary for org-mode to correctly
  parse pythonic (Python 3) indentation.
* Updated the source blocks to recommended upper case for BEGIN_SRC
  and END_SRC.
* Tested and confirmed XHTML output matches correct examples.
* Tested against pseudo-control output via exporting from org-mode to
  org-mode and then exporting that to XHTML.  Remaining differences
  appear to be discarding the custom tags used to provide X[HT]ML id
  elements to each section which does not appear to offer any benefit.
* Exporting directly to XHTML or other HTML output should no longer
  cause problems, but if there are any then the first step should be
  exporting from org-to-org and then exporting that to XHTML.
Tested-by: Ben McGinnes <[email protected]>
Signed-off-by: Ben McGinnes <[email protected]>
| -rw-r--r-- | lang/python/docs/GPGMEpythonHOWTOen.org | 339 | 
1 files changed, 169 insertions, 170 deletions
| diff --git a/lang/python/docs/GPGMEpythonHOWTOen.org b/lang/python/docs/GPGMEpythonHOWTOen.org index c40772f2..a712ec27 100644 --- a/lang/python/docs/GPGMEpythonHOWTOen.org +++ b/lang/python/docs/GPGMEpythonHOWTOen.org @@ -340,41 +340,41 @@ pattern is upper or lower case.  So this is the best method: -#+begin_src python -i +#+BEGIN_SRC python -i  import gpg  k = gpg.Context().keylist(pattern="258E88DCBD3CD44D8E7AB43F6ECB6AF0DEADBEEF")  keys = list(k) -#+end_src +#+END_SRC  This is passable and very likely to be common: -#+begin_src python -i +#+BEGIN_SRC python -i  import gpg  k = gpg.Context().keylist(pattern="0x6ECB6AF0DEADBEEF")  keys = list(k) -#+end_src +#+END_SRC  And this is a really bad idea: -#+begin_src python -i +#+BEGIN_SRC python -i  import gpg  k = gpg.Context().keylist(pattern="0xDEADBEEF")  keys = list(k) -#+end_src +#+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 -i +#+BEGIN_SRC python -i  import gpg  ncsc = gpg.Context().keylist(pattern="ncsc.mil")  nsa = list(ncsc) -#+end_src +#+END_SRC  *** Counting keys @@ -386,7 +386,7 @@ 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 -i +#+BEGIN_SRC python -i  import gpg  c = gpg.Context() @@ -403,7 +403,7 @@ print("""    Number of secret keys:  {0}    Number of public keys:  {1}  """.format(secnum, pubnum)) -#+end_src +#+END_SRC  ** Get key @@ -424,22 +424,22 @@ 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 -i +#+BEGIN_SRC python -i  import gpg  fingerprint = "80615870F5BAD690333686D0F2AD85AC1E42B367"  key = gpg.Context().get_key(fingerprint) -#+end_src +#+END_SRC  Whereas this example demonstrates selecting the author's current key  with the =secret= key word argument set to =True=: -#+begin_src python -i +#+BEGIN_SRC python -i  import gpg  fingerprint = "DB4724E6FA4286C92B4E55C4321E4E2373590E5D"  key = gpg.Context().get_key(fingerprint, secret=True) -#+end_src +#+END_SRC  It is, of course, quite possible to select expired, disabled and  revoked keys with this function, but only to effectively display @@ -463,7 +463,7 @@ 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 -i +#+BEGIN_SRC python -i  import gpg  import os.path  import requests @@ -498,13 +498,12 @@ elif result is not None and hasattr(result, "considered") is True:    The key IDs for all considered keys were:  """.format(num_keys, new_revs, new_sigs, new_subs, new_uids, new_scrt, -	   nochange)) +           nochange))      for i in range(num_keys): -	print(result.imports[i].fpr) -	print("") +        print("{0}\n".format(result.imports[i].fpr))  else:      pass -#+end_src +#+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= @@ -538,13 +537,13 @@ 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 -i +#+BEGIN_SRC python -i  import gpg  import os.path  import sys  print(""" -  This script exports one or more public keys. +This script exports one or more public keys.  """)  c = gpg.Context(armor=True) @@ -568,9 +567,9 @@ else:  if homedir.startswith("~"):      if os.path.exists(os.path.expanduser(homedir)) is True: -	c.home_dir = os.path.expanduser(homedir) +        c.home_dir = os.path.expanduser(homedir)      else: -	pass +        pass  elif os.path.exists(homedir) is True:      c.home_dir = homedir  else: @@ -583,17 +582,17 @@ except:  if result is not None:      with open(keyfile, "wb") as f: -	f.write(result) +        f.write(result)  else:      pass -#+end_src +#+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 -i +#+BEGIN_SRC python -i  import gpg  import os.path  import sys @@ -623,9 +622,9 @@ else:  if homedir.startswith("~"):      if os.path.exists(os.path.expanduser(homedir)) is True: -	c.home_dir = os.path.expanduser(homedir) +        c.home_dir = os.path.expanduser(homedir)      else: -	pass +        pass  elif os.path.exists(homedir) is True:      c.home_dir = homedir  else: @@ -638,10 +637,10 @@ except:  if result is not None:      with open(keyfile, "wb") as f: -	f.write(result) +        f.write(result)  else:      pass -#+end_src +#+END_SRC  *** Exporting secret keys @@ -657,7 +656,7 @@ 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 -i +#+BEGIN_SRC python -i  import gpg  import os  import os.path @@ -690,9 +689,9 @@ else:  if homedir.startswith("~"):      if os.path.exists(os.path.expanduser(homedir)) is True: -	c.home_dir = os.path.expanduser(homedir) +        c.home_dir = os.path.expanduser(homedir)      else: -	pass +        pass  elif os.path.exists(homedir) is True:      c.home_dir = homedir  else: @@ -705,11 +704,11 @@ except:  if result is not None:      with open(keyfile, "wb") as f: -	f.write(result) +        f.write(result)      os.chmod(keyfile, 0o600)  else:      pass -#+end_src +#+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 @@ -718,7 +717,7 @@ 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 -i +#+BEGIN_SRC python -i  import gpg  import os  import os.path @@ -760,9 +759,9 @@ else:  if homedir.startswith("~"):      if os.path.exists(os.path.expanduser(homedir)) is True: -	c.home_dir = os.path.expanduser(homedir) +        c.home_dir = os.path.expanduser(homedir)      else: -	pass +        pass  elif os.path.exists(homedir) is True:      c.home_dir = homedir  else: @@ -770,16 +769,16 @@ else:  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) +        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) +        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"] +        hd = os.environ["GNUPGHOME"]      else: -	hd = subprocess.getoutput(gpgconfcmd) +        hd = subprocess.getoutput(gpgconfcmd)      gpgfile = "{0}/{1}.gpg".format(hd, keyfile)      ascfile = "{0}/{1}.asc".format(hd, keyfile) @@ -792,18 +791,18 @@ except:  if a_result is not None:      with open(ascfile, "wb") as f: -	f.write(a_result) +        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) +        f.write(b_result)      os.chmod(gpgfile, 0o600)  else:      pass -#+end_src +#+END_SRC  * Basic Functions @@ -850,7 +849,7 @@ 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 -i +#+BEGIN_SRC python -i  import gpg  a_key = "0x12345678DEADBEEF" @@ -867,14 +866,14 @@ ciphertext, result, sign_result = c.encrypt(text, recipients=rkey, sign=False)  with open("secret_plans.txt.asc", "wb") as afile:      afile.write(ciphertext) -#+end_src +#+END_SRC  Though this is even more likely to be used like this; with the  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 -i +#+BEGIN_SRC python -i  import gpg  a_key = "0x12345678DEADBEEF" @@ -885,12 +884,12 @@ with open("secret_plans.txt", "rb") as afile:  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) +                                            always_trust=True, +                                            add_encrypt_to=True)  with open("secret_plans.txt.asc", "wb") as afile:      afile.write(ciphertext) -#+end_src +#+END_SRC  If the =recipients= paramater is empty then the plaintext is encrypted  symmetrically.  If no =passphrase= is supplied as a parameter or via a @@ -911,7 +910,7 @@ 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 -i +#+BEGIN_SRC python -i  import gpg  text = b"""Oh look, another test message. @@ -933,24 +932,24 @@ logrus = []  for i in range(len(rpattern)):      if rpattern[i].can_encrypt == 1: -	logrus.append(rpattern[i]) +        logrus.append(rpattern[i])  ciphertext, result, sign_result = c.encrypt(text, recipients=logrus, -					    sign=False, always_trust=True) +                                            sign=False, always_trust=True)  with open("secret_plans.txt.asc", "wb") as afile:      afile.write(ciphertext) -#+end_src +#+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 -i +#+BEGIN_SRC python -i  ciphertext, result, sign_result = c.encrypt(text, recipients=logrus, -					    always_trust=True, -					    add_encrypt_to=True) -#+end_src +                                            always_trust=True, +                                            add_encrypt_to=True) +#+END_SRC  The only keyword arguments requiring modification are those for which  the default values are changing.  The default value of =sign= is @@ -962,7 +961,7 @@ 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 -i +#+BEGIN_SRC python -i  import gpg  with open("secret_plans.txt.asc", "rb") as afile: @@ -974,27 +973,27 @@ logrus = []  for i in range(len(rpattern)):      if rpattern[i].can_encrypt == 1: -	logrus.append(rpattern[i]) +        logrus.append(rpattern[i])      try: -	ciphertext, result, sign_result = c.encrypt(text, recipients=logrus, -						    add_encrypt_to=True) +        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 +        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  invalid recipients if it fails and try again. @@ -1014,7 +1013,7 @@ 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 -i +#+BEGIN_SRC python -i  import gpg  ciphertext = input("Enter path and filename of encrypted file: ") @@ -1022,17 +1021,17 @@ 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) +        plaintext, result, verify_result = gpg.Context().decrypt(cfile)      except gpg.errors.GPGMEError as e: -	plaintext = None -	print(e) +        plaintext = None +        print(e) -    if plaintext is not None: -	with open(newfile, "wb") as nfile: +if plaintext is not None: +    with open(newfile, "wb") as nfile:  	    nfile.write(plaintext)      else: -	pass -#+end_src +        pass +#+END_SRC  The data available in =plaintext= in this example is the decrypted  content as a byte object, the recipient key IDs and algorithms in @@ -1059,13 +1058,13 @@ 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 -i +#+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) -#+end_src +#+END_SRC  The signing examples in the following sections include the explicitly  designated =signers= parameter in two of the five examples; once where @@ -1100,7 +1099,7 @@ 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 -i +#+BEGIN_SRC python -i  import gpg  text0 = """Declaration of ... something. @@ -1113,14 +1112,14 @@ 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()) -#+end_src +#+END_SRC  Though everything in this example is accurate, it is more likely that  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 -i +#+BEGIN_SRC python -i  import gpg  with open("/path/to/statement.txt", "rb") as tfile: @@ -1131,7 +1130,7 @@ 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) -#+end_src +#+END_SRC  *** Detached signing messages and files @@ -1143,7 +1142,7 @@ 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 -i +#+BEGIN_SRC python -i  import gpg  text0 = """Declaration of ... something. @@ -1156,12 +1155,12 @@ 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()) -#+end_src +#+END_SRC  As with normal signatures, detached signatures are best handled as  byte literals, even when the output is ASCII armoured. -#+begin_src python -i +#+BEGIN_SRC python -i  import gpg  with open("/path/to/statement.txt", "rb") as tfile: @@ -1172,7 +1171,7 @@ 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) -#+end_src +#+END_SRC  *** Clearsigning messages or text @@ -1184,7 +1183,7 @@ 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 -i +#+BEGIN_SRC python -i  import gpg  text0 = """Declaration of ... something. @@ -1197,12 +1196,12 @@ 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()) -#+end_src +#+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 -i +#+BEGIN_SRC python -i  import gpg  with open("/path/to/statement.txt", "rb") as tfile: @@ -1213,7 +1212,7 @@ 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) -#+end_src +#+END_SRC  ** Signature verification @@ -1229,7 +1228,7 @@ 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 -i +#+BEGIN_SRC python -i  import gpg  import time @@ -1247,21 +1246,21 @@ except gpg.errors.BadSignatures as e:  if verified is True:      for i in range(len(result.signatures)): -	sign = result.signatures[i] -	print("""Good signature from: +        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))) +           time.ctime(sign.timestamp)))  else:      pass -#+end_src +#+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 -i +#+BEGIN_SRC python -i  import gpg  import time @@ -1279,22 +1278,22 @@ except gpg.errors.BadSignatures as e:  if verified is True:      for i in range(len(result.signatures)): -	sign = result.signatures[i] -	print("""Good signature from: +        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))) +           time.ctime(sign.timestamp)))  else:      pass -#+end_src +#+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 -i +#+BEGIN_SRC python -i  with open(filename, "rb") as afile:      text = afile.read() @@ -1302,7 +1301,7 @@ if text == data:      print("Good signature.")  else:      pass -#+end_src +#+END_SRC  The following two examples, however, deal with detached signatures.  With his method of verification the data that was signed does not get @@ -1310,7 +1309,7 @@ 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 -i +#+BEGIN_SRC python -i  import gpg  import time @@ -1328,18 +1327,18 @@ except gpg.errors.BadSignatures as e:  if verified is True:      for i in range(len(result.signatures)): -	sign = result.signatures[i] -	print("""Good signature from: +        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))) +           time.ctime(sign.timestamp)))  else:      pass -#+end_src +#+END_SRC -#+begin_src python -i +#+BEGIN_SRC python -i  import gpg  import time @@ -1357,16 +1356,16 @@ except gpg.errors.BadSignatures as e:  if verified is True:      for i in range(len(result.signatures)): -	sign = result.signatures[i] -	print("""Good signature from: +        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))) +           time.ctime(sign.timestamp)))  else:      pass -#+end_src +#+END_SRC  * Creating keys and subkeys @@ -1387,7 +1386,7 @@ clearance, so his keys will be 3072-bit keys.  The pre-configured =gpg.conf= file which sets cipher, digest and other  preferences contains the following configuration parameters: -#+begin_src conf +#+BEGIN_SRC conf    expert    allow-freeform-uid    allow-secret-key-import @@ -1400,7 +1399,7 @@ preferences contains the following configuration parameters:    personal-cipher-preferences TWOFISH CAMELLIA256 AES256 CAMELLIA192 AES192 CAMELLIA128 AES BLOWFISH IDEA CAST5 3DES    personal-digest-preferences SHA512 SHA384 SHA256 SHA224 RIPEMD160 SHA1    personal-compress-preferences ZLIB BZIP2 ZIP Uncompressed -#+end_src +#+END_SRC  ** Primary key @@ -1423,7 +1422,7 @@ 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 -i +#+BEGIN_SRC python -i  import gpg  c = gpg.Context() @@ -1432,8 +1431,8 @@ c.home_dir = "~/.gnupg-dm"  userid = "Danger Mouse <[email protected]>"  dmkey = c.create_key(userid, algorithm="rsa3072", expires_in=31536000, -		     sign=True, certify=True) -#+end_src +                     sign=True, certify=True) +#+END_SRC  One thing to note here is the use of setting the =c.home_dir=  parameter.  This enables generating the key or keys in a different @@ -1451,22 +1450,22 @@ 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 -i +#+BEGIN_SRC python -i  print(""" -   Fingerprint:  {0} -   Primary Key:  {1} -    Public Key:  {2} -    Secret Key:  {3} -   Sub Key:  {4} -  User IDs:  {5} -   """.format(dmkey.fpr, dmkey.primary, dmkey.pubkey, dmkey.seckey, dmkey.sub, -	      dmkey.uid)) -#+end_src + Fingerprint:  {0} + Primary Key:  {1} +  Public Key:  {2} +  Secret Key:  {3} + Sub Key:  {4} +User IDs:  {5} +""".format(dmkey.fpr, dmkey.primary, dmkey.pubkey, dmkey.seckey, dmkey.sub, +           dmkey.uid)) +#+END_SRC  Alternatively the information can be confirmed using the command line  program: -#+begin_src shell +#+BEGIN_SRC shell    bash-4.4$ gpg --homedir ~/.gnupg-dm -K    ~/.gnupg-dm/pubring.kbx    ---------------------- @@ -1475,7 +1474,7 @@ program:    uid           [ultimate] Danger Mouse <[email protected]>    bash-4.4$ -#+end_src +#+END_SRC  As with generating keys manually, to preconfigure expanded preferences  for the cipher, digest and compression algorithms, the =gpg.conf= file @@ -1483,7 +1482,7 @@ must contain those details in the home directory in which the new key  is being generated.  I used a cut down version of my own =gpg.conf=  file in order to be able to generate this: -#+begin_src shell +#+BEGIN_SRC shell    bash-4.4$ gpg --homedir ~/.gnupg-dm --edit-key 177B7C25DB99745EE2EE13ED026D2F19E99E63AA showpref quit    Secret key is available. @@ -1499,7 +1498,7 @@ file in order to be able to generate this:         Features: MDC, Keyserver no-modify    bash-4.4$ -#+end_src +#+END_SRC  ** Subkeys @@ -1518,7 +1517,7 @@ 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 -i +#+BEGIN_SRC python -i  import gpg  c = gpg.Context() @@ -1526,26 +1525,26 @@ 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) -#+end_src +                        encrypt=True) +#+END_SRC  As with the primary key, the results here can be checked with: -#+begin_src python -i +#+BEGIN_SRC python -i  print(""" -   Fingerprint:  {0} -   Primary Key:  {1} -    Public Key:  {2} -    Secret Key:  {3} -   Sub Key:  {4} -  User IDs:  {5} -   """.format(dmsub.fpr, dmsub.primary, dmsub.pubkey, dmsub.seckey, dmsub.sub, -	      dmsub.uid)) -#+end_src + Fingerprint:  {0} + Primary Key:  {1} +  Public Key:  {2} +  Secret Key:  {3} + Sub Key:  {4} +User IDs:  {5} +""".format(dmsub.fpr, dmsub.primary, dmsub.pubkey, dmsub.seckey, dmsub.sub, +           dmsub.uid)) +#+END_SRC  As well as on the command line with: -#+begin_src shell +#+BEGIN_SRC shell    bash-4.4$ gpg --homedir ~/.gnupg-dm -K    ~/.gnupg-dm/pubring.kbx    ---------------------- @@ -1555,7 +1554,7 @@ As well as on the command line with:    ssb   rsa3072 2018-03-15 [E] [expires: 2018-09-13]    bash-4.4$ -#+end_src +#+END_SRC  ** User IDs @@ -1574,7 +1573,7 @@ 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 -i +#+BEGIN_SRC python -i  import gpg  c = gpg.Context() @@ -1585,11 +1584,11 @@ key = c.get_key(dmfpr, secret=True)  uid = "Danger Mouse <[email protected]>"  c.key_add_uid(key, uid) -#+end_src +#+END_SRC  Unsurprisingly the result of this is: -#+begin_src shell +#+BEGIN_SRC shell    bash-4.4$ gpg --homedir ~/.gnupg-dm -K    ~/.gnupg-dm/pubring.kbx    ---------------------- @@ -1600,7 +1599,7 @@ Unsurprisingly the result of this is:    ssb   rsa3072 2018-03-15 [E] [expires: 2018-09-13]    bash-4.4$ -#+end_src +#+END_SRC  *** Revokinging User IDs @@ -1611,7 +1610,7 @@ 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 -i +#+BEGIN_SRC python -i  import gpg  c = gpg.Context() @@ -1622,7 +1621,7 @@ key = c.get_key(dmfpr, secret=True)  uid = "Danger Mouse <[email protected]>"  c.key_revoke_uid(key, uid) -#+end_src +#+END_SRC  ** Key certification @@ -1651,7 +1650,7 @@ 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 -i +#+BEGIN_SRC python -i  import gpg  c = gpg.Context() @@ -1660,7 +1659,7 @@ uid = "Danger Mouse <[email protected]>"  dmfpr = "177B7C25DB99745EE2EE13ED026D2F19E99E63AA"  key = c.get_key(dmfpr, secret=True)  c.key_sign(key, uids=uid, expires_in=2764800) -#+end_src +#+END_SRC  * Miscellaneous work-arounds @@ -1682,16 +1681,16 @@ MUAs readily.  The following code, however, provides a work-around for obtaining this  information in Python. -#+begin_src python -i +#+BEGIN_SRC python -i  import subprocess  lines = subprocess.getoutput("gpgconf --list-options gpg").splitlines()  for i in range(len(lines)):      if lines[i].startswith("group") is True: -	line = lines[i] +        line = lines[i]      else: -	pass +        pass  groups = line.split(":")[-1].replace('"', '').split(',') @@ -1704,7 +1703,7 @@ for i in range(len(groups)):  for i in range(len(group_lists)):      group_lists[i][1] = group_lists[i][1].split() -#+end_src +#+END_SRC  The result of that code is that =group_lines= is a list of lists where  =group_lines[i][0]= is the name of the group and =group_lines[i][1]= | 
