1

我能够加密数据,但是在解密数据时出现以下错误:

错误

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

    }
4

3 回答 3

5

如果您在主方法中运行加密和解密方法,它将起作用。但是如果将加密的结果放入一个url,然后再解密url参数,就会失败。

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

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

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

以下是有关实施的一些说明。

  1. 使用公共编解码器之类的库。这是我选择的武器,这个类特别是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);

我只是拿了你的代码并添加了一些 base 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);
    }
}

希望这能回答你的问题。

于 2013-04-29T13:29:12.203 回答
2

您不能像在加密方法的最后一行中那样从随机(在这种情况下为加密)字节创建字符串 - 您需要创建一个Base64 编码的字符串(然后您需要将其解码回解密方法中的字节数组)。或者,只需让您的加密方法返回一个字节数组,并让您的解密方法接受一个字节数组作为其参数。

于 2013-04-28T03:12:28.607 回答
1

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

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

于 2013-04-28T03:14:55.037 回答