Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Decryption breaks on newer Android versions #4

Closed
guilhermesgb opened this issue Feb 5, 2018 · 12 comments
Closed

Decryption breaks on newer Android versions #4

guilhermesgb opened this issue Feb 5, 2018 · 12 comments

Comments

@guilhermesgb
Copy link

guilhermesgb commented Feb 5, 2018

EDIT: to clarify the problem - encryption and decryption on the same platform works! The problem is when you encrypt information on some platforms and then afterwards, decryption of this data is attempted on others. I've seem compatibility problems between these ranges of API versions:

  • 22 or before,
  • 23 through 25,
  • 26 and after,

meaning, encryption-decryption between devices in each range works, but between devices in different ranges doesn't.

ORIGINAL post:

W/System.err: javax.crypto.BadPaddingException: error:1e000065:Cipher functions:OPENSSL_internal:BAD_DECRYPT
W/System.err:     at com.android.org.conscrypt.NativeCrypto.EVP_CipherFinal_ex(Native Method)
W/System.err:     at com.android.org.conscrypt.OpenSSLCipher$EVP_CIPHER.doFinalInternal(OpenSSLCipher.java:570)
W/System.err:     at com.android.org.conscrypt.OpenSSLCipher.engineDoFinal(OpenSSLCipher.java:351)
W/System.err:     at javax.crypto.Cipher.doFinal(Cipher.java:1736)
W/System.err:     at com.pvryan.easycrypt.symmetric.performDecrypt.invoke$easycrypt_release(performDecrypt.kt:70)
W/System.err:     at com.pvryan.easycrypt.symmetric.ECSymmetric$decrypt$1.invoke(ECSymmetric.kt:209)
W/System.err:     at com.pvryan.easycrypt.symmetric.ECSymmetric$decrypt$1.invoke(ECSymmetric.kt:44)
W/System.err:     at org.jetbrains.anko.AsyncKt$doAsync$1.invoke(Async.kt:140)
W/System.err:     at org.jetbrains.anko.AsyncKt$doAsync$1.invoke(Unknown Source:0)
W/System.err:     at org.jetbrains.anko.AsyncKt$sam$Callable$761a5578.call(Unknown Source:2)
W/System.err:     at java.util.concurrent.FutureTask.run(FutureTask.java:266)
W/System.err:     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
W/System.err:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
W/System.err:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
W/System.err:     at java.lang.Thread.run(Thread.java:764)

It seems that this library is experiencing the same issue found in this other library below (in an older version, they fixed it by enforcing usage of Bouncy Castle instead of the new default provider on Android 6.0 onwards).

AArnott/PCLCrypto#61

Please also make this library enforce usage of Bouncy Castle as well as a workaround at least until a fix is found using the new provider on API 23 onwards.
EDIT: As I mention below, apparently just doing this workaround won't be enough :(

I tested on an emulator with API 26.

Thank you!

@ghost
Copy link

ghost commented Feb 6, 2018

Hi @guilhermesgb, what input did you use? I have tested Symmetric encryption and decryption on API22 and up and it worked fine.

@guilhermesgb
Copy link
Author

guilhermesgb commented Feb 6, 2018

I used "API Key/Access Token"-esque strings as input, passing UUIDs as passwords.

The problem happens if you use the ECSymmetric encryption on an API lower than 23 and then afterwards tries decrypting back on API 23 onwards. Doing encryption/decryption on the same platform will always work, the problem is that between different API versions, your underlying crypto layer will use different algorithms/providers and that is not working. Makes sense?

I'm needing to do it because I'm storing encrypted stuff on the codebase. When I test decryption of this information it fails on devices bigger than 23. Actually, testing a lot yesterday, I've come to realize that encrypting stuff on API 23-25 and then trying decrypting back on API 27 also fails as well.

I even tried enforcing usage of this particular provider by injecting my own Cipher via reflection:

            try {
                Field field = ECSymmetric.class.getDeclaredField("cipher");
                field.setAccessible(true);
                Field modifiersField = Field.class.getDeclaredField("accessFlags");
                modifiersField.setAccessible(true);
                modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
                field.set(decryptor, Cipher.getInstance("AES/CBC/PKCS7Padding", "BC"));
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }

I was hopeful this would solve the issue as apparently that's the workaround this other lib I mentioned earlier did, but for some reason that was not the case.

As an workaround, I'm encrypting stuff using these three self-compatible environments (API 22-, API23-25, API26+), and checking which environment I'm at on runtime to pick the appropriate encrypted data to decrypt on these platforms. The encryption process is being done semi-manually, since it's not something that needs to happen everytime.

This workaround has allowed me to keep using this library. Thank you! :)

@ghost
Copy link

ghost commented Feb 6, 2018

Now I understand the problem. I tried to reproduce it by encrypting on API 22 and then decrypting on API 26 and API 27 and it seems to work fine. The workaround that you proposed of injecting your cipher should have worked if the problem was that which you are suggesting, but that is not the case. I think it is something with the input formats or data being manipulated during transfer. Try verifying data before decrypting using hash functions and let me know if that gives you any more insight about the problem.

@guilhermesgb
Copy link
Author

guilhermesgb commented Feb 6, 2018

I started spotting the issue by encrypting on API 19 and then trying to decrypt it on API 24 (using emulators). It probably is related to my input since before encrypting, I also obfuscate the input by applying a manipulation in each character in the input by shifting their ASCII values arbitrarily (and I'm sorry that I forgot to mention this).

Since I'm not very knowledgeable in cryptography, maybe I made the wrong assumption in thinking that any sequence of strings, no matter the format, would be acceptable by the underlying encryption/decryption algorithms.

If that's not the case and I'm actually doing things wrong by manipulating data in such a manner (shifting their individual characters' ASCII values) and expecting it to be properly encrypted/decrypted, you can go ahead and close this issue and thank you for your time anyways.

Otherwise, I could explain to you exactly the kinds of manipulations I'm doing with input before encrypting it (which actually decrypts properly on the same ranges of platforms mentioned on my early responses, btw), such that you could try reproducing the problem on your end as well.

@ghost
Copy link

ghost commented Feb 6, 2018

The manipulations should not matter because the input is converted to bytearray using UTF8 encoding and then processed. Tell me the details and I will try it out.

@guilhermesgb
Copy link
Author

guilhermesgb commented Feb 6, 2018

Essentially, I apply the following function to the token I want to obfuscate, given some other character sequence as the coordinates for the obfuscation: I build a new obfuscated string of same length than token, but with each character i in the new string being the ASCII value of character i in the original token + the ASCII value of the character I'm currently looking at in coordinates (i % sizeof(coordinates)). I also make sure I never leave the ASCII range with % 128.

    private static String obfuscateToken(String token, String coordinates) {
        StringBuilder obfuscated = new StringBuilder();
        for (int i = 0; i < token.length(); i++) {
            obfuscated.append((char) ((((int) token.charAt(i))
                - ((int) coordinates.charAt(i
                    % coordinates.length())))
                        % 128));
        }
        return obfuscated.toString();
    }

Then there's the opposite function for deobfuscating, which essentially does the same as above but adding ASCII values instead of subtracting. It needs the same coordinates string to reach the original token.

I'm also using UUIDs here, as coordinates. You can use as input some API Key from some Google service.

@ghost
Copy link

ghost commented Feb 6, 2018

With the the function that you provided I tried encrypting and decrypting on different API ranges and it is working perfectly fine. Below are the logs for original input and decrypted output. Didn't de-obfuscate it because that is not necessary.

com.pvryan.easycryptsample I/Original: �������������ᅲ)ᅤ￘��¥�E↓ᅯ�) � +Aᅪ←#�ᅡ ̄ ��ᅭ��￳�￁

com.pvryan.easycryptsample I/Decrypted: �������������ᅲ)ᅤ￘��¥�E↓ᅯ�) � +Aᅪ←#�ᅡ ̄ ��ᅭ��￳�￁

@guilhermesgb
Copy link
Author

guilhermesgb commented Feb 7, 2018

Well, yeah, I don't know how help with reproducing the issue then. My only other guess left is that maybe it has to do with the fact that my app requests a decryption of two tokens simultaneously and that is somehow impacting the overall results?... I'll probably enforce these to happen one after the other.

Anyways, I guess I'll close this issue for now and reopen eventually if I find a means of deterministically reproducing it. Thank you for your time.

@Hatzen
Copy link

Hatzen commented Jul 29, 2019

I can reproduce this Issue with A Nexus 5 with Android 5.0 and a Yota 3 with Android 8.1
Encrypting and Decrypting with Symmetric Encryption wont work, although all Input is all the same.
it works fine with Yota and Nexus 5 Emulator with Android 8.1

@guilhermesgb
Copy link
Author

If you can provide the details to @pvasa, he might get interest in checking it out. I closed this ticket because I could not get him to reproduce this issue on his end.

@Salocin808
Copy link

I have the same issue using "AES/CBC/PKCS5Padding". Encrypting data in Android 9 and decrypting it in Android 10 leads to the same error (BadPaddingException).
Probably a relevant information that I found out was that encrypting the data in Android 9 lead to a byte[].size = 2400. Decrypting it in Andorid 10: byte[].size = 2432. (even though same data).

@clickict
Copy link

I have the same issue using "AES/CBC/PKCS5Padding". Encrypting data in Android 9 and decrypting it in Android 10 leads to the same error (BadPaddingException).
Probably a relevant information that I found out was that encrypting the data in Android 9 lead to a byte[].size = 2400. Decrypting it in Andorid 10: byte[].size = 2432. (even though same data).

Did you find the answer finally ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants