#!/usr/staff/bin/perl

# use:
 # encrypt a file:  perl NitNat.pl -e plaintextfilename encryptedfilename  
 # decrypt a file:  perl NitNat.pl -d encryptedfilename decryptedfilename  
 # to input a key, type six digits separated by spaces, ending with RTN

# are we en- or de-crypting?
ckcmd();

# read the input file into a string
$input = getinput();

# open the output file
getoutput();

#ask user for key --> array
@key = getkey();

# unpack input string to array 
@arr = unpack( "C*", $input);

# how many chars is it?
$textlen = @arr;

# cryption algorithm follows
$mask = 0x20;


# prepare the output array
    for ($byte = 0; $byte < $textlen; $byte++)
    {

#  To preserve all "printable ascii", such as delete, null, backspace, 
# and other troublesome bytes, use the following line.
# The output on disk will be fine, will decrypt to the original exactly,
# but looks ugly to print
#      $crypt[$byte] = 0x00 | ( $arr[$byte] & 0x40) ;

# This line limits your input and output character set to chars >= 0x40,
# which includes upper and lower-case letters and a few brackets.
$crypt[$byte] = 0x40 ;

    }

# here we go... encrypt or decrypt depending on $decrypt boolean

for ($i = 0; $i<6; $i++)
{
  $tmask = $mask >> $i;

    for ($byte = 0; $byte < $textlen; $byte++)
    {
	if ($decrypt) { $inindex = ($byte-$key[$i]) % $textlen;}
       else { $inindex = ($byte+$key[$i]) % $textlen;}

	$crypt[$inindex] =  ($arr[$byte] & $tmask) |
	    $crypt[$inindex];
    }
}
# simple, eh?

# array to string
$encrypt = pack ("C*", @crypt);

# I'm worried about char 0x7F -- might not print so I'm zapping it to 7E,
#  which will mean some poor unsuspecting char in msg is off by a
# little bit (no pun intended, heh heh).
# $encrypt =~ tr/\177/\176/;

# write it out
printf (OUTFID "%s\n", $encrypt);

#clean up
close(OUTFID);


################## that's all, folks! ################

#### some subrs...


# read the key into an array
sub getkey
{
    my @keyout;
    printf ("\n Enter space-delimited 6-digit key: ");
    $a = <STDIN>;
#    printf ("\n input: %s ", $a);
    chop($a);
#    printf ("\n input: %s ", $a);
    @keyout = split(/ /, $a);
    return @keyout;
}



# read input into a string, toss out carriage returns.
sub getinput
{
    my $fname ;
    $fname = shift(@ARGV);
    $out = "";
    unless (open INFID, $fname)
    {die "\n Can't open $fname for input!\n";}

while ($line = <INFID>)
{
    chop($line);
    $out = $out  . $line . " " ;
}
chop($out);  
return $out;


}


# read the fake option flag
sub ckcmd()
{

$action = shift(@ARGV);  
#print "\n", $action;
if ($action eq "-d")
{ $decrypt = 99; return;}
if ($action eq "-e")
{ $decrypt = 0; return;}
printf ("\n usage: nitnat <-d | -e> infname outfname  to De or encrypt.");
exit;
}

#return a file ID for output
sub getoutput()

{
    my $fname;
    $fname = shift(@ARGV);
  unless ( open (OUTFID, ">$fname"))
  { die "\nCan't open $fname for output!\n";}
}
