0

Can anyone help in the below code, i am trying to implement AES Encryption in Android but the code generated by android is not matching with the server side .Net AES Encryption. Please find the code below let me know what's wrong :

.Net Code

    private string GetEncryptedData(string clearText)

    {
       string EncryptionKey = "password";
        byte[] clearBytes = Encoding.Unicode.GetBytes(clearText);
        using (Aes encryptor = Aes.Create())
        {
            Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
            encryptor.Key = pdb.GetBytes(32);
            encryptor.IV = pdb.GetBytes(16);
            using (MemoryStream ms = new MemoryStream())
            {
                using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
                {
                    cs.Write(clearBytes, 0, clearBytes.Length);
                    cs.Close();
                }
                clearText = System.Web.HttpContext.Current.Server.UrlEncode(Convert.ToBase64String(ms.ToArray()));
            }
        }
        return clearText;
    }

Java Code in Android :

    private static String secretKey1 = "password";
    private static String salt = "ssshhhhhhhhhhh!!!!";

    public static String encrypt(String strToEncrypt, String secret)

    {
        try
        {
            byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
            IvParameterSpec ivspec = new IvParameterSpec(iv);

            SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
            KeySpec spec = new PBEKeySpec(secret.toCharArray(), salt.getBytes(), 65536, 256);
            SecretKey tmp = factory.generateSecret(spec);
            SecretKeySpec secretKey = new SecretKeySpec(tmp.getEncoded(), "AES");
            //Log.d("qwqwqwqw1",secretKey.toString());

            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivspec);
            //return Base64.getEncoder().encodeToString(cipher.doFinal(strToEncrypt.getBytes("UTF-8")));

            return URLEncoder.encode(Base64.getEncoder().encodeToString(cipher.doFinal(strToEncrypt.getBytes("UTF-8"))), "UTF-8");
        }
        catch (Exception e)
        {
            System.out.println("Error while encrypting: " + e.toString());
        }
        return null;
    }

.Net encryption result:

%2bJnjgtiCX9VSxwTU22jCJluBxh%2bkFxVlfBasAorRO%2fo%3d

Java encryption result

PwoZePSM%2BjoyPubZr780Fg%3D%3D

I try to change this

byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
to byte[] iv = { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 }

In JAVA code still getting error "expected IV length of 16 but was 13"

Can anyone tell whats wrong in this.

Update: Now i am using this. Please let me know whats wrong:

code:

byte[] salt1 =  new byte[] {0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76};

SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
PBEKeySpec pbeKeySpec = new PBEKeySpec(strToEncrypt.toCharArray(), salt1, 1000, 384);
byte[] derivedData = factory.generateSecret(pbeKeySpec).getEncoded();
byte[] key = new byte[32];
byte[] iv = new byte[16];
System.arraycopy(derivedData, 0, key, 0, key.length);
System.arraycopy(derivedData, key.length, iv, 0, iv.length);

SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivSpec);
//return Base64.getEncoder().encodeToString(cipher.doFinal(strToEncrypt.getBytes("UTF-8")));
//byte[] result = cipher.doFinal(Base64.getEncoder().decode(strToEncrypt));

String value = Base64.getEncoder().encodeToString(cipher.doFinal(strToEncrypt.getBytes(StandardCharsets.UTF_16LE)));
String result1 = URLEncoder.encode(value,"UTF_16LE");
Topaco
  • 40,594
  • 4
  • 35
  • 62
Sachin Gupta
  • 41
  • 2
  • 8
  • If yoy want to get same results in both languages you have to use same algorithm, key, iv, block mode and padding mode. Your code is using clearly different values. The "expected IV length" is self-explanatory, the IV in that case is 13 bytes long. See this article for working interoperable encryption. http://mjremijan.blogspot.com/2014/08/aes-encryption-between-java-and-c.html – Pepelui360 Feb 28 '20 at 09:52
  • 1
    This question https://stackoverflow.com/questions/60387628/converting-net-decryption-to-java is presumably related, since even the salts in the C# codes are identical. Although the linked question is about decryption and this question is about encryption, the most important aspects apply in both cases and can therefore be adopted from the associated answer. – Topaco Feb 28 '20 at 11:42
  • Hi @Topaco thanks for quick response , i tried the one you shared , still not same let me update my code – Sachin Gupta Feb 28 '20 at 13:31
  • Probably a copy/paste issue: In the `PBEKeySpec` instantiation the first argument must be `secret.toCharArray()` and not `strToEncrypt.toCharArray()`! – Topaco Feb 28 '20 at 14:00
  • One more thing: Regarding `URLEncoder.encode(value, "UTF_16LE")` you should check by comparison with the result of the C# code if `Utf-8` shouldn't be used. – Topaco Feb 28 '20 at 14:42
  • I check its UTF-16LE only – Sachin Gupta Feb 28 '20 at 14:43
  • .net guys are using System.Web.HttpContext.Current.Server.UrlEncode(Convert.ToBase64String(ms.ToArray())); in our the i am using is correct right ? – Sachin Gupta Feb 28 '20 at 14:45
  • Try `URLEncoder.encode(value, "UTF-8")`! – Topaco Feb 28 '20 at 15:00
  • The plain text must be encoded with UTF16LE in any case! You should only use UTF8 for the URL encoding (**the last line**)! – Topaco Feb 28 '20 at 15:09
  • Thank you very much , its working I will upvote and accept as answer hope this will help others who is new to AES – Sachin Gupta Feb 28 '20 at 15:19

0 Answers0