Sunday, 19 August 2012

AES 256 Symmetric Encryption with BouncyCastle

Java provides the Cipher class to perform symmetric encryption. Several algorithms are available, but unfortunately, not all key sizes are allowed. The recommended solution is to install the unlimited JCE version. However, this is not a portable solution.

Trying to perform AES encryption with a 256 bit key triggers an error. A portable solution is to use BouncyCastle's library instead:
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk16</artifactId>
    <version>1.46</version>
</dependency>
The following class illustrates how BounceCastle can be used for AES:
public class AESBouncyCastle {

    private final BlockCipher AESCipher = new AESEngine();

    private PaddedBufferedBlockCipher pbbc;
    private KeyParameter key;

    public void setPadding(BlockCipherPadding bcp) {
        this.pbbc = new PaddedBufferedBlockCipher(AESCipher, bcp);
    }

    public void setKey(byte[] key) {
        this.key = new KeyParameter(key);
    }

    public byte[] encrypt(byte[] input)
            throws DataLengthException, InvalidCipherTextException {
        return processing(input, true);
    }

    public byte[] decrypt(byte[] input)
            throws DataLengthException, InvalidCipherTextException {
        return processing(input, false);
    }

    private byte[] processing(byte[] input, boolean encrypt)
            throws DataLengthException, InvalidCipherTextException {

        pbbc.init(encrypt, key);

        byte[] output = new byte[pbbc.getOutputSize(input.length)];
        int bytesWrittenOut = pbbc.processBytes(
            input, 0, input.length, output, 0);

        pbbc.doFinal(output, bytesWrittenOut);

        return output;

    }

}
It can be used as following:
KeyGenerator kg = KeyGenerator.getInstance("AES");
kg.init(256);
SecretKey sk = kg.generateKey();

AESBouncyCastle abc = new AESBouncyCastle();
abc.setPadding(new PKCS7Padding());
abc.setKey(sk.getEncoded());

String secret = "This is a secret message!";
System.out.println(secret);
byte[] ba = secret.getBytes("UTF-8");

byte[] encr = abc.encrypt(ba);
System.out.println("Encrypted : "
    + Hex.encodeHexString(encr));
byte[] retr = abc.decrypt(encr);

if ( retr.length == ba.length ) {
    ba = retr;
} else {
    System.arraycopy(retr, 0, ba, 0, ba.length);
}

String decrypted = new String(ba, "UTF-8");
System.out.println(decrypted);
The above starts by creating an AES 256 private key (more about private key generation here). Next, a padding is set. From the Javadoc, available paddings are: ISO10126d2, ISO7816d4, PKCS7, TBC, X923 and ZeroByte.

After retrieving the decrypted byte array, we check for its length, because AES operates with blocks of bytes. The original message length may not be a multiple of these block length.

The generated output is:
This is a secret message!
Encrypted : 6d204e3e52daee09800ba6fd9080653dad04a3d4725f3502b78a89b2150e1f63
This is a secret message!
The Hex class is an Apache Commons tool.