【发布时间】:2019-08-21 11:36:22
【问题描述】:
当我在 android Marshmallow(Android 6.0.1) 上使用此代码时,解密是好的,但是当我在带有 android Oreo(Android 8) 的设备上运行时,解密值不一样并且数据不正确。
private void decrypt(Cipher cipher, Uri uri) throws Exception {
long a = 113845229;
InputStream inputStream = getContentResolver().openInputStream(uri);
CipherInputStream cipherInputStream = new CipherInputStream(inputStream, cipher);
cipherInputStream.skip(a);
byte[] buffer = new byte[8];
cipherInputStream.read(buffer);
}
// create cipher
private Cipher createCipher(byte[] iv, byte[] salt, String password) throws Exception {
IvParameterSpec mIvParameterSpec = new IvParameterSpec(iv);
SecretKeySpec mSecretKeySpec = generate(password, salt);
Cipher mCipher = Cipher.getInstance("AES/CTR/NoPadding");
mCipher.init(Cipher.DECRYPT_MODE, mSecretKeySpec, mIvParameterSpec);
return mCipher;
}
// generate key
private SecretKeySpec generate(String password, byte[] salt) throws Exception {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(salt);
byte[] key = md.digest(password.getBytes(StandardCharsets.UTF_8));
return new SecretKeySpec(key, "AES");
}
缓冲区数据在 android 6 中正常,但在 android 8 中数据不正确。
【问题讨论】:
-
欢迎来到 SO。请在最小、完整、可验证的示例后获得更好的答案。
-
您能测试
skip方法返回的值吗?这总是一种危险的方法,API 可能会跳过比请求更少的字节。还不清楚它对底层密码的作用:字节是否通过它?可能您应该跳过父流。 -
@MaartenBodewes:
skip()方法有效并通过密码传递数据,但您必须绝对检查返回值。由于内部缓冲区的大小,OpenJDK 版本每次调用不会跳过超过 512 个字节。我不知道 Android 是做什么的,但它可能是相似的。 -
我个人会通过使用内存映射文件而不是使用流来解决这个问题。您可以通过巧妙地更改 IV 将计数器设置为 CTR 模式,无需跳过密码本身的任何内容。
-
我应该指出
skip()的工作原理是它可以正确地跳过纯文本,但它对您的问题完全没用。要么使用read()并丢弃字节,要么更有效地根据@MaartenBodewes 的建议和seek()在块(16 字节)边界上将IV 巧妙地更改为您感兴趣的文件中的偏移量。如果流不可搜索,那么您将无法使用read()
标签: java android encryption inputstream android-version