#!/usr/local/bin/perl -s
$dmy=<<"-----BEGIN PGP SIGNED MESSAGE-----"
-----BEGIN PGP SIGNED MESSAGE-----
#!/usr/local/bin/perl -s
; # Deep in the heart of PGP, there is a reason
# for this semicolon.
# Make sure you use perl 5.000 or higher! This program won't even
# compile with a lower one.
# PGPACKET
# PGP Packet analyzer, by Mark E. Shoulson (
[email protected])
# (c) Mark E. Shoulson 1995, 1996
# Version 2.15, January 1996
# Permission is granted to distribute this program freely and make
# modifications or improvements. Please keep the name of the author on
# modified versions, AND note modifications as the products of those
# who made them. This program is signed with pgp key 0x429C07E1 and should
# run both before and after being checked with pgp.
# Please let me know if you like this program.
# This program takes any PGP output and prints out a report of each packet
# it comes across (what type, what's in it, etc). It's not going to crack
# anything or do any real work (like uncompressing or decrypting); it just
# analyzes the structure of the file.
# Version 2.0 (and above) can handle ascii-armored files as well. It does
# its level best to detect when you have an ascii-armored file (it assumes
# that if the file "looks" like text (perl's -T test), it's ascii-armored),
# and will try to skip past any junk at the beginning of the file to get to
# the real stuff. I'm not 100% sure of its ability to find the end of the
# pgp stuff, though; I'm pretty sure there's a possibility of failure.
# Just be prepared, until I fix that. For signed cleartext, it will skip
# the cleartext and analyze only the signature. Currently it will only
# handle the first chunk of PGP ascii-armor in a file. You can also force
# ascii-armor mode with the -a option.
# Actual data is generally not printed, except for N and E of public keys
# and user-ID information, unless the -v (verbose) option is given. Other
# information may be parsed out and displayed, but I don't see much reason
# for printing out the encrypted D or encrypted data. I read all the stuff
# in anyway, often wasting variables and space on it, in case you actually
# want to do anything with it.
# Use the -u option to enable looking up keyIDs in your pubring file (use
# -u=keyfile to specify an alternate file). Makes it easy to find out who
# else someone has included on the readers-list...
# -h gives a usage note.
# Some symbolic names for CTB's...
# Manifest constants would be better, but who cares?
# CTB types:
$CTB_PKE=01; # Public-Key Encrypted
$CTB_SKE=02; # Secret-Key Encypted (signature)
$CTB_SEC=05; # Secret Key Certificate
$CTB_PUB=06; # Public Key Certificate
$CTB_COMP=010; # Compressed Data
$CTB_CKE=011; # Conventional-Key Encrypted
$CTB_RAW=013; # Raw literal data, filename and mode
$CTB_TRUST=014; # Keyring Trust Packet
$CTB_UID=015; # User ID Packet
$CTB_CMT=016; # Comment Packet
sub ctb {
# Stolen from Adam Back's extract-pub, slightly modified for my
# own stylistic preferences.
my ($c,$d,$ct,$lf,$n,$len,$fh);
# This is the only EOF check in the program, aside from packets
# which read the rest of the file. So it won't be terribly
# clean with files that end in the wrong places. Cope.
if (@_) {
($fh)=@_;
}
else {
$fh="PGP";
}
return () if eof($fh);
# Get the next character, which is the CTB.
$d = getc($fh);
$c=unpack('C',$d);
# bit 7 must be set, or this is no CTB.
return (-1,$c) unless $c&0200;
$ct=$c&074;
$ct>>=2;
$lf=$c&03;
if ($lf==0){
$lf=1;
} elsif ($lf==1){
$lf=2;
} elsif ($lf==2){
$lf=4;
} elsif ($lf==3){
$lf=0;
}
if ($lf){
read($fh,$n,$lf);
$n="\0"x(4-$lf).$n;
$len=unpack('N',$n);
} else {
# This isn't really checked for in most of the handlers. Perhaps
# more of them should?
$len=0;
}
return ($ct,$len,$lf);
}
@months=("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep",
"Oct","Nov","Dec");
sub date_fmt {
my($time);
my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst);
# If I'm going to make this available, I might as well avoid
# the month-first/day-first problem. 'Course, by rights I should
# do something about the English month-names. Maybe DD MM YYYY with
# month in roman numerals (e.g. 15 VII 1993)? If you feel like it.
($time)=@_;
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=gmtime($time);
return(sprintf("%d %s %d %02d:%02d:%02d",
$mday,$months[$mon],$year+1900,$hour,$min,$sec));
}
sub data_print {
my($data,$pack);
($data,$pack)=@_;
$data=unpack('H*',$data) unless $pack;
print "Data:\t0x\U$data\E\n";
}
sub length_warn {
my($len,$str);
($len)=@_;
# Warn if length is non-zero.
return unless $len; # Check this first, since it's the usual case.
if ($len>0) {
$str="long";
}
else {
$str="short";
$len= -$len;
}
print "Warning! Length field is $len bytes too $str!\n" unless $t;
}
sub rmpi {
# read a PGP format Multi-Precision Integer
my($len,$nlen,$n,$fh);
if (@_) {
($fh)=@_;
}
else {
$fh="PGP";
}
read($fh,$len,2);$len=unpack('n',$len);
$nlen=int($len/8);
$nlen++ if $len%8;
read($fh,$n,$nlen);
return unpack('H*',$n);
}
sub findkey {
# Find a keyID in the pubring file and print out its UserID.
# For use with the -u function
my($targ,$ct,$len,$lf,$dmy,$nn,$uid);
unless (stat(PUBRING)) {
# Silently return if the file handle isn't open for
# some reason.
return "";
}
($targ)=@_;
seek PUBRING,0,0; # rewind the filehandle
while (($ct,$len,$lf)=&ctb(PUBRING)) {
unless ($ct==$CTB_PUB) {
# Eat the packet.
read(PUBRING,$dmy,$len);
next;
}
outer:
# OK, it's a public key packet. Is it the right one?
read(PUBRING,$dmy,1+4+2+1); # Skip version, timestamp, validity, alg.
$nn=&rmpi(PUBRING); # Get the N.
# It's the one we're looking for if the last 16 chars match.
# Eat the rest of the packet.
read(PUBRING,$dmy,$len-length($nn)/2-2-1-4-2-1);
next unless $nn=~/$targ$/i; # Carry on if no match.
# It's the right one. Look for a UID packet.
inner:
while (($ct,$len,$lf)=&ctb(PUBRING)) {
if ($ct==$CTB_PUB) {
# New public key. No userID, I guess.
# Start again. Have to use a goto.
goto outer;
}
unless ($ct==$CTB_UID) {
# Skip non-uid packets.
read(PUBRING,$dmy,$len);
next;
}
# At long last, found the uid!
read(PUBRING,$uid,$len);
print " User ID for above key: \"$uid\"\n";
next;
}
}
}
sub null_handler {
# Dummy handler; just skip $len bytes.
my($len,$dmy);
($len)=@_;
print "(No handler known. Skipping $len bytes)\n" unless $t;
read(PGP,$dmy,$len);
&data_print($dmy) if $v&&!$t;
}
sub comment_handler {
# Just skip $len bytes.
# Same as above, minus the message. Both are included for modularity.
my($len,$dmy);
($len)=@_;
print "$len bytes of comment.\n";
read(PGP,$dmy,$len);
print "Comment:\t$dmy\n" if $v&&!$t;
}
sub uid_handler {
my($len,$uid);
($len)=@_;
read (PGP,$uid,$len);
printf "User ID:%s\"$uid\"\n",($t?" ":"\t");
}
sub pub_handler {
my($len,$vb,$ts,$valid,$alg,$ee,$nn);
($len)=@_;
read(PGP,$vb,1); $len--; $vb=unpack('C',$vb);
read(PGP,$ts,4); $len-=4; $ts=unpack('N',$ts);
read(PGP,$valid,2); $len-=2; $valid=unpack('n',$valid);
read(PGP,$alg,1); $len--; $alg=unpack('c',$alg);
$nn=&rmpi(); $len-=length($nn)/2+2;
$ee=&rmpi(); $len-=length($ee)/2+2;
unless ($t) {
printf ("Version Byte:\t%d\n",$vb);
print "Key Created:\t".&date_fmt($ts)."\n";
print "Valid for",($valid > 0? ":\t $valid days" : "ever"),"\n";
printf("Algorithm:\t%d (%s)\n",$alg,($alg==1?"RSA":"??"));
print "N:\t0x\U$nn\E\n";
print "E:\t0x\U$ee\E\n";
&length_warn($len) if $len;
}
else {
printf "Key ID: 0x%s\n",substr("\U$nn",-16);
}
}
sub conv_handler {
my ($dmy,$len);
# Yet another "just suck 'em in" handler.
($len)=@_;
print "$len bytes of data...\n";
read(PGP,$dmy,$len);
&data_print($dmy) if $v&&!$t;
}
sub comp_handler {
my ($dmy,$len,$c);
($len)=@_;
read(PGP,$dmy,1); $len--; $dmy=unpack('C',$dmy);
printf ("Algorithm:\t%d (%s)\n",$dmy,($dmy==1?"ZIP":"??")) unless $t;
if ($len>0) {
print "$len bytes of data...\n";
read(PGP,$dmy,$len);
&data_print($dmy) if $v&&!$t;
}
else {
# Presumably runs to the end of the file.
print "And then a mess of data...\n";
print "Data:\t0x" if $v&&!$t;
while (!eof(PGP)) {
$c=getc(PGP);
if ($v&&!$t) {
$c=unpack('H2',$c);
print "\U$c\E";
}
}
print "\n" if $v&&!$t;
}
}
sub trust_handler {
my($len,$byte);
my($work,$ind);
($len)=@_;
read(PGP,$byte,$len);
$ind=''; # Indent set to null.
# Three different meanings, depending on previous packet.
# If the previous packet is neither key nor userID nor signature,
# set $ind (so we can tell later) and remark.
# If TERSE, just print a newline and get on with life.
if ($t) {
print "\n";
return;
}
if ($lastctb!=$CTB_PUB && $lastctb!=$CTB_SEC && $lastctb!=$CTB_UID &&
$lastctb!=$CTB_SKE) {
# If it's not after a permitted type, then show *all* the
# possible meanings, in a slightly different format.
print
"Corrupt file! Trust packet should follow key, userID, or sig.\n";
$ind="\t";
}
printf("Trust byte: %s\n",unpack("B8",$byte));
$byte=unpack('C',$byte);
if ($ind || $lastctb==$CTB_PUB || $lastctb==$CTB_SEC) {
print "Trust information if previous packet is key:\n" if $ind;
# If preceding packet is a KEY packet:
print "${ind}Trust of this key owner:\t";
$work=$byte&07;
if ($work==00) {
print "Undefined\n";
}
elsif ($work==01) {
print "Unknown\n";
}
elsif ($work==02) {
print "Usually do not trust to sign\n";
}
elsif ($work==03) {
print "(reserved 011)\n";
}
elsif ($work==04) {
print "(reserved 100)\n";
}
elsif ($work==05) {
print "Usually trust to sign\n";
}
elsif ($work==06) {
print "Always trust to sign\n";
}
else {
print "Present on secret ring.\n";
}
$work=$byte&040;
if ($work) {
print "${ind}DISABLED\n";
}
else {
print "${ind}Enabled\n";
}
# Other bits reserved
$work=$byte&0200;
if ($work) {
print "${ind}Ultimate Trust: Present on secret ring.\n";
}
}
# If preceding packet is UID:
if ($ind || $lastctb==$CTB_UID) {
print "Trust information if previous packet is user ID:\n" if $ind;
$work=$byte&03;
if ($work==00) {
print "${ind}Unknown if this ID belongs to associated key\n";
}
elsif ($work==01) {
print "${ind}ID not trusted to belong to associated key\n";
}
elsif ($work==02) {
print
"${ind}Marginal confidence that ID belongs to associated key\n";
}
else {
print "${ind}Complete trust that key belongs to associated ID\n";
}
# Other bits reserved
$work=$byte&0200;
if ($work) {
print "${ind}Will only warn if this key is used\n";
}
else {
print "${ind}Will warn and verify before using this key\n";
}
}
if ($ind || $lastctb==$CTB_SKE) {
# If previous packet is SIG:
print "Trust information if previous packet is signature:\n" if $ind;
print "${ind}Trust of the owner of the signing key:\t";
$work=$byte&07;
if ($work==00) {
print "Undefined\n";
}
elsif ($work==01) {
print "Unknown\n";
}
elsif ($work==02) {
print "Usually do not trust to sign\n";
}
elsif ($work==03) {
print "(reserved 011)\n";
}
elsif ($work==04) {
print "(reserved 100)\n";
}
elsif ($work==05) {
print "Usually trust to sign\n";
}
elsif ($work==06) {
print "Always trust to sign\n";
}
else {
print "Present on secret ring.\n";
}
# Other bits reserved
$work=$byte&0100;
if ($work) {
print "${ind}Key checking pass has checked this signature\n";
}
else {
print "${ind}Key checking pass does not trust this signature\n";
}
$work=$byte&0200;
if ($work) {
print
"${ind}Contiguous chain of trusted sigs to ultimate one exists\n";
}
else {
print
"${ind}No contiguous chain of trusted sigs to ultimate one exists\n";
}
}
}
sub pke_handler {
my ($len,$version,$kid,$alg,$dmy);
($len)=@_;
read(PGP,$version,1); $len--;
$version=unpack('C',$version);
read(PGP,$kid,8); $len-=8;
$kid=unpack('H*',$kid);
read(PGP,$alg,1); $len--;
$dmy=&rmpi();
printf ("Version:\t%d\n",$version) unless $t;
print "Key ID:\t0x\U$kid\E\n";
unless ($t) {
&findkey($kid) if $u;
$alg=unpack('C',$alg);
printf ("Algorithm:\t%d (%s)\n",$alg,(1==$alg ? "RSA" : "??"));
print length($dmy)/2, " bytes of data.\n";
$len-=length($dmy)/2+2; # add two bytes for length field
&data_print($dmy,1) if $v;
&length_warn($len) if $len;
}
}
sub ske_handler {
my ($len,$vb,$md5len,$class,$ts,$kid,$pkalg,$digalg,$chk,$dmy);
($len)=@_;
read(PGP,$vb,1); $len--; $vb=unpack('C',$vb);
read(PGP,$md5len,1); $len--; $md5len=unpack('C',$md5len);
read(PGP,$class,1); $len--; $class=unpack('C',$class);
printf("Version:\t%d\n",$vb) unless $t;
printf("Adding %d bytes of header to digest\n",$md5len) unless $t;
if ($class==0x0) {
print "Signature of binary document";
}
elsif ($class==0x1) {
print "Signature of canonical text document";
}
elsif ($class==0x10) {
print "Generic Key certification";
}
# Most of these are unsupported
elsif ($class==0x11) {
print "Persona Key certification (unsupported)";
}
elsif ($class==0x12) {
print "Casual ID Key certification (unsupported)";
}
elsif ($class==0x13) {
print "Positive ID Key certification (unsupported)";
}
elsif ($class==0x20) {
print "Key Compromise certificate, revoking public key";
}
elsif ($class==0x30) {
print "Key/UserID Revocation certificate (unsupported)";
}
elsif ($class==0x40) {
print "Timestamp of signature (unsupported)";
}
else {
printf("Unknown signature classification (%x)",$class);
}
read(PGP,$ts,4); $len-=4; $ts=unpack('N',$ts);
read(PGP,$kid,8); $len-=8; $kid=unpack("H*",$kid);
read(PGP,$pkalg,1); $len--; $pkalg=unpack('C',$pkalg);
read(PGP,$digalg,1); $len--; $digalg=unpack('C',$digalg);
read(PGP,$chk,2); $len-=2; $chk=unpack('H*',$chk);
$dmy=&rmpi();
unless ($t) {
print "\nSignature Created:\t".&date_fmt($ts)."\n";
print "Signing Key ID:\t0x\U$kid\E\n";
&findkey($kid) if $u;
printf("Public Key Algorithm:\t%d (%s)\n",
$pkalg,($pkalg==1?"RSA":"??"));
printf("Message Digest Algorithm:\t%d (%s)\n",
$digalg,($digalg==1?"MD5":"??"));
print "Check bytes:\t0x\U$chk\E\n";
print length($dmy)/2, " bytes of data\n";
$len-=length($dmy)/2+2; # Add two for bitcount field
&data_print($dmy,1) if $v;
&length_warn($len) if $len;
}
else {
print " (0x\U$kid\E)\n";
}
}
sub sec_handler {
my($len,$vb,$ts,$valid,$alg,$nn,$ee,$ciph,$iv,$dd,$pp,$qq,$uu,
$chksum);
($len)=@_;
read(PGP,$vb,1); $len--; $vb=unpack('C',$vb);
read(PGP,$ts,4); $len-=4; $ts=unpack('N',$ts);
read(PGP,$valid,2); $len-=2; $valid=unpack('n',$valid);
read(PGP,$alg,1); $len--; $alg=unpack('C',$alg);
$nn=&rmpi(); $len-=length($nn)/2+2;
$ee=&rmpi(); $len-=length($ee)/2+2;
read(PGP,$ciph,1); $len--; $ciph=unpack('C',$ciph);
unless ($t) {
print "Version Byte:\t$vb\n";
print "Key Created:\t".&date_fmt($ts)."\n";
printf("Valid for%s\n",($valid?"\t$valid days":"ever"));
printf("Algorithm:\t%d (%s)\n",$alg,(1==$alg?"RSA":"??"));
print "N:\t0x\U$nn\E\n";
print "E:\t0x\U$ee\E\n";
printf("Protection Algorithm:\t%d (%s)\n",$ciph,
($ciph ? (1==$ciph ? "IDEA" : "??") : "None"));
}
else {
printf "0x%s\n",substr("\U$nn",-16,16);
}
if ($ciph) {
read(PGP,$iv,8); $len-=8;
print "8 bytes of cipher feedback\n" unless $t;
}
$dd=&rmpi(); $len-=length($dd)/2+2;
$pp=&rmpi(); $len-=length($pp)/2+2;
$qq=&rmpi(); $len-=length($qq)/2+2;
$uu=&rmpi(); $len-=length($uu)/2+2;
read(PGP,$chksum,2); $len-=2; $chksum=unpack('H*',$chksum);
unless ($t) {
if ($ciph && !$v) {
printf "D: (encrypted: %d bytes)\n",length($dd)/2;
printf "P: (encrypted: %d bytes)\n",length($pp)/2;
printf "Q: (encrypted: %d bytes)\n",length($qq)/2;
printf "U: (encrypted: %d bytes)\n",length($uu)/2;
}
else {
# If there's no cipher encryption, print out P, Q, D, and U.
print "D:\t0x\U$dd\E\n";
print "P:\t0x\U$pp\E\n";
print "Q:\t0x\U$qq\E\n";
print "U:\t0x\U$uu\E\n";
}
print "Checksum:\t0x\U$chksum\E\n";
&length_warn($len) if $len;
}
}
sub raw_handler {
my($len,$mode,$namelen,$name,$ts,$data);
($len)=@_;
read(PGP,$mode,1); $len--;
read(PGP,$namelen,1); $len--; $namelen=unpack('C',$namelen);
read(PGP,$name,$namelen); $len-=$namelen;
read(PGP,$ts,4); $len-=4; $ts=unpack('N',$ts);
# There's also 'l'ocal mode, undocumented.
printf("Mode:\t%s (%s)\n",$mode,
('b' eq $mode ? "binary" : ('t' eq $mode ? "canonical text" :
"unknown"))) unless $t;
print "Length of filename:\t$namelen\n" unless $t;
print "Filename:\t$name\n";
unless ($t) {
if ($ts) {
print "Timestamp:\t".&date_fmt($ts)."\n";
}
else {
# Timestamp can be (and often is) zero, which may mean
# whatever, but certainly doesn't mean it was created
# 1 Jan 1970. Better just to say it's zero.
print "Timestamp:\tZero\n";
}
}
if ($len>0) {
read(PGP,$data,$len);
print "$len bytes of data.\n" unless $t;
&data_print($data) if $v&&!$t;
}
else {
print "And then a mess of data...\n" unless $t;
while (!eof(PGP)) {
$c=getc(PGP);
if ($v&&!$t) {
$c=unpack('H2',$c);
print "\U$c\E";
}
}
print "\n" if $v&&!$t;
}
}
sub process_packet {
my($ct,$lf,$len,$typestr,$handler);
return 0 unless (($ct,$len,$lf)=&ctb());
if ($ct<0) {
# Error! CTB with bit 7 not set found.
print "\nINVALID CTB ($len)! Bit 7 not set.\n";
exit(10);
}
if ($ct==$CTB_PKE) {
$typestr="Public-Key Encrypted Packet";
$handler=\&pke_handler;
}
elsif ($ct==$CTB_SKE) {
$typestr="Secret-Key Encrypted Packet (signature)";
$handler=\&ske_handler;
}
elsif ($ct==$CTB_SEC) {
$typestr="Secret Key Packet";
$handler=\&sec_handler;
}
elsif ($ct==$CTB_PUB) {
$typestr="Public Key Packet";
$handler=\&pub_handler;
}
elsif ($ct==$CTB_COMP) {
$typestr="Compressed Data Packet";
$handler=\&comp_handler;
}
elsif ($ct==$CTB_CKE) {
$typestr="Conventionally Encrypted Packet";
$handler=\&conv_handler;
}
elsif ($ct==$CTB_RAW) {
$typestr="Raw Data Packet";
$handler=\&raw_handler;
}
elsif ($ct==$CTB_TRUST) {
$typestr="Keyring Trust Packet";
$handler=\&trust_handler;
}
elsif ($ct==$CTB_UID) {
$typestr="User ID Packet";
$handler=\&uid_handler;
}
elsif ($ct==$CTB_CMT) {
$typestr="Comment Packet";
$handler=\&comment_handler;
}
else {
$typestr=sprintf("UNKNOWN PACKET!! (%o)",$ct);
$handler=\&null_handler;
}
print "\n---------------------------\nPacket Type:\t" unless $t;
print "$typestr",($t?": ":"\n");
print "Length:\t$len\n" unless $t;
&$handler($len);
$lastctb=$ct;
return(1);
}
# MAIN PROGRAM
die "Usage: $0 [-v] [-a] [-v] [-u[=pubfile]] [pgpfile], stopped"
if $#ARGV>1; # -v for verbose, -a to force ascii mode.
# Check an option or two...
if ($h) {
# print help message and exit
print<<"EEOOFF"
PGPACKET: analyze the output of PGP.
Usage: $0 [options] [pgpfile]
If no file is specified, reads stdin.
Options:
\t-v: Verbose. Print out more information.
\t-t: Terse. Print out very little information. Overrides -v and -u.
\t-a: ASCII mode. Presume ASCII mode, even if first char is 8-bit
\t-u[=pubring]: Look up keyIDs in pubring file.
\t\tIf pubring is not specified, defaults to ~/.pgp/pubring.pgp.
EEOOFF
;
exit(1);
}
if ($u) {
# User-ID lookup enabled. Open the pubring.
if ($u==1) {
# No value specified. Default to $HOME/.pgp/pubring.pgp
# I realize that this makes it tough to specify a keyring file
# named "1".
$u=$ENV{'HOME'}.'/.pgp/pubring.pgp';
}
unless (open(PUBRING,$u)) {
print "Warning: $u could not be opened. User-ID lookup disabled.\n";
$u=0;
}
}
if (@ARGV) {
die "Couldn't open $ARGV[0]" unless open(PGP,$ARGV[0]);
}
else {
open(PGP,"<&STDIN");
}
# Test for binaryness.
if (-T PGP || $a) {
# If it's a text file, assume this is ascii-armored and dearmor it.
# To dearmor, try forking and running a dearmor script in the child,
# piping the output back to the parent.
# Have to read in the first line here. Otherwise, the -T test eats
# the first line in the child, so if you're starting right at the
# -----BEGIN line it won't find it.
$_=<PGP>;
open(PGP2,"<&PGP");
if (!open(PGP,"-|")) {
# In the child...
# Search for and eat frame.
# Skip past the header. Note special-case, to ignore the top of a
# signed plain-text document; skip down to the real sig.
until (/^-----BEGIN PGP / &! /^-----BEGIN PGP SIGNED MESSAGE/) {
$_=<PGP2>;
}
$_=<PGP2> until /^\s*\n?$/;
while (1) {
$last=0;
$_=<PGP2>;
# equals signs are used to pad out the end.
s/^([^-=]*)[-=].*/\1/;
# Only last chunk may be less than 64chars. This may not always
# be able to exclude the checksum. Oh well.
$last=1 if length($_)<64;
tr@A-Za-z0-9+/@`!-_@d; # matching `
$_=pack('C',length($_)*3/4+040).$_;
$_=unpack("u",$_);
$_=~s/\0$// if $last; # Strip *one* trailing null
print $_;
last if $last;
}
# And finish! The child needs to exit here.
exit(0);
}
close(PGP2);
}
# Otherwise, just continue.
$lastctb=0; # Last seen ctb;
while (1) {
last unless &process_packet;
}
exit(0);
$dmy=<<"-END"
- -END
;
-----BEGIN PGP SIGNATURE-----
Version: 2.6.2
iQCVAwUBMPPgkdjId3FCnAfhAQFSlgP/VZPqwalySFqnGWtW4kF8m00MTkKxXyF8
bfdAJHdZ9kKBWJO1YJpFlxcMmzZD04MkQsa99hBwZDu3H/rJf3tk9zF31RuFLvuE
H292mj88BAzI4M/O+J9v31Xh+kOFCpulAn5rj7vm0OkYApJeaQaFUB9tlgeV0xdH
xbebYFTQCcM=
=KPto
-----END PGP SIGNATURE-----
-END
;