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