Sometimes you need to store a password in the app itself, such as a username/password for communicating with your own server. In these cases it's not possible to follow the normal process of storing passwords - i.e. hash the password, store the hash, compare to hashed user input - because you don't have any user input to compare the hash to. The password needs to be provided by the app itself. So how to protect the stored password in the APK? Would a password-generating function like the one below be reasonably secure?
Plain text:
String password = "$()&HDI?=!";
Simple obfuscation:
private String getPassword(){
String pool = "%&/@$()7?=!656sd8KJ%&HDI!!!G98y/&%=?=*^%&ft4%(";
return pool.substring(4, 7) + pool.substring(20, 24) + pool.substring(8, 11);
}
I know ProGuard has some obfuscation capabilities, but I'm curious about what the above "obfuscation" technique does when it's compiled, and how hard it would be for someone to figure it out by looking in the APK and/or using other more sophisticated techniques?
tl;dr If you know how to decompile APK, you can easily get the password, no matter how obfuscated the code was. Don't store passwords in APK, it's not secure.
I will show you how easy it is. Here is an Android SSCCE which we will decompile:
MyActivity.java
:main.xml
:After compiling it and running we can see
$()&HDI?=!
on aTextView
.Let's decompile an APK:
unzip myapp.apk
or right-click on the APK andUnzip here
.classes.dex
file appears.classes.dex
to JAR file with dex2jar. After executingdex2jar.sh classes.dex
,classes_dex2jar.jar
file appears.Using some Java decompiler on
classes_dex2jar.jar
, for example JD-GUI, we retrieve such Java code fromMyActivity.class
:ProGuard can't help much, the code will be still easily readable.
Based on the above, I can already give you an answer for this question:
No. As you can see, it increases difficulty of reading deobfuscated code by a tiny bit. We should not obfuscate the code in such way, because:
In the official Android documentation, in the Security and Design part, they're advising this to protect your Google Play public key:
Ok, so let's try that:
Gives
$()&HDI?=!
on aTextView
, good.Decompiled version:
Very similar situation like before.
Even if we had extremely complicated function
soStrongObfuscationOneGetsBlind()
, we can always run decompiled code and see what is it producing. Or debug it step-by-step.