I’ve been exposed to programming most of my life. My first computer was a Commodore 16 with no hard drive and a whopping 16 kilobytes of RAM…boy how things have changed. I gained a real interest in programming about 15 years ago, about the same time Visual Basic 3 was released. I remember stumbling across a program that could encrypt files. I studied how it worked, played around with it a bit, but finally set it aside and forgot about it. A few years ago while studying Java in college; I decided to recreate it from memory. It’s a very basic version, and perhaps one of these days I’ll wrap a nice GUI around it, but for now it is what it is.
The main purpose of this tutorial is to demonstrate how encryption works, but I’ll also touch on other topics like binary file I-O, random number generation, and logical operators. Here's the full source:
Below I'll take a look at the various parts of this program.Code:/* Author TA Lucas Purpose to password encrypt any file Program encrypt.java */ // included files import java.io.*; import java.util.Random; public class encrypt { //seed random number private static Random generator = new Random(5); public static void main(String[]args) throws Exception { InputStreamReader keyReader = new InputStreamReader(System.in); BufferedReader keyInput = new BufferedReader(keyReader); //Get the full path and filename for input file System.out.print("Input filename: "); String inputFilePath = keyInput.readLine();; File inFile = new File(inputFilePath); if (inFile.exists()){ FileInputStream reader = new FileInputStream(inFile); // variables String passWord = ""; int passWordLength = 0; String EncryptedFilePath = ""; int originalByte = 0; int encryptedByte = 0; int mask = 0; int counter = 0; //Get the full path and filename for output file System.out.print("Output filename: "); EncryptedFilePath = keyInput.readLine(); FileOutputStream writer = new FileOutputStream(EncryptedFilePath); // prompt user for password System.out.print("Please enter a password: "); passWord = keyInput.readLine(); passWordLength = passWord.length(); // loop through each byte of the input file for (int i = 0; i<inFile.length(); i++) { originalByte = reader.read(); // read original byte mask = loopNum((int)passWord.charAt(counter)); // generate mask by password encryptedByte = mask ^ originalByte; // encrypt byte with mask writer.write(encryptedByte); // write encrypted byte // after password is looped it is reset and done again. counter++; if(counter >= passWordLength) { counter=0; } } writer.close(); } else { System.out.println("Source file was not found."); } }// end main ////////////////////////////////////////////////////////////////////// // accepts nothing just generates numbers loops // // returns nothing for mask // ////////////////////////////////////////////////////////////////////// public static int loopNum(int loopEnd) { for (int i = 0; i<= loopEnd; i++) { generator.nextInt(256); } return generator.nextInt(256); }// end loopNum }// end class
I always start my code with a comment header that gives just a brief description of what the file does. Take the time to document your code properly...it will save you time later, and its a good habit to develop. I also included the io and random classes.Code:/* Author TA Lucas Purpose to password encrypt any file Program encrypt.java */ // included files import java.io.*; import java.util.Random;
I've used the random class to create a random number. Java uses an algorithm to create its random numbers. The way it works, a number is passed to the constructor, and based off of that number Java will produce a set of numbers. If you use the same seed, it will always produce the exact set of numbers. If I seed it with 5 and then create 100,000 numbers then the next time I execute the program...if I've left the code the same then it will produce those same 100,000 numbers in the exact same order.Code:public class encrypt { //seed random number private static Random generator = new Random(5);
If you don't give the constructor a value, then it will use the system time as a seed....which will give you an almost random value. However for our purposes, we want it to generate the exact set every time.
I won't spend a lot of time on this section, but there are a couple things that need a bit of explaining. The InputStreamReader and BufferedReader are used to read in keyboard input....our filename (need to include path).Code:public static void main(String[]args) throws Exception { InputStreamReader keyReader = new InputStreamReader(System.in); BufferedReader keyInput = new BufferedReader(keyReader); //Get the full path and filename for input file System.out.print("Input filename: "); String inputFilePath = keyInput.readLine();; File inFile = new File(inputFilePath); if (inFile.exists()){ FileInputStream reader = new FileInputStream(inFile); // variables String passWord = ""; int passWordLength = 0; String EncryptedFilePath = ""; int originalByte = 0; int encryptedByte = 0; int mask = 0; int counter = 0;
I chose to use the FileInputStream because it opens the file in binary format. This is important because you'll need to do some bit operations a bit (no pun intended) later.
In this part we open the output file in binary also, and then prompt for a password that is used to encrypt the file.Code://Get the full path and filename for output file System.out.print("Output filename: "); EncryptedFilePath = keyInput.readLine(); FileOutputStream writer = new FileOutputStream(EncryptedFilePath); // prompt user for password System.out.print("Please enter a password: "); passWord = keyInput.readLine(); passWordLength = passWord.length();
This bit of code is the core of the program. The loop will read a byte from the input file create an encrypted byte based upon the password, and then write that byte to the output file....and continue through the entire file.Code:// loop through each byte of the input file for (int i = 0; i<inFile.length(); i++) { originalByte = reader.read(); // read original byte mask = loopNum((int)passWord.charAt(counter)); // generate mask by password encryptedByte = mask ^ originalByte; // encrypt byte with mask writer.write(encryptedByte); // write encrypted byte // after password is looped it is reset and done again. counter++; if(counter >= passWordLength) { counter=0; } }
originalByte = reader.read();
This line will read in a byte of data from the input file. A byte is 8 bits, and the first read may look something like this: {01101001 010010101 10100001}
mask = loopNum((int)passWord.charAt(counter));
To make it simple the mask is a random number from 0 - 255. This line of code calls the loopNum function which returns an integer within that range, but it uses a character of the password to determine which random number it returns. The counter is an integer used to loop through each letter of the password.
Let's say our password is apple, and we are on the first itteration of the loop. It has already read in byte: 01101001, and is now calling the loopNum function with the value (int)passWord.charAt(counter)). The first character of the password is a lower case 'a', and if you cast it to an integer you get the number 97...so basically we pass 97 to the loopNum function. LoopNum will then generate 97 random numbers, toss them to the side, and then return the 98th, which will be an integer between 0 and 255, and that will be our mask.
There are 256 possible number between 0 - 255, and that is important because that is also the largest number possible with a byte. The binary number 11111111 is equal to the decimal number 255. So the number returned is always the size of one byte....our mask is a random number the size of a byte.
Now lets say that loopNum returned the number decimal number 133 which is the binary number 10000101. So now we have:
01101001 - original byte
10000101 - mask
encryptedByte = mask ^ originalByte;
This line will create the encrypted byte by using the XOR operator. The Exclusive or will compare bit for bit...so you remember those truth tables, well here's the one for Xor: 1 Xor 1 = 0, 1 Xor 0 = 1, 0 Xor 1 = 1, and 0 Xor 0 = 0.
01101001 - original byte
10000101 - mask
____________________________XOR
11101100 - encrypted byte
So how does this work? Well...when you run the encrypted file back through the same program, it will read in the encrypted byte, and when Xor'd with the same mask, it will produce the original byte. So the fact that the Xor acts like a switch that will flip the bits back to the original, and that java will produce the exact random numbers each time is what makes this possible. Check it out:
11101100 - encrypted byte
10000101 - mask
____________________________XOR
01101001 - original byte
Have fun, and let me know what you think...take the code and play with it a bit. like i said, this program is pretty simple, and does not have a lot of error checking built in. For my testing, I usually encrypt a file on the C drive so I don't have to worry about file paths. Something like c:\inputfile.txt c:\outputfile.txt.


LinkBack URL
About LinkBacks




Reply With Quote









Bookmarks
Algorithms and Data Structures
Java tutorials
Algorithms Forum