Unlocking the Secrets of Java Cryptography Extensions: The Basics, Page 5
Listing 3.2 shows the reverse process of grabbing the encrypted key from the file and decrypting the data file.
package com.dlt.developer.crypto;
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import javax.crypto.*;import java.security.Key;
import java.io.*;
/**
* @author David Thurmond
* An example of decrypting a text file using Data Encryption
* Standard encryption.
*/
public class DecryptFileExample {
public static void main(String[] args) throws Exception {
// First, create the encryption key...
System.out.println("Reading key from file...");
BufferedInputStream in =
new BufferedInputStream(new FileInputStream
("encrypted_key.txt"));
byte[] keyBytes = new byte[in.available()];
in.read(keyBytes);
System.out.println("Bytes read=" + keyBytes.length);
in.close();
SecretKeySpec skeySpec = new SecretKeySpec(keyBytes, "DES");
// Now, create the cipher object with appropriate parameters...
System.out.println("Decrypting file using DES/ECB/PKCS5Padding");
Cipher desCipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
desCipher.init(Cipher.DECRYPT_MODE, skeySpec);
System.out.println("Reading encrypted file and decrypting...");
BufferedOutputStream outData =
new BufferedOutputStream(new FileOutputStream
("decrypted_data.txt"));
BufferedInputStream inData =
new BufferedInputStream(new FileInputStream
("encrypted_data.txt"));
while (inData.available() > 0) {
// Read the next chunk of bytes...
byte[] encryptedBytes = new byte[inData.available()];
inData.read(encryptedBytes);
// Now, decrypt them and write them to the encrypted file...
byte[] cleartextBytes = desCipher.update(encryptedBytes);
outData.write(cleartextBytes, 0, cleartextBytes.length);
} // while
outData.write(desCipher.doFinal());
inData.close();
outData.flush();
outData.close();
System.out.println("Done!");
} // main
}
Listing 3.2: DecryptFileExample.java
In Listing 3.2, the file encrypted_key.txt is read, and the key's raw bytes are retrieved and loaded into a key spec for use by the Cipher object:
FileInputStream("encrypted_key.txt"));
byte[] keyBytes = new byte[in.available()];
...Create the cipher object with the right decription...
...parameters and key spec...
SecretKeySpec skeySpec = new SecretKeySpec(keyBytes, "DES");
Cipher desCipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
desCipher.init(Cipher.DECRYPT_MODE, skeySpec);
The remainder of the process is just the reverse of the previous example. Data is read from encrypted_data.txt, is decrypted by using the Cipher.update() and Cipher.doFinal() methods just as before, and is written out to decrypted_data.txt. Note that without the final invocation of doFinal(), a chunk of data would be missing at the end of the decrypted file. By examining decrypted_data.txt and cleartext.txt, the input to the file encryption program, you will see that the files are identical.
Password-Based Encryption
Although password-based encryption is not considered to be as secure as the secret-key encryption method shown above, it is probably the most commonly used method of encrypting and decrypting data. Listing 4.1 shows how to encrypt a file using a predetermined password, "mybigsecret". The password algorithm in this example uses a predetermined source of randomness, called a salt, and an iteration counter to determine a block size for the encryption, to make cracking the password a bit more difficult. In a real-world example, the salt and iteration counter might be determined based on some pre-determined agreement between the encrypting and decrypting parties, rather than being a hard-coded value.
package com.dlt.developer.crypto;
import javax.crypto.*;import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.*;
import java.io.*;
/**
* @author David Thurmond
* An example of encrypting a text file using password-based
* encryption.
*/
public class EncryptFilePasswordExample {
public static void main(String[] args) throws Exception {
PBEKeySpec pbeKeySpec;
PBEParameterSpec pbeParamSpec;
SecretKeyFactory keyFac;
// Salt
byte[] salt = {(byte)0x9f, (byte)0x33, (byte)0x4e, (byte)0xfe,
(byte)0xd4, (byte)0xee, (byte)0x12, (byte)0x54};
// Iteration count
int count = 17;
// Create PBE parameter set
pbeParamSpec = new PBEParameterSpec(salt, count);
char[] password = {'m', 'y', 'b', 'i', 'g', 's', 'e', 'c',
'r', 'e', 't'};
pbeKeySpec = new PBEKeySpec(password);
keyFac = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
SecretKey pbeKey = keyFac.generateSecret(pbeKeySpec);
// Create PBE Cipher
Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
// Initialize PBE Cipher with key and parameters
pbeCipher.init(Cipher.ENCRYPT_MODE, pbeKey, pbeParamSpec);
System.out.println("Encrypting file using
DES/ECB/PKCS5Padding");
System.out.println("Reading cleartext file and encrypting...");
BufferedOutputStream outData =
new BufferedOutputStream(new FileOutputStream
("password_encrypted_data.txt"));
BufferedInputStream in =
new BufferedInputStream(new FileInputStream
("cleartext.txt"));
while (in.available() > 0) {
// Read the next chunk of bytes...
byte[] cleartextBytes = new byte[in.available()];
in.read(cleartextBytes);
// Now, encrypt them and write them to the encrypted file...
byte[] encryptedBytes = pbeCipher .update(cleartextBytes);
outData.write(encryptedBytes, 0, encryptedBytes.length);
} // while
// Take care of any pending padding operations
outData.write(pbeCipher .doFinal());
in.close();
outData.flush();
outData.close();
System.out.println("Done!");
} // main
}
Listing 4.1: EncryptFilePasswordExample.java
