2016-08-03 27 views
0

我想使用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的理解是,输入明文不必具有特殊的大小(与块长度对齐等)。

回答

1

印鉴数据成小块,然后调用更新,当它到达了最后一块调用doFinal

+2

换句话说:要么使用'密码#update'方法或使用'CipherInputStream' –

+0

@ArtjomB。我想你的意思是'CipherOutputStream' – paleozogt

+0

@paleozogt你可以使用两者。 –