JDK17升级之路:JCE cannot authenticate the provider BC问题

Posted 沛沛老爹

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JDK17升级之路:JCE cannot authenticate the provider BC问题相关的知识,希望对你有一定的参考价值。

问题的产生

报错代码运行环境
JDK:Oracle JDK17
CentOS7.8

这个问题刚拿到比较棘手。原因是本地windows是OK的,centos上是不成功的,报了下面的错误:

Caused by: java.lang.SecurityException: JCE cannot authenticate the provider BC
        at java.base/javax.crypto.Cipher.getInstance(Cipher.java:722)
        at cn.hutool.crypto.SecureUtil.createCipher(SecureUtil.java:1032)
        ... 72 common frames omitted

问题的背景

说问题的背景,主要是因为现有系统中需要对小程序自动登录的相关数据进行解密。网络上将小程序使用的是Pkcs7Padding的方式。

问题的解决方案

解决方案一

按照网上的解决思路,貌似能解决问题,但是感觉不是最好的办法。

1、在jdk目录目录下创建jre/lib目录

2、复制bcmail-jdk16-1.46.jar bcprov-jdk16-1.46.jar文件放入当前目录下
(添加 bcprov-jdk16-146.jar, bcmail-jdk16.143 到 /path_to_your_jvm/jre/lib/ext)

3、在/etc/profile文件下CLASSPATH添加jre相关目录

4、在jdk目录/conf/security/java.security
添加下面命令
security.provider.13=org.bouncycastle.jce.provider.BouncyCastleProvider

security.provider.13 这个根据上面的排序来,到几就是几,不一定是13。

5、如果还有问题的话,在maven项目中引入bcmail-jdk16-1.46.jar bcprov-jdk16-1.46.jar两个文件。

运行后,在后台debug可以看到正常解密了。
但是这种改法对JVM的侵入比较深。

解决方案二

我根据实际情况,使用了下面的这种方法。
将PKCS7Padding修改为PKCS5Padding,其他都不变,测试发现代码解密是OK的。

Cipher.getInstance("AES/CBC/Pkcs5Padding")

问题的分析

Java中的填充算法(Cipher)

算法名描述
NoPadding不填充
ISO10126PaddingW3C的“XML加密语法和处理”文档中的5.2块加密算法描述了块密码的填充。
OAEPPadding, OAEPWithAndPaddingPKCS1中定义的最佳非对称加密填充方案,其中<摘要>应被消息摘要替换,<mgf>应被掩码生成函数替换。示例:OAEPWithMD5AndMGF1填充和OAEPWithSHA-512AndMGF1填充。 如果使用OAEPAdding,则使用ajavax.crypto.spec.OAEPParameterSpec对象初始化Cipher对象,以支持OAEPAddition所需的值。
PKCS1PaddingPKCS1中描述的填充方案,与RSA算法一起使用。
PKCS5Padding“PKCS5:基于密码的加密标准”1.5版,1993年11月RSA Laboratories描述了填充方案。
SSL3PaddingSSL协议3.0版(1996年11月18日)第5.2.3.2节(CBC分组密码)中定义的填充方案:块加密结构不透明含量[SSL压缩长度];不透明MAC[CipherSpec.hash_size];uint8填充[GenericBlockCipher.padding_length];uint8填充长度;GenericBlockCipher;GenericBlockCipher实例的大小必须是块密码的块长度的倍数。始终存在的填充长度有助于填充,这意味着如果:sizeof(内容)+sizeof(MAC)%block_length=0,由于存在填充长度,填充长度必须为(block_length-1)字节。这使得填充方案与PKCS5Padding相似(但不完全相同),其中填充长度在填充中编码(范围从1到block_length)。使用SSL方案,sizeof(padding)以始终存在的padding_length编码,因此范围从0到block_length-1。

JDK本身是不支持PKCS7Padding的。
不支持的原因可能也和JAVA对块大小的支持有一定的关系。在PKCS5Padding中,明确定义Block的大小是8位,而在PKCS7Padding定义中,对于块的大小是不确定的,可以在1-255之间(块长度超出255的尚待研究),填充值的算法都是一样的:

value=k - (l mod k) ,K=块大小,l=数据长度,如果l=8, 则需要填充额外的8个byte的8。

理论上来讲,用PKCS7Padding加密,使用PKCS5Padding解密也是可以行得通的。

根据这个思路,和对国内的一般的实现,基本上都会调用默认的方式,这样基本上PKCS5Padding和PKCS7Padding的使用不存在异样的。这样JDK17兼容就很简单的修改了(这里后面可能会存在问题,但是我想JDK不实现PKCS7Padding,应该也是它本身存在一定的问题)

以上是关于JDK17升级之路:JCE cannot authenticate the provider BC问题的主要内容,如果未能解决你的问题,请参考以下文章

JCE cannot authenticate the provider BC

linux上java解加密(AES/CBC)异常:java.lang.SecurityException: JCE cannot authenticate the provider BC办法(示例代码

关于JDK8采坑JCE加密限制版本问题

JDK8安装JCE解决加密限制问题

jce_policy安装java密码扩展无限制权限策略文件安装

JDK1.8 Received fatal alert: handshake_failure 替换jce不能解决问题的情况