我想使用Android Keystore对大型(多MB)数据文件进行对称AES加密。Android Keystore对称加密的最大纯文本大小?
我已经编写了演示代码,它将使用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.
我改为分块明文,因为它g OES成暗号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
的理解是,输入明文不必具有特殊的大小(与块长度对齐等)。
换句话说:要么使用'密码#update'方法或使用'CipherInputStream' –
@ArtjomB。我想你的意思是'CipherOutputStream' – paleozogt
@paleozogt你可以使用两者。 –