Mail::SpamCannibal::GoodPrivacy - PGP for spamcannibal mail


Mail-SpamCannibal documentation Contained in the Mail-SpamCannibal distribution.

Index


Code Index:

NAME

Top

  Mail::SpamCannibal::GoodPrivacy - PGP for spamcannibal mail

SYNOPSIS

Top

  use Mail::SpamCannibal::GoodPrivacy;

  $plaintext = decrypt(\$hash);
	or	-- defaults shown
  $plaintext = decrypt(
	Data	  => $data,
	ExeFile	  => '/usr/local/bin/pgp',
	KeyPath	  => '.pgp',
	Password  => 'sometext',
	UserID	  => 'default userid',
	Version	  => '2.62',
  );

  ($begin,$end) = is_pgp(\@lines,\$err);
  $nullchar = whiteclean(\@array);
  $outstrng = whiteclean($instring);

DESCRIPTION

Top

Mail::SpamCannibal::GoodPrivacy is a standardized wrapper around 'pgp2x', 'pgp6x', or 'gnupg' that provides encryption and decryption for IPTable::IPv4::DBTables::SpamCannibal.

Mail::SpamCannibal::GoodPrivacy has been tested using pgp-2.6.2g, pgp-6.5.8, and gpg-1.2.2 on RSA keys generated by pgp-2.6.2g which are included with this distribution.

Utilities to verify that a message has PGP encrypted content prior to decryption so that plain text messages are not inadvertently passed to the decrypt program;

$plaintext = decrypt(\$hash);
  Decrypt an encoded message.

  input:	a hash or hash pointer
  return:	plaintext or '' on error

  %hash = (
	Data	  => $data,
	ExeFile	  => '/usr/local/bin/gpg',
	KeyPath	  => './',
	Password  => 'sometext',
	UserID	  => '',
	Version	  => '',
  );

    Data:	data to decrypt

    ExeFile:	location of executable
	i.e.	/usr/local/bin/pgp
		/usr/local/bin/gpg

	WARNING: use appropriate default
		 keyring names.

    KeyPath:    directory for keyrings

    Password:	password for decryption

    UserID:	Optional default user for decryption.

		The user 'name' or keyID

	i.e. 	'test' or

		E56C91B9 as displayed by
		pgp -kv ./keyrings/secring.pgp
		  or
		ENVGPGHOME=./keyrings gpg --list-secret-keys

    Version:	Version compliance (gpg only)
		(none) for standard gpg,
		2.6x and 6.x for pgp support

($begin,$end) = is_pgp(\@lines,\$err);

Test an array of lines to determine if they represent a valid PGP encrypted message.

  input:	pointer to array of lines,
		[optional] pointer to 
		error return string

  returns:	() empty array on failure
    or	begin = pointer to -----BEGIN PGP
	end   = pointer to -----END
    for the input array

    $err will contain and empty string
	on success or a text message
	indicating the failure reason

	not an array ref
	signed cleartext
	no BEGIN PGP
	no blank line
	no armor text
	invalid armor
	no END

  i.e.	if (@_ = is_pgp(\@lines)) {
	  ($begin,$end) = @_;
	} else {
	  # sorry, not a PGP message
	}

$nullchar = whiteclean(\@array);

See below:

$outstrng = whiteclean($string);

Cleans trailing whitespace from a text string or an array of text lines.

If the input is an array pointer to an array of text lines, cleans the lines of trailing whitespace in place.

If the input is a string, returns a string with trailing whitespace removed.

  input:	array pointer
	   or	string
  returns:	'' if input = ARRAY
		$outstring
	   if the input was a string

DEPENDENCIES

Top

  Mail::SpamCannibal::ParseMessage
	and
  You must install at least one of the following
  on your system to use this module.

PGP
  Recommend versions of freeware from:
  http://www.pl.pgpi.org/versions/freeware.shtml

  in the US:	PGP 2.6.2g, the "rebel" version
  ftp://sunsite.smc.univie.ac.at/pub/crypto/cypherpunks/pgp/pgp262/pgp262g.zip

  outside US:	PGP 2.6.3i
  http://www.pgpi.org/
  i.e. pgp263is.tar.gz + pgp263i.patch
	or
  outside US:	PGP 6.5.8
  http://www.pgpi.org/
  i.e. 'pgpsrc658unix-gnu.tar.gz',
	PGPcmdln_6.5.8.Lnx_FW.tar.gz,
    or	PGPcmdln_6.5.8.Lnx_FW.rpm.tar

  2.6.2 rebel was the default used to 
  develop this module.

GnuPG
  http://www.gnupg.org/

If you plan to user PGP 2.6x or 6.x compatibility modes and you are in a country where there are not patent restrictions, then you will also need to download:

  ftp://ftp.gnupg.dk/pub/contrib-dk/idea.c.gz

and place it in the SRC/gnupg-1.x.x/cipher directory.

NOTE: in all cases the default key file required.
	PGP 2.6.x	pubring.pgp, secring.pgp
	PGP 6.5.8	pubring.pkr, secring.skr
	GnuPG		pubring.gpg, secring.gpg

EXPORT_OK

Top

        decrypt
        is_pgp
        whiteclean

AUTHOR

Top

Michael Robinton <michael@bizsystems.com>

COPYRIGHT

Top

SEE ALSO

Top

perl(1)


Mail-SpamCannibal documentation Contained in the Mail-SpamCannibal distribution.
#!/usr/bin/perl
package Mail::SpamCannibal::GoodPrivacy;
use strict;
#use diagnostics;
use vars qw($VERSION @ISA @EXPORT_OK);

$VERSION = do { my @r = (q$Revision: 0.03 $ =~ /\d+/g); sprintf "%d."."%02d" x $#r, @r };

use Mail::SpamCannibal::ParseMessage qw(
	array2string
	string2array
);
require Exporter;
@ISA = qw(Exporter);
@EXPORT_OK = qw(
	decrypt
	is_pgp
	whiteclean
);

## test the input array

sub _testme {
  my $me = shift;
  # Data
  die "No data present\n"
	unless exists $me->{Data} && $me->{Data};

  # ExeFile
  die "PGP exe file missing or not executable by effective UID\n"
	unless exists $me->{ExeFile} && $me->{ExeFile} &&
	-e $me->{ExeFile} && -x $me->{ExeFile};

  # KeyPath
  $_ = $me->{KeyPath} || './';
  if ($_ eq '.') {
    $_ = './';
  } elsif ($_ ne './' && $_ ne '/') {
    chop $_ if $_ =~ m|/$|;
    $_ = './'.$_ unless $_ =~ m|^\.*/|;
  }
  die "Key path $_ does not exist\n"
	unless -d $_;
  $me->{KeyPath} = $_;

  # UserID
  $me->{UserID} = '' unless $me->{UserID};

  # Password
  $me->{Password} = '' unless $me->{Password};

  # Version
  $me->{Version} = '' unless $me->{Version};
}

sub decrypt {
  my $me = $_[0];
  return '' unless $me;
  $me = {@_} if @_ > 1;
  _testme($me);

  my $data = '';
  my $pgpcmd = '|'. $me->{ExeFile};
  $pgpcmd .= ' -u '. $me->{UserID} if $me->{UserID};
    
  if ($pgpcmd =~ m|/pgp[^/]*$|) {
    $pgpcmd .= ' -f +batchmode +force 2>/dev/null';
    $ENV{PGPPATH} = $me->{KeyPath};
    $ENV{PGPPASS} = $me->{Password};
  }
  elsif( $pgpcmd =~ m|/gpg[^/]*$|) {
    $data .= $me->{Password}."\n";
    $pgpcmd .= ' --pgp2' if $me->{Version} =~ /^2\./;
    $pgpcmd .= ' --pgp6' if $me->{Version} =~ /^6\./;
    $pgpcmd .= ' --decrypt --batch --passphrase-fd 0 2>/dev/null';
    $ENV{GNUPGHOME} = $me->{KeyPath};
  }
  else {
    die "could not find pgp or gpg executable\n";
  }

  $data .= $me->{Data};

  my $rv = '';
  my $pid = open(FROMCHILD, '-|');
  if($pid) {
    local $/;
    $rv = <FROMCHILD>;
    close FROMCHILD || ($rv = '');	# kid exited

  } else {	# child

    open(PGP,$pgpcmd) or die "could not exec pgpcmd\n";
    $|++;
    print PGP $data;
    close PGP;
    exit;
  }
  waitpid $pid,0;

  $ENV{PGPPASS} = '';
  return $rv;
}

#
# 1) find a begin statement:	-----BEGIN PGP
# 2) that is not clear signed:	-----BEGIN PGP SIGN
# 3) ignore any number lines:	comment (not case sensitive)
#    starting like this		version (not case sensitive
# 4) find one and only one:	(blank line)
# 5) find 1 or more rad64:	lines
# 6) find and end statement:	-----END

sub is_pgp {
  my($ap,$ep) = @_;
  if (ref $ep) {
    $$ep = '';
  } else {
    undef $ep;
  }
  unless (ref $ap) {
    $$ep = 'not an array ref' if $ep;
    return ();
  }
  my $TOPMSG	= '-----BEGIN PGP';		# beginning of PGP
  my $SIGMSG	= $TOPMSG . ' SIGNED';	# clear signed
  my $notRAD64	= "[^a-zA-Z0-9/\+\=]";
  my $END	= '-----END';

  my $noblank = 1;
  my $noarmor = 1;
  my $ptr;
  foreach(0..$#{$ap}) {
    unless (defined $ptr) {			# begin found??
      next unless $ap->[$_] =~ /$TOPMSG/o;
# if SIGNED message found, this is cleartext, punt!
      if ($ap->[$_] =~ /$SIGMSG/o) {
	$ptr = -1;
	last;
      }
      $ptr = $_;		# defined, pointer to message start
    }
    elsif ($noblank) {				# drop comments, check for 1 blank line
      next if	$ap->[$_] =~ /^comment/i ||
		$ap->[$_] =~ /^version/i;	# skip comments
      last if $ap->[$_] =~ /\S/;		# PUNT, not blank line
      $noblank = undef;
    }
    elsif ($noarmor) {				# must find ascii armor
      last if $ap->[$_] !~ /\S/ ||
	      $ap->[$_] =~ m|$notRAD64|o ;	# PUNT, not ascii armor
      $noarmor = 0;
    } else {					# searching for end
      return ($ptr,$_)
	if $ap->[$_] =~ /^$END/o;		# FOUND end, GOOD exit
      if ($ap->[$_] !~ /\S/ ||
	  $ap->[$_] =~ m|$notRAD64|o) {		# PUNT, not ascii armor;
	$noarmor = 2;
	last;
      }
    }
  }
  if ($ep) {
    unless (defined $ptr) {
      $$ep = 'no BEGIN';
    } elsif ($ptr < 0) {
      $$ep = 'signed cleartext';
    } elsif ($noblank) {
      $$ep = 'no blank line';
    } elsif ($noarmor == 1) {
      $$ep = 'no armor text'
    } elsif ($noarmor == 2) {
      $$ep = 'invalid armor'
    } else {
      $$ep = 'no END';
    }
  }
  return ();					# did not find PGP message
}

sub _whiteAcln {
  my $ap = shift;
  foreach(0..$#{$ap}) {
    $ap->[$_] =~ s/\s+$//g;
  }
}

sub whiteclean($) {
  my $thing = shift;
  my $rv = '';
  if (ref $thing eq 'ARRAY') {
    _whiteAcln($thing);
    return '';
  }
  @_ = split(/\n/,$thing);
  _whiteAcln(\@_);
  array2string(\@_);
}

1;
__END__

1;