Search code examples
javaphpandroidmcrypt

Java decrypt error: data not block size aligned


I'm trying to encrypt data between my android application and a PHP webservice.

I found the next piece of code in this website: http://schneimi.wordpress.com/2008/11/25/aes-128bit-encryption-between-java-and-php/

But when I try to decrypt I get the Exception of the title "data not block size aligned"

This are the method in my MCrypt class

public String encrypt(String text) throws Exception
{
    if(text == null || text.length() == 0)
        throw new Exception("Empty string");

    Cipher cipher;
    byte[] encrypted = null;

    try {
        cipher = Cipher.getInstance("AES/CBC/NoPadding");
        cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);

        encrypted = cipher.doFinal(padString(text).getBytes());
    } catch (Exception e)
    {           
        throw new Exception("[encrypt] " + e.getMessage());
    }

    return new String( encrypted );
}

public String decrypt(String code) throws Exception
{
    if(code == null || code.length() == 0)
        throw new Exception("Empty string");

    Cipher cipher;
    byte[] decrypted = null;

    try {
        cipher = Cipher.getInstance("AES/CBC/NoPadding");
        cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
        decrypted = cipher.doFinal(hexToBytes(code));
    } catch (Exception e)
    {
        throw new Exception("[decrypt] " + e.getMessage());
    }
    return new String( decrypted );
}


private static byte[] hexToBytes(String hex) {
  String HEXINDEX = "0123456789abcdef";
  int l = hex.length() / 2;
  byte data[] = new byte[l];
  int j = 0;

  for (int i = 0; i < l; i++) {
    char c = hex.charAt(j++);
    int n, b;

    n = HEXINDEX.indexOf(c);
    b = (n & 0xf) << 4;
    c = hex.charAt(j++);
    n = HEXINDEX.indexOf(c);
    b += (n & 0xf);
    data[i] = (byte) b;
  }

  return data;
}

private static String padString(String source)
{
  char paddingChar = ' ';
  int size = 16;
  int x = source.length() % size;
  int padLength = size - x;

  for (int i = 0; i < padLength; i++)
  {
      source += paddingChar;
  }

  return source;
}

And this is how I'm using it in my activity to test:

String encrypted = mcrypt.encrypt(jsonUser.toString());
String decrypted = mcrypt.decrypt(encrypted);

the encrypt method works fine, but the second throws an exception.


Solution

  • At last! I made it work! Thanks for all your suggestion. I would like to share the code just in case somebody get stuck like me:

    JAVA

    import java.security.NoSuchAlgorithmException;
    
    import javax.crypto.Cipher;
    import javax.crypto.NoSuchPaddingException;
    import javax.crypto.spec.IvParameterSpec;
    import javax.crypto.spec.SecretKeySpec;
    
    public class MCrypt {
    
        private String iv = "fedcba9876543210";//Dummy iv (CHANGE IT!)
        private IvParameterSpec ivspec;
        private SecretKeySpec keyspec;
        private Cipher cipher;
    
        private String SecretKey = "0123456789abcdef";//Dummy secretKey (CHANGE IT!)
    
        public MCrypt()
        {
            ivspec = new IvParameterSpec(iv.getBytes());
    
            keyspec = new SecretKeySpec(SecretKey.getBytes(), "AES");
    
            try {
                cipher = Cipher.getInstance("AES/CBC/NoPadding");
            } catch (NoSuchAlgorithmException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (NoSuchPaddingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    
        public byte[] encrypt(String text) throws Exception
        {
            if(text == null || text.length() == 0)
                throw new Exception("Empty string");
    
            byte[] encrypted = null;
    
            try {
                cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
    
                encrypted = cipher.doFinal(padString(text).getBytes());
            } catch (Exception e)
            {           
                throw new Exception("[encrypt] " + e.getMessage());
            }
    
            return encrypted;
        }
    
        public byte[] decrypt(String code) throws Exception
        {
            if(code == null || code.length() == 0)
                throw new Exception("Empty string");
    
            byte[] decrypted = null;
    
            try {
                cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
    
                decrypted = cipher.doFinal(hexToBytes(code));
            } catch (Exception e)
            {
                throw new Exception("[decrypt] " + e.getMessage());
            }
            return decrypted;
        }
    
    
    
        public static String bytesToHex(byte[] data)
        {
            if (data==null)
            {
                return null;
            }
    
            int len = data.length;
            String str = "";
            for (int i=0; i<len; i++) {
                if ((data[i]&0xFF)<16)
                    str = str + "0" + java.lang.Integer.toHexString(data[i]&0xFF);
                else
                    str = str + java.lang.Integer.toHexString(data[i]&0xFF);
            }
            return str;
        }
    
    
        public static byte[] hexToBytes(String str) {
            if (str==null) {
                return null;
            } else if (str.length() < 2) {
                return null;
            } else {
                int len = str.length() / 2;
                byte[] buffer = new byte[len];
                for (int i=0; i<len; i++) {
                    buffer[i] = (byte) Integer.parseInt(str.substring(i*2,i*2+2),16);
                }
                return buffer;
            }
        }
    
    
    
        private static String padString(String source)
        {
          char paddingChar = ' ';
          int size = 16;
          int x = source.length() % size;
          int padLength = size - x;
    
          for (int i = 0; i < padLength; i++)
          {
              source += paddingChar;
          }
    
          return source;
        }
    }
    

    HOW TO USE IT (JAVA)

    mcrypt = new MCrypt();
    /* Encrypt */
    String encrypted = MCrypt.bytesToHex( mcrypt.encrypt("Text to Encrypt") );
    /* Decrypt */
    String decrypted = new String( mcrypt.decrypt( encrypted ) );
    

    ====================================================

    PHP

    <?php 
    
    class MCrypt
    {
        private $iv = 'fedcba9876543210'; #Same as in JAVA
        private $key = '0123456789abcdef'; #Same as in JAVA
    
    
        function __construct()
        {
        }
    
        function encrypt($str) {
    
          //$key = $this->hex2bin($key);    
          $iv = $this->iv;
    
          $td = mcrypt_module_open('rijndael-128', '', 'cbc', $iv);
    
          mcrypt_generic_init($td, $this->key, $iv);
          $encrypted = mcrypt_generic($td, $str);
    
          mcrypt_generic_deinit($td);
          mcrypt_module_close($td);
    
          return bin2hex($encrypted);
        }
    
        function decrypt($code) {
          //$key = $this->hex2bin($key);
          $code = $this->hex2bin($code);
          $iv = $this->iv;
    
          $td = mcrypt_module_open('rijndael-128', '', 'cbc', $iv);
    
          mcrypt_generic_init($td, $this->key, $iv);
          $decrypted = mdecrypt_generic($td, $code);
    
          mcrypt_generic_deinit($td);
          mcrypt_module_close($td);
    
          return utf8_encode(trim($decrypted));
        }
    
        protected function hex2bin($hexdata) {
          $bindata = '';
    
          for ($i = 0; $i < strlen($hexdata); $i += 2) {
            $bindata .= chr(hexdec(substr($hexdata, $i, 2)));
          }
    
          return $bindata;
        }
    
    }
    

    HOW TO USE IT (PHP)

    <?php 
    
    $mcrypt = new MCrypt();
    #Encrypt
    $encrypted = $mcrypt->encrypt("Text to encrypt");
    #Decrypt
    $decrypted = $mcrypt->decrypt($encrypted);