我们在获取到小程序的加密数据后,首先做的是校验数据,校验通过后进行数据的解密
一、新建隐私数据解密工具类——WXBizDataUtil
/**
* @Author: zp.wei
* @DATE: 2020/7/7 14:47
*/
public class WXBizDataUtil {
public static String illegalAesKey = "-41001";//非法密钥
public static String illegalIv = "-41002";//非法初始向量
public static String illegalBuffer = "-41003";//非法密文
public static String decodeBase64Error = "-41004"; //解码错误
public static String noData = "-41005"; //数据不正确
private String appid;
private String sessionKey;
public WXBizDataCrypt(String appid, String sessionKey) {
this.appid = appid;
this.sessionKey = sessionKey;
}
/**
* 检验数据的真实性,并且获取解密后的明文.
*
* @param encryptedData string 加密的用户数据
* @param iv string 与用户数据一同返回的初始向量
* @return String 返回用户信息
*/
public String decryptData(String encryptedData, String iv) {
if (StringUtils.length(sessionKey) != 24) {
return illegalAesKey;
}
// 对称解密秘钥 aeskey = Base64_Decode(session_key), aeskey 是16字节。
byte[] aesKey = Base64.decodeBase64(sessionKey);
if (StringUtils.length(iv) != 24) {
return illegalIv;
}
// 对称解密算法初始向量 为Base64_Decode(iv),其中iv由数据接口返回。
byte[] aesIV = Base64.decodeBase64(iv);
// 对称解密的目标密文为 Base64_Decode(encryptedData)
byte[] aesCipher = Base64.decodeBase64(encryptedData);
try {
byte[] resultByte = AESUtil.decrypt(aesCipher, aesKey, aesIV);
if (null != resultByte && resultByte.length > 0) {
String userInfo = new String(resultByte, "UTF-8");
JSONObject jsons = JSON.parseObject(userInfo);
String id = jsons.getJSONObject("watermark").getString("appid");
if (!StringUtils.equals(id, appid)) {
return illegalBuffer;
}
return userInfo;
} else {
return noData;
}
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
/**
* 根据微信数据和sessionkey生成用于校验的签名
*
* rawData 微信数据
* sessionKey sessionkey
*/
public static String getsignature2(String rawData, String sessionKey) throws UnsupportedEncodingException, NoSuchAlgorithmException {
String stringASCII = rawData + sessionKey;
String signature2 = null;
try {
//指定sha1算法
MessageDigest digest = MessageDigest.getInstance("SHA-1");
digest.update(stringASCII.getBytes("UTF-8"));
//获取字节数组
byte messageDigest[] = digest.digest();
// 创建 Hex 字符串
StringBuffer hexString = new StringBuffer();
// 字节数组转换为 十六进制 数
for (int i = 0; i < messageDigest.length; i++) {
String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
if (shaHex.length() < 2) {
hexString.append(0);
}
hexString.append(shaHex);
signature2 = hexString.toString().toLowerCase();
}
} catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
throw e;
}
return signature2;
}
}
二,新建AES解密工具类——AESUtil
/**
* @Author: zp.wei
* @DATE: 2020/7/7 14:48
*/
public class AESUtil {
static {
Security.addProvider(new BouncyCastleProvider());
}
/**
* AES解密
*
* @param content 密文
* @return
* @throws InvalidAlgorithmParameterException
* @throws NoSuchProviderException
*/
public static byte[] decrypt(byte[] content, byte[] keyByte, byte[] ivByte)
throws InvalidAlgorithmParameterException {
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
Key sKeySpec = new SecretKeySpec(keyByte, "AES");
//生成iv
AlgorithmParameters params = AlgorithmParameters.getInstance("AES");
params.init(new IvParameterSpec(ivByte));
cipher.init(Cipher.DECRYPT_MODE, sKeySpec, params);// 初始化
return cipher.doFinal(content);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
二、在controller相关方法里调用该工具类下的 decryptData 方法,即下面代码所示
private JSONObject getUserInfo(String iv, String encryptedData, String sessionKey) {
String userInfo = null;
//解密数据
try {
WXBizDataCrypt biz = new WXBizDataCrypt(CommonConfig.appletAppID, sessionKey);
userInfo = biz.decryptData(encryptedData, iv);
} catch (Exception e) {
e.printStackTrace();
}
return JSONObject.parseObject(userInfo);
}
最后获取到的 userInfo 就是解密后的用户隐私数据了