2010-12-30 13 views
5

Mam następujący kod.Błąd deszyfrowania: Blokada bloku uszkodzona

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)); 

Działa doskonale. Ale raz konwertuję to do klasy. Zawsze trafia błąd w tej linii.

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

Error:Pad block corrupted 

Sprawdziłem i oba są dokładnie takie same. Nawet wartość przekazana w ciągu konwersji do bajtu nie różni się od powyższego kodu. Masz pojęcie, co jest nie tak z kodem?

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

Chyba że jesteś absolutnie pewien, czy pracują tylko na jeden blok na raz, nigdy nie powinieneś używać trybu ECB. Zawsze. –

+0

Użyj CBC zamiast: – Codefor

Odpowiedz

1

Określono opcję wypełniania PKCS7. Czy twoje dopełnienie jest zachowane, gdy jest przechowywane w twoim obiekcie String? Czy Twój obiekt typu string jest dopasowany w stosunku 1: 1 do bajtów wyjściowych z szyfru? Ogólnie String nie nadaje się do przekazywania danych binarnych, takich jak dane wyjściowe z szyfru.

+0

Przepraszam, pomieszam pomylenie twojego pytania, Czy twoje dopełnienie zostało zachowane, gdy jest przechowywane w twoim obiekcie String? -> Jak mogę sprawdzić? Czy twój obiekt typu string jest dopasowany w stosunku 1: 1 do bajtów wyjściowych z szyfru? -> Masz na myśli, że ciąg znaków, który wprowadzam do szyfrowania, musi być zgodny z danymi wyjściowymi bajtów? Ogólnie rzecz biorąc, ciąg nie nadaje się do przekazywania danych binarnych, takich jak dane wyjściowe z szyfru .-> Po co to pisać? Kiedy otrzymam tekst szyfrowany, przekonwertowałem go za pomocą ASCII.Niekonwertuję go na tablicę bajtową, otrzymuję dokładnie taką samą wartość . – kangalert

+0

Możesz sprawdzić, czy bajty w łańcuchu pasują do pierwszej tablicy bajtów []. Poważnie wątpię, że by to zrobili. "US-ASCII"! = Dane binarne. –

0

W twoim przypadku, gdy cipher używa wypełnienia, oznacza to, że dane wejściowe zostaną dopełnione/zaokrąglone do bloków o pewnym wcześniej zdefiniowanym rozmiarze (co zależy od algorytmu wypełniania). Powiedzmy, że dostarczyłeś 500 bajtów do zaszyfrowania, rozmiar bloku wypełniającego to 16 bajtów, więc zaszyfrowane dane będą miały rozmiar 512 bajtów (32 bloki) - 12 bajtów zostanie dopełnionych.

W kodzie oczekujesz zaszyfrowanej tablicy o tym samym rozmiarze co tablica wejściowa, co powoduje wyjątek. Musisz przeliczyć wyjściowy rozmiar tablicy, pamiętając o dopełnieniu.

+0

Masz na myśli, że szyfrowany ciąg musi być taki sam jak mój blok wypełniający? – kangalert

+0

Nie, ciąg (właściwie nie ciąg, ale bajt [] tablica) powinien być zaokrąglony do bloków dopełniających rozmiar – barmaley

3

Jak powiedział Yann Ramin, użycie String jest błędem dla wejścia/wyjścia szyfru. Są to dane binarne

  • może zawierać 0x00
  • może zawierać wartości, które nie są określone lub odwzorowane na dziwnych miejscach kodowania wykorzystanego

Zastosowanie zwykły bajt [], jak w przykładzie pierwszym albo idź na kodowanie szesnastkowe lub base64 kodując bajt [].

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

Ten ciąg może być bezpiecznie transportowany i mapowany z powrotem na bajty.

EDIT

Być może najbezpieczniejszym sposobem radzenia sobie z problemem długość jest, aby zawsze używać strumieniowe realizacji (IMHO):

Przykład

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

Dzięki. Ale mam błąd w bos.write (cipher.update (bytes [i])); cipher.update akceptuje tylko tablicę bajtów. – kangalert

+0

@kangalert zauważyłeś podpis metody? bajty [i] ** to ** tablica bajtów. Może dostosujesz podpis do swoich potrzeb, użyjesz tablicy tablic lub listy ... – mtraut