Java服務端微信小程序解密用戶信息、手機號需用到session_key也需要decode,以下是官方描述:
加密數據解密算法
接口如果涉及敏感數據(如wx.getUserInfo當中的 openId 和 unionId),接口的明文內容將不包含這些敏感數據。開發者如需要獲取敏感數據,需要對接口返回的加密數據(encryptedData) 進行對稱解密。 解密算法如下:
- 對稱解密使用的算法為 AES-128-CBC,數據采用PKCS#7填充。
- 對稱解密的目標密文為 Base64_Decode(encryptedData)。
- 對稱解密秘鑰 aeskey = Base64_Decode(session_key), aeskey 是16字節。
- 對稱解密算法初始向量 為Base64_Decode(iv),其中iv由數據接口返回。
Base64_Decode(session_key),用java.util包里的就可以:
import java.util.Base64; ... byte[] keyByte = Base64.getDecoder().decode(sessionKey); ...
有時候用code獲取到的session_key會有反斜杠,如:
GET https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
{"session_key":"tErsom\/ZTDEkKZ1saEiX2w==","openid":""}
重點:對session_key只要轉JSON格式,反斜杠就沒有了,示例如下:
附上完整解析算法:
import com.alibaba.fastjson.JSONObject; import org.bouncycastle.jce.provider.BouncyCastleProvider; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.security.AlgorithmParameters; import java.security.Security; import java.util.Arrays; import java.util.Base64; /** * @description: * @author: ruJun * @create: 2020/5/9 10:08 */ public class WXUtils { private volatile static BouncyCastleProvider bouncyCastleProvider = null; /** * @description: 解密小程序的用戶信息,手機號加密數據 * @author: ruJun * @create: 2020/5/9 10:09 */ public static JSONObject decode(String encryptedData, String sessionKey, String iv) throws Exception { // 被加密的數據 byte[] dataByte = Base64.getDecoder().decode(encryptedData); // 加密秘鑰 byte[] keyByte = Base64.getDecoder().decode(sessionKey); // 偏移量 byte[] ivByte = Base64.getDecoder().decode(iv); // 如果密鑰不足16位,那么就補足. 這個if 中的內容很重要 int base = 16; if (keyByte.length % base != 0) { int groups = keyByte.length / base + (keyByte.length % base != 0 ? 1 : 0); byte[] temp = new byte[groups * base]; Arrays.fill(temp, (byte) 0); System.arraycopy(keyByte, 0, temp, 0, keyByte.length); keyByte = temp; } // 初始化 Security.addProvider(getInstance()); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC"); SecretKeySpec spec = new SecretKeySpec(keyByte, "AES"); AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES"); parameters.init(new IvParameterSpec(ivByte)); cipher.init(Cipher.DECRYPT_MODE, spec, parameters);// 初始化 byte[] resultByte = cipher.doFinal(dataByte); if (null != resultByte && resultByte.length > 0) { String result = new String(resultByte, "UTF-8"); return JSONObject.parseObject(result); } return null; } public static BouncyCastleProvider getInstance() { if (bouncyCastleProvider == null) { synchronized (BouncyCastleProvider.class) { if (bouncyCastleProvider == null) { bouncyCastleProvider = new BouncyCastleProvider(); } } } return bouncyCastleProvider; } }