記一次對接小程序時遇到的加密問題“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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM