Hiding strings in Obfuscated code
Hi all.
Let
secret
be the text you want to hideFind the keyhash of your debug/release.keystore. Let
k1
be this key.
(use tools keytool+openssl: keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore | openssl sha1 -binary | openssl base64
)
Use a tool (external to the android code) to encrypt
secret
withk1
encrypted = encode (secret, k1)
(For instance: https://jwt.io, for java: https://github.com/jwtk/jjwt).
- In your android java code write down
encrypted
. When you need the decoded version ofencrypted
(this is, the originalsecret
) write
original = decode(encrypted, get_my_keyhash_programmatically() )
That's all. This works because the original secret
is not shown on java source code, neither the k1
to decode it. And, if a hacker wants to print your
decoded secret, he must change code and recompile, signing his .apk
with his own keystore not yours, and thus not getting the right original
secret
. (The "only" point is whether k1
can be figured out from your original .apk).
Note: get_my_keyhash_programmatically():
try {
PackageInfo info = getPackageManager().getPackageInfo(
"el nombre de su paquete por ejemplo com.tarea.u8",
PackageManager.GET_SIGNATURES);
for (Signature signature : info.signatures) {
MessageDigest md = MessageDigest.getInstance("SHA");
md.update(signature.toByteArray());
Log.d("KeyHash:", Base64.encodeToString(md.digest(), Base64.DEFAULT));
}
} catch (PackageManager.NameNotFoundException e) {
} catch (NoSuchAlgorithmException e) {
}
Assuming you are happy with obscure rather than secure, there a number of mechanisms you could use, but obfuscaters like proguard are not going to be able to help you.
To achieve this you will need to do encoding or encryption of the string yourself, the approach you use depends on what you are trying to defend against, if it you are just trying to hide from obvious inspection, than encoding may be sufficient (see android.util.Base64, http://developer.android.com/reference/android/util/Base64.html). Note that encoding is in NO WAY SECURE and all it will to is remove the obvious reference to your site.
If you are trying to defend against something more, then you could move to actually encrypting the string, to do this you would use a symmetric cipher like AES via javax.crypto.Cipher, http://www.androidsnippets.org/snippets/39/index.html provides a decent usage example. Again this is more annoying then secure to would be hackers, as you will need to store the key somewhere in your jar thus negating any cryptographic security.
To make this clearer, the basic steps would be:
- Manually create an encrypt your string using a known key.
- Convert your code to use a decrypted version of this string, example:
Before:
public class Foo {
private String mySecret = "http://example.com";
...
}
Becomes:
public class Foo {
private String encrypted = "<manually created encrypted string>";
private String key = "<key used for encryption";
private String mySecret = MyDecryptUtil.decrypt(encrypted, key);
...
}
A (good) alternative to all of this is considering using a third party drm solution such as the licensing server google provides http://android-developers.blogspot.com/2010/07/licensing-service-for-android.html. This may be more secure than something you roll your self, but is subject to very similar limitations to what I described above.