2016-08-03 25 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你可以使用兩者。 –