java 小程序開發PKCS7Padding 解密方法實現,以及錯誤Cannot find any provider supporting AES/CBC/PKCS7Padding 解決辦法


近日在對接小程序API,其中wx.getUserInfo api返回的數據encryptedData 的解密算法要求為: AES-128-CBC,數據采用PKCS#7填充。

經過一番查詢,得到java自帶了PKCS5Padding算法實現,但是沒有PKCS7Padding(注:說的應該是jdk8之前的版本,jdk8的版本有)。需要借助BouncyCastle組件來實現。於是加了如下依賴:

<dependency>
	  <groupId>org.bouncycastle</groupId>
	  <artifactId>bcprov-jdk16</artifactId>
	  <version>1.46</version>
</dependency> 

並寫了如下代碼:

import java.security.AlgorithmParameters;
import java.security.Key;
import java.security.Security;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.log4j.Logger;

import com.sun.org.apache.xml.internal.security.utils.Base64;

public class DecryptUtil {
	
	private static final Logger log = Logger.getLogger(DecryptUtil.class);
	
	
	private static final String AES ="AES";
	private static final String AES_CBC_PKCS7 ="AES/CBC/PKCS7Padding";
	

	/**
	 * <p>對小程序wx.getUserInfo 返回的數據進行解密</p>
	 * 
	 * <br>開發者如需要獲取敏感數據,需要對接口返回的加密數據( encryptedData )進行對稱解密。 解密算法如下:</br>
	 * <li>對稱解密使用的算法為 AES-128-CBC,數據采用PKCS#7填充</li>
	 * <li>對稱解密的目標密文為 Base64_Decode(encryptedData)</li>
	 * <li>對稱解密秘鑰 aeskey = Base64_Decode(session_key), aeskey 是16字節。</li>
	 * <li>對稱解密算法初始向量 為Base64_Decode(iv),其中iv由數據接口返回</li>
	 * 
	 * @param encryptedData		小程序wx.getUserInfo接口返回的密文
	 * @param sessionKey		會話key
	 * @param iv				小程序接口返回的初始向量
	 * @return {"openId":"oJ1P50LFpYwzZYaPhV1bjOrM2etY","nickName":"dimi","gender":1,"language":"zh_CN","city":"Haidian","province":"Beijing","country":"CN","avatarUrl":"http://wx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTJjUAIicI0k90UNwz7tTyWt46HrMMaxgSFPcR7Zh0MKZ4vzKibht4Sy3SrTwmYWoFSFOZOE0O1QJ0GQ/0","unionId":"orZ7js0oYCV859piu1kybaWlKGVc","watermark":{"timestamp":1493360456,"appid":"wxe87de3069cac4cf9"}}
	 * @throws WechatBusinessException 
	 */
	public static String decryptJsUserInfo(String encryptedData,String iv,String sessionKey) {
		
		try {
			byte[] data = Base64.decode(encryptedData);
			byte[] aseKey = Base64.decode(sessionKey);
			byte[] ivData = Base64.decode(iv);
			Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
			
			Cipher cipher = Cipher.getInstance(AES_CBC_PKCS7);
			Key sKeySpec = new SecretKeySpec(aseKey, AES);	
			cipher.init(Cipher.DECRYPT_MODE, sKeySpec, generateIv(ivData));// 初始化 
			
			byte[] result = cipher.doFinal(data);
			return new String(result);
		} catch (Exception e) {
			log.error("=======>小程序用戶信息解密失敗:"+e);
			return null;
		}  
		
	}
	
    public static AlgorithmParameters generateIv(byte[] iv) throws Exception{  
        AlgorithmParameters params = AlgorithmParameters.getInstance("AES");  
        params.init(new IvParameterSpec(iv));  
        return params;  
    }
       
	public static void main(String[] args){
		
	}
	
}

結果在本機jdk1.8的環境運行單元測試,解密成功。放到測試環境tomcat之后,解密失敗,(在jdk1.7環境下運行都會失敗)並報錯:

java.security.NoSuchAlgorithmException: Cannot find any provider supporting AES/CBC/PKCS7Padding

一番搜索,發現stackoverflow上面也有人碰到了和我一樣的問題

this is my code:
static {
    Security.addProvider(new BouncyCastleProvider());
}
......
final Cipher sifra = Cipher.getInstance("AES/CBC/PKCS7Padding");
Junit works fine but When I deploy my application to weblogic server I got these exception:
java.security.NoSuchAlgorithmException: Cannot find any provider supporting AES/CBC/PKCS7Padding

Can you hlp me what is wrong ?

問題下面的回答:

That's the old strange problem of different versions and missing cryptography files. I believe PKCS5Padding instead of PKCS7Padding will work. Anyway, it has something to do with Unlimited Strength Jurisdiction Policy Files which can be downloaded from Oracle ... or some other missing part or old version of Java Cryptography Extension.

同時,stackoverflow上又有人說:

PKCS7 padding and PKCS5 padding are the same thing.

於是,我把AES/CBC/PKCS7Padding 替換成AES/CBC/PKCS5Padding,也能解密成功,不報錯。

這個回答

看了這么多回答之后,雖然有點懵逼,但是最終我還是解決了問題,因為我感覺是PKCS7Padding算法實現的問題,上面提到依賴了bcprov-jdk16,於是我在倉庫中搜索 看是否有高版本的實現,結果發現了bcprov-ext-jdk16,名字多了個ext,我猜想是可以的,於是下載jar包反編譯了一下看看,發現bcprov-jdk16的代碼是他的子集。我修改了依賴包:

	<dependency>
	  <groupId>org.bouncycastle</groupId>
	  <artifactId>bcprov-ext-jdk16</artifactId>
	  <version>1.45</version>
	</dependency>

修改了這個依賴之后,運行成功。以上,供參考。


免責聲明!

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



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