Исключение недопустимого размера блока Длина входных данных должна быть кратна 16 при дешифровании с помощью дополненного шифра.

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

Исключение:

Illegal Block Size Exception Input length must be multiple of 16 when decrypting with padded cipher.

Ниже мой код:

Функция для шифрования значения

public static String symmetricEncrypt(String text, String secretKey) {
    BASE64Decoder decoder = new BASE64Decoder();
    byte[] raw;
    String encryptedString;
    SecretKeySpec skeySpec;
    BASE64Encoder bASE64Encoder = new BASE64Encoder();
    byte[] encryptText = text.getBytes();
    Cipher cipher;
    try {
        raw = decoder.decodeBuffer(secretKey);
        skeySpec = new SecretKeySpec(raw, "AES");
        cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
        encryptedString = bASE64Encoder.encode(cipher.doFinal(encryptText));
    } 
    catch (Exception e) {
        e.printStackTrace();
        return "Error";
    }
    return encryptedString;
}

Функция для расшифровки значения

public static String symmetricDecrypt(String text, String secretKey) {
    BASE64Decoder decoder = new BASE64Decoder();
    BASE64Decoder base64Decoder = new BASE64Decoder();
    Cipher cipher;
    String encryptedString;
    byte[] encryptText = null;
    byte[] raw;
    SecretKeySpec skeySpec;
    try {
        raw = decoder.decodeBuffer(secretKey);
        skeySpec = new SecretKeySpec(raw, "AES");
        encryptText = base64Decoder.decodeBuffer(text);
        cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.DECRYPT_MODE, skeySpec);
        encryptedString = new String(cipher.doFinal(encryptText));
    } catch (Exception e) {
        e.printStackTrace();
        return "Error";
    }
    return encryptedString;
}

Ниже приведены значения, которые я шифрую и расшифровываю.

String secretKey = "XMzDdG4D03CKm2IxIWQw7g==";
String value1= "ABCD";
String enctypedValue1= "3uweh4pzoVyH1uODQmVNJA==";
String enctypedValue2= "37PTC20w4DMZYjG3f+GWepSvAbEJUccMXwS/lXilLav1qM/PrCTdontw5/82OdC1zzyhDEsFVRGo rV6gXAQcm+Zai15hliiUQ8l8KRMtUl4=";
String value4= "20000";

/**  Ecnryption and decryption of value1 **/
String encryptedValue1= symmetricEncrypt(value1, secretKey);
String decryptedValue1 = symmetricDecrypt(encryptedValue1, secretKey);

/**  Decryption of  enctypedValue1 **/
String decryptedValue2 = symmetricDecrypt(enctypedValue1, secretKey);
System.out.println(decryptedValue2);

/**  Decryption of  enctypedValue2 (Not decrypted)**/
String decryptedValue3 = symmetricDecrypt(enctypedValue2, secretKey);
System.out.println(decryptedValue3);

/**  Ecnryption and decryption of value4 **/
String encryptedValue4= symmetricEncrypt(value4, secretKey);
String decryptedValue4 = symmetricDecrypt(encryptedValue4, secretKey);

В тестовой функции я написал следующие три тестовых примера.

  1. Новое значение (value1) шифруется и расшифровывается с помощью секретного ключа.
  2. Два примера зашифрованных значений (enctypedValue1, enctypedValue2), которые расшифровываются с использованием одного и того же секретного ключа. зашифрованное значение2, у которого возникла проблема при расшифровке с использованием того же секретного ключа.
  3. Новое значение (value4) шифруется и расшифровывается с помощью секретного ключа.

При расшифровке зашифрованного значения2 я получаю следующее исключение:

Illegal Block Size Exception Input length must be multiple of 16 when decrypting with padded cipher

Ниже приводится то, что я получил до сих пор.

  1. Проблемное значение, кажется, имеет проблему при его декодировании, оно возвращает массив длины 81, который не может быть расшифрован?

  2. Если бы эта проблема возникла, она должна была случиться со всеми значениями.

  3. Является ли это проблемой, связанной со значением, или это что-то, связанное с заполнением, или оно может иметь различное поведение в разных браузерах, разных ОС?


person JankiPanwala    schedule 10.07.2013    source источник
comment
в вашем методе расшифровки вы использовали cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); Однако в вашем методе шифрования вы использовали cipher = Cipher.getInstance("AES");. Они должны быть одинаковыми. Добавьте дополнение к шифру в методе шифрования.   -  person Multithreader    schedule 10.07.2013
comment
Эта ссылка может быть полезной: stackoverflow.com/questions/7640463/   -  person Suresh Atta    schedule 10.07.2013
comment
@Multithreader спасибо за исправление. На самом деле ошибка в написании. Пожалуйста, смотрите отредактированный вопрос.   -  person RAS    schedule 10.07.2013
comment
@Multithreader требуется ли добавлять дополнение в SecretKeySpec или при создании секретного ключа?   -  person JankiPanwala    schedule 10.07.2013
comment
Само по себе это не требуется. Однако в реальном мире алгоритмы блочного шифрования не используются непосредственно для передачи данных. Они используются в нескольких режимах, таких как режим CBC, который используется в SSL. Вот хорошая статья о дополнении: en.wikipedia.org/wiki/Padding_%28cryptography% 29 Также я настоятельно рекомендую прочитать об алгоритмах блочного шифрования (AES — это алгоритм блочного шифрования): en.wikipedia.org/wiki/Block_cipher   -  person Multithreader    schedule 11.07.2013


Ответы (1)


Я смог запустить код без каких-либо проблем. Однако я использовал Apache Base64 для кодирования/декодирования... возможно, в вашем Base64 есть ошибки. Если вы написали его сами, есть большая вероятность, что вы пропустили некоторые случаи. Для реального производственного кода используйте тщательно протестированные библиотеки, такие как Apache.

Вы можете найти библиотеку, которую я использовал для Base64, здесь: http://commons.apache.org/proper/commons-codec/download_codec.cgi

Вот полный рабочий код:

    package security.symmatric;

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

    import org.apache.commons.codec.binary.Base64;

    public class AES {
        public static String symmetricEncrypt(String text, String secretKey) {
            byte[] raw;
            String encryptedString;
            SecretKeySpec skeySpec;
            byte[] encryptText = text.getBytes();
            Cipher cipher;
            try {
                raw = Base64.decodeBase64(secretKey);
                skeySpec = new SecretKeySpec(raw, "AES");
                cipher = Cipher.getInstance("AES");
                cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
                encryptedString = Base64.encodeBase64String(cipher.doFinal(encryptText));
            } 
            catch (Exception e) {
                e.printStackTrace();
                return "Error";
            }
            return encryptedString;
        }

        public static String symmetricDecrypt(String text, String secretKey) {
            Cipher cipher;
            String encryptedString;
            byte[] encryptText = null;
            byte[] raw;
            SecretKeySpec skeySpec;
            try {
                raw = Base64.decodeBase64(secretKey);
                skeySpec = new SecretKeySpec(raw, "AES");
                encryptText = Base64.decodeBase64(text);
                cipher = Cipher.getInstance("AES");
                cipher.init(Cipher.DECRYPT_MODE, skeySpec);
                encryptedString = new String(cipher.doFinal(encryptText));
            } catch (Exception e) {
                e.printStackTrace();
                return "Error";
            }
            return encryptedString;
        }

        public static void main(String[] args) {
            String secretKey = "XMzDdG4D03CKm2IxIWQw7g==";
            String value1= "ABCD";
            String enctypedValue1= "3uweh4pzoVyH1uODQmVNJA==";
            String enctypedValue2= "37PTC20w4DMZYjG3f+GWepSvAbEJUccMXwS/lXilLav1qM/PrCTdontw5/82OdC1zzyhDEsFVRGo rV6gXAQcm+Zai15hliiUQ8l8KRMtUl4=";
            String value4= "20000";

            /**  Ecnryption and decryption of value1 **/
            String encryptedValue1= symmetricEncrypt(value1, secretKey);
            String decryptedValue1 = symmetricDecrypt(encryptedValue1, secretKey);
            System.out.println(decryptedValue1);

            /**  Decryption of  enctypedValue1 **/
            String decryptedValue2 = symmetricDecrypt(enctypedValue1, secretKey);
            System.out.println(decryptedValue2);

            /**  Decryption of  enctypedValue2 **/
            String decryptedValue3 = symmetricDecrypt(enctypedValue2, secretKey);
            System.out.println(decryptedValue3);

            /**  Ecnryption and decryption of value4 **/
            String encryptedValue4= symmetricEncrypt(value4, secretKey);
            String decryptedValue4 = symmetricDecrypt(encryptedValue4, secretKey);
            System.out.println(decryptedValue4);
        }
    }
person Multithreader    schedule 11.07.2013
comment
Спасибо. Это сработало. Я использую Sun Base64. Я хотел спросить, в чем разница между Base64 Apache и Base64 Sun? Должен ли я заменить его на Apache Base64 в моей программе? - person JankiPanwala; 11.07.2013
comment
Да, я настоятельно рекомендую использовать Apache. Старайтесь любой ценой избегать использования библиотек Sun. Почему? потому что их библиотеки созданы для внутреннего использования только в Sun (не представлены как общедоступный API). Таким образом, они могут изменить API, нарушить обратную совместимость и прекратить поддержку API в любой момент и без предварительного уведомления. По крайней мере, это то, что я понимаю... - person Multithreader; 11.07.2013
comment
Этот код отлично работает из основного метода, но не когда я писал внутри класса апплета. Предоставление целевого исключения вызова. Любая помощь? - person Suresh Atta; 12.07.2013
comment
Как вы генерируете секретный ключ? - person jantox; 23.12.2013