From 67a847605769d5e255168a65d780594383569b75 Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Sat, 2 Nov 2019 01:28:24 -0400 Subject: email-print-mime-structure: add decryption capability MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- debian/control | 1 + email-print-mime-structure | 34 ++++++++++++++++++++++++++++++++++ email-print-mime-structure.1.pod | 8 ++++++++ 3 files changed, 43 insertions(+) diff --git a/debian/control b/debian/control index 6d3a54f..fc2bccc 100644 --- a/debian/control +++ b/debian/control @@ -39,6 +39,7 @@ Recommends: devscripts, git, notmuch, + python3-pgpy, Architecture: all Description: collection of scripts for manipulating e-mail on Debian This package provides a collection of scripts for manipulating e-mail 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) diff --git a/email-print-mime-structure.1.pod b/email-print-mime-structure.1.pod index 03a8e29..209c725 100644 --- a/email-print-mime-structure.1.pod +++ b/email-print-mime-structure.1.pod @@ -21,6 +21,14 @@ something like "cat -n". =over 4 +=item B<--pgpkey=>I + +I should name an OpenPGP transferable secret key that is not +password-protected. If a PGP/MIME-encrypted message is found on +standard input, this key will be tried for decryption. May be used +multiple times if you want to try decrypting with more than one secret +key. + =item B<--help>, B<-h> Show usage instructions. -- cgit v1.2.3