使用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); } 

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

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

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

其他注释中建议的修复是添加编码/解码步骤。 加密后,应将该值编码为包含ascii字符的格式。 Base 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);

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

希望这能回答你的问题。

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

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

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