2010-12-30 13 views
5

Ich habe den folgenden Code.Entschlüsselungsfehler: Pad Block beschädigt

byte[] input = etInput.getText().toString().getBytes(); 
    byte[] keyBytes = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 
     0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 }; 

    SecretKeySpec key = new SecretKeySpec(keyBytes, "AES"); 

    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC"); 

    // encryption pass 
    cipher.init(Cipher.ENCRYPT_MODE, key); 

    byte[] cipherText = new byte[cipher.getOutputSize(input.length)]; 
    int ctLength = cipher.update(input, 0, input.length, cipherText, 0); 
    ctLength += cipher.doFinal(cipherText, ctLength); 

    cipher.init(Cipher.DECRYPT_MODE, key); 
    byte[] plainText = new byte[cipher.getOutputSize(ctLength)]; 
    int ptLength = cipher.update(cipherText, 0, ctLength, plainText, 0); 

    String strLength = new String(cipherText,"US-ASCII"); 
    byte[] byteCiphterText = strLength.getBytes("US-ASCII"); 
    Log.e("Decrypt", Integer.toString(byteCiphterText.length)); 

    etOutput.setText(new String(cipherText,"US-ASCII")); 

    cipherText = etOutput.getText().toString().getBytes("US-ASCII"); 
    Log.e("Decrypt", Integer.toString(cipherText.length)); 

    ptLength += cipher.doFinal(plainText, ptLength); 
    Log.e("Decrypt", new String(plainText)); 
    Log.e("Decrypt", Integer.toString(ptLength)); 

Es funktioniert perfekt. Aber sobald ich es in die Klasse umwandeln. Es traf immer den Fehler in dieser Zeile.

ptLength += cipher.doFinal(plainText, ptLength); 

Error:Pad block corrupted 

Ich habe überprüft und beide Code sind genau gleich. Selbst der Wert, der in der Konvertierungszeichenfolge in Byte all übergeben wird, unterscheidet sich nicht von dem obigen Code. Irgendeine Idee, was ist mit dem Code falsch?

public String Encrypt(String strPlainText) throws Exception, NoSuchProviderException, 
     NoSuchPaddingException { 
    byte[] input = strPlainText.getBytes(); 
    byte[] keyBytes = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 
      0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 
      0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 }; 

    SecretKeySpec key = new SecretKeySpec(keyBytes, "AES"); 

    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC"); 

    // encryption pass 
    cipher.init(Cipher.ENCRYPT_MODE, key); 

    byte[] cipherText = new byte[cipher.getOutputSize(input.length)]; 
    int ctLength = cipher.update(input, 0, input.length, cipherText, 0); 
    ctLength += cipher.doFinal(cipherText, ctLength); 

    return new String(cipherText, "US-ASCII"); 
} 

public String Decrypt(String strCipherText) throws Exception, 
     NoSuchProviderException, NoSuchPaddingException { 
    byte[] cipherText = strCipherText.getBytes("US-ASCII"); 
    int ctLength = cipherText.length; 
    byte[] keyBytes = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 
      0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 
      0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 }; 

    SecretKeySpec key = new SecretKeySpec(keyBytes, "AES"); 

    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC"); 

    // decryption pass 
    cipher.init(Cipher.DECRYPT_MODE, key); 
    byte[] plainText = new byte[cipher.getOutputSize(ctLength)]; 
    int ptLength = cipher.update(cipherText, 0, ctLength, plainText, 0); 
    ptLength += cipher.doFinal(plainText, ptLength); 

    return new String(plainText); 
} 
+0

Es sei denn, Sie absolut sicher sind, oder arbeiten nur auf Block für Block sollten Sie niemals den ECB-Modus verwenden. Je. –

+0

Verwenden Sie stattdessen CBC – Codefor

Antwort

1

Sie haben PKCS7 Padding angegeben. Wird Ihre Auffüllung beibehalten, wenn sie in Ihrem String-Objekt gespeichert wird? Ist Ihr String-Objekt eine 1: 1-Übereinstimmung mit den Bytes, die von der Chiffre ausgegeben werden? Im Allgemeinen ist String zum Übergeben von Binärdaten ungeeignet, z. B. eine Chiffreausgabe.

+0

Sorry, abit verwirren auf Ihre Frage, Ist Ihre Auffüllung beibehalten, wenn in Ihrem String-Objekt gespeichert? -> Wie könnte ich überprüfen? Ist Ihr String-Objekt eine 1: 1-Übereinstimmung mit den Bytes, die von der Chiffre ausgegeben werden? -> Sie meinen, die Zeichenfolge, die ich für die Verschlüsselung eingegeben habe, muss mit der Byte-Ausgabe übereinstimmen? Im Allgemeinen ist String ungeeignet für die Übergabe von Binärdaten, wie zum Beispiel eine Chiffre-Ausgabe .-> Warum sagst du? Sobald ich den Chiffretext habe, habe ich ihn mit ASCII konvertiert.Auch wenn ich es in Byte-Array zurückkonvertiere, erhält er genau denselben Wert zurück . – kangalert

+0

Sie können überprüfen, ob die Bytes in der Zeichenfolge mit Ihrem ersten Array byte [] übereinstimmen. Ich bezweifle ernsthaft, dass sie es tun würden. "US-ASCII"! = Binäre Daten. –

0

In Ihrem Fall verwendet die Chiffre Padding, dh Eingabedaten werden in Blöcke mit einer vordefinierten Größe (die vom Auffüllalgorithmus abhängt) aufgefüllt/gerundet. Angenommen, Sie haben 500 Byte zum Verschlüsseln bereitgestellt, die Blockgröße für das Auffüllen beträgt 16 Byte. Die verschlüsselten Daten haben also eine Größe von 512 Byte (32 Blöcke). 12 Byte werden aufgefüllt.

In Ihrem Code erwarten Sie ein verschlüsseltes Array der gleichen Größe wie das Eingabe-Array, das eine Ausnahme verursacht. Sie müssen die Größe des Ausgabe-Arrays neu berechnen, wobei Sie auf das Padding achten müssen.

+0

Sie meinen, die Zeichenfolge, die ich verschlüsselt habe, muss die gleiche Größe meines Padding-Blocks haben? – kangalert

+0

Nein, String (eigentlich kein String aber byte [] Array) sollte auf Padding Blöcke gerundet werden. Größe – barmaley

3

Wie Yann Ramin sagte, ist die Verwendung von String ein Fehler bei der Chiffre-Eingabe/Ausgabe. Dies ist binäre Daten, die

  • 0x00
  • Werte enthalten kann enthalten kann, die nicht definiert sind oder verwendet

Verwenden Ebene byte [] wie in Ihrem ersten Beispiel an fremden Orten in der Codierung abgebildet oder Gehen Sie für Hex-Codierung oder Base64-Codierung das Byte [].

// this is a quick example - dont use sun.misc inproduction 
// - go for some open source implementation 
String encryptedString = new sun.misc.BASE64Encoder.encodeBuffer(encryptedBytes); 

Diese Zeichenkette kann sicher transportiert und in Byte zurückversetzt werden.

EDIT

Vielleicht sicherste Art und Weise mit der Länge Thema zu befassen ist immer zu verwenden Umsetzung Streaming (IMHO):

Beispiel

static public byte[] decrypt(Cipher cipher, SecretKey key, byte[]... bytes) 
     throws GeneralSecurityException, IOException { 
    cipher.init(Cipher.DECRYPT_MODE, key); 
    ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
    for (int i = 0; i < bytes.length; i++) { 
     bos.write(cipher.update(bytes[i])); 
    } 
    bos.write(cipher.doFinal()); 
    return bos.toByteArray(); 
} 
+1

Danke. Aber ich habe einen Fehler in bos.write (cipher.update (bytes [i])); cipher.update akzeptiert nur Byte-Array. – kangalert

+0

@kangalert hast du die Methodensignatur bemerkt? Bytes [i] ** ist ** ein Byte-Array. Vielleicht passen Sie die Signatur an Ihre Bedürfnisse an, verwenden Sie Array oder Liste ... – mtraut

Verwandte Themen