Symmetric-key encryption in Java

Having introduced the the notion of an encryption key,
we turn our attention to symmetric-key encryption. This is the
case where the same key is used to both encrypt and decrypt.
It sometimes called secret-key encryption,
single-key encryption or simply symmetric encryption.

In traditional fashion, we'll assume that Alice wants to send some data
securely to Bob. This means Alice is going to encrypt the data, and then when he
receives it, Bob will decrypt it again. Firstly, somehow or other, Alice and Bob have to agree between
them on what the secret key will be. We'll assume that the key is some sequence of
bytes of an appropriate length. (We mentioned in our inntroduction to encryption
keys that in fact, with certain algorithms, you have to make sure the key has a
certain structure and/or avoid "weak" keys; in fact, it turns out that for our particular
example this won't be a problem.)
In a moment, we'll come back to the problem of how the key is
chosen, what length it should be, and how Alice and Bob can agree in advance on what
that key is. For now, let's pretend they "just know" what the secret key is,
and worry about the Java code that they each run to actually
encrypt and decrypt their data.

In this example, we're going to use a widely-adopted encryption algorithm
called AES. (We'll consider one or two other algorithms later.
But in general, if you need to use a symmetric encryption system and
you're not sure which algorithm to pick, AES is probably the one you'll end up
using unless you have a strong reason to use something else.)
Then, as a first attempt (which we will need to revise),
this is essentially the pattern for encryption/decryption:

Very basic AES encryption/decryption functions in Java.
N.B. In reality, this code contains some insecurities that we
would need to revise for various common uses (see below).

If you want to test this code, just pick any 16-byte sequence as the key.
If you put the same key into each side, you should find that data encrypted by
Alice's code can be decrypted by Bob's. And if you try printing out the encrypted
bytes, you should find that it looks like a series of undecipherable random bytes.
Indeed, in principle at least, these bytes will be computationally undecipherable
without the key.

But unfortunately, that's not the whole story... To see why,
we need to first consider how AES and similar algorithms work, and in
particular the notion of block ciphers.