2013-06-21 2 views
13

Dostaję odszyfrowywania błąd w klasie Java:javax.crypto.IllegalBlockSizeException: długość wejściowa musi być wielokrotnością 16 podczas odszyfrowywania z wyściełane szyfr

javax.crypto.IllegalBlockSizeException : 
    Input length must be multiple of 16 when decrypting with padded cipher. 

Co mogę zrobić, aby rozwiązać ten problem?

UPDATE:

Zapomniałem wspomnieć, że działa po raz drugi raz im próbuje wykonać go ponownie jego wyrzuceniem wyżej wymieniony błąd.

package com.tb.module.service; 
import java.security.Key; 
import java.security.spec.InvalidKeySpecException; 

import javax.crypto.Cipher; 
import javax.crypto.spec.SecretKeySpec; 

import sun.misc.*; 

/** 
* This class is used for encrypt and decrypt the password field. 
* 
*/ 
public class PswdEnc { 

    private static final String ALGO = "AES"; 
    private static final byte[] keyValue = new byte[] { 'T', 'h', 'e', 'B', 'e', 's', 't','S', 'e', 'c', 'r','e', 't', 'K', 'e', 'y' }; 

    public static String encrypt(String Data) throws Exception { 
     Key key = generateKey(); 
     Cipher c = Cipher.getInstance(ALGO); 
     c.init(Cipher.ENCRYPT_MODE, key); 
     byte[] encVal = c.doFinal(Data.getBytes()); 
     String encryptedValue = new BASE64Encoder().encode(encVal); 
     return encryptedValue; 
    } 

    public static String decrypt(String encryptedData) throws Exception { 
     Key key = generateKey(); 
     Cipher c = Cipher.getInstance(ALGO); 
     c.init(Cipher.DECRYPT_MODE, key); 
     byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedData); 
     byte[] decValue = c.doFinal(decordedValue); 
     String decryptedValue = new String(decValue); 
     return decryptedValue; 
    } 


    private static Key generateKey() throws Exception { 
     Key key = new SecretKeySpec(keyValue, ALGO); 
     return key; 
    } 

} 
+0

Cokolwiek odszyfrujesz, ma nieodpowiedni rozmiar. Musi to być wielokrotność rozmiaru bloku (16), inaczej nie można go odszyfrować. Jak otrzymujesz odszyfrowane dane? – thegrinner

+0

tak naprawdę szyfruję hasło przed zapisaniem go w sql db. następnie podczas pobierania próbuję odszyfrować to. – baburao113

+0

Czy jesteś pewien, że dane, które zapisujesz i dane, które czytasz są tej samej długości? – thegrinner

Odpowiedz

2

Kilka komentarzy:

import sun.misc.*; nie rób tego. Jest nietypowy i nie gwarantuje, że jest identyczny między implementacjami. Istnieją inne biblioteki z dostępną konwersją Base64.

byte[] encVal = c.doFinal(Data.getBytes()); Tu polegają Państwo na domyślnym kodowaniu znaków. Zawsze określaj kodowanie znaków, którego używasz: byte[] encVal = c.doFinal(Data.getBytes("UTF-8")); Ustawienia domyślne mogą się różnić w różnych miejscach.

Jak zaznaczył @grishner, należy dokładnie sprawdzić długość macierzy bajtów. Jeśli istnieje rozbieżność, porównaj bajt po bajcie, aby zobaczyć, gdzie różnica jest wkradająca się.

+0

* Dostępne są inne biblioteki z konwersją Base64 *> Od wersji 6 Java wypróbuj 'DatatypeConverter'. –

57

Algorytm, którego używasz, "AES", jest skrótem dla "AES/ECB/NoPadding". Oznacza to, że używasz AES algorithm z kluczem 128-bitowym i block size, z ECBmode of operation i no padding.

Innymi słowy: dane są szyfrowane tylko w blokach 128-bitowych lub 16-bajtowych. Właśnie dlatego otrzymujesz wyjątek od IllegalBlockSizeException.

Jeśli chcesz zaszyfrować dane w rozmiarach, które nie są wielokrotnością 16 bajtów, będziesz musiał użyć jakiegoś dopełnienia lub strumienia szyfrów. Na przykład można użyć CBC mode (tryb działania, który skutecznie przekształca szyfr blokowy na stream cipher), określając "AES/CBC/NoPadding" jako algorytm, lub dopełnienie PKCS5, określając "AES/ECB/PKCS5", co spowoduje automatycznie dodaje kilka bajtów na końcu danych w bardzo określonym formacie, aby rozmiar zaszyfrowanego tekstu był wielokrotny 16 bajtów, i w taki sposób, że algorytm odszyfrowujący zrozumie, że musi zignorować niektóre dane.

W każdym razie zdecydowanie sugeruję, abyś przestał teraz robić to, co robisz, i popracuj nad kilkoma bardzo wstępnymi materiałami na temat kryptografii. Na przykład sprawdź Crypto I on Coursera. Powinieneś bardzo dobrze zrozumieć konsekwencje wyboru jednego lub drugiego trybu, jakie są ich mocne strony i, co najważniejsze, ich słabości. Bez tej wiedzy bardzo łatwo jest budować systemy, które są bardzo łatwe do złamania.


Aktualizacja: na podstawie swoich uwag dotyczących kwestii, nie zawsze szyfrowania haseł podczas zapisywania ich w bazie danych !!!!! Nigdy nie powinieneś tego robić. Musisz haseł, poprawnie wysolonych, które są całkowicie różne od szyfrowania. Naprawdę, proszę, nie rób tego, co próbujesz zrobić ... Szyfrując hasła, można je odszyfrować. Oznacza to, że ty, jako menedżer bazy danych i znasz tajny klucz, będziesz mógł odczytać każde hasło przechowywane w bazie danych.Albo to wiedziałeś i robisz coś bardzo, bardzo źle, albo nie wiedziałeś tego i powinieneś się zszokować i przestać.

+0

Nie wiedziałem o tym, że nie powinienem szyfrować hasła i przechowywać go w bazie danych. Dzięki za informację. – baburao113

+0

@ baburao113 wtedy powinieneś naprawdę zaakceptować odpowiedź –

+6

+1 za polecanie haszu nad szyfrowaniem –

2

Aby rozwiązać problem, wystarczy kilka drobnych zmian w kodzie, aby po prostu wprowadzić typ szyfrowania() API twojej klasy to tablica bajtów [] i funkcja API deszyfrowania() tablicy bajtów klasy [] to można rozwiązać wiele długości wejściowych 16 wyjątków.

Patrz poniżej kod pracy:

public static byte[] encrypt(String value) { 
     byte[] encrypted = null; 
     try { 

      byte[] raw = new byte[]{'T', 'h', 'i', 's', 'I', 's', 'A', 'S', 'e', 'c', 'r', 'e', 't', 'K', 'e', 'y'}; 
      Key skeySpec = new SecretKeySpec(raw, "AES"); 
      Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
      byte[] iv = new byte[cipher.getBlockSize()]; 

      IvParameterSpec ivParams = new IvParameterSpec(iv); 
      cipher.init(Cipher.ENCRYPT_MODE, skeySpec,ivParams); 
      encrypted = cipher.doFinal(value.getBytes()); 
      System.out.println("encrypted string:" + encrypted.length); 

     } catch (Exception ex) { 
      ex.printStackTrace(); 
     } 
     return encrypted; 
    } 

    public static byte[] decrypt(byte[] encrypted) { 
     byte[] original = null; 
     Cipher cipher = null; 
     try { 
      byte[] raw = new byte[]{'T', 'h', 'i', 's', 'I', 's', 'A', 'S', 'e', 'c', 'r', 'e', 't', 'K', 'e', 'y'}; 
      Key key = new SecretKeySpec(raw, "AES"); 
      cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
      //the block size (in bytes), or 0 if the underlying algorithm is not a block cipher 
      byte[] ivByte = new byte[cipher.getBlockSize()]; 
      //This class specifies an initialization vector (IV). Examples which use 
      //IVs are ciphers in feedback mode, e.g., DES in CBC mode and RSA ciphers with OAEP encoding operation. 
      IvParameterSpec ivParamsSpec = new IvParameterSpec(ivByte); 
      cipher.init(Cipher.DECRYPT_MODE, key, ivParamsSpec); 
      original= cipher.doFinal(encrypted); 
     } catch (Exception ex) { 
      ex.printStackTrace(); 
     } 
     return original; 
    } 
0

Dobrze, że właśnie z powodu

jesteś tylko w stanie szyfrować dane w blokach po 128 bitów lub 16 bajtów. Właśnie dlatego otrzymujesz wyjątek IllegalBlockSizeException. i jedynym sposobem jest zaszyfrowanie tych danych bezpośrednio w ciągu znaków.

Zobacz to. Spróbuj i rozwiąż ten problem, aby pomóc Ci w rozwiązaniu tego problemu.

Powiązane problemy