1
votes

I've recently developed an app that I am soon to put on the Google play store. In this app I plan on adding one in-app purchase that once purchased allows the user to change colour settings(background & text).

I realised that checking the Google play store is unnecessary every time the application runs, especially if the purchase has been made already.It may also cause a problem if the user doesn't have GPRS/Wifi when using the app!

I was therefore thinking about creating a shared preference which would act as the condition to check whether the user has purchased the in-app purchase.

Is there any other way that is maybe more secure? as I've read shared preferences can be altered quite easily.

Any advice or suggestions would be appreciated.

1

1 Answers

1
votes

You may use ProGuard.

Or you can save purchased status in secure way using some Encrypted text either in shared preference or in database. So it gets harder to manipulate it.

Encryption example:

Encrypt:

 MCrypt mcrypt = new MCrypt();
 String encrypted = MCrypt.bytesToHex(mcrypt.encrypt("Text to Encrypt"));

Decrypt:

MCrypt mcrypt = new MCrypt();
String decrypted = new String(mcrypt.decrypt(encrypted));

Mcrypt.java

public class MCrypt {

    private String iv = "fedcba9876543210";//Dummy iv (CHANGE IT!)
    private IvParameterSpec ivspec;
    private SecretKeySpec keyspec;
    private Cipher cipher;
    private String SecretKey = "0123456789abcdef";//Dummy secretKey (CHANGE IT!)

    public MCrypt() {
        ivspec = new IvParameterSpec(iv.getBytes());

        keyspec = new SecretKeySpec(SecretKey.getBytes(), "AES");

        try {
            cipher = Cipher.getInstance("AES/CBC/NoPadding");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        }
    }

    public byte[] encrypt(String text) throws Exception {
        if (text == null || text.length() == 0) throw new Exception("Empty string");

        byte[] encrypted = null;

        cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);

        encrypted = cipher.doFinal(padString(text).getBytes());
        try { 
            encrypted = android.util.Base64.encode(encrypted, android.util.Base64.NO_PADDING);
        } catch (NoClassDefFoundError e) {
        }

        return encrypted;
    }

    public byte[] decrypt(String code) throws Exception {
        if (code == null || code.length() == 0) throw new Exception("Empty string");

        byte[] decrypted = null;

        cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);

        try { 
            decrypted = cipher.doFinal(android.util.Base64.decode(code, android.util.Base64.NO_PADDING));
        } catch (NoClassDefFoundError e) {
        }
        return decrypted;
    }



    private static String padString(String source) {
        char paddingChar = ' ';
        int size = 16;
        int x = source.length() % size;
        int padLength = size - x;

        for (int i = 0; i < padLength; i++) {
            source += paddingChar;
        }

        return source;
    }
}

Reference:

128 bit encryption