#!/usr/bin/perl #Pine Privacy Guard - A Pine filter to GPG for handling email securely. #Copyright (C) 2001 Matt Pulver # #This program is free software; you can redistribute it and/or modify it #under the terms of the GNU General Public License as published by the #Free Software Foundation; either version 2 of the License, or (at your #option) any later version. # #This program is distributed in the hope that it will be useful, but #WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY #or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License #for more details. # #You should have received a copy of the GNU General Public License along #with this program; if not, write to: # Free Software Foundation, Inc., # 59 Temple Place - Suite 330 # Boston, MA 02111-1307, USA die "Pine Privacy Guard 1.02\n" unless @ARGV; ########################### # Set full paths to files # ########################### $cp = '/bin/cp'; $gpg = '/usr/bin/gpg'; $null = '/dev/null'; $stty = '/bin/stty'; $TTY = '/dev/tty'; $ALIASES = "$ENV{HOME}/.pinepg_aliases"; #Set to nonzero to prefix lines beginning with "From" with a ">" # so that some email transporters don't alter the email body of # clear-signed messages. $prefix_From = 1; $comment = 'For info see http://quantumlab.net/pine_privacy_guard/'; $fake_length = 255; #length of padded phrase use IPC::Open2; ########################################## # Determine what to do based on filename # ########################################## $_ = __FILE__; s/^.*?(\w+)$/$1/; if( /clearsign/ ) { ($resultfile,$datafile) = @ARGV; $command = "$gpg --clearsign ".($comment?"--comment \"$comment\" ":''). "--passphrase-fd 0 2> $resultfile"; } elsif( /decrypt/ ) { ($resultfile,$datafile) = @ARGV; $command = "$gpg --decrypt --passphrase-fd 0 2> $resultfile"; } elsif( /encrypt/ ) { $datafile = pop; $resultfile = pop; if( open ALIASES ) { /\w/ && !/^#/ && push @userids, split /\s+/, $_, 2 while ; close ALIASES; } %userids = @userids; $command = "$gpg --encrypt ".($comment?"--comment \"$comment\" ":''). "--armor --sign --passphrase-fd 0 "; for(@ARGV) { $_ = $userids{$_} if $userids{$_}; $command .= "--recipient $_ " for split; } $command .= "2> $resultfile"; } elsif( /verify/ ) { ($tmpfile,$resultfile) = @ARGV; system "$gpg --verify $tmpfile 2> $resultfile"; exit; } else { die 'Incorrect call to '.__FILE__.".\n"; } ########################################################################### # Get passphrase either from user, or _DATAFILE_ if it is of nonzero size # ########################################################################### $sessionkey = 'pine_privacy_guard'.; chomp $sessionkey; if( -z $datafile ) { ################################ # Get passphrase from the user # ################################ system "$stty -echo < $TTY"; print STDERR 'Passphrase: '; open TTY or die "Couldn't open $TTY: $!"; $passphrase = ; chomp $passphrase; close TTY or die "Couldn't close $TTY: $!"; print STDERR "\n"; system "$stty echo < $TTY"; ########################################################## # Pad passphrase with random bytes, encrypt and store it # ########################################################## $padded_phrase = $passphrase; $padded_phrase .= chr int rand 256 while length $padded_phrase<$fake_length; open GPG, "| $gpg --symmetric --batch --yes --passphrase-fd 0 ". "--output $datafile" or die "Couldn't write to $datafile: $!"; print GPG "$sessionkey\n".chr(length $passphrase).$padded_phrase; close GPG or die "Couldn't close $datafile: $!"; } else { ######################################################## # Get passphrase from Pine's _DATAFILE_ and decrypt it # ######################################################## open2 \*RDR, \*WTR, $gpg, '--decrypt', '--passphrase-fd', 0, $datafile or die "Couldn't execute $gpg to retrieve stored passphrase: $!"; print WTR $sessionkey; close WTR or die "Couldn't close $gpg during passphrase retrieval: $!"; read RDR, $_, $fake_length+1; close RDR; $passphrase = substr $_, 1, ord; } ################################################## # Execute GPG for clearsign, decrypt, or encrypt # ################################################## open GPG, "| $command" or die "Couldn't pipe to $command: $!"; print GPG "$passphrase\n", $prefix_From && $command =~ / --clearsign / ? map { /^From / ? ">$_" : $_ } : ; close GPG; if( $return_value = $?>>8 ) #Hmm, an error. Let's just clear the datafile. { system $cp, '-f', $null, $datafile; chmod 0600, $datafile; } exit if $command =~ / --decrypt /; exit $return_value;