正确代码如下:
package org.springblade.common.utils;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
public class AESDecryptionExample {
//加密
public static String aesEncrypt(String key, String encryptStr) {
byte[] encodedKey = key.getBytes(StandardCharsets.UTF_8);
SecretKeySpec secretKeySpec = new SecretKeySpec(encodedKey, "AES");
Cipher cipher = null;
try {
cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
byte[] encryptedBytes = cipher.doFinal(encryptStr.getBytes(StandardCharsets.UTF_8));
String encryptedText = Base64.getEncoder().encodeToString(encryptedBytes);
System.out.println("加密后的文本:" + encryptedText);
return encryptedText;
} catch (IllegalBlockSizeException e) {
throw new RuntimeException(e);
} catch (BadPaddingException e) {
throw new RuntimeException(e);
} catch (InvalidKeyException e) {
throw new RuntimeException(e);
} catch (NoSuchPaddingException e) {
throw new RuntimeException(e);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
public static String aesDEncrypt(String key,String encryptStr){
byte[] encodedKey = key.getBytes(StandardCharsets.UTF_8);
SecretKeySpec secretKeySpec = new SecretKeySpec(encodedKey, "AES");
Cipher cipher = null;
try {
cipher = Cipher.getInstance("AES");
// 解密
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
byte[] decryptedBytes = new byte[0];
decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptStr));
String decryptedText = new String(decryptedBytes, StandardCharsets.UTF_8);
System.out.println("解密后的文本:" + decryptedText);
return decryptedText;
} catch (IllegalBlockSizeException e) {
throw new RuntimeException(e);
} catch (BadPaddingException e) {
throw new RuntimeException(e);
} catch (InvalidKeyException e) {
throw new RuntimeException(e);
} catch (NoSuchPaddingException e) {
throw new RuntimeException(e);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
}
异常代码如下:
package com.ctf.mall.utils;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
/**
* @PACKAGE_NAME: com.ctf.mall.common.utils
* @NAME: AESDecryptionExample
* @author: 周政
* @since: Created on 2024年03月26日 15:43
* @DESCRIPTION: 手机号加解密工具
*/
public class AESDecryptionExample {
//加密
public static String aesEncrypt(String key, String encryptStr) {
byte[] encodedKey = key.getBytes(StandardCharsets.UTF_8);
SecretKeySpec secretKeySpec = new SecretKeySpec(encodedKey, "AES");
Cipher cipher = null;
try {
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] ivBytes = new byte[16]; // 初始化向量(IV)必须与块大小一致,对于AES使用128位的块,因此IV长度为16字节
IvParameterSpec iv = new IvParameterSpec(ivBytes);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, iv);
byte[] encryptedBytes = cipher.doFinal(encryptStr.getBytes(StandardCharsets.UTF_8));
String encryptedText = Base64.getEncoder().encodeToString(encryptedBytes);
System.out.println("加密后的文本:" + encryptedText);
return encryptedText;
} catch (IllegalBlockSizeException e) {
throw new RuntimeException(e);
} catch (BadPaddingException e) {
throw new RuntimeException(e);
} catch (InvalidAlgorithmParameterException e) {
throw new RuntimeException(e);
} catch (InvalidKeyException e) {
throw new RuntimeException(e);
} catch (NoSuchPaddingException e) {
throw new RuntimeException(e);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
public static String aesDEncrypt(String key,String encryptStr){
byte[] encodedKey = key.getBytes(StandardCharsets.UTF_8);
SecretKeySpec secretKeySpec = new SecretKeySpec(encodedKey, "AES");
Cipher cipher = null;
try {
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] ivBytes = new byte[16]; // 初始化向量(IV)必须与块大小一致,对于AES使用128位的块,因此IV长度为16字节
IvParameterSpec iv = new IvParameterSpec(ivBytes);
// 解密
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, iv);
byte[] decryptedBytes = new byte[0];
decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptStr));
String decryptedText = new String(decryptedBytes, StandardCharsets.UTF_8);
System.out.println("解密后的文本:" + decryptedText);
return decryptedText;
} catch (IllegalBlockSizeException e) {
throw new RuntimeException(e);
} catch (BadPaddingException e) {
throw new RuntimeException(e);
} catch (InvalidAlgorithmParameterException e) {
throw new RuntimeException(e);
} catch (InvalidKeyException e) {
throw new RuntimeException(e);
} catch (NoSuchPaddingException e) {
throw new RuntimeException(e);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
}
问题现象:手机号(数字)加解密正常,中文(湖北省-武汉市-洪山区-东湖高新中建大公馆3期B9号楼1单元12楼1202)和别的.net系统生成的加密后的值不一致,并且解密失败报异常;
异常信息:Exception in thread "main" java.lang.RuntimeException: javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
at com.ctf.mall.utils.AESDecryptionExample.aesDEncrypt(AESDecryptionExample.java:73)
at com.ctf.mall.utils.AESDecryptionExample.main(AESDecryptionExample.java:88)
Caused by: javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:991)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:847)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
at javax.crypto.Cipher.doFinal(Cipher.java:2164)
at com.ctf.mall.utils.AESDecryptionExample.aesDEncrypt(AESDecryptionExample.java:65)
... 1 more
错误原因:因为获取Cipher实例的时候用了多种方式"AES/CBC/PKCS5Padding",而IvParameterSpec这个入参应该是CBC还是DES才用到的导致加解密异常;
区别位置参考:获取实例位置和捕捉异常位置
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] ivBytes = new byte[16]; // 初始化向量(IV)必须与块大小一致,对于AES使用128位的块,因此IV长度为16字节
IvParameterSpec iv = new IvParameterSpec(ivBytes);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, iv);