Saturday, November 17, 2012

Example for Encrypt and Decrypt using AES with Android 4.2

I'll put in here the test that I did:
As after test the code on my Nexus it's worked encrypting and decrypting (before just encrypt was working), I got a String from an other phone, from SQLite, copied and sent it via email client (GMAIL) to my Nexus, then I have copied it and replace with the one that had been created on 4.2 (the copied one, was from 4.0.4 SII 3G), then started the app again and debugging I could see the correct string returning from this method:
public static String decrypt(String seed, String encrypted) throws Exception {
            byte[] seedByte = seed.getBytes();
            System.arraycopy(seedByte, 0, key, 0, ((seedByte.length < 16) ? seedByte.length : 16));
            String base64 = new String(Base64.decode(encrypted, 0));
            byte[] rawKey = getRawKey(seedByte);
            byte[] enc = toByte(base64);
            byte[] result = decrypt(rawKey, enc);
            return new String(result);

I've made an example to show how it's works.

Activity_main.xml (layout):
<RelativeLayout xmlns:android=""
    tools:context=".MainActivity" >

        android:text="App name" />

        android:text="This is the seed." />
        android:text="This is the text to encrypt" />

        android:text="Encrypted text" />

        android:text="Decrypted text" />

    </RelativeLayout> :
  1: package com.example.encryptdecrittest;
  3:         import;
  4:         import android.os.Bundle;
  5:         import android.util.Log;
  6:         import android.view.Menu;
  7:         import android.widget.TextView;
  9:         public class MainActivity extends Activity {
 11:     private String seedWith16Chars = "This is my seed.";
 12:     private String textToEncrypt = "Hi, this is a test to check its gone work or not.";
 14:     private TextView seed;
 15:     private TextView text;
 16:     private TextView encryptedValue;
 17:     private TextView decryptedValue;
 20:     @Override
 21:     protected void onCreate(Bundle savedInstanceState) {
 22:         super.onCreate(savedInstanceState);
 23:         setContentView(R.layout.activity_main);
 25:         seed = (TextView) findViewById(;
 26:         seed.setText(seedWith16Chars);
 28:         text = (TextView) findViewById(;
 29:         text.setText(textToEncrypt);
 31:         encryptedValue = (TextView) findViewById(;
 32:         decryptedValue = (TextView) findViewById(;
 34:         try {
 35:             // This value was got when did run it from an 2.3.3 device a Galaxy SII running Android 4.0.4
 36:             String encrypted = "MzA3RDBCMjMxMjQzNzcxREUxMUYxNjg1NzgwOTU1MjU1M0FDOUZEN0M3Q0JGQ0Q5MTI2NEIyNTE2"
 39:             // Uncomment the line bellow and comment the line above to run it on an Android 4.1.2 or older.
 40:             // String encrypted = EncodeDecodeAES.encrypt(seedWith16Chars, textToEncrypt);
 41:             Log.e("Encrypt", encrypted);
 42:             encryptedValue.setText(encrypted);
 44:             String decrypted = EncodeDecodeAES.decrypt(seedWith16Chars, encrypted);
 45:             decryptedValue.setText(decrypted);
 46:             Log.e("Decrypt", decrypted);
 47:         } catch (Exception e) {
 48:             Log.e("Exception", e.getLocalizedMessage());
 49:         }
 51:     }
 54:     @Override
 55:     public boolean onCreateOptionsMenu(Menu menu) {
 56:         // Inflate the menu; this adds items to the action bar if it is present.
 57:         getMenuInflater().inflate(, menu);
 58:         return true;
 59:     }
 61: }
 63: :
  1: package com.example.encryptdecrittest;
  3: import;
  5: import javax.crypto.Cipher;
  6: import javax.crypto.KeyGenerator;
  7: import javax.crypto.SecretKey;
  8: import javax.crypto.spec.SecretKeySpec;
 10: import android.util.Base64;
 12: public class EncodeDecodeAES {
 14:  private final static String HEX = "0123456789ABCDEF";
 15:  private final static int JELLY_BEAN_4_2 = 17;
 16:  private final static byte[] key = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 19:  // static {
 20:  // Security.addProvider(new BouncyCastleProvider());
 21:  // }
 23:  public static String encrypt(String seed, String cleartext) throws Exception {
 24:   byte[] rawKey = getRawKey(seed.getBytes());
 25:   byte[] result = encrypt(rawKey, cleartext.getBytes());
 26:   String fromHex = toHex(result);
 27:   String base64 = new String(Base64.encodeToString(fromHex.getBytes(), 0));
 28:   return base64;
 29:  }
 32:  public static String decrypt(String seed, String encrypted) throws Exception {
 33:   byte[] seedByte = seed.getBytes();
 34:   System.arraycopy(seedByte, 0, key, 0, ((seedByte.length < 16) ? seedByte.length : 16));
 35:   String base64 = new String(Base64.decode(encrypted, 0));
 36:   byte[] rawKey = getRawKey(seedByte);
 37:   byte[] enc = toByte(base64);
 38:   byte[] result = decrypt(rawKey, enc);
 39:   return new String(result);
 40:  }
 43:  public static byte[] encryptBytes(String seed, byte[] cleartext) throws Exception {
 44:   byte[] rawKey = getRawKey(seed.getBytes());
 45:   byte[] result = encrypt(rawKey, cleartext);
 46:   return result;
 47:  }
 50:  public static byte[] decryptBytes(String seed, byte[] encrypted) throws Exception {
 51:   byte[] rawKey = getRawKey(seed.getBytes());
 52:   byte[] result = decrypt(rawKey, encrypted);
 53:   return result;
 54:  }
 57:  private static byte[] getRawKey(byte[] seed) throws Exception {
 58:   KeyGenerator kgen = KeyGenerator.getInstance("AES"); // , "SC");
 59:   SecureRandom sr = null;
 60:   if (android.os.Build.VERSION.SDK_INT >= JELLY_BEAN_4_2) {
 61:    sr = SecureRandom.getInstance("SHA1PRNG", "Crypto");
 62:   } else {
 63:    sr = SecureRandom.getInstance("SHA1PRNG");
 64:   }
 65:   sr.setSeed(seed);
 66:   try {
 67:    kgen.init(256, sr);
 68:    // kgen.init(128, sr);
 69:   } catch (Exception e) {
 70:    // Log.w(LOG, "This device doesn't suppor 256bits, trying 192bits.");
 71:    try {
 72:     kgen.init(192, sr);
 73:    } catch (Exception e1) {
 74:     // Log.w(LOG, "This device doesn't suppor 192bits, trying 128bits.");
 75:     kgen.init(128, sr);
 76:    }
 77:   }
 78:   SecretKey skey = kgen.generateKey();
 79:   byte[] raw = skey.getEncoded();
 80:   return raw;
 81:  }
 84:  private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception {
 85:   SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
 86:   Cipher cipher = Cipher.getInstance("AES"); // /ECB/PKCS7Padding", "SC");
 87:   cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
 88:   byte[] encrypted = cipher.doFinal(clear);
 89:   return encrypted;
 90:  }
 93:  private static byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception {
 94:   SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
 95:   Cipher cipher = Cipher.getInstance("AES"); // /ECB/PKCS7Padding", "SC");
 96:   cipher.init(Cipher.DECRYPT_MODE, skeySpec);
 97:   byte[] decrypted = cipher.doFinal(encrypted);
 98:   return decrypted;
 99:  }
102:  public static String toHex(String txt) {
103:   return toHex(txt.getBytes());
104:  }
107:  public static String fromHex(String hex) {
108:   return new String(toByte(hex));
109:  }
112:  public static byte[] toByte(String hexString) {
113:   int len = hexString.length() / 2;
114:   byte[] result = new byte[len];
115:   for (int i = 0; i < len; i++)
116:    result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2), 16).byteValue();
117:   return result;
118:  }
121:  public static String toHex(byte[] buf) {
122:   if (buf == null)
123:    return "";
124:   StringBuffer result = new StringBuffer(2 * buf.length);
125:   for (int i = 0; i < buf.length; i++) {
126:    appendHex(result, buf[i]);
127:   }
128:   return result.toString();
129:  }
132:  private static void appendHex(StringBuffer sb, byte b) {
133:   sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f));
134:  }
136: }

Then I did run it from a SII with that line that have a ciphered text commented,

        String encrypted =    "MzA3RDBCMjMxMjQzNzcxREUxMUYxNjg1NzgwOTU1MjU1M0FDOUZEN0M3Q0JGQ0Q5MTI2NEIyNTE2"

and the one that have

        String encrypted = EncodeDecodeAES.encrypt(seedWith16Chars, textToEncrypt);

Uncomented. Then the LogCat show me the encrypted value, remember that we are still running it from an Anroid 4.0.4 (SII). After that I've copied the text encrypted to be received by **encrypted** String, and unplugged the SII plugged my Nexus with 4.2 and ran the code and worked.
Maybe if you are using a seed (or password) with less than 16 digits it's gone fail. If it's the case try complete it from the text length (that is less then 16th position), with something like spaces or zeros, or even 1 and 0's - 10101..) up to the 16th position.
Also you need to pay attention if your previous code is initializing the keyGen with 128 bits and the class published above try first 256 and then if it's fail go downgrading up to 128bits, then you should comment all of them leaving only the one that has 128.
If you want to download the example project please go to 
I hope that it helps you.


  1. Excelente post; however, could you explain why does the seed has to be >= 16 digits?

  2. Hi Pedro,

    Thank you for the compliment. It's has to do with the keyGen init that it's initializing it with 256bits, if it's has been initialized with 128 then 8 chars length would be enough.
    Now the reason as AES uses PKCS7Padding for 256bits and PKCS5Padding for 128bits (and such probably also for 192bits) once the Class got first 256 you must have at least 16digits length as those values have as base the number 8, and for 128bits at least 8chars length.
    The way the AES works means that 64bits password (8chars) will generate a 128bits cipher, and 128bits password (16chars) will generate a 256bit cipher.
    For more details please refer those links bellow: ; ; ;

  3. This comment has been removed by the author.

  4. Hi, I am John.

    I read your solution about the Cipher problem on Android 4.2, I am running into the same problem.
    I have some questions:
    1. what's the array "key" for? I note that the "key" array is never used in your code, you just copy seed bytes into it, but not use it.
    private final static byte[] key = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
    The "key" is never used in your source code.

    2. How to decrypt the string that encrypted by the old way?

    3. Here's my code, and some of my app's users have already saved their information with the "encrypt" function, I don't know how to decrypt the information correctly.

    public class MyCipher {
    public static String encrypt(String seed, String cleartext)
    throws Exception {
    byte[] rawKey = getRawKey(seed.getBytes());
    byte[] result = encrypt(rawKey, cleartext.getBytes());
    return toHex(result);

    public static String decrypt(String seed, String encrypted)
    throws Exception {
    byte[] rawKey = getRawKey(seed.getBytes());
    byte[] enc = toByte(encrypted);
    byte[] result = decrypt(rawKey, enc);
    return new String(result);

    private static byte[] getRawKey(byte[] seed) throws Exception {
    KeyGenerator kgen = KeyGenerator.getInstance("AES");
    SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
    kgen.init(128, sr); // 192 and 256 bits may not be available
    SecretKey skey = kgen.generateKey();
    byte[] raw = skey.getEncoded();
    return raw;

    private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception {
    SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
    byte[] encrypted = cipher.doFinal(clear);
    return encrypted;

    private static byte[] decrypt(byte[] raw, byte[] encrypted)
    throws Exception {
    SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.DECRYPT_MODE, skeySpec);
    byte[] decrypted = cipher.doFinal(encrypted);
    return decrypted;

    public static byte[] toByte(String hexString) {
    int len = hexString.length() / 2;
    byte[] result = new byte[len];
    for (int i = 0; i < len; i++)
    result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2),
    return result;

    public static String toHex(byte[] buf) {
    if (buf == null)
    return "";
    StringBuffer result = new StringBuffer(2 * buf.length);
    for (int i = 0; i < buf.length; i++) {
    appendHex(result, buf[i]);
    return result.toString();

    private final static String HEX = "0123456789ABCDEF";

    private static void appendHex(StringBuffer sb, byte b) {
    sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f));

    Thank you very much.

    1. I want encrypt & decrypt .apk file in android is it possible ?

    2. Hi Sanjakumar,

      If you want mean get your .apk file and encrypt then decrypt, you can as you can do with any file, however Android will not be able to install or read it, for this it's necessary decrypt the file.
      For do that you can load the file into memory then encrypt or decrypt (if encrypted) and save it, however would be better if you did it reading/saving as stream.

    3. Sorry I miss the part read decrypt or encrypt then save.

  5. Hi John,

    Answering a couple of your questions:
    1. I just have used it because for some reason I wasn't getting 0 as byte if the password didn't have enough length (16 chars), when decrypting it.

    2. To decrypt it using the old way, I had to took a look on the old code running in an Android version older then 4.2 (did try it on 2.3.6 and 4.0.4), what I did was to take a deep look into the cipher object being returned when encrypting and decrypting and then did a comparation against the counter part from 4.2. The encrypt was going well on both though the decrypt as getting different bytes from the padding, that worked fine after set it with 0's (from the key byte array).

    3. I'll give a try on your code, this weekend, though try look into the cipher object and check if the padding is the same, because 4.2 now use a different getInstance to get the SecureRandom (sr).
    if (android.os.Build.VERSION.SDK_INT >= JELLY_BEAN_4_2) {
    sr = SecureRandom.getInstance("SHA1PRNG", "Crypto");
    } else {
    sr = SecureRandom.getInstance("SHA1PRNG");

    and this is what you are doing :
    KeyGenerator kgen = KeyGenerator.getInstance("AES");
    SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");

    A good way to test it is get a HEX text that you have generated on the old version (<4.2) and create a test project with 4.2 api where you set you text encrypted as I did on the example above, and try to decrypt it, I believe that changing those lines from your getRawKey for those that I have on my code (above) should do the trick. Please let me know if you still are facing a problem.

    1. Hi Klaus,

      Thank you so much for your reply.

      I think I should learn more deep into the Cipher class.


  6. I want to follow this algorithm., Just want to know if I can use it or not for my requirement
    I need to do authorization before my app starts.
    I thought to use unique android ID and use this algorithm and save it locally .
    SO before my app starts I will validate if the Unique ID matches or not
    IS this right approach ?

  7. Hi,

    What you are trying to do looks very similar to the Google LVL ( take a look on the example code that should be at the same path level as android sdk (you can download it using the Android SDK manager). Other thing it's that not all Android devices or OS versions have a unique ID.
    A good approach has been shown on G+ from Romain Guy ( However if you want to create a 'in home' solution you can try using RSA that uses public and private keys, mean your app would make a ws call to your server and pass o the payload those data or details encrypted with your public key and only you will be able to decrypt it with your private key. To do that you will gone need the Android Bouncy Castle jar. Try don't save any important data on device, do it only if it's really necessary.
    I hope have answered your doubt. I could give you some extra ideas though as. Y work pc has died today I'm sending this through my Nexus 7

  8. Your code works great but i have some issue about AES decryption. First of all what i do if my password does not have 16 chars. I recive a document encrypted with aes and a password that has 10 chars how i need to handle the password to get the 16 chars key?

    And second question can i use this to decrypt large files like .xml for example? I tryed to take the file and put it in a string then decrypt but no succes yet.

  9. Hi Marian,

    If your password is already encrypted, then the framework should have filled the extra chars with 0 (this is the reason that for decryption I have created an array with 0s), actually the example should work if your password has been created already in a mobile (can be from any Android, but it will not work out of box if this come from a PC/Server). If the file come from a PC/Server you gone need use the bouncy castle package because the one that come with Android is crippled and there quite more options for AES on the Java (for PC). This example just work if the old encrypted password has been created with Android libs, if it's not the case then you need to import the sponge bounce castle jar (
    and this is a complete set with all Java supported types and algorithms.
    (disregard those questions if the password and xml file are coming from a server running Java and not Android Java)
    Are you getting any error when try to decrypt it, what message is coming if failing?
    Have you used it before and was it working?

    If this xml file is encrypted in an Android device you can, other else you will need know all settings from the PC version and using the Sponge Castle jar, create the class with those settings.
    I have one old app it's called Data Safe and it's encrypt and decrypt any sort of file, though it doesn't receive anything encrypted from any PC or server, and works pretty well.
    To decrypt xml files try to AsyncTask or a background service (because you can leave the activity without window leaked and crash the app).
    I hope that it has helped you.
    Please feel free to ask more if you still have doubts


    1. Hello ,

      Thanks for your quick answers. Let me try to explain what debugging i have made and try to explain the most important issue .
      First of all I don't understand why encryption of one file must be done in Android in order to make the decryption work . From what i know AES algorithm it's pretty simple and involves just one complicated formula : multiplying polinoms at some point and reducing them .

      Anyway , back to my very annoying 3 full day issue :) .
      My file is encrypted from Mac OS platform , uploaded to server , decryption on Mac OS of course working . Key size set to 128.
      jre is decrypting perfectly but same code placed in Android not.

      text_to_encrypt : "ASD"
      key : "parolatest"
      bytes_array of result on Mac OS platform : a37d8b74 015ae91a b3b95b05 121d6898
      of course the same on jre and android when preparing for decryption and of course different results in Android.

      Can you please explain why these differences exists ? Shouldn't the OS react the same on such easy algorithms ? I mean it's just an AES with very simple operations ...
      Of course a fast solution is to prepare the encrypted files from Android which I think that I will do next.
      But why this is happening ? :)


  10. Marian,

    Even encryption been AES it has different "sort" of PADDINGs that make the byte key generated be slightly different and each language (as Android Java, Java or Objective C) has a different default values set. Please take a look on the answer from this post :
    As Android has quite less PADDING modes, certainly the default mode is different, and such probably the encrypted password from your MAC/iOS is having a different default. I have an experience like yours and the padding been used by the iOS (for iPhone) simply don't exist on Android but exist on Java and Sponge.
    A rule of thumb is take a look on the Cipher on Android and the correspondent on your Mac/iOS they should be different. The biggest problem is t to decrypthat Android having less 'padding modes' you need adapt what is been generated to be able to decrypt on Android, or use the Sponge Bounce Castle and set the same PADDING when get the rawKey to decrypt.
    Basically you need debug your cipher and find out the Chipher object and see the Padding and bits encryption (if it's getting 128, because by default in some devices it's get 256 straight away, and on Apple is 256 as default), then you need check if exist that PADDING mode on Android (like ECB,CBC and so on), if not and you can't change from the Apple side, then you need to import the jar (Sponge) and set the PADDING to match the with your on Mac.
    Don't do the fast solution, workaround usually just make things messier and if you work for one company with tight timeframe, such probably you will never fix it again due that amount of code that will be relying on this workaround.
    I hope that it has helped you and answered your questions.
    Feel free to contact me if you still have any doubt.


  11. Correcting a misspelling. It's not Sponge Castle is Spongy Castle.
    Link :

    Sorry for that.

  12. EncodeDecodeAES cannot be resolved line number 39

    i am getting this error

  13. Hi Pritam,

    Have you debug the code, because the method from line 39 is called from the one on line 50, and looks like that you are getting something wrong or null? Try check the method from line 50 to see if all variables aren't null, like seed and rawkey.

  14. hi guys the program is working now
    now i have 1 question the encrypted text what we get after i comment the line 36 and uncomment line 40
    the encrypted text we i tried to match that text with online aes tool on web using same key it different can nybudy explain y is it so

  15. It's due different Padding settings. Take a look on your Cipher class and check for the padding.

  16. i didnt what is the padding setting and which is the cipher class
    can u also do 1 more favour to me i want to add the time stamp with the encryption and randomiz the key
    i am not so good in cryptography but i want to use this example for login authentication

  17. For you have a timestamp as part of the key it's easy, it's just get the time from Date or calendar and format it using SimpleDateFormat if you want, then parse it to string.
    For you have a random seed take a look in this link:
    Just keep aware that it's quite easy read strings from the apk and also those strings that are hard coded (not from resource files).

  18. i m getting this prob : java.lang.IllegalArgumentException: bad base-64

  19. and this is compatible with .net webservice encryption.

  20. Hi Murtaza,

    You could be a little bit more especific in telling how you are encrypt and decrypting it, what padding it's been used (you need to check the objects to see which one it's been used). Because each OS platform has a different default padding, also keep aware that Android doesn't have all paddings that most languages have. If you need a padding that the native Android libs doesn't have you will need to download and import the Sponge Castle jar in your project and use it rather the native Android lib.
    I was looking around and could find out this :!topic/android-developers/vZ9xYTSWa9s , I can't be more specific due that you have provided quite few details to me, however .Net should use a different Padding default than Android does.
    Basically you need she that Padding it's been used in the server side (or the app responsible to encrypt), and get those details and set it into your Android client (don't forget to check if Android does have those Paddings or algorithms).

  21. Thanks alot! Few notes
    1- could you make the class downloadable, copying then deleting all the line numbers was a pain.
    2 - a little addition i made to your class was to make a seed generator from password (as i am generating the seed in real time)

    public static String generateSeed(String password){

    String seed = null;
    if (password.length() <32){
    int numberToAdd = 32-password.length();
    seed = password;
    for (int i =0; i32){
    seed = password.substring(0, 31);

    return seed;

    I then used this in any instance where you use the seed input variable in the public static methods, this allows the user to provide any sized seed and it will convert it into a 32char string.

    Thanks for this post most helpful encryption post i have found on the web!