security icon

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;
}

Home page