使用Blowfish错误加密和解密 - 使用填充密码解密时,输入长度必须是8的倍数

时间:2013-04-28 03:00:48

标签: java encryption blowfish

我能够加密数据但是在解密时我收到以下错误:

错误

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

    }

3 个答案:

答案 0 :(得分:4)

如果在main方法中运行加密和解密方法,它将起作用。但是如果将加密结果放入url然后解密url参数,它将失败。

加密后,字节数组包含URLS(非ascii)字符集之外的值,因此该值在填充到url中时会被编码。而你收到一个损坏的版本进行解密。

例如,当我从加密的字节数组创建一个字符串时,它看起来像Ž¹Qêz¦,但如果我将它放入一个URL,它就变成了Ž%0B¹Qêz¦

正如其他评论中所建议的那样,修复是添加编码/解码步骤。加密后,应将该值编码为包含ascii字符的格式。 Base 64是一个很好的选择。因此,您在网址中返回加密和编码的值。收到参数后,先解码然后解密,然后你就会得到原始数据。

以下是有关实施的一些注意事项。

  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")));您现在可以安全地将加密值传递到网址

  5. 在你的解密中,你的第一步是解码。所以第一行会变成byte[] encryptedData = base64.decodeBase64(encrypted);

  6. 我刚刚接受了你的代码,并添加了一些基础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);
        }
    }
    

    希望这能回答你的问题。

答案 1 :(得分:1)

您无法创建随机(在本例中为加密)字节的字符串,就像您在加密方法的最后一行中所做的那样 - 您需要创建一个Base64 encoded string代替(您需要)在解密方法中解码回字节数组)。或者,只需让你的encrypt方法返回一个字节数组,让你的decrypt方法接受一个字节数组作为参数。

答案 2 :(得分:1)

问题在于您从原始加密String数据中创建byte[]个实例的方式。您需要使用javax.xml.bind.DatatypeConverter通过parseHexBinaryprintHexBinary方法提供的binhex编码,或使用相同的parseBase64BinaryprintBase64Binary方法对象

另一个建议,永远不要依赖默认模式和填充,总是明确的。根据您的需求使用Cipher.getInstance("Blowfish/CBC/PKCS5Padding")之类的内容。