Title: Professional Java Security
ISBN: 1861004257
US Price: $ 49.99
Canadian Price:
C$ 74.95
UK Price: £ 39.99
© Wrox Press Limited, US and UK.

Reviews : Java Books :
Professional Java Security : Symmetric Encryption

CipherStreams

Some of the most useful classes that the JCE provides are the two CipherStream classes in the javax.crypto package: CipherInputStream and CipherOutputStream. They provide convenient wrappers around standard input and output streams that automatically encrypt and decrypt. You can use them anywhere you use a normal InputStream or OutputStream, like network programming or file IO.

CipherInputStream and CipherOutputStream are both constructed by a call to new() with the stream to wrap and the cipher to use. If we have a cipher prepared, we could encrypt a file with:

	FileInputStream input = new FileInputStream("plaintext_filename");
	FileOutputStream output = new FileOutputStream("ciphertext_filename");
	CipherOutputStream cipherOutput = new CipherOutputStream(output, cipher);
	int r = 0;
	while (r=input.read() != -1) {
		cipherOutput.write(r);
	}
	cipherOutput.close();
	output.close();
	input.close();

Decrypting is similar to this -- we simply place the cipher in DECRYPT_MODE, and use the cipher streams in the same fashion.

When using cipher streams, it is important to set the mode properly. ECB mode, as we mentioned, isn't a good idea for large chunks of data that are non-random, like a text file. Instead, we'll need to use a mode like CBC, which requires an initialization vector. We'll show setting the mode in the code example coming up.

Initializing a Cipher with an IV

javax.crypto.spec.IVParameterSpec encapsulates an initialization vector in the JCE. One is constructed with a byte array and a call to new() for IVParameterSpec.

To create the bytes for the IV, we should use java.security.SecureRandom to generate a byte array equivalent to the block size for the cipher we are using. Most block ciphers have a block size of 64 bits (8 bytes). AES has a variable block size, either 128, 192, or 256 bits, but is typically set to 128-bit (16 bytes).

SecureRandom

SecureRandom is easy to use. We can construct one normally, with the default constructor, and then pass byte arrays to it with nextBytes() and receive them back filled with random data. For instance, to create an 8-byte array using secure random we could do the following:

	byte[] randomBytes = new byte[8];
	SecureRandom random = new SecureRandom();
	random.nextBytes(randomBytes);

As an aside, you may have noticed a delay during the running of the examples we have seen so far and wondered what causes it. Well, it's not the encryption that's so slow; it's the initialization of java.security.SecureRandom. Sun's implementation of SecureRandom creates a great number of threads and checks their interaction over a period of time. It then uses that to initialize a Pseudo-Random Number Generator (PRNG). It's the thread creation and interaction that takes so long.

To combat this, a couple of providers have created implementations of SecureRandom that are at least partially native, giving a huge speed increase in the seeding of the random number generator. Cryptix (http://www.cryptix.org) provides an implementation that runs on Linux and the various BSDs, and Virtual Unlimited (http://www.virtualunlimited.com) provides one for Windows.

Also, the initialization of SecureRandom is only expensive the first time it's done in a single Java VM instance. If you have a long-running program or a server, you can initialize SecureRandom on startup and all later operations will run quite quickly. You may also want to try to architect your programs so that they run for a longer period of time rather than starting and stopping often. This would allow you to amortize the cost of initialization.

Creating and Using an IV

To create the IV with those random bytes, just construct a new instance of IVParameterSpec:

	IVParameterSpec iv = new IVParameterSpec(randomBytes);
Now we can use the IV to initialize a cipher, like so:
	Cipher cipher = Cipher.getInstance("Blowfish/CBC/PKCS5Padding");
	cipher.init(Cipher.ENCRYPT_MODE, key, iv);

And we're ready to use that cipher in a cipher output stream.

Keeping Track of the IV

It's important to realize that that same IV needs to be used to initialize a cipher for decrypting as well. It's a lot like the salt used with password-based encryption. Just like the salt, it doesn't need to be hidden like the key does. We can safely expose it along with the ciphertext that we've encrypted.

A common way to handle this is to place the initialization vector at the beginning of the ciphertext. That's exactly what we're going to do in the next example, which will encrypt and decrypt a file, and also keep a symmetric key stored in the filesystem encrypted with a password.

How to Add Java Applets to Your Site

New on the Java Boutique:

New Review:

Time Management Made Easy with the Quartz Enterprise Job Scheduler
Why not just use the Java timer API? This open source scheduling API boasts simplicity, ease-of-integration, a well-rounded feature set, and it's free!

New Applet:

Reverse Complement
Reverse Complement is a simple applet that converts DNA or RNA sequences into three useful formats.

Elsewhere on internet.com:

WebDeveloper Java
Lots of Java information on webdeveloper.com

WDVL Java
Thorough Java resource at the Web Developer's Virtual Library.

ScriptSearch Java
Hundreds of free Java code files to download.

jGuru: Your View of the Java Universe
Customizable portal with online training, FAQs, regular news updates, and tutorials.