Android Keystoreを使用して、大(マルチMB)データファイルの対称AES暗号化を行いたいと思います。Androidキーストアの対称暗号化の最大平文サイズ?
私は、キーストアのマルチKBのファイル暗号化/復号化しますデモコードを書いているが、ファイルサイズが大きくなりすぎたときには落下を開始します。この最大サイズはデバイスによって異なり、〜80KB〜1MBの範囲で使用できます。私がテストしたすべてのAndroid-Mデバイス(エミュレータを含む)では、暗号化が失敗する最大サイズがあるようです。
それが失敗した場合、それはsilently--失敗しかし暗号文サイズは、典型的には、それは(もちろん、その後復号化することができない)であるべきであるよりもかなり小さくなっています。
それはどちらか、複数のデバイス間でとても普及だ、私は何か間違ったこと(そう!)をやっている、またはキーストアに暗号化できるものに文書化されていない制限のいくつかの種類がありますので。
問題を示す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として平文をチャンクに変更しましたCYPHER like thisへのOES:
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 update'方法を使用するか、または' CipherInputStream' –
@ArtjomBを使用しますか。私はあなたが 'CipherOutputStream'を意味すると思う。 – paleozogt
@paleozogt両方を使うことができます。 –