javax.crypto.BadPaddingException при использовании cipherInputStream - PullRequest
0 голосов
/ 12 мая 2018

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

String keyString = Base64.getEncoder().encodeToString(symmetricKey.getEncoded());

, чтобы сохранить его в файле конфигурации (чтобы я мог получить ключ в функции расшифровки).

Теперь в функции расшифровки мне нужно вернуть эту строку обратно в формат ключа, чтобы я мог отправить ее в качестве параметра на шифр в режиме dercypt.Я конвертирую его обратно в ключ следующим образом:

byte[] keyBytes = key.getBytes(Charset.forName("UTF-8"));
Key newkey = new SecretKeySpec(keyBytes,0,keyBytes.length, "AES"); 

И передаю его в шифр и записываю вывод (расшифрованные данные), используя CipherInputStream:

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, newkey, newiv, SecureRandom.getInstance("SHA1PRNG"));
        CipherInputStream cipherInputStream = new CipherInputStream(
                new ByteArrayInputStream(encryptedBytes), cipher);


        ArrayList<Byte> decryptedVal = new ArrayList<>();
        int nextByte;
        while ((nextByte = cipherInputStream.read()) != -1) {
            decryptedVal.add((byte) nextByte);
        }

        byte[] bytes = new byte[decryptedVal.size()];
        for (int i = 0; i < bytes.length; i++) {
            bytes[i] = decryptedVal.get(i);
        }
        String decryptedData = new String(bytes);
        cipherInputStream.close();
        System.out.println("decryptedData: " + decryptedData);

Я получаюэта ошибка:

Исключение в потоке "main" java.io.IOException: javax.crypto.BadPaddingException: данный последний блок заполнен неправильно.Такие проблемы могут возникнуть, если во время расшифровки используется плохой ключ.

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

Есть предложения?была бы признательна за помощь!

Ответы [ 2 ]

0 голосов
/ 12 мая 2018

Конечно, вы получаете эту ошибку: сначала вы применяете кодировку base 64:

String keyString = Base64.getEncoder().encodeToString(symmetricKey.getEncoded());

, а затем используете кодировку символов, чтобы превратить ее в байты:

byte[] keyBytes = key.getBytes(Charset.forName("UTF-8"));

, чтопросто придерживайтесь кодировки base64, возможно, увеличив размер ключа с 16 до 24 байтов, что соответствует 192-битному ключу вместо 128-битного ключа.Или 24-байтовый ключ к 32-байтовому ключу, конечно - оба, кажется, работают.

Для решения этой проблемы вам нужно использовать Base64.getDecoder() и декодировать ключ.

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


Напоминание:

  • , например, основание64 или hex: кодирование байтов в текстовую строку
  • , например, UTF-8 или ASCII: кодирование текстовой строки в байты

Онине противоположности, это будет декодирование и декодирование символов соответственно.


Примечания:

  • да, слушайте Ashfin ;вам нужно использовать случайный IV во время шифрования, а затем использовать его во время дешифрования, например, с префиксом к зашифрованному тексту (незашифрованный);
  • не используйте ArrayList<Byte>;который хранит ссылку на каждый отдельный байт (!) - используйте ByteArrayOutputStream или любой другой OutputStream вместо
  • , вы можете лучше использовать байтовый буфер и использовать его для чтения / записи в потоки (обратите внимание, чтофункция чтения может не заполнять буфер, даже если он находится в начале или в середине потока) - чтение одного байта за раз не является производительным;
  • lookup try-with-resources для Java;
  • с использованием KeyStore может быть лучше, чем сохранение в файле конфигурации;
  • Режим GCM (AES / GCM / NoPadding) также аутентифицирует данные и должен быть предпочтительнее, чем CBCрежим.
0 голосов
/ 12 мая 2018

Я думаю, вы не отправили IV в функцию дешифрования.Для дешифрования в режиме CBC необходимо указать IV, который используется в процессе шифрования.

Обновление :

IV повлияет только на первый блокв режиме CBC расшифровки.Так что мой ответ может повлиять на распаковку, если ваши данные меньше 1 блока.В противном случае он просто изменит дешифрованный открытый текст первого блока.

...