diff options
author | Daniel Kahn Gillmor <dkg@fifthhorseman.net> | 2019-11-02 01:28:24 -0400 |
---|---|---|
committer | Sean Whitton <spwhitton@spwhitton.name> | 2019-11-02 08:44:19 -0700 |
commit | 67a847605769d5e255168a65d780594383569b75 (patch) | |
tree | ffdc4362c00917605de5baf23f033be46eda3ef2 /email-print-mime-structure | |
parent | a858e19c0eb6c2a12d832b3dd256ef64c72f0fc1 (diff) | |
download | mailscripts-67a847605769d5e255168a65d780594383569b75.tar.gz |
email-print-mime-structure: add decryption capability
Add simple decryption capability for email-print-mime-structure, so
that it can do stuff like this:
$ email-print-mime-structure --pgpkey alice@openpgp.example.sec.asc < msg.eml
└┬╴multipart/encrypted 2190 bytes
├─╴application/pgp-encrypted 11 bytes
└─╴application/octet-stream 1613 bytes
↧ (decrypts to)
└─╴text/plain 425 bytes
$
At the moment, it only works with keys that can be found in the
filesystem, and when the pgpy module is installed.
Possible future work:
- try using gpg to do the decryption from whatever gpg's system
capabilities are
I've added python3-pgpy to the list of Recommends, since it is not a
hard dependency.
Signed-off-by: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
Diffstat (limited to 'email-print-mime-structure')
-rwxr-xr-x | email-print-mime-structure | 34 |
1 files changed, 34 insertions, 0 deletions
diff --git a/email-print-mime-structure b/email-print-mime-structure index 33579a7..eb513b3 100755 --- a/email-print-mime-structure +++ b/email-print-mime-structure @@ -38,6 +38,11 @@ from typing import Optional, Union, List, Tuple, Any from email.charset import Charset from email.message import Message +try: + import pgpy #type: ignore +except ImportError: + pgpy = None + class MimePrinter(object): def __init__(self, args:Namespace): self.args = args @@ -66,6 +71,33 @@ class MimePrinter(object): print(f'{prefix}{z.get_content_type()}{cset}{disposition}{fname} {nbytes:d} bytes') + if self.args.pgpkey and \ + (parent is not None) and \ + (parent.get_content_type().lower() == 'multipart/encrypted') and \ + (str(parent.get_param('protocol')).lower() == 'application/pgp-encrypted') and \ + (num == 2): + if pgpy is None: + logging.warning(f'Python module pgpy is not available, not decrypting (try "apt install python3-pgpy")') + else: + cryptopayload:Optional[Message] = None + keyname:str + for keyname in self.args.pgpkey: + try: + key:pgpy.PGPKey + key, _ = pgpy.PGPKey.from_file(keyname) + msg:pgpy.PGPMessage = pgpy.PGPMessage.from_blob(z.get_payload()) + msg = key.decrypt(msg) + cryptopayload = email.message_from_bytes(msg.message) + break + except: + pass + if cryptopayload is None: + logging.warning(f'Unable to decrypt') + else: + newprefix = prefix[:-3] + ' ' + print(f'{newprefix}↧ (decrypts to)') + self.print_tree(cryptopayload, newprefix + '└', z, 0) + def print_tree(self, z:Message, prefix:str, parent:Optional[Message], num:int) -> None: if (z.is_multipart()): self.print_part(z, prefix+'┬╴', parent, num) @@ -88,6 +120,8 @@ class MimePrinter(object): def main() -> None: parser:ArgumentParser = ArgumentParser(description='Read RFC2822 MIME message from stdin and emit a tree diagram to stdout.', epilog="Example: email-print-mime-structure < message.eml") + parser.add_argument('--pgpkey', metavar='KEYFILE', action='append', + help='OpenPGP Transferable Secret Key for decrypting') args:Namespace = parser.parse_args() msg:Union[Message, str, int, Any] = email.message_from_file(sys.stdin) |