使用AES和Base64编码进行加密和解密

我有以下加密数据的程序。

import java.security.Key; import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.binary.Base64; public class Test { private static final String ALGORITHM = "AES"; private static final byte[] keyValue = "ADBSJHJS12547896".getBytes(); public static void main(String args[]) throws Exception { String encriptValue = encrypt("dude5"); decrypt(encriptValue); } /** * @param args * @throws Exception */ public static String encrypt(String valueToEnc) throws Exception { Key key = generateKey(); Cipher c = Cipher.getInstance(ALGORITHM); c.init(Cipher.ENCRYPT_MODE, key); System.out.println("valueToEnc.getBytes().length "+valueToEnc.getBytes().length); byte[] encValue = c.doFinal(valueToEnc.getBytes()); System.out.println("encValue length" + encValue.length); byte[] encryptedByteValue = new Base64().encode(encValue); String encryptedValue = encryptedByteValue.toString(); System.out.println("encryptedValue " + encryptedValue); return encryptedValue; } public static String decrypt(String encryptedValue) throws Exception { Key key = generateKey(); Cipher c = Cipher.getInstance(ALGORITHM); c.init(Cipher.DECRYPT_MODE, key); byte[] enctVal = c.doFinal(encryptedValue.getBytes()); System.out.println("enctVal length " + enctVal.length); byte[] decordedValue = new Base64().decode(enctVal); return decordedValue.toString(); } private static Key generateKey() throws Exception { Key key = new SecretKeySpec(keyValue, ALGORITHM); return key; } } 

在这里,我得到以下输出exception?

 valueToEnc.getBytes().length 5 encValue length16 encryptedValue [B@aa9835 Exception in thread "main" javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..) at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..) 

有人能解释我的原因吗? 解密该长度时,为什么它只能说是16.它不会像使用doFinal方法加密那样转换为16。

并且例外情况说“ 如何在没有填充密码的情况下进行解密?”

您的加密订单: getBytes,encrypt,encode,toString
您的解密订单: getBytes,decrypt,decode,toString

两个问题:

  1. 正如有人提到的那样,你应该颠倒解密操作的顺序。 你不这样做。
  2. encrypt给你16个字节,编码24个字节,但toString给出106个字节。 与无效字符占用额外空间有关。

注意:此外,您不需要两次调用generateKey()

通过使用相反的解释顺序修复问题#1。 正确的顺序: getBytes,decode,decrypt,toString
通过用new String(xxx)替换xxx.toString()修复问题#2。 在加密和解密function中执行此操作。

你的解密应该是这样的:

 c.init(Cipher.DECRYPT_MODE, key) val decodedValue = new Base64().decode(encryptedValue.getBytes()) val decryptedVal = c.doFinal(decodedValue) return new String(decryptedVal) 

这应该给你回“dude5”

这条线

 String encryptedValue = encryptedByteValue.toString(); 

是问题。 encryptedByteValue的类型是byte [],并且在它上面调用toString不是你想要做的。 相反,试试

 String encryptedValue = Base64.getEncoder().encodeToString(encValue); 

然后在解密时使用Base64.decodeBase64(encryptedValue) 。 您必须在尝试解密之前执行此操作。 您必须按加密方法的相反顺序撤消操作。

你在哪里得到一个具有encodeToString或encodeBase64String的apache编解码器版本?

我从apache站点下载了1.5,虽然它在文档中说这些方法存在,但是当你完成代码时它们不会出现,并且当你提供它们时它们会创建一个未知的方法。

我能做到:

 byte raw[] = md.digest(); //step 4 byte hashBytes[] = Base64.encodeBase64(raw); //step 5 StringBuffer buffer = new StringBuffer(); for( int i=0; i 

然后我获得的字符串非常长,但它正确解密。

我不认为这是做事的“正确”方式,但找不到文档所说的方法。

那没关系,你只需要

1)使用new String而不是toString(),因为toString()不会返回你需要的东西(在这两种情况下,加密和解密)

2)您需要先解码,因为该值是在base64中编码的。

我遇到了这个post但是花了一些时间来找出实际的点……我正在为其他遇到此问题的人发布我的代码。

 public abstract class EncryptionDecryption { static byte[] key = "!@#$!@#$%^&**&^%".getBytes(); final static String algorithm="AES"; public static String encrypt(String data){ byte[] dataToSend = data.getBytes(); Cipher c = null; try { c = Cipher.getInstance(algorithm); } catch (NoSuchAlgorithmException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (NoSuchPaddingException e) { // TODO Auto-generated catch block e.printStackTrace(); } SecretKeySpec k = new SecretKeySpec(key, algorithm); try { c.init(Cipher.ENCRYPT_MODE, k); } catch (InvalidKeyException e) { // TODO Auto-generated catch block e.printStackTrace(); } byte[] encryptedData = "".getBytes(); try { encryptedData = c.doFinal(dataToSend); } catch (IllegalBlockSizeException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (BadPaddingException e) { // TODO Auto-generated catch block e.printStackTrace(); } byte[] encryptedByteValue = new Base64().encode(encryptedData); return new String(encryptedByteValue);//.toString(); } public static String decrypt(String data){ byte[] encryptedData = new Base64().decode(data); Cipher c = null; try { c = Cipher.getInstance(algorithm); } catch (NoSuchAlgorithmException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (NoSuchPaddingException e) { // TODO Auto-generated catch block e.printStackTrace(); } SecretKeySpec k = new SecretKeySpec(key, algorithm); try { c.init(Cipher.DECRYPT_MODE, k); } catch (InvalidKeyException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } byte[] decrypted = null; try { decrypted = c.doFinal(encryptedData); } catch (IllegalBlockSizeException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (BadPaddingException e) { // TODO Auto-generated catch block e.printStackTrace(); } return new String(decrypted); } public static void main(String[] args){ String password=EncryptionDecryption.encrypt("password123"); System.out.println(password); System.out.println(EncryptionDecryption.decrypt(password)); } } 

从根本上说,加密function和解密function之间存在不对称性。 加密时执行AES加密,然后执行base64编码,解密时不要先撤消base64编码步骤。

我认为你的base64编码有问题,并且[不应该出现在base64编码的字符串中。

查看org.apache.commons.codec.binary.Base64的文档,您应该可以在编码时执行此操作:

 String encryptedValue = Base64.encodeBase64String(encValue); 

这解码:

 byte[] encValue = Base64.decodeBase64(encryptedValue); 

我在示例中替换了一行:

 String encryptedValue = encryptedByteValue.toString(); 

下一个:

 String encryptedValue = new String(encryptedByteValue); 

一切正常!