2011-01-04 5 views
10

Ich habe eine einfache Klasse zu versuchen und verschlüsseln Verschlüsselung für die Verwendung an anderer Stelle in meinem Programm.Wie behandelt man "letzten Block unvollständig in der Entschlüsselung"

import java.security.SecureRandom; 
import javax.crypto.Cipher; 
import javax.crypto.KeyGenerator; 
import javax.crypto.spec.SecretKeySpec; 

public final class StupidSimpleEncrypter 
{ 
    public static String encrypt(String key, String plaintext) 
    { 
     byte[] keyBytes = key.getBytes(); 
     byte[] plaintextBytes = plaintext.getBytes(); 
     byte[] ciphertextBytes = encrypt(keyBytes, plaintextBytes); 
     return new String(ciphertextBytes); 
    } 

    public static byte[] encrypt(byte[] key, byte[] plaintext) 
    { 
     try 
     { 
      Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); 
      SecretKeySpec spec = new SecretKeySpec(getRawKey(key), "AES"); 
      cipher.init(Cipher.ENCRYPT_MODE, spec); 
      return cipher.doFinal(plaintext); 
     } 
     catch(Exception e) 
     { 
      // some sort of problem, return null because we can't encrypt it. 
      Utility.writeError(e); 
      return null; 
     } 
    } 

    public static String decrypt(String key, String ciphertext) 
    { 
     byte[] keyBytes = key.getBytes(); 
     byte[] ciphertextBytes = ciphertext.getBytes(); 
     byte[] plaintextBytes = decrypt(keyBytes, ciphertextBytes); 
     return new String(plaintextBytes); 
    } 

    public static byte[] decrypt(byte[] key, byte[] ciphertext) 
    { 
     try 
     { 
      Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); 
      SecretKeySpec spec = new SecretKeySpec(getRawKey(key), "AES"); 
      cipher.init(Cipher.DECRYPT_MODE, spec); 
      return cipher.doFinal(ciphertext); 
     } 
     catch(Exception e) 
     { 
      // some sort of problem, return null because we can't encrypt it. 
      Utility.writeError(e); 
      return null; 
     } 
    } 

    private static byte[] getRawKey(byte[] key) 
    { 
     try 
     { 
      KeyGenerator gen = KeyGenerator.getInstance("AES"); 
      SecureRandom rand = SecureRandom.getInstance("SHA1PRNG"); 
      rand.setSeed(key); 
      gen.init(256, rand); 
      return gen.generateKey().getEncoded(); 
     } 
     catch(Exception e) 
     { 
      return null; 
     } 
    } 
} 

Es scheint, Verschlüsselung richtig zu handhaben, aber nicht so viel, wenn die Entschlüsselung, die auf der markierte Linie einen javax.crypto.IllegalBlockSizeException „letzter Block unvollständig in Entschlüsselung“ wirft. Hier ist der Stack-Trace:

 
Location:com.xxxxxx.android.StupidSimpleEncrypter.decrypt ln:49 
last block incomplete in decryption 
javax.crypto.IllegalBlockSizeException: last block incomplete in decryption 
    at org.bouncycastle.jce.provider.JCEBlockCipher.engineDoFinal(JCEBlockCipher.java:711) 
    at javax.crypto.Cipher.doFinal(Cipher.java:1090) 
    at com.xxxxxx.android.StupidSimpleEncrypter.decrypt(StupidSimpleEncrypter.java:44) 
    at com.xxxxxx.android.StupidSimpleEncrypter.decrypt(StupidSimpleEncrypter.java:34) 

ich eine gute Menge an schlug meinen Kopf gegen meinen Schreibtisch, dies zu versuchen, herauszufinden, getan haben, aber wenn ich irgendwo überhaupt bekommen, es endet eine andere Ausnahme. Ich kann auch nicht viel durch Suchen finden.

Was fehlt mir? Ich würde jede Hilfe schätzen.

Antwort

19

Ich weiß nicht, ob das das Problem mit der ist, aber Sie sollten den Schlüssel nicht als String codieren, vor allem ohne Angabe der Zeichencodierung. Wenn Sie dies tun möchten, verwenden Sie etwas wie Base-64, das dazu bestimmt ist, irgendwelche "binären" Daten zu kodieren, anstatt eine Zeichencodierung, die nur bestimmte Bytes auf Zeichen abbildet.

Der Schlüssel wird im Allgemeinen Byte-Werte enthalten, die nicht einem Zeichen in der Standard-Plattformcodierung entsprechen. Wenn Sie in diesem Fall String erstellen, wird das Byte in das "Ersatzzeichen" U + FFFD (& # xFFFD;) übersetzt, und der korrekte Wert wird unwiederbringlich verloren sein.

Der Versuch, die korrupte String Darstellung des Schlüssels später zu verwenden, verhindert, dass der Klartext wiederhergestellt wird. es ist möglich, dass es die IllegalBlockSizeException verursachen könnte, aber ich vermute, dass eine ungültige Polsterung Ausnahme wahrscheinlicher wäre.

Eine andere Möglichkeit ist, dass die Zeichencodierungen der Quellplattform und der Zielplattform unterschiedlich sind und dass das "Decodieren" des Chiffretextes zu wenig Bytes ergibt. Zum Beispiel ist die Quellencodierung UTF-8 und interpretiert zwei Bytes in der Eingabe als ein einzelnes Zeichen, während die Zielcodierung ISO-Latin-1 ist, die dieses Zeichen als ein einzelnes Byte darstellt.

+0

Dies ist die Ursache für mein Problem war, aber es war mit der Nutzlast und nicht der Schlüssel, der immer eine Standard-Zeichenfolge in meinem Fall sein.Ich änderte es so in der String-Encrypt-Methode, der Chiffretext, der zurückgegeben wird, wird Base64 aus dem Byte-Array codiert, und in der Entschlüsselungsmethode wird die Chiffretext-String Base64 in ein Byte-Array decodiert. Das bedeutet, dass Daten nicht mehr verloren gehen und der Code jetzt funktioniert. –

+0

Dasselbe gilt für den verschlüsselten String selbst. Es muss als Byte [] gespeichert werden. – user1666456

6

Ihre getKeySpec() Methode ist falsch. Sie generieren einen neuen zufälligen Schlüssel für die Ver- und Entschlüsselungsrichtungen. Sie müssen für beide den gleichen Schlüssel verwenden. Sie sollten bemerkt haben, dass Sie das Argument key für diese Methode nicht verwenden.

+1

Das war ein Teil des Problems und etwas, das ich für eine Weile bemerkt hätte. Vielen Dank. –

1

Wenn Sie an Byte-Array arbeiten, müssen Sie die gleiche Puffergröße verwenden. Zum Beispiel gibt es Bytearray, dessen Größe 1000 ist. Nach der Verschlüsselung wird diese Größe zu 2000. (Dies ist kein realer Wert). Wenn Sie Puffer verwenden, um die gesamte verschlüsselte Datei zu lesen, dann sollten Sie Puffergröße bis 2000 wählen. Ich löste das gleiche Problem auf diese Weise.

0

Für mich bemerke ich dieses Problem, wenn die zu entschlüsselnden Daten beschädigt sind (fehlt 1 Zeichen). Es könnte an der Übertragung von Daten über WiFi liegen.

4

Ich habe mir dabei meine Haare ausgerissen, zwischen "bad base 64" und "last block incomplete" Fehlern ... bis es natürlich asymmetrisch ist. Hier ist das Wesen, wie ich am Ende, es zu tun, die hoffentlich mehr ergänzt die Diskussion, als wenn ich zu erklären versucht:

public String crypto(SecretKey key, String inString, boolean decrypt){ 
    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); 
    byte[] inputByte = inString.getBytes("UTF-8"); 
    if (decrypt){ 
     cipher.init(Cipher.DECRYPT_MODE, key); 
     return new String (cipher.doFinal(Base64.decode(inputByte, Base64.DEFAULT))); 
    } else { 
     cipher.init(Cipher.ENCRYPT_MODE, key); 
     return new String (Base64.encode(cipher.doFinal(inputByte), Base64.DEFAULT)); 
    } 
}