使用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
两个问题:
- 正如有人提到的那样,你应该颠倒解密操作的顺序。 你不这样做。
- 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);
一切正常!