2016-08-03 16 views
0

Ich möchte die Android Keystore verwenden, um symmetrische AES-Verschlüsselung von großen (Multi MB) -Dateien durchzuführen.Max. Klartextgröße für Android Keystore symmetrische Verschlüsselung?

Ich habe Demo-Code geschrieben, der Multi-KB-Dateien mit dem Keystore verschlüsseln/entschlüsseln wird, aber wenn die Dateigröße zu groß wird, beginnt sie zu fallen. Diese maximale Größe variiert je nach Gerät und kann irgendwo zwischen ~ 80 KB und ~ 1 MB liegen. Auf jedem Android-M-Gerät, auf dem ich getestet habe (einschließlich des Emulators), scheint eine maximale Größe zu sein, nach der die Verschlüsselung fehlschlägt.

Wenn es fehlschlägt, schlägt es im Hintergrund fehl - jedoch ist die Chiffretextgröße normalerweise ein wenig kleiner als sie sein sollte (was natürlich nicht entschlüsselt werden kann).

Da es über mehrere Geräte hinweg so verbreitet ist, mache ich entweder etwas falsch (wahrscheinlich!), Oder es gibt eine Art undokumentiertes Limit für das, was im Keystore verschlüsselt werden kann.

Ich habe eine Demo-App auf Github geschrieben, die das Problem zeigt (here, speziell this file). Sie können die App GUI ausführen, um das Problem manuell auftreten zu lassen, oder die Instrumentierungstests ausführen, um dies zu ermöglichen.

Jede Hilfe oder Hinweise auf Dokumentation zu diesem Problem würde sehr geschätzt werden!

Als Referenz bin ich Erzeugen des symmetrischen Schlüssels 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()); 

und ich bin Verschlüsselung 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)); 

Update:

Per Vorschläge von user2481360 und Artjom B. Ich änderte den Klartext wie es g oes in die Chiffre 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); 

Dies scheint das Problem mit dem verschlüsselten Text ist völlig falsch zu lösen. Ich kann jetzt sehr große Klartextgrößen verwenden.

Je nach Größe werden die Daten jedoch manchmal nicht abgerundet. Wenn ich zum Beispiel 1 MB nutze, fehlen am abgerundeten Klartext ein paar Bytes am Ende. Aber wenn ich 1MB + 1B verwende, wird es funktionieren. Mein Verständnis von AES/GCM war, dass der Eingabe-Klartext keine spezielle Größe haben muss (ausgerichtet auf die Blocklänge, usw.).

Antwort

1

Hieb die Daten in kleine Stücke und rufen Sie dann zu aktualisieren, wenn es das letzte Stück doFinal

+2

Mit anderen Worten rufen erreichen: entweder die 'Cipher # update' Methode oder verwenden Sie eine' CipherInputStream' –

+0

@ArtjomB. Ich denke du meinst "CipherOutputStream" – paleozogt

+0

@paleozogt Sie können beide verwenden. –