Symmetric-key encryption in Java (ctd): AES and block ciphers

The basic Java encryption code we've just looked at gives us the very basic building block for securely storing or transmitting data. Unfortunately, like all good building blocks, it's generally not enough on its own. To get proper security, we need to use the building blocks properly.

The first thing we need to consider is that AES, like other common encryption algorithms, is a block cipher. That means that it always operates on units or "blocks" that are some fixed number of bytes in size. In the case of AES, a block is 16 bytes, or 128 bits. (Coincidentally, we're also using a 16-byte key in our examples, but the block size and key size aren't necessarily the same. AES can be used with other key sizes. And another algorithm, DES, has a 7-byte key but an 8-byte block size.) AES and various other block ciphers essentially take each n-byte block of bytes and "mix" that block together with the key, thus outputting an encrypted block.

Mixing typically involves simple bitwise operations such as the XOR operation and bitshifts, possibly arithmetic operations (addition and multiplication), plus a technique called "substitution" (whereby at points during the process, parts of the encryption buffer are used as indicies into an array of alternative "random" bytes/bits for which they are swapped). Mixing occurs in "rounds": the mixing procedure is repeated some number of times on each block, often with some variation on each round (e.g. different bytes might be used from the key on different rounds).

The upshot is that:

By default with a block cipher, a given block-length sequence will always result in the same sequence of encrypted bytes when encrypted with a given key.

To illustrate this, consider Alice's encryption code from the previous page. Supposing we define the data to be encrypted as follows (in other words, bytes 16-31 of the block will be a repetition of bytes 0-15):

byte[] plaintext = new byte[32];
for (int i = 0; i < 32; i++) {
  plaintext[i] = (byte) (i % 16);

Now, we pick a random key (if you're not familiar with it, see this site's explanation of the SecureRandom class; for reasons discussed there, never use poor-quality generators such as java.util.Random for generating random keys):

byte[] key = new byte[16];
SecureRandom r = new SecureRandom();

But let's see what happens when we encrypt plaintext using key, which, remember, contains 16 random bytes. We run Alice's encryption code, save the encrypted bytes, and look at them in a hex editor (or write a little Java method to print them out). What we actually get is something such as this:

6BA71D86E3115D2D49F54A12B5800291 k..?..]-I.J..?.?
6BA71D86E3115D2D49F54A12B5800291 k..?..]-I.J..?.?
6F91863A50238AD46AACC5064E902B8D o??:P#?.j...N?+?

Although each individual line contains undecipherable garbage as we'd hope, the first and second lines of encrypted data are identical. Because our plaintext consisted of a repeated pattern, where the pattern itself is exactly the length of a block, the encrypted result contains two identical blocks. (The third block is something called padding: we'll come back to that.) In other words, the cipher is leaking information about the structure of our plaintext. Depending on our application, this could be really bad news.

Unfortunately, you'll see that this happens with the "default" options. When we constructed our AES Cipher object, we didn't set any special option to say "please operate in insecure mode". And yet that's what it decided to do. So I'm just guessing there could be one or two commercial systems out there handling sensitive data with this insecurity. What's the solution?

Well, the solution is essentially quite low-tech at first glance. We simply arrange things so that by the time our data is fed into the encryption algorithm, we "never encrypt the same block twice". And to do that, we choose an appropriate option from what are called block modes.

If you enjoy this Java programming article, please share with friends and colleagues. Follow the author on Twitter for the latest news and rants.

Editorial page content written by Neil Coffey. Copyright © Javamex UK 2021. All rights reserved.