Шифрование и дешифрование с использованием ошибки Blowfish. Длина входных данных должна быть кратна 8 при дешифровании с помощью дополненного шифра.

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

Ошибка

HTTP Status 500 - Request processing failed; nested exception is javax.crypto.IllegalBlockSizeException: Input length must be multiple of 8 when decrypting with padded cipher

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is javax.crypto.IllegalBlockSizeException: Input length must be multiple of 8 when decrypting with padded cipher
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:894)
    org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:778)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:728)

Вот мой код шифрования и дешифрования

//secret key 8 
    private static String strkey ="Blowfish";

ОБНОВЛЕНО

 //encrypt using blowfish algorithm
    public static byte[] encrypt(String Data)throws Exception{

        SecretKeySpec key = new SecretKeySpec(strkey.getBytes("UTF8"), "Blowfish");
         Cipher cipher = Cipher.getInstance("Blowfish");
         cipher.init(Cipher.ENCRYPT_MODE, key);

         return (cipher.doFinal(Data.getBytes("UTF8")));

    }

    //decrypt using blow fish algorithm
    public static String decrypt(byte[] encryptedData)throws Exception{
         SecretKeySpec key = new SecretKeySpec(strkey.getBytes("UTF8"), "Blowfish");
         Cipher cipher = Cipher.getInstance("Blowfish");
         cipher.init(Cipher.DECRYPT_MODE, key);
         byte[] decrypted = cipher.doFinal(encryptedData);
         return new String(decrypted); 

    }

person devdar    schedule 28.04.2013    source источник


Ответы (3)


Если вы запустите свои методы шифрования и дешифрования в основном методе, это сработает. Но если результаты шифрования помещаются в URL-адрес, а затем параметр URL-адреса расшифровывается, произойдет сбой.

После шифрования массив байтов содержит значения, выходящие за пределы набора символов URL-адресов (не-ascii), поэтому это значение кодируется, когда оно вставляется в URL-адрес. И вы получаете поврежденную версию для расшифровки.

Например, когда я создал строку из зашифрованного массива байтов, она выглядела так Ž ¹Qêz¦, но если я вставил ее в URL-адрес, она превратилась в Ž%0B¹Qêz¦.

Исправление, предложенное в других комментариях, заключается в добавлении шага кодирования/декодирования. После шифрования значение должно быть закодировано в формате, который содержит символы ascii. База 64 - отличный выбор. Таким образом, вы возвращаете зашифрованное и закодированное значение в URL-адресе. Когда вы получите параметр, сначала декодируйте, а затем расшифруйте, и вы получите исходные данные.

Вот несколько замечаний по реализации.

  1. Используйте библиотеку, например кодек Commons. Это мое любимое оружие, конкретно этот класс http://commons.apache.org/proper/commons-codec/apidocs/org/apache/commons/codec/binary/Base64.html.

  2. В классе, который выполняет шифрование и дешифрование, есть общий экземпляр Base64. Чтобы создать его, используйте new Base64(true);, это создает безопасные строки URL.

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

  4. Таким образом, последняя строка вашего шифрования станет чем-то вроде return base64.encodeToString(cipher.doFinal(Data.getBytes("UTF8"))); Теперь вы можете безопасно передать зашифрованное значение в URL-адресе.

  5. В вашем дешифровании ваш первый шаг - декодирование. Таким образом, первая строка станет чем-то вроде byte[] encryptedData = base64.decodeBase64(encrypted);

Я просто взял ваш код и добавил кое-что из базы 64, результат выглядит так:

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

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


public class Test {

    private static String strkey ="Blowfish";
    private static Base64 base64 = new Base64(true);

     //encrypt using blowfish algorithm
    public static String encrypt(String Data)throws Exception{

        SecretKeySpec key = new SecretKeySpec(strkey.getBytes("UTF8"), "Blowfish");
         Cipher cipher = Cipher.getInstance("Blowfish");
         cipher.init(Cipher.ENCRYPT_MODE, key);

         return base64.encodeToString(cipher.doFinal(Data.getBytes("UTF8")));

    }

    //decrypt using blow fish algorithm
    public static String decrypt(String encrypted)throws Exception{
        byte[] encryptedData = base64.decodeBase64(encrypted);
         SecretKeySpec key = new SecretKeySpec(strkey.getBytes("UTF8"), "Blowfish");
         Cipher cipher = Cipher.getInstance("Blowfish");
         cipher.init(Cipher.DECRYPT_MODE, key);
         byte[] decrypted = cipher.doFinal(encryptedData);
         return new String(decrypted); 

    }

    public static void main(String[] args) throws Exception {
        String data = "will this work?";
        String encoded = encrypt(data);
        System.out.println(encoded);
        String decoded = decrypt(encoded);
        System.out.println(decoded);
    }
}

Надеюсь, это ответит на ваши вопросы.

person Akshay    schedule 29.04.2013
comment
Я получаю следующую ошибку в классе. Конструктор Base64 (логический) не определен для частного статического Base64 base64 = new Base64 (true); - person devdar; 30.04.2013
comment
Можете ли вы дать мне несколько советов по этому вопросу title="весеннее сопоставление URL-адресов mvc в контроллере для динамических URL-адресов"> stackoverflow.com/questions/16290808/ - person devdar; 30.04.2013
comment
Не могли бы вы также взглянуть на этот вопрос для меня, пожалуйста, stackoverflow.com/questions/16305926/ - person devdar; 01.05.2013
comment
@devdar Base64 находится в пакете org.apache.tomcat.util.codec.binary.Base64. - person null; 05.02.2015

Вы не можете создать строку из случайных (в данном случае зашифрованных) байтов, как вы делаете в последней строке вашего метода шифрования — вам нужно создать строка в кодировке Base64 (которую затем необходимо декодировать обратно в массив байтов в метод расшифровки). В качестве альтернативы просто сделайте так, чтобы ваш метод шифрования возвращал массив байтов, а метод расшифровки принимал массив байтов в качестве параметра.

person Zim-Zam O'Pootertoot    schedule 28.04.2013
comment
Я не уверен, что полностью понимаю, что мне следует удалить cipher.doFinal и просто выполнить Data.getBytes(UTF8)? - person devdar; 28.04.2013
comment
Удалите часть new String, сохраните часть return cipher.doFinal(Data.getBytes("UTF8")); измените encrypt так, чтобы он возвращал byte[] вместо String, и измените decrypt так, чтобы он принимал byte[] encryptedData - person Zim-Zam O'Pootertoot; 28.04.2013
comment
Попробуйте протестировать два метода из метода main или метода test, чтобы изолировать их от остальной части вашей программы — я подозреваю, что у вас есть другой метод, который повреждает массив байтов. - person Zim-Zam O'Pootertoot; 28.04.2013

Проблема заключается в том, как вы создаете String экземпляры из необработанных зашифрованных byte[] данных. Вам нужно либо использовать кодировку binhex, подобную предоставленной javax.xml.bind.DatatypeConverter с помощью методов parseHexBinary и printHexBinary или с основанием 64 с использованием методов parseBase64Binary и printBase64Binary одного и того же объекта.

Еще один совет: никогда не полагайтесь на режим и заполнение по умолчанию, всегда будьте явными. Используйте что-то вроде Cipher.getInstance("Blowfish/CBC/PKCS5Padding") в зависимости от ваших потребностей.

person laz    schedule 28.04.2013