AES Encryption and Decryption Using a Password in Java

Encrypt a file using a password with strong AES security.

“My tastes are simple: I am easily satisfied with the best.”
― Winston S. Churchill

1. Introduction

In a previous article, we have explained how to use AES for encryption and decryption. After encryption, the AES key will need to be communicated to the receiver via a secure channel for decrypting the file.

We have also covered using RSA with AES for the same purpose (file encryption). Here, the AES key is secured using RSA and included in the output file. The receiver will need access to the sender’s public key for decryption.

In this article, we explain how to encrypt and sign a file for secure transmission. This covers the same case as above with the difference that the contents of the file are authenticated during decryption.

Let us now see how to use a password with AES for secure file transmission. In this case, the receiver will need the password to be able to decrypt the file.

2. Java Imports

The following java imports are required to compile the program.

import java.io.InputStream;
import java.io.OutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Arrays;
import java.util.Base64;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.spec.KeySpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.IvParameterSpec;

3. Generating the AES Key

We use a user-specified password to generate an AES key. The class PBEKeySpec can generate the key using the password and an 8-bit salt.

byte[] salt = new byte[8];
srandom.nextBytes(salt);
SecretKeyFactory factory =
    SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 10000, 128);
SecretKey tmp = factory.generateSecret(spec);
SecretKeySpec skey = new SecretKeySpec(tmp.getEncoded(), "AES");

4. Generate the Initialization Vector (IV)

An 8-byte initialization vector is needed for a 128-bit AES key, which we obtain from SecureRandom.

byte[] iv = new byte[128/8];
srandom.nextBytes(iv);
IvParameterSpec ivspec = new IvParameterSpec(iv);

5. Encrypting the File

The output file is generated by writing the salt, followed by the initialization vector.

FileOutputStream out = new FileOutputStream(inputFile + ".enc");
out.write(salt);
out.write(iv);

To encrypt the file contents, we create a Cipher object from the AES key.

Cipher ci = Cipher.getInstance("AES/CBC/PKCS5Padding");
ci.init(Cipher.ENCRYPT_MODE, skey, ivspec);

Finally, the file contents are encrypted and written into the output.

try (FileInputStream in = new FileInputStream(inputFile)) {
    processFile(ci, in, out);
}

The static method processFile() is shown below. It is common for both encryption and decryption.

static private void processFile(Cipher ci,InputStream in,OutputStream out)
    throws javax.crypto.IllegalBlockSizeException,
           javax.crypto.BadPaddingException,
           java.io.IOException
{
    byte[] ibuf = new byte[1024];
    int len;
    while ((len = in.read(ibuf)) != -1) {
        byte[] obuf = ci.update(ibuf, 0, len);
        if ( obuf != null ) out.write(obuf);
    }
    byte[] obuf = ci.doFinal();
    if ( obuf != null ) out.write(obuf);
}

This completes the file encryption. It can be sent to the receiver who can decrypt the file using just the password.

6. Decrypting the File

First step is to load the salt, and the initialization vector, each of which are 8 bytes in length.

FileInputStream in = new FileInputStream(inputFile);
byte[] salt = new byte[8], iv = new byte[128/8];
in.read(salt);
in.read(iv);

Generate the AES key from the password and the salt.

SecretKeyFactory factory =
    SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 10000, 128);
SecretKey tmp = factory.generateSecret(spec);
SecretKeySpec skey = new SecretKeySpec(tmp.getEncoded(), "AES");

Create the decryption Cipher using the AES key.

Cipher ci = Cipher.getInstance("AES/CBC/PKCS5Padding");
ci.init(Cipher.DECRYPT_MODE, skey, new IvParameterSpec(iv));

And finally decrypt the file.

try (FileOutputStream out = new FileOutputStream(inputFile+".ver")){
    processFile(ci, in, out);
}

The static method processFile() is the same one that has been shown above.

And that completes the decryption.

Conclusion

In this article, we learned how to encrypt and decrypt a file using a password. The password is used to generate an AES key which is used to encrypt the file contents. The output file is generated by concatenating the salt, the initialization vector and the encrypted data. It can be decrypted using just the password.