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();
r.nextBytes(key);
```

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..?.?