Benjamin Wolf
Benjamin Wolf

Reputation: 93

Obfuscate Strings

we use some Networkcredentials in out App. I just decompiled the app and was able to see the Credentials like Name and Password. I do not really get how to prevent this. I think the word "obfuscator" is the direction which I have to go. We test proguard but it does not have string encryption or am I wrong?

Is there an easy and free way to do this?

Thank you.

Upvotes: 6

Views: 6362

Answers (3)

Giulio Biagini
Giulio Biagini

Reputation: 920

You should consider to encipher the username and the password: How to encrypt String in Java.

// bytes to encrypt
byte[] input;

// the key and the initialization vector
byte[] keyBytes;
byte[] ivBytes;

// initialize the Cipher
SecretKeySpec key = new SecretKeySpec(keyBytes, "DES");
IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");

// encryption
cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
byte[] encrypted= new byte[cipher.getOutputSize(input.length)];
int enc_len = cipher.update(input, 0, input.length, encrypted, 0);
enc_len += cipher.doFinal(encrypted, enc_len);

// decryption
cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
byte[] decrypted = new byte[cipher.getOutputSize(enc_len)];
int dec_len = cipher.update(encrypted, 0, enc_len, decrypted, 0);
dec_len += cipher.doFinal(decrypted, dec_len);

Usually, the key (bytes array) should be stored in a file that is only accessible on the specific instance where the server is running and not coded into the app source file.

Otherwise you can use hash (e.g: md5 or sha1) and store the fingerprint instead of the plain string:

// SHA1("hello world") -> "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed

This is a simple method which allows you to calculate the SHA1 hash of a string:

public static String SHA1(String text) throws NoSuchAlgorithmException, UnsupportedEncodingException { 
    MessageDigest md = MessageDigest.getInstance("SHA-1");
    md.update(text.getBytes("iso-8859-1"));
    byte[] hash = md.digest();

    Formatter formatter = new Formatter();
    for (byte b : hash)
        formatter.format("%02x", b);
    return formatter.toString();
}

Import java.io.UnsupportedEncodingException, java.security.MessageDigest and java.security.NoSuchAlgorithmException are required.

Upvotes: 3

Petr Janeček
Petr Janeček

Reputation: 38424

Sorry, but this simply does't work no matter what you'll try. If you obfuscate / encrypt the credentials, the program still must be able to decrypt them at run-time. Therefore, the encryption keys must also be in the generated bytecode somewhere and therefore it's possible to take them, and decrypt the credentials manually outside the program (or just step through the program and read the credentials once they're decrypted).

What you're trying to do is Security by Obscurity and it doesn't work.

Whatever you do, if the program can obtain the credentials at run-time without any external help, a skilled attacker can do the same given enough time.

What you should do:

  1. Store the credentials in plain-text in a property file. Don't bother with encryption, it's pointless. You must make sure the db user you're using is read-only or add-only or something similar so you prevent any damage.
  2. Let the user input the password. If it's not stored in the bytecode, it's safe. He could e.g. input his password and have an account in the db...
  3. Use a safe and known authentication mechanism. Plaintext login+password is not that.
  4. Don't let your application go anywhere near a DB. Set up a service somewhere, with an API, which would hold the read DB conenction. Your application could connect to that and get data via this API. This way, an attacker can't directly access your DB. He could call anything in the new service, though, so you must make sure there's no sensitive data accessible in there.

Upvotes: 8

Guy Bouallet
Guy Bouallet

Reputation: 2125

Your issue is related to encryption and not obfuscation. You may use this library to store the credentials in an encrypted way: http://www.jasypt.org/encrypting-configuration.html There are different ways to pass the encryption key to it.

Otherwise, depending on your context, consider using different authentication mechanisms (SSO like) instead of login/password.

Upvotes: 0

Related Questions