Symmetric Encryption 83 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.