Исключение в алгоритме дешифрования AES в Java

Я получил исключение в следующем коде для алгоритма AES в Java.

Код дешифрует зашифрованную строку и возвращает исходную строку.

Помогите мне зафиксировать это.

Код:

public class AES 

{

public byte[] encrypted;

 public byte[] original;

 public String originalString;

public static String asHex (byte buf[]) 

{ 

StringBuffer strbuf = new StringBuffer(buf.length * 2);

 int i; for (i = 0; i < buf.length; i++) 

{

 if (((int) buf[i] & 0xff) < 0x10) strbuf.append("0"); 

strbuf.append(Long.toString((int) buf[i] & 0xff, 16)); 

}

 return strbuf.toString();

 }

 public String AESencryptalgo(byte[] text)

 { 

String newtext=""; 

// Get the KeyGenerator

 try

 {

    KeyGenerator kgen = KeyGenerator.getInstance("AES");

    kgen.init(128); // 192 and 256 bits may not be available

 // Generate the secret key specs. 

SecretKey skey = kgen.generateKey();

 byte[] raw = skey.getEncoded();

 SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");

 // Instantiate the cipher Cipher cipher = Cipher.getInstance("AES"); 

cipher.init(Cipher.ENCRYPT_MODE, skeySpec); encrypted = cipher.doFinal(text); 

System.out.println("encrypted string: " + asHex(encrypted)); 

cipher.init(Cipher.DECRYPT_MODE, skeySpec); original = cipher.doFinal(encrypted); 

originalString = new String(original); System.out.println("Original string: " + originalString + " " + asHex(original));

 } 

catch(Exception e)

 { } 

finally 

{

 newtext=new String(encrypted);

 System.out.println("ENCRYPTED "+newtext);

//AESdecryptalgo(newtext.getBytes()); 

return newtext;

 }

 } 

public String AESdecryptalgo(byte[] text)

 { 

// Get the KeyGenerator

 try

 {

 KeyGenerator kgen = KeyGenerator.getInstance("AES");

 kgen.init(128); // 192 and 256 bits may not be available 

// Generate the secret key specs. 

SecretKey skey = kgen.generateKey();

 byte[] raw = skey.getEncoded(); 

SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); 

// Instantiate the cipher

 Cipher cipher = Cipher.getInstance("AES"); 

cipher.init(Cipher.DECRYPT_MODE, skeySpec);

 original = cipher.doFinal(text); //Exception occurs here

 originalString = new String(original);

 System.out.println("Original string: " + originalString + " " + asHex(original)); 

}

 catch(Exception e)

 {

 System.out.println("exception"); 

}

 finally

{ 

System.out.println("DECRYPTED "+originalString);

 return originalString;

 } 

} 

public static void main(String[] args)

{

AES a=new AES();

a.AESencryptalgo("hello".getBytes());

System.out.println(); 

}} 
`

исключение:

javax.crypto.BadPaddingException: Given final block not properly padded at  
com.sun.crypto.provider.SunJCE_f.b(DashoA13*..) at
com.sun.crypto.provider.SunJCE_f.b(DashoA13*..) at
com.sun.crypto.provider.AESCipher.engineDoFinal(DashoA13*..) at
javax.crypto.Cipher.doFinal(DashoA13*..) 
5
задан James Reinstate Monica Polk 5 July 2010 в 18:28
поделиться

3 ответа

Ну, если это ошибка, то длина ввода должна быть кратна 16 при расшифровке с использованием шифра с набивкой. Тогда ответ очевиден, длина вашего буфера должна быть кратна 16. Проверяли ли вы длину buf[]?

0
ответ дан 18 December 2019 в 13:10
поделиться

Согласно Java™ Cryptography Architecture (JCA) Reference Guide (выделение мое):

Объекты Cipher получаются при использовании одного из Cipher getInstance() статических фабричных методов. Здесь алгоритм имя немного отличается от других классов движков, в том смысле, что задается не просто имя алгоритма, но и "преобразование". A преобразование - это строка, которая описывает операцию (или набор операций), которая должна быть выполнена на заданным входом для получения некоторого выхода. A преобразование всегда включает имя криптографического алгоритма (например, DES), за ним может следовать режим и схема набивки.

Преобразование имеет вид:

  • "algorithm/mode/padding" или
  • "algorithm"

Например, следующие преобразования являются допустимыми:

  • "DES/CBC/PKCS5Padding"
  • "DES"

Если указано только имя преобразования, то система будет определит, существует ли реализация запрашиваемого преобразования, доступная в среде, и если их несколько одна, возвращает предпочтительную.

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

Если режим или прокладка не указаны, используются специфические для поставщика значения по умолчанию для используются значения по умолчанию для режима и схемы прокладки. Например, провайдер SunJCE использует. ECB в качестве режима по умолчанию, и PKCS5Padding в качестве схемы набивки по умолчанию. для DES, DES-EDE и Blowfish. шифры. Это означает, что в случае провайдера SunJCE:

Cipher c1 = Cipher.getInstance("DES/ECB/PKCS5Padding");

и

Cipher c1 = Cipher.getInstance("DES");

являются эквивалентными утверждениями.

Использование режимов таких как CFB и OFB, блочные шифры могут шифровать данные в единицах, меньших, чем фактический размер блока шифра. Когда запросе такого режима, вы можете опционально указать количество битов обрабатываемых за один раз, добавив это число к имени режима, как показано в "DES/CFB8/NoPadding" и "DES/OFB32/PKCS5Padding" преобразования. Если такой номер не указан не указано, используется значение по умолчанию, заданное провайдером используется. (Например, SunJCE поставщик использует значение по умолчанию 64 бита для DES.) Таким образом, блочные шифры могут быть превратить в байт-ориентированные потоковые шифры, используя 8-битный режим, такой как CFB8 или OFB8.

Приложение А этого документа содержит список стандартных имен, которые могут быть использовать для указания имени алгоритма, режим и компоненты схемы набивки преобразования.

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

Поскольку в вашем коде не указан режим или padding, используются специфические для провайдера значения по умолчанию. Похоже, что ваш провайдер - SunJCE, а его padding по умолчанию, вероятно, "NoPadding". С помощью этой прокладки вы отвечаете за то, чтобы размер зашифрованного массива байтов был кратен количеству байтов в секретном ключе. Вы можете облегчить себе жизнь, указав режим и padding в своем преобразовании:

Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");

ВНИМАНИЕ: Вы не должны использовать режим ECB в реальном коде. Попробуйте вместо него CBC.

Обновление: Мне показалось нечестным рекомендовать режим CBC, не предложив небольшой пример того, как он работает:

public static void main(String... args) throws Exception {
    byte[] data = "hello".getBytes();

    KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
    keyGenerator.init(128); // 192 and 256 bits may not be available

    SecretKey secretKey = keyGenerator.generateKey();

    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

    // By initializing the cipher in CBC mode, an "initialization vector" has been randomly
    // generated. This initialization vector will be necessary to decrypt the encrypted data.
    // It is safe to store the initialization vector in plain text for later use. You can obtain
    // it's bytes by calling iv.getIV().
    cipher.init(Cipher.ENCRYPT_MODE, secretKey);
    IvParameterSpec iv = cipher.getParameters().getParameterSpec(IvParameterSpec.class);
    byte[] encryptedData = cipher.doFinal(data);

    // When decrypting the encrypted data, you must provide the initialization vector used
    // during the encryption phase.
    cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
    byte[] decryptedData = cipher.doFinal(encryptedData);

    if (!Arrays.equals(data, decryptedData)) {
        throw new Exception("Data was not decrypted successfully");
    }
}
14
ответ дан 18 December 2019 в 13:10
поделиться

Ваш код умудряется почти во всем ошибаться. Для начала, ваши ошибки включают:

  1. генерацию нового случайного симметричного ключа перед шифрованием и дешифрованием. Для расшифровки нужно использовать тот же ключ, который использовался для шифрования.
  2. использование String в качестве контейнера для двоичных данных. Вывод шифра не может быть надежно превращен в String, если вы не используете кодировку, например base64.
  3. Ваша обработка исключений некорректна.

Более того, ваш код работает без исключений для меня.

0
ответ дан 18 December 2019 в 13:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: