现象
两个module A和B分别采用了infosec的不同版本,虽然classloader已经保证了A和B所依赖的资源均可以正确的load, 并且成功地newInstance() 或者new构造,但是仍然出现ClassCastException、ClassNotFoundException、NoSuchMethodException等异常
问题分析
Security vendor有infosecurity,bouncycastle等好几种,在JCE框架里面都被抽象成Provider,每个供应商实现抽象类Provider,JVM会管理这些Provider.同一个JVM中,不同的module依赖了同一个Provider(eg.Infosecurity)的不同版本,如果Provider之间是不兼容的,尽管通过ClassLoader机制让不通的module分别load到了各自对应的Provider,但是因为JCE管理Provider的方式,它们的name完全相同,B的会把A的infosec Provider给覆盖。这会导致A使用了B的provider,仍然会产生可恶的ClassCastException、NoSuchMethodException等。
问题探索
一步步的看Provider是被管理使用的。首先从MessageDigest开始,一般我们这么使用
MessageDigest md = MessageDigest.getInstance("SHA-1","INFOSEC");
//or
MessageDigest md = MessageDigest.getInstance("MD5");
看看里面怎么做的,很明显,找到多个取第一个。
public static MessageDigest getInstance(String paramString)
throws NoSuchAlgorithmException
{
try
{
Object[] arrayOfObject = Security.getImpl(paramString, "MessageDigest", (String)null);
if (arrayOfObject[0] instanceof MessageDigest)
{
localObject = (MessageDigest)arrayOfObject[0];
((MessageDigest)localObject).provider = ((Provider)arrayOfObject[1]);
return localObject;
}
Object localObject = new Delegate((MessageDigestSpi)arrayOfObject[0], paramString);
((MessageDigest)localObject).provider = ((Provider)arrayOfObject[1]);
return localObject;
}
catch (NoSuchProviderException localNoSuchProviderException)
{
throw new NoSuchAlgorithmException(paramString + " not found");
}
}
然后就到Security类了
static Object[] getImpl(String paramString1, String paramString2, String paramString3)
throws NoSuchAlgorithmException, NoSuchProviderException
{
if (paramString3 == null)
return GetInstance.getInstance(paramString2, getSpiClass(paramString2), paramString1).toArray();
return GetInstance.getInstance(paramString2, getSpiClass(paramString2), paramString1, paramString3).toArray();
}
getSpiClass方法暂时忽略掉,这里有2个分支,为了方便直接看第二个分支。
public static Instance getInstance(String paramString1, Class paramClass, String paramString2, String paramString3)
throws NoSuchAlgorithmException, NoSuchProviderException
{
return getInstance(getService(paramString1, paramString2, paramString3), paramClass);
}
public static Provider.Service getService(String paramString1, String paramString2, String paramString3)
throws NoSuchAlgorithmException, NoSuchProviderException
{
if ((paramString3 == null) || (paramString3.length() == 0))
throw new IllegalArgumentException("missing provider");
Provider localProvider = Providers.getProviderList().getProvider(paramString3);
if (localProvider == null)
throw new NoSuchProviderException("no such provider: " + paramString3);
Provider.Service localService = localProvider.getService(paramString1, paramString2);
if (localService == null)
throw new NoSuchAlgorithmException("no such algorithm: " + paramString2 + " for provider " + paramString3);
return localService;
}
可以看到,最终的是在Providers所管理的ProviderList里面保存所有的Provider,而且保存的方式是以paramString3参数,也就是"INFOSEC"去获取Provider。而相同vendor的不同版本Provider的Name是完全一样的,区别是version不同,这里印证了猜想:
不同的Provider因为相同的name而被认为是同一个Provider而产生的同名覆盖
如何解决。Security,Providers,ProviderList是java core包的类,不可轻易改动,否则后果很难估计。我在这里采用的方法比较简陋,从Providers类做改动,直接覆盖Providers类的管理逻辑:针对当前Thread的classloader的类型做判断,如果是SystemClassLoader,则使用自己的Provider管理逻辑,否则还是使用之前的管理方式。
完成后对Providers重新打包成providers.jar,加入启动参数-Xbootclasspath/p:/data/overwrite/providers.jar以覆盖rt.jar中的Providers类。大功告成。
分享到:
相关推荐
在与银联的对接中,调试过程中报错或使用类似登入加密:java.lang.SecurityException: JCE cannot authenticate the provider BC 进行问题解决,里面包含 bcprov-jdk16-143.jar与bcprov-jdk15-135.jar与具体文件存放...
解决org/bouncycastle/jce/provider/bouncycastlepr错误专用。
JAVA 加密 JCE Java密码扩展的基础 关于JCE的基础
1.修改 jre/lib/security/java.security文件 security.provider.9=org.bouncycastle.jce.provider.BouncyCastleProvider, 2.添加2个扩展包到jre/lib/ext目录下:bcprov-jdk15-135.jar bcprov-jdk16-143.jar
jar包下载地址 : http://www.rsdown.cn/down/164019.html 下载后将sunjce_provider.jar放入webapp/WEB-INF/lib中
NULL 博文链接:https://lwpsoft.iteye.com/blog/2254348
JCE,Java Cryptography Extension 1.8, java jce8 java jce
jce_policy-8.zip jar包,jdk,安全,security,oracle官网下载 稍微麻烦 上传供大家方便下载
Diffie-Hellman密钥一致协议和DES程序需要JCE工具库的支持
jce8、jce7下载 jdk8无政策限制权限文件,用于AES加密算法,AES加密扩展包因为某些国家的进口管制限制,Java发布的运行环境包中的加解密有一定的限制。比如默认不允许256位密钥的AES加解密,解决方法就是修改策略文件...
jce-jdk13-139.jar是提供给java扩展包,放至jre/lib/ext目录下,并..\jre\lib\security\java.security文件中在配置security.provider.11=org.bouncycastle.jce.provider.BouncyCastleProvider后使用
jce_policy-6.zip,jce_policy-8.zip,UnlimitedJCEPolicyJDK7.zip
免费的JCE提供者。Bouncy Castle 是一种用于 Java 平台的开放源码的轻量级密码术包。它支持大量的密码术算法,并提供 JCE 1.2.1 的实现。因为 Bouncy Castle 被设计成轻量级的,所以从 J2SE 1.4 到 J2ME(包括 MIDP...
微信企业号开发JCE6,JCE包需要根据自己的jdk版本下载,对应JDK6
jce_policy-8,JCE(Java Cryptography Extension)是一组包,它们提供用于加密、密钥生成和协商以及 Message Authentication Code(MAC)算法的框架和实现。 它提供对对称、不对称、块和流密码的加密支持,它还...
用于替换jdk里的两个jar,解决无法使用AES192、256位加密解密的问题 jce7,jce8
joomla JCE最新版本2.3.2.4 繁体中文语言包
jce policy 8 有需要的下载来,分分钟解决你遇到的问题! jce_policy-8,JCE(Java Cryptography Extension)是一组包,它们提供用于加密、密钥生成和协商以及 Message Authentication Code(MAC)算法的框架和实现...
jce6到8对应jar.zip,jce6、jce7、jce8对应的jar,详情可以参考https://stackoverflow.com/questions/38203971/javax-net-ssl-sslhandshakeexception-received-fatal-alert-handshake-failure
JCE 加密、解密算法