用户可以购买我的应用程序的“专业”版本。当他们这样做时,我按如下方式存储并验证他们的购买。
- 结合用户的 UUID 和另一个唯一字符串。
- 然后使用静态种子对生成的字符串进行加密。我这样做是使用
SecureRandom.getInstance("SHA1PRNG", "Crypto")
- 这就是问题所在! - 生成的加密字符串就是“解锁码”。
- 因此,我始终知道用户预期的唯一解锁码值。
- 当用户购买“Pro”时,我将“解锁码”存储在数据库中。
- 我通过查看数据库中存储的“解锁代码”是否与基于其唯一信息的预期代码匹配来检查用户是否拥有“Pro”。
所以,不是最好的系统,但对于我不起眼的应用程序来说,一切都已经足够模糊了。
问题是SecureRandom.getInstance("SHA1PRNG", "Crypto")
在 N 上失败,因为不支持“加密”。我了解到,依赖特定的提供者是不好的做法,并且 Crypto 不受 N 支持。哎呀。
所以我有一个问题:我依靠价值种子对的加密来始终具有相同的输出。Android N 不支持我使用的加密提供程序,所以我不知道如何确保 N 上的加密输出与其他设备上的相同。
我的问题:
- 是否可以在我的 APK 中包含“加密”以便它始终可用?
- 在 Android N 上加密值-种子对时,我能否以其他方式确保相同的输出?
我的代码:
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();
}