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