【问题标题】:max plaintext size for Android Keystore symmetric encryption?Android Keystore 对称加密的最大明文大小?
【发布时间】: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));

更新:

根据user2481360Artjom 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


    【解决方案1】:

    将数据切成小块,然后调用update,当它到达最后一块时调用doFinal

    【讨论】:

    • 换句话说:要么使用Cipher#update方法,要么使用CipherInputStream
    • @ArtjomB。我想你的意思是CipherOutputStream
    • @paleozogt 你可以同时使用。
    猜你喜欢
    • 2014-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-03
    • 1970-01-01
    • 2015-12-20
    相关资源
    最近更新 更多