[Mimedefang] PGP encyption of outging email

Gary Funck gary at intrepid.com
Thu May 28 00:51:14 EDT 2009


On 05/06/09 12:52:59, Pete wrote:
> Is there a method for encrypting outgoing email using PGP (or other
> methods). I am thinking of doing this on a per recipient basis. I.e encrypt
> email to people I regularly email and leave plain the rest. 
> 
> Any suggestions or ideas welcome. 

Something that I've done in the past is to set up a Mailman
mailing list and to then direct secure email via that
mailing list.  A public/private key pair is created for
each secure mailing list; this key pair is distributed
to the mailing list recipients.  List members configure
their mail client to encrypt mail sent to the list with
the private key, and to decode with the public key.

A more general purpose method is described here:
"The Secure List Server: an OpenPGP and S/MIME aware Mailman"
http://non-gnu.uvt.nl/mailman-pgp-smime/

Attached, is a Perl script that I use, that is called
via procmail that decodes PGP-encrypted attachments; it
is derived from mgpg-test, part of the Mail::GPG package.
The script handles most commonly occurring PGP attachments.
You'll note that it looks for a passphrase that is read
from a file in the user's home directory.
(You wouldn't want to use this method for extremely
confidential/secure mail.)

-------------- next part --------------
#!/usr/bin/perl -w
#
# derived from mgpg-test, part of the Mail::GPG package
#
use strict;
use lib 'lib';
use Mail::GPG;
use Mail::Address;
use MIME::Parser;
use MIME::Entity;
use MIME::Head;
use MIME::Body;
use Getopt::Std;
use Socket;
use Net::Domain qw(hostname hostfqdn hostdomain);


sub decrypt_part ($)
{
  my $entity_ref = shift;
  my $entity = $$entity_ref;
  my $mg = Mail::GPG->new ();
  # mail is encrypted, ask Mail::GPG for the
  # key to decrypt this mail
  my ($key_id, $key_mail) = $mg->get_decrypt_key (entity => $entity);
  return 0 if !defined $key_id;
  my ($addr) = Mail::Address->parse($key_mail);
  return 0 if !defined $addr;
  my $uid = $addr->user;
  return 0 if !defined $uid;
  # obtain passphrase from file.
  my $home = $ENV{'HOME'} || '~';
  my $passfile = "$home/.gnupg/passphrase-${uid}.txt";
  my $passphrase;
  open (PASSPHRASE, "<$passfile") || return 0;
  chomp ( $passphrase = <PASSPHRASE> );
  close (PASSPHRASE);
  # decode the mail
  my ($decrypted, $result) = eval { $mg->decrypt (entity     => $entity,
		                                  passphrase => $passphrase) };
  return 0 if $@;
  $$entity_ref = $decrypted;
  return 1;
}

sub decrypt_msg ($);
sub decrypt_msg ($)
{
  my $entity_ref = shift;
  my $entity = $$entity_ref;
  my $decrypted = 0;
  my $mg = Mail::GPG->new ();
  if ( $mg->is_encrypted ( entity => $entity ) )
    {
      $decrypted = decrypt_part ($entity_ref);
      $entity = $$entity_ref;
      my $body = $entity->bodyhandle;
      if ($body) {
        my $btext = $body->as_string;
        if ($btext =~ /^[[:print:][:space:]]*$/)
          {
            # remove spurious <cr><lf>'s
            if ($btext =~ s/\r\n/\n/g)
	      {
	        my $B = $body->open("w") || return 0;
		$B->print($btext);
		$B->close;
	      }
	    $entity->effective_type('plain/text');
          }
      }
    }
  elsif ($entity->parts)
    {
      my @new_parts;
      for my $p ($entity->parts)
	{
	  $decrypted |= decrypt_msg (\$p);
          push @new_parts, $p;
        }
      $entity->parts (\@new_parts) if $decrypted;
    }
  return $decrypted;
}

$| = 1;

#  for debugging;
open (STDIN, "<test-pgp-mail.txt") || die "open failed" if $^P;

my $msg;

{
  local $/;
  $msg = <STDIN>; # slurp
}


my $entity = Mail::GPG->parse ( mail_sref => \$msg );

exit 2 if !decrypt_msg (\$entity);

# remove temp. files created by MIME::Entity
$entity->purge;

# Dump the decoded message
my ($from_line) = ($msg =~ /^(From [^\n]*)/);
print "$from_line\n" if defined $from_line;

my $host = hostfqdn();
my $ip_addr = inet_ntoa( scalar gethostbyname( $host || 'localhost' ));

my $head = $entity->head;
my $old_content_type = $head->get('Old-Content-Type');
if ($old_content_type)
  {
    $head->replace('Content-Type', $old_content_type);
    $head->delete('Old-Content-Type');
  }
$head->replace('X-GPG-Decrypt:', "Decrypted on host $ip_addr at " . scalar localtime);

$entity->print(\*STDOUT);


More information about the MIMEDefang mailing list