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:

Alice's encryption codeBob's decryption code
byte[] key = //... secret sequence of bytes
byte[] dataToSend = ...

Cipher c = Cipher.getInstance("AES");
SecretKeySpec k =
  new SecretKeySpec(key, "AES");
c.init(Cipher.ENCRYPT_MODE, k);
byte[] encryptedData = c.doFinal(dataToSend);

// now send encryptedData to Bob...
byte[] key = //... we know the secret!
byte[] encryptedData = //... received from Alice

Cipher c = Cipher.getInstance("AES");
SecretKeySpec k =
  new SecretKeySpec(key, "AES");
c.init(Cipher.DECRYPT_MODE, k);
byte[] data = c.doFinal(encryptedData);

// do something with data
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.

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.