记一次对接小程序时遇到的加密问题“Cannot find any provider supporting AES/CBC/PKCS7Padding”

前情提要:

  依然是先碎碎念一下,这个问题是早几个月前,和我们小程序开发对接时候遇到的,并且解决后当时就打算写博客记一下,大致的保存了下资料,但是当时快下班了嘛,就想着改天再说。。。。。。然后人太咸鱼了,这等我下次扑腾一下已经是几个月后的今天了,明明上班不少很闲的时间,结果都拿来和项目经理一起开黑上王者了。。罪过罪过。

  然后说说具体问题,这个依稀记得是因为获取小程序的用户手机号,要对加密内容进行解密,原文是这么写的

加密数据解密算法
接口如果涉及敏感数据(如wx.getUserInfo当中的 openId 和 unionId),接口的明文内容将不包含这些敏感数据。开发者如需要获取敏感数据,需要对接口返回的加密数据(encryptedData) 进行对称解密。 解密算法如下:
对称解密使用的算法为 AES
-128-CBC,数据采用PKCS#7填充。 对称解密的目标密文为 Base64_Decode(encryptedData)。 对称解密秘钥 aeskey = Base64_Decode(session_key), aeskey 是16字节。 对称解密算法初始向量 为Base64_Decode(iv),其中iv由数据接口返回。

  然后问题就出在这个 PKCS#7 填充这个地方,我用的jdk是1.8的,报错一直提示“Cannot find any provider supporting AES/CBC/PKCS7Padding”,经查验,本身java只支持到 PKCS5 填充,这个PKCS7 默认是不支持的,好像是涉及到了AES256加密什么的,长度过程被限制了。

处理方法:

  首先,解密的代码中加上这一行:Security.addProvider(new BouncyCastleProvider());

  然后说一个别的地方看见的解决办法,内容如下。。。另外不是我不想贴来源,实在是几个月前的我真的找不到从哪找的文字了~

在这段代码可以运行之前,还有一个问题需要解决。
Java本身限制密钥的长度最多128位,而AES256需要的密钥长度是256位,因此需要到Java官网上下载一个Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files。

官方网站提供了JCE无限制权限策略文件的下载:
JDK6的下载地址:
http://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html

JDK7的下载地址:
http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html

JDK8的下载地址:
http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html

下载后解压,可以看到local_policy.jar和US_export_policy.jar以及readme.txt。
如果安装了JRE,将两个jar文件放到%JRE_HOME%\lib\security下覆盖原来文件,记得先备份。
如果安装了JDK,将两个jar文件也放到%JDK_HOME%\jre\lib\security下。

  另外再说一个处理办法:

其实我们1.8的jdk(具体哪个版本开始不知道)中自带了这个无限制策略文件的,
比如我的目录是:E:\jdk-ALL\jdk1.8.0_152\jre\lib\security\policy,在这个文件夹下能看见两个文件夹,分别是“limited”和“unlimited”,两个文件夹下面的内容都是“local_policy.jar和US_export_policy.jar”这两个东西,我们要取用的是“unlimited”下的jar
如果你是要给linux上的jdk进行处理,则可在自己电脑上将其取出,然后去linux服务器上对它进行覆盖即可,记得做好备份。参考路径如:/usr/local/java/jdk1.8.0_131/jre/lib/security
如果你是要给windows上的jdk进行处理,则直接在java.security这个文件中,将“#crypto.policy=unlimited”这段话取消注释即可,该文件所在参考路径如:E:\jdk-ALL\jdk1.8.0_152\jre\lib\security

 最后:

  实话说我也记不清是不是这样就行了,但是我自己印象中是这样就完事了,如果说谁看见了,发现还是没解决了,麻烦给我留下言,谢谢。。。。。。另外希望我以后可别再这么懒了,好歹要写的博客周末给它写掉,时间一长都忘记完了。

参考代码:

    /**
         * 对称解密使用的算法为 AES-128-CBC,数据采用PKCS#7填充。
         * 对称解密的目标密文为 Base64_Decode(encryptedData)。
         * 对称解密秘钥 aeskey = Base64_Decode(session_key), aeskey 是16字节。
         * 对称解密算法初始向量 为Base64_Decode(iv),其中iv由数据接口返回。
         */
        String sessionKey = json.getString("session_key").trim();
        String encryData = json.getString("encry_data").trim();
        String iv = json.getString("iv").trim();
        //解密手机号
        Security.addProvider(new BouncyCastleProvider());//因为jdk本身只支持pkcs5,加代码以及修改jdk配置支持pkcs7
        Base64 base64 = new Base64();
        byte[] content = base64.decode(encryData);
        byte[] aesKey = base64.decode(sessionKey);
        byte[] ivs = base64.decode(iv);
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
        SecretKeySpec skeySpec = new SecretKeySpec(aesKey, "AES");
        cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec(ivs));
        byte[] result = cipher.doFinal(content);
        JSONObject caller = JSONObject.parseObject(new String(result).toLowerCase());
        String xcxMobile = caller.getString("phonenumber");//解密出小程序手机号

  上述代码中的json是前端传过来的json参数,这三个参数就是小程序那边取到的。

  Base64 用的包是org.apache.commons.codec.binary.Base64

  Security 用的包是java.security.Security

posted @ 2022-03-02 17:37  咸鱼老李  阅读(4034)  评论(0编辑  收藏  举报