encrypt.pl
#!/usr/bin/perl
use strict;
# Syntax: perl encrypt.pl message_file onetimepad_file encrypted_file
# This:
# encrypts message_file to encrypted_file using onetimepad_file
# deletes the part of onetimepad_file used for the encryption
# updates the bookmark in onetimepad_file
# deletes the message_file
my $True = 1;
my $False = 0;
# Execution starts here
&main;
sub main()
{
my $intNumArgs = $#ARGV + 1;
if ($intNumArgs != 3)
{
print "Syntax: perl encrypt.pl message_file onetimepad_file encrypted_file\n";
exit 1;
}
# Read the arguments on the command line
my $strMessageFilename = $ARGV[0];
my $strPadFilename = $ARGV[1];
my $strEncryptedFilename = $ARGV[2];
my $lngMessageFileSize = -s $strMessageFilename;
my $lngPadFileSize = -s $strPadFilename;
my $lngCurrentPadBookmark = ReadBookmark($strPadFilename);
if ($lngCurrentPadBookmark == 0)
{
print "Bad bookmark found in one-time pad\n";
exit 1;
}
# Check we have enough unused pad
if ($lngMessageFileSize > $lngPadFileSize - $lngCurrentPadBookmark)
{
print "Message file is too large for remaining one-time pad\n";
exit 1;
}
# encrypt the message file to an encrypted file using the one-time pad
if (EncryptMessage($strMessageFilename,
$strPadFilename,
$strEncryptedFilename,
$lngMessageFileSize,
$lngCurrentPadBookmark) == $False)
{
exit 1;
}
# delete the part of onetimepad_file used for the encryption and update the bookmark
my $lngNewPadBookmark = $lngCurrentPadBookmark + $lngMessageFileSize;
if (DeleteDataAndSetBookmark($strPadFilename,
$lngCurrentPadBookmark,
$lngNewPadBookmark) == $False)
{
exit 1;
}
# overwrite and delete the message file
if (DeleteMessage($strMessageFilename) == $False)
{
exit 1;
}
exit 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 EncryptMessage($$$$$)
{
my $strMessageFilename = $_[0];
my $strPadFilename = $_[1];
my $strEncryptedFilename = $_[2];
my $lngMessageFileSize = $_[3];
my $lngCurrentPadBookmark = $_[4];
if (!open MESSAGE_FILE, "<$strMessageFilename")
{
print "ERROR:Can't open file $strMessageFilename\n";
return $False;
}
# Handle the file as bytes instead of text
binmode MESSAGE_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 ENCRYPTED_FILE, ">$strEncryptedFilename")
{
print "ERROR:Can't create file $strEncryptedFilename\n";
return $False;
}
# Handle the file as bytes instead of text
binmode ENCRYPTED_FILE;
# Write the part of the one-time pad used to encrypt to the start of the encrypted file
print ENCRYPTED_FILE pack('L', $lngCurrentPadBookmark);
# Move the file pointer to the start of the unused part of the pad
seek(PAD_FILE, $lngCurrentPadBookmark, 0);
my $MessageByte;
my $PadByte;
my $EncryptedByte;
for(my $lngCounter = 0; $lngCounter < $lngMessageFileSize; $lngCounter++)
{
# Read byte from message file
seek(MESSAGE_FILE, $lngCounter, 0);
$MessageByte = unpack('C', <MESSAGE_FILE>);
# Read byte from one-time pad
seek(PAD_FILE, $lngCurrentPadBookmark + $lngCounter, 0);
$PadByte = unpack('C', <PAD_FILE>);
# XOR the two bytes to get the encrypted byte
$EncryptedByte = $MessageByte ^ $PadByte;
# Uncomment these lines to see how each byte is processed
# printf("Message byte 0x%02X pad byte 0x%02X encrypted byte 0x%02X\n",
# $MessageByte,
# $PadByte,
# $EncryptedByte);
print ENCRYPTED_FILE pack('C', $EncryptedByte);
}
close MESSAGE_FILE;
close PAD_FILE;
close ENCRYPTED_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;
}
