How to encrypt/decrypt files in Java with AES in CBC mode using Bouncy Castle API and NetBeans or Eclipse

3 comments -

The Bouncy Castle Crypto API for Java provides a lightweight cryptography API that is an alternative to the standard Sun Java Cryptographic Architecture (JCA) and Java Cryptographic Extension (JCE) bundled in the JDK. The API can be used in J2ME MIDlet applications or in other Java applications up to the 1.7 platform.

The Bouncy Castle lightweight cryptographic API can be used as a:

  • Cryptographic Service Provider (CSP) for the JCA;
  • external library.

In this post we will see how to use the the Bouncy Castle lightweight cryptographic API in both situations, as the syntax differs from one approach to the other. To highlight the differences, the advantages and the disadvantages of the two solutions, the Bouncy Castle API is used in a console Java application to encrypt/decrypt files with the AES (Advanced Encryption Standard) or Rijndael algorithm in Cipher Block Chaining (CBC) mode.

For the J2ME platform implementation you can read How to encrypt / decrypt with AES from Bouncy Castle API in J2ME applications.

In order to be able to use the Bouncy Castle Cryptographic API in either NetBeans or Eclipse read the How to use Bouncy Castle Cryptographic API in NetBeans or Eclipse for Java JSE projects post as it describes all the necessary steps for installing the API as a provider or external library. The examples in this post assumes that the Bouncy Castle is available to the Java project.

The AES (Advanced Encryption Standard) or Rijndael algorithm important characteristics are:

  • winner of the AES (Advanced Encryption Standard) contest launched by NIST in 1997;
  • Rijndael comes from its creators: two Belgians mathematicians: Joan Daemen and Vincent Rijman;
  • cryptographic standard since 2000;
  • can use keys with 128, 192 or 256 bits;
  • symmetric cryptographic algorithm as the same key is used both for encryption and decryption;
  • can process blocks of 128, 192 or 256 bits;
  • can be implemented on 32 bit processors and smart cards (8-bitprocessors);
  • faster than DES and more secure than 3DES.

In order to encrypt/decrypt files in Java with AES in Cipher Block Chaining (CBC) mode using Bouncy Castle API and NetBeans or Eclipse, we need:

 

Solution 1. Use the Bouncy Castle Cryptographic API as a provider in NetBeans or Eclipse to encrypt/decrypt with AES in Java applications

In order to be able to use the Bouncy Castle Cryptographic API in either NetBeans or Eclipse read the How to use Bouncy Castle Cryptographic API in NetBeans or Eclipse for Java JSE projects.

The main advantage of the JAC is that provides a single interface for invoking multiple cryptographic providers as SunJCE or Bouncy Castle. The abstract layer defined by the JAC hides the classes and methods of the provider and simplifies the development and maintenance of the application code. That means we will use the Cipher class.

For any type of encryption algorithm, the JCE API for JSE platform provides one implementation (the description is taken from the JCA Reference Guide):

Cipher – “The Cipher class provides the functionality of a cryptographic cipher used for encryption and decryption….Cipher objects are obtained by using one of the Cipher getInstance() static factory methods.” [JCA Reference Guide]

In this example, we use the standard implementation of AES, that processes 128 bits (16 bytes) blocks and will use a 128 bit key (a 192 bit one is recommended).

Because, the files that are going to be encrypted may have (most of the times) a dimension that is NOT multiple of block size (128 bits), we must use padding for the last block. In this case we will use the PKCS5Padding method (the NoPadding option will work only for files with a dimension that is a multiple of block size).

The solution (complete solution file for AES encryption/decryption in CBC mode using Bouncy Castle as a JCA provider) is defined by the next steps:

1.1. Define the Cipher instance used for encryption, encryptCipher in this solution, and for decryption, decryptCipher; the Cipher class provides one static method (it doesn’t have public constructors), getInstance(), used to create Cipher instances;

public static final Cipher getInstance(String transformation, String provider)

the method requires

  • a transformation string that has 2 forms: “algorithm/mode/padding” or “algorithm”, [JCA Reference Guide]; we will use the first form: “AES/CBC/PKCS5Padding”;
  • a provider name that can be BC for Bouncy Castle or SunJCE for the standard cryptographic API that comes with the JDK; the advantage of the JCA/JCE framework is that you can change anytime the provider, even at the runtime;

As you can see, we use the Cipher Block Chaining – CBC encryption mode, which is more secure than Electronic Code Book – ECB. CBC mode requires an an initialization vector for the first step of the encryption process;

1.2. Initialize the ciphers with a 128 bit key (for a 192 bit one read the last section). The key could be predefined or received in the constructor. The IV vector is given in the constructor or it used with its default value (0 for all 16 bytes).

These 2 first steps are implemented by the class constructors:

public class BouncyCastleProvider_AES_CBC {
 
    // The default block size
    public static int blockSize = 16;
 
    Cipher encryptCipher = null;
    Cipher decryptCipher = null;
 
    // Buffer used to transport the bytes from one stream to another
    byte[] buf = new byte[blockSize];       //input buffer
    byte[] obuf = new byte[512];            //output buffer
 
    // The key
    byte[] key = null;
    // The initialization vector needed by the CBC mode
    byte[] IV = null;
 
    public BouncyCastleProvider_AES_CBC(){
        //for a 192 key you must install the unrestricted policy files
        //  from the JCE/JDK downloads page
        key ="SECRET_1SECRET_2".getBytes();
        //default IV value initialized with 0
        IV = new byte[blockSize];
    }
 
    public BouncyCastleProvider_AES_CBC(String pass, byte[] iv){
        //get the key and the IV
        key = pass.getBytes();
        IV = new byte[blockSize];
        System.arraycopy(iv, 0 , IV, 0, iv.length);
    }
    public BouncyCastleProvider_AES_CBC(byte[] pass, byte[]iv){
        //get the key and the IV
        key = new byte[pass.length];
        System.arraycopy(pass, 0 , key, 0, pass.length);
        IV = new byte[blockSize];
        System.arraycopy(iv, 0 , IV, 0, iv.length);
    }
 
    public void InitCiphers()
            throws NoSuchAlgorithmException,
            NoSuchProviderException,
            NoSuchProviderException,
            NoSuchPaddingException,
            InvalidKeyException,
            InvalidAlgorithmParameterException{
       //1. create the cipher using Bouncy Castle Provider
       encryptCipher =
               Cipher.getInstance("AES/CBC/PKCS5Padding", "BC");
       //2. create the key
       SecretKey keyValue = new SecretKeySpec(key,"AES");
       //3. create the IV
       AlgorithmParameterSpec IVspec = new IvParameterSpec(IV);
       //4. init the cipher
       encryptCipher.init(Cipher.ENCRYPT_MODE, keyValue, IVspec);
 
       //1 create the cipher
       decryptCipher =
               Cipher.getInstance("AES/CBC/PKCS5Padding", "BC");
       //2. the key is already created
       //3. the IV is already created
       //4. init the cipher
       decryptCipher.init(Cipher.DECRYPT_MODE, keyValue, IVspec);
    }
}

1.3.[optionally] If you want to use Electronic Code Book – ECB encryption mode (it’s simpler that CBC) you must discard the initialization vector and replace the transformation String with “AES/ECB/PKCS5Padding”;

1.4.[optionally] Because the initialization vector – IV is used in the encryption it is also required in the decryption. As the strength of the encryption is given by the key, you can send the IV value with the encrypted message. A solution is to write it at the beginning of the encrypted file in order to get it easily at the decryption.

1.5. Read 16 bytes (the size of the block) from the file and process them; in the solution each block is processed by the

int update(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset)

method; the output of the processed block is put in the out buffer which is written in the encrypted file.

1.6. VERY IMPORTANT STEP ! always call the doFinal() method which will process the last block in the buffer; the internal mechanism of the algorithm implementation, based in its encryption mode (ECB, CBC, or other) keeps an internal buffer which must be also discarded into the output file (this is NOT the last block of the input file); the doFinal() it is a MUST DO step and is a common error to forgetting it.

The last two steps are implemented by the encrypt function, CBCEncrypt():

    public void CBCEncrypt(InputStream fis, OutputStream fos)
            throws IOException,
            ShortBufferException,
            IllegalBlockSizeException,
            BadPaddingException
    {
       //optionally put the IV at the beggining of the cipher file
       //fos.write(IV, 0, IV.length);
 
       byte[] buffer = new byte[blockSize];
       int noBytes = 0;
       byte[] cipherBlock =
               new byte[encryptCipher.getOutputSize(buffer.length)];
       int cipherBytes;
       while((noBytes = fis.read(buffer))!=-1)
       {
           cipherBytes =
                   encryptCipher.update(buffer, 0, noBytes, cipherBlock);
           fos.write(cipherBlock, 0, cipherBytes);
       }
       //always call doFinal
       cipherBytes = encryptCipher.doFinal(cipherBlock,0);
       fos.write(cipherBlock,0,cipherBytes);
 
       //close the files
       fos.close();
       fis.close();
    }

The decryption solution is similar to the encryption one and is implemented by the decrypt method, CBCDecrypt().

The complete solution is implemented by the BouncyCastleProvider_AES_CBC class in complete solution file for AES encryption/decryption in CBC mode using Bouncy Castle as a JCA provider.
 

Solution 2. Use the Bouncy Castle Cryptographic API as an external library in NetBeans or Eclipse to encrypt/decrypt with AES in Java applications

In order to be able to use the Bouncy Castle Cryptographic API in either NetBeans or Eclipse read the How to use Bouncy Castle Cryptographic API in NetBeans or Eclipse for Java JSE projects.

For AES, the Bouncy Castle Crypto API for J2ME platform provides three implementations (their description is taken from the Bouncy Castle API documentation):

  • AESEngine – “The middle performance version uses only one 256 word table for each, for a total of 2Kbytes, adding 12 rotate operations per round to compute the values contained in the other tables from the contents of the first” [Bouncy Castle API documentation]
  • AESFastEngine – “The fastest uses 8Kbytes of static tables to precompute round calculations, 4 256 word tables for encryption and 4 for decryption” [Bouncy Castle API documentation]
  • AESLightEngine – “The slowest version uses no static tables at all and computes the values in each round” [Bouncy Castle API documentation]

In this example, we use the first implementation – AESEngine, that processes 128 bits (16 bytes) blocks and will use a 192 bit key.

Because, the files that are going to be encrypted may have (most of the times) a dimension that is NOT multiple of block size (128 bits), we must use padding for the last block. In this case we will use the PaddedBufferedBlockCipher class, which is “a wrapper class that allows block ciphers to be used to process data in a piecemeal fashion with padding” [Bouncy Castle API documentation]. The default padding mechanism used is the one outlined in PKCS5/PKCS7 standard.

To increase the strength of the cipher we use Cipher Block Chaining as the encryption mode. The Bouncy Castle lightweight API provides the CBCBlockCipher class that implements the CBC mode for a Block Cipher. This requires an initialization vector – IV.

The solution (complete solution file for AES encryption/decryption in CBC mode using Bouncy Castle as an external library) is defined by the next steps:

2.1. define an object that will implement the AES engine in CBC mode with padding; to do that using Bouncy Castle lightweight API it means to read the API documentation and to define an object for each option (one disadvantage of using directly the API and not as a JCA provider):

  • AESEngine – for the AES cryptographic algorithm;
  • CBCBlockCipher – for the Cipher Block Chaining mode;
  • PaddedBufferedBlockCipher – for the PKCS5/PKCS7 padding;
Classes needed to define AES instance in CBC mode with padding in Bouncy Castle API

Classes needed to define AES instance in CBC mode with padding in Bouncy Castle API

2.2. Initialize the cipher for encryption with a 192 bit key that could be predefined or received. The IV vector is given in the constructor or it used with its default value (0 for all 16 bytes). In order to manage the cryptographic engine parameters the Bouncy Castle API provides the ParametersWithIV and KeyParameter classes.

The first two steps are implemented by the BouncyCastleAPI_AES_CBC class constructors:

public class BouncyCastleAPI_AES_CBC {
    PaddedBufferedBlockCipher encryptCipher = null;
    PaddedBufferedBlockCipher decryptCipher = null;
 
    // Buffer used to transport the bytes from one stream to another
    byte[] buf = new byte[16];              //input buffer
    byte[] obuf = new byte[512];            //output buffer
    // The key
    byte[] key = null;
    // The initialization vector needed by the CBC mode
    byte[] IV =  null;
 
    // The default block size
    public static int blockSize = 16;
 
    public BouncyCastleAPI_AES_CBC(){
        //default 192 bit key
        key = "SECRET_1SECRET_2SECRET_3".getBytes();
        //default IV vector with all bytes to 0
        IV = new byte[blockSize];
    }
    public BouncyCastleAPI_AES_CBC(byte[] keyBytes){
        //get the key
        key = new byte[keyBytes.length];
        System.arraycopy(keyBytes, 0 , key, 0, keyBytes.length);
 
        //default IV vector with all bytes to 0
        IV = new byte[blockSize];
    }
 
    public BouncyCastleAPI_AES_CBC(byte[] keyBytes, byte[] iv){
        //get the key
        key = new byte[keyBytes.length];
        System.arraycopy(keyBytes, 0 , key, 0, keyBytes.length);
 
        //get the IV
        IV = new byte[blockSize];
        System.arraycopy(iv, 0 , IV, 0, iv.length);
    }
 
    public void InitCiphers(){
        //create the ciphers
        // AES block cipher in CBC mode with padding
        encryptCipher = new PaddedBufferedBlockCipher(
                new CBCBlockCipher(new AESEngine()));
 
        decryptCipher =  new PaddedBufferedBlockCipher(
                new CBCBlockCipher(new AESEngine()));
 
        //create the IV parameter
        ParametersWithIV parameterIV =
                new ParametersWithIV(new KeyParameter(key),IV);
 
        encryptCipher.init(true, parameterIV);
        decryptCipher.init(false, parameterIV);
    }

2.3.[optionally] For Electronic Code Book – ECB encryption mode (it’s simpler and faster that CBC, but less secure) you must discard the initialization vector and replace the CBCBlockCipher instance with a BlockCipher one;

2.4.[optionally] As in the previous solution you can write the IV value at the beginning of the encrypted file in order to get it easily at the decryption.

2.5. Read bytes from the file and encrypt them. In the solution, we read blocks of 16 bytes from the file and each block is processed by the

int processBytes(byte[] in,int inOff, int len, byte[] out, int outOff)

method. The output of the processed block is put in the out buffer which is written in the encrypted file.

2.6. VERY IMPORTANT STEP call the doFinal() method which will process the last block in the buffer. The internal mechanism of the algorithm implementation, based in its encryption mode (ECB, CBC, or other) keeps an internal buffer which must be also discarded into the output file (this is NOT the last block of the input file). The call to doFinal() it is a MUST DO step.

The last two steps are implemented by the CBCEncrypt method:

public void CBCEncrypt(InputStream in, OutputStream out)
throws ShortBufferException, 
        IllegalBlockSizeException,
        BadPaddingException,
        DataLengthException,
        IllegalStateException,
        InvalidCipherTextException,
        IOException
{
    // Bytes written to out will be encrypted
    // Read in the cleartext bytes from in InputStream and
    //      write them encrypted to out OutputStream
 
    //optionaly put the IV at the beggining of the cipher file
    //out.write(IV, 0, IV.length);
 
    int noBytesRead = 0;        //number of bytes read from input
    int noBytesProcessed = 0;   //number of bytes processed
 
    while ((noBytesRead = in.read(buf)) >= 0) {
        noBytesProcessed =
                encryptCipher.processBytes(buf, 0, noBytesRead, obuf, 0);
        out.write(obuf, 0, noBytesProcessed);
    }
 
    noBytesProcessed = encryptCipher.doFinal(obuf, 0);
    out.write(obuf, 0, noBytesProcessed);
    out.flush();
 
    in.close();
    out.close();
}

The decryption solution is similar to the encryption one and is implemented by the CBCDecrypt method.

The complete solution is implemented by the BouncyCastleAPI_AES_CBC class in complete solution file for AES encryption/decryption in CBC mode using Bouncy Castle as an external library.

 

How to encrypt/decrypt files in Java with AES in CBC mode using Bouncy Castle API and NetBeans or Eclipse IDE

In order to test the previous two solutions you must:

  • create a simple console Java application in NetBeans or Eclipse IDE
  • install the Bouncy Castle API as a JCA provider and as an eternal library for the Java project (How to use Bouncy Castle Cryptographic API in NetBeans or Eclipse for Java JSE projects)
  • add the two classes: BouncyCastleProvider_AES_CBC and BouncyCastleAPI_AES_CBC (the complete code files are available using the links at the end);
  • create a simple text file, clear.txt, with some content;
  • edit the main method with the next source code and run the test application
   public static void main(String[] args) throws FileNotFoundException, IOException {
        try {
            FileInputStream fis =
                    new FileInputStream(new File("clear.txt"));
            FileOutputStream fos =
                    new FileOutputStream(new File("encrypt.txt"));
 
            //solution 1
            //BouncyCastleAPI_AES_CBC bc = new BouncyCastleAPI_AES_CBC();
            //solution 2
            BouncyCastleProvider_AES_CBC bc =
                    new BouncyCastleProvider_AES_CBC();
            bc.InitCiphers();
 
            //encryption
            bc.CBCEncrypt(fis, fos);
 
            fis = new FileInputStream(new File("encrypt.txt"));
            fos = new FileOutputStream(new File("clear_test.txt"));
 
            //decryption
            bc.CBCDecrypt(fis, fos);
 
        } catch (ShortBufferException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalBlockSizeException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        } catch (BadPaddingException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        } catch (DataLengthException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalStateException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        } catch (Exception ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }
 
        System.out.println("Test done !");
  • verify the output text file after the decryption.

 

Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files for Java 6 and 7

The normal JDK download has a set of policy files that impose restrictions on the key sizes. Key sizes are limited in general to 128 bits. One exception is the symmetric cipher Triple-DES, 3DES.

The above example regarding how to encrypt/decrypt files in Java with AES in CBC mode is affected because you must use a 128 bits key for AES.

If you want to use a 192 bit key, the solution for this restriction is to download the unrestricted policy files from the Java JDK downloads page at java.oracle.com (it is placed at the bottom of the page with a Unlimited Strength Jurisdiction Policy Files link.

On Windows, copy the two files, local_policy.jar and US_export_policy.jar, to the \lib\security\ subfolder of your JRE folder (Attention ! Do not forget that if you have installed the JDK, it also has a JRE instance).

 
The full source code of the two presented solutions is available at:

Related posts:

Like it? Then share this post or check the external adds. Sharing is the best way to appreciate the author.

, , , , ,


  1. #1 by Amri Shodiq on September 18th, 2013

    Hi there,
    I find this tutorial help me a lot in my homework. After experiments with AES with CBC and ECB I found no problem at all. However, I find difficulties when try to use OFB. The result is pretty different with test vector provided by NIST: http://csrc.nist.gov/groups/STM/cavp/documents/aes/KAT_AES.zip.

    Can we have a discussion around this issue?

  2. #2 by Lok on September 19th, 2013

    Thanks so much for writing this. It’s been incredibly helpful.

    I had to modify the API script to encrypt using the ECB cipher mode (don’t ask, out of my control), so I can provide that to you if you like to include on your site.

    However it seems as though Bouncy Castle doesn’t provide an ECBBlockCipher class any more (and BlockCipher is an interface so can’t be instanciated) so I used the source code for ECBBlockCipher from this location:

    http://isaacyang1988.googlecode.com/svn/trunk/Crypt/src/org/bouncycastle/crypto/modes/ECBBlockCipher.java

    I also used the ParametersWithRandom class in place of the ParametersWithIV class.

    Anyway, thanks again.

(will not be published)