Подтвердить что ты не робот

Javax.crypto.IllegalBlockSizeException: длина ввода должна быть кратной 16 при расшифровке с дополненным шифрованием

Я получаю дешифрующую ошибку в классе java:

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

Что я могу сделать для решения этой проблемы?

UPDATE:

Я забыл упомянуть, что он работает один раз, и когда во второй раз я пытаюсь выполнить его снова, он бросает вышеупомянутую ошибку.

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

}
4b9b3361

Ответ 1

Алгоритм, который вы используете, "AES", является сокращением для "AES/ECB/NoPadding". Это означает, что вы используете алгоритм AES с 128-битным размером ключа и размером блока, с ECB режим работы и без прокладки.

Другими словами: вы можете только шифровать данные в блоках из 128 бит или 16 байтов. Вот почему вы получаете это исключение IllegalBlockSizeException.

Если вы хотите зашифровать данные в размерах, не кратных 16 байтам, вам придется либо использовать какое-то дополнение, либо поток шифрования. Например, вы можете использовать режим CBC (режим работы, который эффективно трансформирует блочный шифр в поток шифрования), указав "AES/CBC/NoPadding" в качестве алгоритма или дополнение PKCS5, указав "AES/ECB/PKCS5", который автоматически добавит некоторые байты в конце ваших данных в очень конкретном формате, чтобы сделать размер зашифрованный текст, кратный 16 байтам, и таким образом, что алгоритм дешифрования будет понимать, что он должен игнорировать некоторые данные.

В любом случае, я настоятельно рекомендую вам сейчас остановиться, что вы делаете, и изучите некоторые очень вводные материалы по криптографии. Например, проверьте Crypto я на Coursera. Вы должны очень хорошо понимать последствия выбора того или иного способа, каковы их сильные стороны и, самое главное, их слабости. Без этих знаний очень легко создавать системы, которые очень легко сломать.


Обновление: на основе ваших комментариев по вопросу, никогда не шифрует пароли при их хранении в базе данных!!!!! Вы никогда не должны этого делать. Вы должны HASH пароли, правильно соленые, которые полностью отличаются от шифрования. На самом деле, пожалуйста, не делайте то, что вы пытаетесь сделать... Шифруя пароли, они могут быть дешифрованы. Это означает, что вы, как менеджер баз данных и знающий секретный ключ, сможете читать каждый пароль, хранящийся в вашей базе данных. Либо вы знали это, и делали что-то очень-очень плохое, или вы не знали об этом, и должны были шокироваться и останавливать его.

Ответ 2

Несколько комментариев:

import sun.misc.*; Не делай этого. Он не является стандартным и не гарантируется одинаковым между реализациями. Существуют и другие библиотеки с возможностью преобразования Base64.

byte[] encVal = c.doFinal(Data.getBytes()); Здесь вы полагаетесь на кодировку символов по умолчанию. Всегда указывайте, какую кодировку символов вы используете: byte[] encVal = c.doFinal(Data.getBytes("UTF-8")); Значения по умолчанию могут быть разными в разных местах.

Как отметил @thegrinner, вам нужно явно проверить длину ваших байтовых массивов. Если есть расхождение, то сравните их байтом по байту, чтобы увидеть, где разница ползут.

Ответ 3

Чтобы решить проблему с небольшими изменениями, которые вы должны сделать в своем коде, просто введите тип возвращаемого типа encrypt() API вашего класса - массив byte [] и в decrypt() API вашего массива pass pass by [], чтобы сделать это вы можете разрешить длину ввода, кратное 16 исключению.

См. ниже рабочий код:

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

Ответ 4

Ну, это из-за

вы можете только шифровать данные в блоках из 128 бит или 16 байтов. Вот почему вы получаете исключение IllegalBlockSizeException. и один способ - зашифровать эти данные непосредственно в строку.

Посмотрите это. Попробуйте, и вы сможете решить эту проблему.

public static String decrypt(String encryptedData) throws Exception {

    Key key = generateKey();
    Cipher c = Cipher.getInstance(ALGO);
    c.init(Cipher.DECRYPT_MODE, key);
    String decordedValue = new BASE64Decoder().decodeBuffer(encryptedData).toString().trim();
    System.out.println("This is Data to be Decrypted" + decordedValue);
    return decordedValue;
}

надеюсь, что это поможет.