我想使用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你可以使用兩者。 –