Users can purchase the "Pro" version of my application. When they do this, I save and verify their purchase as follows.
- Combine the custom UUID and another unique string.
- The resulting string is then encrypted using static seed. I do this with
SecureRandom.getInstance("SHA1PRNG", "Crypto") - that’s the problem! - As a result, the encrypted string is an “unlock code”.
- Therefore, I always know the expected unique value of the unlock code for the user.
- When a user buys "Pro", I save the "unlock code" in the database.
- I check if the user has “Pro”, seeing if the saved “unlock code” is stored in the database of the expected code based on their unique information.
So, not the best system, but everything is confusing enough for my modest application.
The problem is that SecureRandom.getInstance("SHA1PRNG", "Crypto") does not work in N, because "Crypto" is not supported. I found out that relying on specific vendors is bad practice, and Crypto is not supported in N. Unfortunately.
So, I have a problem: I rely on encrypting the value-seed pair to always have the same result. Android N does not support the encryption provider that I use, so I don’t know how to ensure that the encryption output is the same on N as on other devices.
My questions:
- Can I include "Crypto" in my APK so that it is always available?
- Can I otherwise provide the same output when encrypting a value-seed pair on Android N?
My code is:
public static String encrypt(String seed, String cleartext) throws Exception { byte[] rawKey = getRawKey(seed.getBytes(), seed); byte[] result = encrypt(rawKey, cleartext.getBytes()); return toHex(result); // "unlock code" which must always be the same for the same seed and clearText accross android versions } private static byte[] getRawKey(byte[] seed, String seedStr) throws Exception { SecureRandom sr; sr = SecureRandom.getInstance("SHA1PRNG", "Crypto"); // what used to work KeyGenerator kgen = KeyGenerator.getInstance("AES"); sr.setSeed(seed); kgen.init(128, sr); SecretKey skey = kgen.generateKey(); byte[] raw = skey.getEncoded(); return raw; } private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception { SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.ENCRYPT_MODE, skeySpec); byte[] encrypted = cipher.doFinal(clear); return encrypted; } public static String toHex(byte[] buf) { if (buf == null) return ""; StringBuffer result = new StringBuffer(2 * buf.length); for (int i = 0; i < buf.length; i++) { appendHex(result, buf[i]); } return result.toString(); }
android random cryptography android-n secure-random
NSouth
source share