security icon

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

Home page