• 记一次对接小程序时遇到的加密问题“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

  • 相关阅读:
    轻量化ViewControllers,读文章做的总结
    项目开发一点总结和吐槽
    简要解析XMPP框架及iOSObjectiveC的使用
    分享,iOS国家手机区号代码.plist
    Storyboard中使用UIscrollView添加约束的开发总结
    朋友由一道面试题想到的递归的解决办法
    最精简SQL教程,查漏补疑
    C#操作注册表的两种方法及引申出调用脚本的通用方法
    nunit的最精简教程
    一些基础知识
  • 原文地址:https://www.cnblogs.com/lilh/p/15955811.html
Copyright © 2020-2023  润新知