Podany ostatni blok nie jest prawidłowo wyściełany

Próbuję zaimplementować algorytm szyfrowania oparty na hasłach, ale dostaję ten wyjątek:

Javax.krypto.BadPaddingException: Given final block not properly padded
W czym może być problem? (Jestem nowy w Javie.)

Oto Mój kod:

public class PasswordCrypter {

    private Key key;

    public PasswordCrypter(String password)  {
        try{
            KeyGenerator generator;
            generator = KeyGenerator.getInstance("DES");
            SecureRandom sec = new SecureRandom(password.getBytes());
            generator.init(sec);
            key = generator.generateKey();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public byte[] encrypt(byte[] array) throws CrypterException {
        try{
            Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, key);

            return cipher.doFinal(array);
        } catch (Exception e) { 
            e.printStackTrace();
        }
        return null;
    }

    public byte[] decrypt(byte[] array) throws CrypterException{
        try{
            Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, key);

            return cipher.doFinal(array);
        } catch(Exception e ){
            e.printStackTrace();
        }
        return null;
    }
}

(Test JUnit)

public class PasswordCrypterTest {

    private static final byte[] MESSAGE = "Alpacas are awesome!".getBytes();
    private PasswordCrypter[] passwordCrypters;
    private byte[][] encryptedMessages;

    @Before
    public void setUp() {
        passwordCrypters = new PasswordCrypter[] {
            new PasswordCrypter("passwd"),
            new PasswordCrypter("passwd"),
            new PasswordCrypter("otherPasswd")
        };

        encryptedMessages = new byte[passwordCrypters.length][];
        for (int i = 0; i < passwordCrypters.length; i++) {
            encryptedMessages[i] = passwordCrypters[i].encrypt(MESSAGE);
        }
    }

    @Test
    public void testEncrypt() {
        for (byte[] encryptedMessage : encryptedMessages) {
            assertFalse(Arrays.equals(MESSAGE, encryptedMessage));
        }

        assertFalse(Arrays.equals(encryptedMessages[0], encryptedMessages[2]));
        assertFalse(Arrays.equals(encryptedMessages[1], encryptedMessages[2]));
    }

    @Test
    public void testDecrypt() {
        for (int i = 0; i < passwordCrypters.length; i++) {
            assertArrayEquals(MESSAGE, passwordCrypters[i].decrypt(encryptedMessages[i]));
        }

        assertArrayEquals(MESSAGE, passwordCrypters[0].decrypt(encryptedMessages[1]));
        assertArrayEquals(MESSAGE, passwordCrypters[1].decrypt(encryptedMessages[0]));

        try {
            assertFalse(Arrays.equals(MESSAGE, passwordCrypters[0].decrypt(encryptedMessages[2])));
        } catch (CrypterException e) {
            // Anything goes as long as the above statement is not true.
        }

        try {
            assertFalse(Arrays.equals(MESSAGE, passwordCrypters[2].decrypt(encryptedMessages[1])));
        } catch (CrypterException e) {
            // Anything goes as long as the above statement is not true.
        }
    }
}
Author: aldok, 2011-11-08

2 answers

Jeśli spróbujesz odszyfrować dane wyściełane PKCS5 niewłaściwym kluczem, a następnie je rozpakować( co jest wykonywane automatycznie przez klasę Szyfrów), najprawdopodobniej uzyskasz wyjątek BadPaddingException (z prawdopodobnie nieco mniejszym niż 255/256, około 99,61%), ponieważ wyściełanie ma specjalną strukturę, która jest sprawdzana podczas rozpakowywania i bardzo niewiele kluczy utworzyłoby prawidłowe wyściełanie.

Tak więc, jeśli otrzymasz ten wyjątek, złap go i potraktuj jako "zły klucz".

To również może się zdarzyć, gdy podajesz błędne hasło, które następnie jest używane do uzyskania klucza z magazynu kluczy lub które jest konwertowane na klucz za pomocą funkcji generowania kluczy.

Oczywiście, złe wypełnienie może się również zdarzyć, jeśli Twoje dane są uszkodzone podczas transportu.

To powiedziawszy, są pewne uwagi dotyczące bezpieczeństwa dotyczące Twojego planu:

  • W przypadku szyfrowania opartego na hasłach, powinieneś użyć SecretKeyFactory i PBEKeySpec zamiast używać SecureRandom z KeyGenerator. Powodem jest to, że SecureRandom może być innym algorytmem w każdej implementacji Javy, dającym inny klucz. SecretKeyFactory wykonuje wyprowadzanie klucza w określony sposób (i sposób, który jest uważany za Bezpieczny, jeśli wybierzesz odpowiedni algorytm).

  • Nie używaj trybu EBC. Szyfruje każdy blok niezależnie, co oznacza, że identyczne bloki zwykłego tekstu również dają zawsze identyczne bloki szyfrowe.

    Najlepiej używać bezpiecznego trybu działania , takiego jak CBC (Cipher block chaining) lub CTR (Counter). Alternatywnie, użyj trybu, który obejmuje również uwierzytelnianie, jak GCM (Galois-Counter mode) lub CCM (Counter with CBC-MAC), patrz następny punkt.

  • Zwykle nie chcesz tylko poufności, ale także uwierzytelniania, które zapewnia, że wiadomość nie jest manipulowana. (Zapobiega to również atakom za pomocą wybranych szyfrów na Twój szyfr, tzn. pomaga w zachowaniu poufności.) Dodaj więc do wiadomości kod uwierzytelniający Mac (message authentication code) lub użyj trybu szyfrowania która obejmuje uwierzytelnianie (patrz poprzedni punkt).

  • DES ma efektywny rozmiar klucza tylko 56 bitów. Ta przestrzeń klucza jest dość mała, może być brutalnie wymuszona w kilka godzin przez dedykowanego atakującego. Jeśli wygenerujesz klucz za pomocą hasła, stanie się to jeszcze szybsze. Ponadto, DES ma rozmiar bloku tylko 64 bitów, co dodaje więcej słabości w trybach łańcuchowania. Zamiast tego użyj nowoczesnego algorytmu, takiego jak AES, który ma rozmiar bloku 128 bitów i rozmiar klucza 128 bitów (dla standardu wariant).

 166
Author: Paŭlo Ebermann,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-23 17:23:11

W zależności od używanego algorytmu kryptograficznego, przed zaszyfrowaniem tablicy bajtów może być konieczne dodanie na końcu bajtów wypełnienia, tak aby długość tablicy bajtów była wielokrotnością rozmiaru bloku:

Specjalnie w Twoim przypadku wybrany schemat wypełnienia to PKCS5, który jest opisany tutaj: http://www.rsa.com/products/bsafe/documentation/cryptoj35html/doc/dev_guide/group_CJ_SYM__PAD.html

(zakładam, że masz problem, gdy próbujesz encrypt)

Możesz wybrać schemat wypełnienia podczas tworzenia instancji obiektu szyfru. Obsługiwane wartości zależą od dostawcy zabezpieczeń, którego używasz.

Przy okazji czy na pewno chcesz użyć symetrycznego mechanizmu szyfrowania do szyfrowania haseł? Nie byłoby lepiej w jedną stronę? Jeśli naprawdę musisz być w stanie odszyfrować hasła, DES jest dość słabym rozwiązaniem, możesz być zainteresowany użyciem czegoś mocniejszego, takiego jak AES, jeśli musisz pozostać przy algorytmie symetrycznym.

 0
Author: fpacifici,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-09 22:00:08