Gegeven laatste blok dat niet goed is ingevuld

Ik probeer een op wachtwoorden gebaseerd coderingsalgoritme te implementeren, maar ik krijg deze uitzondering:

javax.crypto.BadPaddingException: gegeven laatste blok niet goed opgevuld

Wat kan het probleem zijn?

Hier is mijn code:

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

(De JUnit-test)

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.
        }
    }
}

Antwoord 1, autoriteit 100%

Als u PKCS5-gevoerde gegevens probeert te decoderen met de verkeerde toets, en vervolgens het automatisch door de coderingsklasse), krijgt u hoogstwaarschijnlijk de BadpaddingException (met waarschijnlijk iets minder dan 255/256, Ongeveer 99.61%), omdat de vulling een speciale structuur heeft die is gevalideerd tijdens de PARD en zeer weinig sleutels zou een geldige opvulling produceren.

Dus, als u deze uitzondering krijgt, vang deze en behandel het als “verkeerde toets”.

Dit kan ook gebeuren wanneer u een verkeerd wachtwoord verstrekt, dat vervolgens wordt gebruikt om de sleutel van een keystore te krijgen, of die wordt geconverteerd in een sleutel met behulp van een toetsgeneratiefunctie.

Natuurlijk kan slechte vulling ook gebeuren als uw gegevens zijn beschadigd in transport.

Dat gezegd hebbende, er zijn enkele beveiligingsopmerkingen over uw regeling:

  • Voor op wachtwoord gebaseerde codering moet u een secreteyfactory en pbekeyspec gebruiken in plaats van een securerandom te gebruiken met KeyGenerator. De reden is dat de Securferandom een ​​ander algoritme kan zijn op elke Java-implementatie, waardoor u een andere sleutel krijgt. De SecretkeyFactory doet de belangrijkste afleiding op een gedefinieerde manier (en een manier die wordt geacht beveiligd, als u het juiste algoritme selecteert).

  • Gebruik de ECB-modus niet. Het codeert elk blok onafhankelijk, wat betekent dat identieke platte tekstblokken ook altijd identieke ciphertext-blokken geven.

    Gebruik bij voorkeur een beveiligde modus van werking , zoals CBC (coderingsblokketting) of CTR ( Balie). U kunt ook een modus gebruiken die ook authenticatie bevat, zoals GCM (Galois-Counter-modus) of CCM (teller met CBC-MAC), zie het volgende punt.

  • Normaal gesproken wil je niet alleen vertrouwelijkheid, maar ook authenticatie, die ervoor zorgt dat er niet met het bericht wordt geknoeid. (Dit voorkomt ook aanvallen met gekozen cijfertekst op uw codering, dwz helpt voor de vertrouwelijkheid.) Voeg dus een MAC (message authenticatiecode) toe aan uw bericht, of gebruik een coderingsmodus die authenticatie omvat (zie vorige punt).

  • DES heeft een effectieve sleutelgrootte van slechts 56 bits. Deze sleutelruimte is vrij klein en kan in enkele uren bruut worden geforceerd door een toegewijde aanvaller. Als u uw sleutel genereert met een wachtwoord, gaat dit nog sneller.
    DES heeft ook een blokgrootte van slechts 64 bits, wat wat meer zwakke punten in ketenmodi toevoegt.
    Gebruik in plaats daarvan een modern algoritme zoals AES, dat een blokgrootte heeft van 128 bits en een sleutelgrootte van
    128 bits (voor de standaardvariant).


Antwoord 2

Dit kan ook een probleem zijn als u een verkeerd wachtwoord invoert voor uw tekensleutel.


Antwoord 3

afhankelijk van het cryptografie-algoritme dat u gebruikt, moet u mogelijk wat opvulbytes aan het einde toevoegen voordat u een bytearray versleutelt, zodat de lengte van de bytearray een veelvoud is van de blokgrootte:

Specifiek in uw geval is het opvulschema dat u hebt gekozen PKCS5, dat hier wordt beschreven:
http://www.rsa.com/products/bsafe /documentation/cryptoj35html/doc/dev_guide/group_CJ_SYM__PAD.html

(Ik neem aan dat je het probleem hebt wanneer je probeert te versleutelen)

U kunt uw opvullingsschema kiezen wanneer u het Cipher-object instantieert. Ondersteunde waarden zijn afhankelijk van de beveiligingsprovider die u gebruikt.

Trouwens, weet u zeker dat u een symmetrisch versleutelingsmechanisme wilt gebruiken om wachtwoorden te versleutelen? Zou een one-way hasj niet beter zijn? Als je echt wachtwoorden moet kunnen ontsleutelen, is DES een vrij zwakke oplossing. Misschien ben je geïnteresseerd in iets sterkers zoals AES als je bij een symmetrisch algoritme wilt blijven.


Antwoord 4

Ik heb dit probleem ondervonden vanwege het besturingssysteem, een eenvoudig tot een ander platform over JRE-implementatie.

new SecureRandom(key.getBytes())

krijgt dezelfde waarde in Windows, terwijl het in Linux anders is. Dus in Linux moet worden gewijzigd in

SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
secureRandom.setSeed(key.getBytes());
kgen.init(128, secureRandom);

“SHA1PRNG” is het gebruikte algoritme, u kunt verwijzen naar hiervoor meer info over algoritmen.

Other episodes