【发布时间】:2016-08-03 22:57:49
【问题描述】:
我想使用Android Keystore 对大型(多 MB)数据文件进行对称 AES 加密。
我编写的演示代码将使用 Keystore 加密/解密多 KB 文件,但是当文件大小变得太大时,它开始下降。此最大大小因设备而异,范围从 ~80KB 到 ~1MB。在我测试过的每台 Android-M 设备(包括模拟器)上,似乎都有一个最大尺寸,超过该尺寸后加密将失败。
当它失败时,它会默默地失败——但是密文大小通常比它应该的小很多(当然不能被解密)。
由于它在多个设备中如此普遍,要么我做错了什么(很可能!),要么在 Keystore 中可以加密的内容存在某种未记录的限制。
我在 Github 上编写了一个演示应用程序来显示问题(here,特别是 this file)。您可以运行应用程序 gui 以手动使问题发生,或运行仪器测试以使其发生。
任何有关此问题的文档的帮助或指针将不胜感激!
作为参考,我正在生成对称密钥like this:
KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
keyGenerator.init(
new KeyGenParameterSpec.Builder(KEY_ALIAS, KeyProperties.PURPOSE_ENCRYPT|KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.build()
);
SecretKey key = keyGenerator.generateKey();
SecretKeyFactory factory = SecretKeyFactory.getInstance(key.getAlgorithm(), "AndroidKeyStore");
KeyInfo keyInfo= (KeyInfo)factory.getKeySpec(key, KeyInfo.class);
logger.debug("isInsideSecureHardware: {}", keyInfo.isInsideSecureHardware());
我正在加密like this:
KeyStore keyStore= KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
KeyStore.SecretKeyEntry keyEntry= (KeyStore.SecretKeyEntry)keyStore.getEntry(KEY_ALIAS, null);
Cipher cipher= getCipher();
cipher.init(Cipher.ENCRYPT_MODE, keyEntry.getSecretKey());
GCMParameterSpec params= cipher.getParameters().getParameterSpec(GCMParameterSpec.class);
ByteArrayOutputStream byteStream= new ByteArrayOutputStream();
DataOutputStream dataStream= new DataOutputStream(byteStream);
dataStream.writeInt(params.getTLen());
byte[] iv= params.getIV();
dataStream.writeInt(iv.length);
dataStream.write(iv);
dataStream.write(cipher.doFinal(plaintext));
更新:
根据user2481360 和Artjom B. 的建议,我更改为在明文进入密码like this 时将其分块:
ByteArrayInputStream plaintextStream= new ByteArrayInputStream(plaintext);
final int chunkSize= 4*1024;
byte[] buffer= new byte[chunkSize];
while (plaintextStream.available() > chunkSize) {
int readBytes= plaintextStream.read(buffer);
byte[] ciphertextChunk= cipher.update(buffer, 0, readBytes);
dataStream.write(ciphertextChunk);
}
int readBytes= plaintextStream.read(buffer);
byte[] ciphertextChunk= cipher.doFinal(buffer, 0, readBytes);
dataStream.write(ciphertextChunk);
这似乎解决了密文完全错误的问题。我现在可以使用非常大的纯文本大小。
但是,根据大小,有时数据不会往返。例如,如果我使用 1MB,则往返明文最后会丢失几个字节。但如果我使用 1MB+1B,它会起作用。我对AES/GCM 的理解是,输入明文不必具有特殊大小(与块长度对齐等)。
【问题讨论】:
标签: android security encryption-symmetric