java 小程序开发PKCS7Padding 解密相关问题

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

原文地址:https://www.cnblogs.com/JackpotHan/p/13276202.html