How to encrypt / decrypt with AES from Bouncy Castle API in J2ME applications

19 comments -

In this post we will see how to use the AES (Advanced Encryption Standard) or Rijndael algorithm implementation from the Bouncy Castle API for J2ME platform. The example will use the AES lightweight engine to encrypt and decrypt a file managed by a J2ME (Midlet) application.

The Bouncy Castle Crypto API for Java provides a lightweight cryptographic API that works with everything from the J2ME to the JDK 1.6 platform.

The API is different for J2ME platform than the one for JDK platform. For example, the lightweight API has different implementations for the two platforms:

and also, at functions level, the situation in also different:

  • for the JDK platform the main class for cryptographic algorithms is Cipher;
  • for the J2ME platform there are classes for each cryptographic algorithm; e.g. for AES there are 3: AESEngine, AESFastEngine and AESLightEngine.

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

  • finalist and winner of the AES (Advanced Encryption Standard) contest launched by NIST in 1997
  • created by two Belgians mathematicians: Joan Daemen and Vincent Rijman (Rijndael comes from their name)
  • became cryptographic standard in 2000
  • uses keys with 128, 192 or 256 bits
  • is a symmetric cryptographic algorithm (the same key is used both for encryption and decryption)
  • processes blocks of 128, 192 or 256 bits;
  • effective both on Intel platforms and other software or hardwareplatforms
  • it can be implemented on 32 bit processors and smart cards (8-bitprocessors);
  • faster than DES;
  • it is more secure than 3DES;

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 will use the first implementation – AESEngine, that will process 128 bits (16 bytes) blocks and will use a 192 bit key.

Because, the files that are going to be encrypted may have or NOT (most of the times) a dimension that is 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 encryption solution (complete encryption/decryption solution file) is defined by these steps:

1. define the PaddedBufferedBlockCipher instance used for encryption – encryptCipher in this solution; the PaddedBufferedBlockCipher class provides 2 constructors; both require a BlockCipher instance:

  • one constructor uses by default PKCS7 padding (used by this solution)
  • the second constructor requires a BlockCipherPadding instance;

for the BlockCipher instance it is created an AESEngine object;

2. init the cipher for encryption with a key; the key could be predefined or received; these two first steps are implemented by the class constructors:

public class AES_BC {
 
    PaddedBufferedBlockCipher encryptCipher;
    PaddedBufferedBlockCipher decryptCipher;
 
    // 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
 
    byte[] key = null;
 
    public AES_BC(){
	//predefined 192 bit key value
        key = "SECRET_1SECRET_2SECRET_3".getBytes();
        InitCiphers();
    }
    public AES_BC(byte[] keyBytes){
        key = new byte[keyBytes.length];
        System.arraycopy(keyBytes, 0 , key, 0, keyBytes.length);
        InitCiphers();
    }
 
    private void InitCiphers(){
        encryptCipher = new PaddedBufferedBlockCipher(new AESEngine());
        encryptCipher.init(true, new KeyParameter(key));
        decryptCipher =  new PaddedBufferedBlockCipher(new AESEngine());
        decryptCipher.init(false, new KeyParameter(key));
    }

3. read bytes from the file; in the solution, we read 16 bytes blocks from the file; each block is processed by the int processBytes(byte[] in,int inOff, int len, byte[] out, int outOff) function; the output of the processed block is put in the out buffer which is written in the encrypted file.

4. VERY IMPORTANT STEP call the doFinal function 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.

The last two steps are implemented by the encrypt function:

    public void encrypt(InputStream in, OutputStream out)
    throws ShortBufferException, IllegalBlockSizeException,
    BadPaddingException,DataLengthException,
    IllegalStateException, InvalidCipherTextException
    {
        try {
            // Bytes written to out will be encrypted
            // Read in the cleartext bytes from in InputStream and
            //      write them encrypted to out OutputStream
 
            int noBytesRead = 0;        //number of bytes read from input
            int noBytesProcessed = 0;   //number of bytes processed
 
            while ((noBytesRead = in.read(buf)) >= 0) {
                //System.out.println(noBytesRead +" bytes read");
 
                noBytesProcessed =
		 encryptCipher.processBytes(buf, 0, noBytesRead, obuf, 0);
 
		//System.out.println(noBytesProcessed +" bytes processed");
                out.write(obuf, 0, noBytesProcessed);
            }
 
             //System.out.println(noBytesRead +" bytes read");
             noBytesProcessed = encryptCipher.doFinal(obuf, 0);
 
             //System.out.println(noBytesProcessed +" bytes processed");
             out.write(obuf, 0, noBytesProcessed);
 
            out.flush();
        }
        catch (java.io.IOException e) {
            System.out.println(e.getMessage());
        }
    }

The decryption solution is similar to the encryption one and is implemented by the decrypt function.

The complete solution is implemented by the AES_BC class in this complete encryption/decryption solution file.

In order to use these 2 functions you must open the cleartext file and the encrypted one. This is a sample from a running MIDlet that show you how to use the encryption:

    void encryptFile(String fileName)
    {
         try {
            FileConnection fci =
                (FileConnection)Connector.open("file://localhost/" + currDirName + fileName);
            if (!fci.exists()) {
                throw new IOException("File does not exists");
            }
             //createFile("encrypt.txt", false);
             FileConnection fco =
                (FileConnection)Connector.open("file://localhost/" + currDirName + "encrypt.txt");
 
             if (!fco.exists())
                 fco.create();
 
            if (!fco.exists()) {
                throw new IOException("Can not create encrypted file");
            }
 
            InputStream fis = fci.openInputStream();
            OutputStream fos = fco.openOutputStream();
 
            AES_BC encrypter = new AES_BC();
 
	    // Encrypt
            encrypter.encrypt(fis, fci.fileSize(), fos);
 
            fis.close();
            fos.close();
 
            Alert alert =
                new Alert("Confirmation","File encryption terminated", null, AlertType.INFO);
            alert.setTimeout(Alert.FOREVER);
            Display.getDisplay(this).setCurrent(alert);
         }
         catch (Exception e) {
            Alert alert =
                new Alert("Encryption error!",
                    "Can not access file " + fileName + " in directory " + currDirName +
                    "Exception: " + e.getMessage(), null, AlertType.ERROR);
            alert.setTimeout(Alert.FOREVER);
            Display.getDisplay(this).setCurrent(alert);
        }
    }

The complete solution is implemented by the AES_BC class in this complete encryption/decryption solution file.

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 Chethan on February 2nd, 2011

    Thanks a Lot. A Very Useful Tutorial

  2. #2 by John on May 6th, 2011

    I would only like encrypt a String, how can I do?

    • #3 by catalin.boja on June 5th, 2011

      Hi John,

      Sorry for the late response. If you want to encrypt a String you can use the solution implemented by the encrypt method, but you must convert your String value to a byte array. This can be done using String getBytes() method:

      String msg1 = “Message”;
      byte [] bytes = msg1.getBytes();
      String msg2 = new String(bytes);

      After decryption, you reconstruct your String using the class constructor.
      I hope my answer will help you.

  3. #4 by SIVAKUMAR.J on May 10th, 2011

    Hi,
    Its very usefull.But i need how to use 3DES encryption in j2me using bouncycastle libraries,
    I did not know anything about 3DES.So please send me some information about 3DES.
    Which jar file is need to download .Please send the download link.

    Thanks & Regards,
    Sivakumar.J

  4. #6 by Danilow on May 20th, 2011

    THANK YOU VERY MUUUUUUUUUCH!!!!!!

  5. #7 by Asiri on July 26th, 2011

    pls help
    mobile says “fail to write to file”
    y?

  6. #8 by Asiri on July 26th, 2011

    add this for comment 7
    error occur in
    out.write(obuf, 0, noBytesProcessed);
    thanks help me

    • #9 by catalin.boja on July 26th, 2011

      Hi Asiri,

      This is the first call to out.write(obuf, 0, noBytesProcessed); or somewhere in the encryption process ?
      I ask you because it is clearly a problem with the file (most probably is not opened or it’s not created) if the error is given by the first call to write method.

      Also modify the catch block to display the call stack and the exception class type with:
      System.out.println(e.getClass());
      e.printStackTrace();
      This will provide more info on the error.

      Also, if you are using Netbeans check for the file in the folder used by the mobile emulator. It is somewhere (if you are using Windows) in
      C:\Users\Catalin\javame-sdk\3.0\work\6\appdb\filesystem\root1\private\2

      Maybe this can be helpful. The reasons for the error can be multiple and its is better to check them one at the time.

  7. #10 by maltom on August 16th, 2011

    Thank you! This is realy great article. Now i’m in developing of midlet aplication for Symbian S60 3RD FP1 (Nokia E51) and i testing it in emulator from Nokia in NetBeans IDE.
    I use BouncyCastle AES for String encryption… but i have a problem with decrypting – when i call commands (from main class):

    String pas = “password”; // only testing code
    pas = crypter.encryptStringWithAES(pas);
    // here looks output ok – it gives unreadable chars
    pas = crypter.decryptStringWithAES(pas);
    // but here only exception message :-(

    it throws an exception “DataLengthException” with message “last block incomplete in decryption”.

    I have a methods:
    public String encryptStringWithAES(String inS {
    String outS;
    //byte[] strBytes = inS.getBytes();
    InputStream is = convertStringToStream(inS);
    try {
    OutputStream os = encryptWithAES(is);
    outS = os.toString();
    return outS;
    } catch…

    and

    public String decryptStringWithAES(String inS) {
    String outS;
    InputStream is = convertStringToStream(inS);
    //try {
    OutputStream os;
    try {
    os = decryptWithAES(is);
    outS = os.toString();
    return outS;
    } catch…

    convertStringToStream is conversion method for conversion String to InputStream only

    the decryptWithAES method is practicaly the same as your method encrypt (only with small edits):

    public OutputStream decryptWithAES(InputStream is/*, OutputStream os*/) throws InvalidCipherTextException, IllegalStateException, DataLengthException, IllegalBlockSizeException, BadPaddingException, ShortBufferException {
    OutputStream os = new ByteArrayOutputStream();
    try {

    return os;
    } catch (IOException ioe) {
    //System.out.println(ioe.getMessage());
    return null;
    }

    Can somebody help me with this problem? If you know pls tell me where i make mistake??

    (I’m sorry – my english is not good)

    • #11 by catalin.boja on August 16th, 2011

      Hi Maltom,

      Your English is ok and I have understood the problem.
      The source code you have provided is not useful because the problem may be in the initialization of the ciphers or in the encrypt and decrypt methods. So please check the following:
      - the password has 128, 192 or 256 bits; the test password has only 64 bits and it is too short;
      - you are using PaddedBufferedBlockCipher to create the ciphers;
      - the input buffer has a size equal to 128, 192 or 256 bits;
      - the call to the doFinal() method it is a MUST DO step, even if your clear message is very short (shorter than the block size) and can be processed in one round;
      - check the size of the encrypted message; its size must be a multiple of the block size ;

      I hope these hints will help you to solve the problem. If not I will think to something else.

    • #12 by maltom on August 17th, 2011

      Hi Catalin.Boja,

      Thank you for you answer. Problem was in other place of code. I had a bug in the “way of convert” – “byte[] to String”… here is the right solution, wich works ok:
      String out = new String (os.toString ());
      where os is OutputStream… with this is decryption ok

      Thank you for help ;-) Have a nice day

    • #13 by catalin.boja on August 17th, 2011

      Hi Maltom,

      I am glad that in the end you work it out and that this post has helped you.

    • #14 by maltom on August 20th, 2011

      Hi Catalin.Boja

      i have a next problem with AES. There is the modificated code of yours example (for String input and output):

      http://www.sdilejkod.cz/kod/k2567fs7tn

      In the J2ME aplication for my phone it works maybe ok, but when i probed, functionality of the same code, in classical J2SE Swing application, it comes the next error with decryption

      this is only simple testing code:
      //when i run the method (from main class):
      String a = cr.encryptStringWithAes(“welcome_in_AES_.”);
      //the output is:
      J6 =��NJB����#�;Ө=�~Nx��C^g
      //but when i call the method for decryption:
      String b = cr.decryptStringWithAes(a);

      in the console i have ouput strings:

      16 bytes read
      0 bytes processed
      16 bytes read
      16 bytes processed
      16 bytes read
      16 bytes processed
      4 bytes read
      16 bytes processed
      -1 bytes read

      and it throws exception with message:

      “last block incomplete in decryption”

      Can you tell me, where’s my mistake now?
      The code is the same as in the J2ME for mobile phone, but on PC aplication it gives wrong outputs. I don’t understand it :-(

    • #15 by Catalin on August 20th, 2011

      Hi Maltom,

      The problem is in the encryptStringWithAes() method. If you check it in the debugger you will see that in the next sequence:

      os.write(oBuffer, 0, noBytesProcessed);
      os.flush();
      vystup = os.toString();
      return vystup;

      the os array has 32 bytes (which is ok because it is a multiple of the AES block size), but after call to toString(), the vystup String, has only 31 symbols (J6 =��NJB����#�;Ө=�~Nx��C^g).

      This is the reason why you get the exceptions in decryptStringWithAes() method. The cipher is broken and can’t be decrypted.

      The description (from the API) of the toString() method is:

      Returns a string representation of the object. In general, the toString method returns a string that “textually represents” this object.

      Remember that the encrypted result is a stream of bytes and not a stream of chars, despite the form of the initial message. Because not all bytes values can be converted to a char it is better to keep the cipher as a stream of bytes.
      Another suggestion is to use the BouncyCastle library for the JSE and not the one for the J2ME because it uses the full power of the JSE framework.
      I will put tomorrow a post with an example of using Bouncy Castle for JSE.

      Ok, so a solution for your problem is to NOT use String as a storage and to work with ByteArrayOutputStream and ByteArrayInputStream (using InputStream and OutputStream you will get back to ByteArrayOutputStream when trying to convert an OutputStream to an InputStream).
      Make these modifications:

      public ByteArrayOutputStream encryptStringWithAes(String inRetezec) 
      throws ShortBufferException, ... {
              InputStream is = convertStringToStream(inRetezec);
              ByteArrayOutputStream  os = new ByteArrayOutputStream();
              ....
              os.write(oBuffer, 0, noBytesProcessed);
              os.flush();
              vystup = os.toString();
              //return vystup;
              return os;
      } catch (IOException e) {
              //return e.getMessage();
              return null;
      }
       
      public String decryptStringWithAes(InputStream inRetezec) 
                  throws ShortBufferException...... {
       
              InputStream is = inRetezec;
              OutputStream os = new ByteArrayOutputStream();
              ....
             }

      and test it with

      CrypterBC cr = new CrypterBC();
              try
              {
              ByteArrayOutputStream a = 
      cr.encryptStringWithAes("welcome_in_AES_.");
              System.out.println(a.toString());
       
              String b = cr.decryptStringWithAes(
      new ByteArrayInputStream(a.toByteArray()));
              System.out.println(b);
              }
              catch(Exception er)
              {
                  System.out.println(er.getMessage());
                  er.printStackTrace();
              }

      If you have problems with the code I will put it in a zip file.

  8. #16 by Joe on November 4th, 2011

    hello Catalin
    really thanx for you help

    I try to run the code in
    http://www.sdilejkod.cz/kod/k2567fs7tn

    and I made all modification you told him

    but my quastion is how to test the application
    kuz I am begginer in j2me
    and I using neatbeans and Nokia symbian belly SDK?
    and can I use this code with AES (128)?
    my application idea is near from this code
    that I want to decrypt text by using 128key

    thanx in advance

(will not be published)