一。 问题来源
最近使用了hutool工具包里的 国密4工具类来实现加解密。本地环境正常,但部署到测试环境 linux下的k8s集群中 就会出现解密报错问题
完整的报错日志如下
Caused by: cn.hutool.crypto.CryptoException: SecurityException: JCE cannot authenticate the provider BC
at cn.hutool.crypto.SecureUtil.createCipher(SecureUtil.java:1034)
at cn.hutool.crypto.CipherWrapper.<init>(CipherWrapper.java:39)
at cn.hutool.crypto.symmetric.SymmetricCrypto.init(SymmetricCrypto.java:150)
at cn.hutool.crypto.symmetric.SymmetricCrypto.<init>(SymmetricCrypto.java:127)
at cn.hutool.crypto.symmetric.SM4.<init>(SM4.java:171)
at cn.hutool.crypto.symmetric.SM4.<init>(SM4.java:146)
at cn.hutool.crypto.symmetric.SM4.<init>(SM4.java:78)
at com.style.common.config.encryptor.Sm4Encryptor.<clinit>(Sm4Encryptor.java:60)
... 31 common frames omitted
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)
... 38 common frames omitted
Caused by: java.lang.IllegalStateException: zip file closed
at java.base/java.util.zip.ZipFile.ensureOpen(ZipFile.java:831)
at java.base/java.util.zip.ZipFile.getManifestName(ZipFile.java:1057)
at java.base/java.util.zip.ZipFile$1.getManifestName(ZipFile.java:1100)
at java.base/javax.crypto.JarVerifier.verifySingleJar(JarVerifier.java:461)
at java.base/javax.crypto.JarVerifier.verifyJars(JarVerifier.java:317)
at java.base/javax.crypto.JarVerifier.verify(JarVerifier.java:260)
at java.base/javax.crypto.ProviderVerifier.verify(ProviderVerifier.java:130)
at java.base/javax.crypto.JceSecurity.verifyProvider(JceSecurity.java:190)
at java.base/javax.crypto.JceSecurity.getVerificationResult(JceSecurity.java:218)
at java.base/javax.crypto.Cipher.getInstance(Cipher.java:718)
... 39 common frames omitted
二。问题分析
SecurityException: JCE cannot authenticate the provider BC: 这个错误与Bouncy Castle(BC)加密提供程序的验证有关。这可能是因为Bouncy Castle库的某些问题,或者JCE(Java Cryptography Extension)无法验证Bouncy Castle作为提供程序。
我们遇到的这个错误应该时第二个 无法验证Bouncy Castle作为提供程序。
三。解决办法
那这个解决办法无非两个
- 第一个 解决无法验证Bouncy Castle作为提供程序的问题。
- 第二个 找一个不验证的Bouncy Castle作为提供程序的jdk
很明显 第二种方式简单粗暴 但是不是所有的环境都满足条件 直接升级
目前我们也是用的这种方式解决
替换 oracle-jdk17 为 open-jdk17
当然第一种方式也是可以解决的 只是步骤有点稍微繁琐,而且不一定能解决 也会被Bouncy Castle版本影响
jdk1.8的 解决步骤如下
1、找到jdk安装的根路径 打开jre/lib
2、下载bcprov 对应版本的jar 例如 需要某个加密依赖 org.bouncycastle:bcprov-jdk15on:jar:1.70 1.7的版本 那我就下载1.7版本
复制下载的jar 到 /jdk的根路径/jre/lib/ext 如果这个ext 目录不存在的话 需要新建 (应该都会存在)
3、在/etc/profile文件下CLASSPATH添加jre相关目录
export CLASSPATH=$JAVA_HOME/lib:$JAVA_HOME/jre/lib/ext
4、在{jdk根目录}/jre/lib/security
例如 /usr/local/develop/java/jdk1.8.0_181/jre/lib/security
打开java.security 这个文件
先找到 security.provider 对应的文件配置
添加如下配置
security.provider.11=org.bouncycastle.jce.provider.BouncyCastleProvider
security.provider.11 这个根据上面的排序来,我的本机排序是到了11,所以我这里加了11。
保存该配置后,在进行测试。
jdk17的配置方法大同小异 (需要自行测试下)
唯一不一样的 根目录下没有jre
我们需要使用命令 生成jre目录
在jdk17的根目录下执行
#mac / linux
/bin/jlink --module-path jmods --add-modules java.desktop --output jre
#win
\bin\jlink --module-path jmods --add-modules java.desktop --output jre
- 然后进入到 jdk根路径/jre/lib
- 新建 ext目录
- 然后复制下的 jar到这里
- 打开安全配置 这个和之前路径不太一样
/jdk根目录/conf/security
- 和之前方式一样 找到security.provider 对应的配置
添加如下配置
security.provider.14=org.bouncycastle.jce.provider.BouncyCastleProvider
security.provider.14 这个根据上面的排序来,我的本机排序是到了14,所以我这里加了14。
保存该配置后,在进行测试。
文章出处登录后可见!