近日小程序开发需求--获取用户小程序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 解密相关问题全部解决. 简单记录一下.