Исключение в алгоритме расшифровки AES в Java - PullRequest
5 голосов
/ 05 июля 2010

Я получил исключение в следующем коде для алгоритма 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*..) 

Ответы [ 3 ]

14 голосов
/ 05 июля 2010

Согласно Справочному руководству по архитектуре криптографии Java ™ (JCA) (выделено):

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

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

  • " алгоритм / режим / заполнение " или
  • " алгоритм "

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

  • "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.

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

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

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

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");
    }
}
0 голосов
/ 05 июля 2010

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

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

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

0 голосов
/ 05 июля 2010

Хорошо, если это ошибка. Длина ввода должна быть кратна 16 при расшифровке с использованием шифра с добавлением.Если ответ очевиден, длина вашего буфера должна быть кратна 16. Вы проверили длину буфера []?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...