近日小程序開發需求--獲取用戶小程序unionid(UnionID獲取途徑),考慮到用戶非必須關注公眾號,只能通過wx.getUserInfo從解密數據中獲取 UnionID ,api返回的數據encryptedData 的解密算法要求為: AES-128-CBC,數據采用PKCS#7填充。
但是,在解密時出現了異常(使用的java 11)
java.security.NoSuchAlgorithmException: Cannot find any provider supporting AES/CBC/PKCS7Padding
查詢了一波,大致的問題是java不支持PKCS7Padding,只支持PKCS5Padding,Java的默認crypto類,AES算法使用PKCS5Padding 填充模式,而iOS使用PKCS7Padding填充模式。
PKCS7Padding VS PKCS5Padding 的區別也很簡單 PKCS5Padding 的blocksize為8字節,而PKCS5Padding 的blocksize范圍 1~255字節. 參考 PKCS5Padding 和 PKCS7Padding
於是自以然的覺得把PKCS7Padding換成PKCS5Padding問題不久解決了嘛? 然后結果卻啪啪啪的打臉,這條道走不了,只能想辦法讓java兼容PKCS7Padding.
借助強大的Google了解到要實現java支持PKCS7Padding就必須要借助第三方組件來實現--bouncycastle,在MVN倉庫查詢后發現相關的依賴有兩個
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk16</artifactId>
<version>1.46</version>
</dependency>
//以及
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-ext-jdk16</artifactId>
<version>1.45</version>
</dependency>
有點懵逼啊,那么我該選擇哪一個呢?把兩個jar包下載下來后反編譯看了下,驚訝的發現bcprov-jdk16的代碼是bcprov-ext-jdk16的子集,於是依然選擇了下面的依賴.
so easy 輕輕松松解決問題,程序跑起來,然而,又出現了一個新的錯誤
javax.crypto.BadPaddingException: pad block corrupted
於是又google了一波,stackoverflow上一位大佬的回答引起了我的注意,參見-stackoverflow,以下是大佬的回答.

意思很明顯,需要定義一個provider,於是我定義了一個靜態方法
static { Security.addProvider(new BouncyCastleProvider()); }
終於成功解密了.
后來查看源碼,發現Cipher有一個getInstance(String transformation, String provider)方法,源碼如下
public static final Cipher getInstance(String transformation, String provider) throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException { if (transformation != null && !transformation.equals("")) { if (provider != null && provider.length() != 0) { Provider p = Security.getProvider(provider); if (p == null) { throw new NoSuchProviderException("No such provider: " + provider); } else { return getInstance(transformation, p); } } else { throw new IllegalArgumentException("Missing provider"); } } else { throw new NoSuchAlgorithmException("Null or empty transformation"); } }
於是,又在網上搜索了Cipher provider相關知識,發現一個很有趣的provider-"BC",使用方法如下
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding","BC");
啟動,測試,完美,一次點亮.
自此.java 小程序開發PKCS7Padding 解密相關問題全部解決. 簡單記錄一下.
