decrypt.pl
#!/usr/bin/perl
use strict;
# Syntax: perl decrypt.pl encrypted_file onetimepad_file message_file
# This:
# decrypts encrypted_file to message_file using onetimepad_file
# deletes the part of onetimepad_file used for the decryption
# updates the bookmark in onetimepad_file
# deletes the encrypted_file
my $True = 1;
my $False = 0;
# Execution starts here
&main;
sub main()
{
my $intNumArgs = $#ARGV + 1;
if ($intNumArgs != 3)
{
print "Syntax: perl decrypt.pl encrypted_file onetimepad_file message_file\n";
exit 1;
}
# Read the arguments on the command line
my $strEncryptedFilename = $ARGV[0];
my $strPadFilename = $ARGV[1];
my $strMessageFilename = $ARGV[2];
my $lngEncryptedBookmark = ReadBookmark($strEncryptedFilename);
if ($lngEncryptedBookmark == 0)
{
print "ERROR:Bad bookmark found in encrypted file\n";
exit 1;
}
my $lngCurrentPadBookmark = ReadBookmark($strPadFilename);
if ($lngCurrentPadBookmark == 0)
{
print "ERROR:Bad bookmark found in one-time pad\n";
exit 1;
}
if ($lngEncryptedBookmark < $lngCurrentPadBookmark)
{
print "ERROR:This part of the one-time pad has already been deleted\n";
exit 1;
}
my $lngEncryptedFileSize = -s $strEncryptedFilename;
# Decrypt encrypted_file to message_file using one-time pad_file
if (DecryptMessage($strEncryptedFilename,
$strPadFilename,
$strMessageFilename,
$lngEncryptedFileSize,
$lngEncryptedBookmark) == $False)
{
exit 1;
}
# Delete the part of onetimepad_file used for the decryption and update the bookmark
my $lngNewPadBookmark = $lngEncryptedBookmark + $lngEncryptedFileSize - 4;
if (DeleteDataAndSetBookmark($strPadFilename,
$lngCurrentPadBookmark,
$lngNewPadBookmark) == $False)
{
exit 1;
}
# Delete the encrypted_file
if (DeleteMessage($strEncryptedFilename) == $False)
{
exit 1;
}
return 0;
}
sub ReadBookmark($)
{
my $strPadFilename = $_[0];
if (!open PAD_FILE, "<$strPadFilename")
{
print "ERROR:Can't open file $strPadFilename\n";
return 0;
}
# Handle the file as bytes instead of text
binmode PAD_FILE;
my $lngBookmark = unpack('L', <PAD_FILE>);
close PAD_FILE;
return $lngBookmark;
}
sub DecryptMessage($$$$$)
{
my $strEncryptedFilename = $_[0];
my $strPadFilename = $_[1];
my $strMessageFilename = $_[2];
my $lngEncryptedFileSize = $_[3]; # include bookmark at start
my $lngEncryptedBookmark = $_[4];
if (!open ENCRYPTED_FILE, "<$strEncryptedFilename")
{
print "ERROR:Can't open file $strEncryptedFilename\n";
return $False;
}
# Handle the file as bytes instead of text
binmode ENCRYPTED_FILE;
if (!open PAD_FILE, "<$strPadFilename")
{
print "ERROR:Can't open file $strPadFilename\n";
return $False;
}
# Handle the file as bytes instead of text
binmode PAD_FILE;
if (!open MESSAGE_FILE, ">$strMessageFilename")
{
print "ERROR:Can't create file $strMessageFilename\n";
return $False;
}
# Handle the file as bytes instead of text
binmode MESSAGE_FILE;
# Move the file pointer to the start of the encryped data
seek(ENCRYPTED_FILE, 4, 0);
# Move the file pointer to the start of the part of the pad used to encrypt
seek(PAD_FILE, $lngEncryptedBookmark, 0);
my $EncryptedByte;
my $PadByte;
my $MessageByte;
for(my $lngCounter = 0; $lngCounter < $lngEncryptedFileSize - 4; $lngCounter++)
{
# Read byte from encrypted file
seek(ENCRYPTED_FILE, 4 + $lngCounter, 0);
$EncryptedByte = unpack('C', <ENCRYPTED_FILE>);
# Read byte from one-time pad
seek(PAD_FILE, $lngEncryptedBookmark + $lngCounter, 0);
$PadByte = unpack('C', <PAD_FILE>);
# XOR the two bytes to get the encrypted byte
$MessageByte = $EncryptedByte ^ $PadByte;
# Uncomment these lines to see how each byte is processed
# printf("Encrypted byte 0x%02X pad byte 0x%02X message byte 0x%02X\n",
# $EncryptedByte,
# $PadByte,
# $MessageByte);
print MESSAGE_FILE pack('C', $MessageByte);
}
close ENCRYPTED_FILE;
close PAD_FILE;
close MESSAGE_FILE;
return $True;
}
sub DeleteDataAndSetBookmark($$$)
{
my $strPadFilename = $_[0];
my $lngCurrentPadBookmark = $_[1];
my $lngNewPadBookmark = $_[2];
if (!open PAD_FILE, "+<$strPadFilename")
{
print "ERROR:Can't open file $strPadFilename\n";
return $False;
}
# Handle the file as bytes instead of text
binmode PAD_FILE;
# Write the new bookmark at the start of the file
seek(PAD_FILE, 0, 0);
print PAD_FILE pack('L', $lngNewPadBookmark);
print "Bookmark updated to ".$lngNewPadBookmark."\n";
# Delete data between old and new bookmarks
seek(PAD_FILE, $lngCurrentPadBookmark, 0);
for(my $lngCounter = $lngCurrentPadBookmark; $lngCounter < $lngNewPadBookmark; $lngCounter++)
{
my $byte = 0;
print PAD_FILE pack('C', $byte);
}
print "Data up to new bookmark deleted\n";
close PAD_FILE;
return $True;
}
# Overwrite the contents of the message file and the delete it
sub DeleteMessage($$)
{
my $strMessageFilename = $_[0];
my $lngMessageFileSize = $_[1];
if (!open MESSAGE_FILE, "+<$strMessageFilename")
{
print "ERROR:Can't open file $strMessageFilename\n";
return $False;
}
# Overwrite the file contents with zeros
for(my $lngCounter = 0; $lngCounter < $lngMessageFileSize; $lngCounter++)
{
print MESSAGE_FILE pack('C', 0);
}
close MESSAGE_FILE;
# Delete the file
unlink $strMessageFilename;
return $True;
}
