Учитывая, что последний блок не заполнен неправильно

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

javax.crypto.BadPaddingException: данный конечный блок неправильно заполнен

Что может быть проблемой? (Я новичок в Java.)

Вот мой код:

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

(Тест 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. } } } 

Если вы попытаетесь расшифровать данные с запасом PKCS5 с неправильным ключом, а затем распакуйте его (что автоматически выполняется classом Cipher), вы, скорее всего, получите исключение BadPaddingException (возможно, чуть меньше 255/256, около 99,61% ), потому что прокладка имеет специальную структуру, которая проверяется во время unpad, и очень немногие ключи выдают допустимое дополнение.

Итак, если вы получите это исключение, поймите его и рассмотрите как «неправильный ключ».

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

Конечно, плохое дополнение также может произойти, если ваши данные повреждены при protractorовке.

Тем не менее, есть некоторые замечания по поводу вашей схемы:

  • Для шифрования на основе пароля вы должны использовать SecretKeyFactory и PBEKeySpec вместо использования SecureRandom с KeyGenerator. Причина в том, что SecureRandom может быть другим алгоритмом для каждой реализации Java, предоставляя вам другой ключ. SecretKeyFactory выполняет ключевой вывод определенным образом (и способ, который считается безопасным, если вы выберете правильный алгоритм).

  • Не используйте ECB-режим. Он шифрует каждый блок независимо, что означает, что одинаковые текстовые блоки также дают всегда одинаковые блоки зашифрованного текста.

    Предпочтительно использовать безопасный режим работы , например CBC (цепочка блоков шифрования) или CTR (счетчик). В качестве альтернативы используйте режим, который также включает аутентификацию, такую ​​как GCM (режим Galois-Counter) или CCM (счетчик с CBC-MAC), см. Следующую точку.

  • Обычно вам не нужна только конфиденциальность, но также и аутентификация, которая гарантирует, что сообщение не подделано. (Это также предотвращает атаки с выбранным шифротекстом на ваш шифр, то есть помогает обеспечить конфиденциальность.) Таким образом, добавьте в сообщение сообщение MAC (код аутентификации сообщения) или используйте режим шифрования, который включает проверку подлинности (см. Предыдущий пункт).

  • DES имеет эффективный размер ключа всего 56 бит. Это ключевое пространство довольно мало, оно может быть принудительно в течение нескольких часов выделенным атакующим. Если вы сгенерируете свой ключ с помощью пароля, это будет еще быстрее. Кроме того, DES имеет размер блока всего 64 бит, что добавляет еще некоторые недостатки в режимах цепочки. Вместо этого используйте современный алгоритм, такой как AES, размер блока 128 бит и размер ключа 128 бит (для стандартного варианта).

в зависимости от алгоритма шифрования, который вы используете, вам, возможно, придется добавить некоторые байты заполнения в конце перед шифрованием байтового массива, чтобы длина массива байтов была кратной размеру блока:

В частности, в вашем случае выбранная схема заполнения – это PKCS5, которая описана здесь: http://www.rsa.com/products/bsafe/documentation/cryptoj35html/doc/dev_guide/group_ CJ _SYM__PAD.html

(Я предполагаю, что у вас есть проблема, когда вы пытаетесь зашифровать)

Вы можете выбрать схему заполнения, когда вы создаете экземпляр объекта Cipher. Поддерживаемые значения зависят от поставщика безопасности, который вы используете.

Кстати, вы уверены, что хотите использовать симметричный механизм шифрования для шифрования паролей? Разве не было бы лучшего варианта hashа? Если вам действительно нужно расшифровывать пароли, DES – довольно слабое решение, вам может быть интересно использовать что-то более сильное, как AES, если вам нужно остановиться с симметричным алгоритмом.

  • Использование SHA1 и RSA с java.security.Signature против MessageDigest и Cipher
  • Как я должен придерживаться этического подхода к хранилищу паролей пользователей для последующего поиска в открытом виде?
  • Как узнать модуль и показатель открытого ключа RSA на iPhone / objective C
  • Какая лучшая библиотека шифрования в C / C ++?
  • Как hash-строку с sha256 в Java?
  • В чем разница между шифрованием и подписью в асимметричном шифровании?
  • Как создать уникальный открытый и закрытый ключ через RSA
  • Хранение зашифрованных данных в Postgres
  • Какова цель кодирования базы 64 и почему она используется в базовой аутентификации HTTP?
  • javax.crypto.BadPaddingException
  • Пароль к ключевой функции, совместимой с командами OpenSSL?
  • Давайте будем гением компьютера.