您的位置:首页 > 移动开发 > WebAPP

Bouncy Castle 多版本 与 Classloader 的问题

2011-03-26 11:51 639 查看
最近在做一个安全工具, 需要与多个第三方公司进行安全通信, 其中就用到了Bouncy Castle.

 

在连接B公司时,偶尔就会出现这样的异常:

 

java.lang.NoClassDefFoundError: org/bouncycastle/crypto/engines/RC2Engine
        at org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithSHAAnd40BitRC2.<init>(JCEBlockCipher.java:906)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
        at java.lang.Class.newInstance0(Class.java:355)
        at java.lang.Class.newInstance(Class.java:308)
        at java.security.Provider$Service.newInstance(Provider.java:1221)
        at javax.crypto.Cipher.getInstance(DashoA13*..)
        at javax.crypto.Cipher.getInstance(DashoA13*..)
        at org.bouncycastle.jce.provider.JDKPKCS12KeyStore.decryptData(JDKPKCS12KeyStore.java:590)
        at org.bouncycastle.jce.provider.JDKPKCS12KeyStore.engineLoad(JDKPKCS12KeyStore.java:802)
        at java.security.KeyStore.load(KeyStore.java:1185)

 

 

代码大概是这样的

provider=new org.bouncycastle.jce.provider.BouncyCastleProvider()

Security.addProvider(provider);

CertificateFactory cf = CertificateFactory.getInstance("X509", "BC");

// Read the Private Key
KeyStore ks = KeyStore.getInstance("PKCS12", "BC");
ks.load(new FileInputStream(keyPath), keyPass.toCharArray()); //执行到这里报错

 

 

为什么呢? 分析过程

 

1. 打开WEB-INF/lib/bcprov-jdk15-133.jar, 所有类以及依赖都有. 那怎么会报异常呢?

2. 打开调试器, 查看"Security.getProvider("BC").getClass().getClassLoader()", 发现这个classloader根本就是web应用的classloader,而是一个自定义的classloader, 找到它加载的jar, 打开一看, 果然找不到RC2Engine, 因为它加载的是一个低版本的bcprov-jdk13.jar

 

原来如此



当A classloader加载BouncyCastleProvider 1.3版已经注册后"Security.addProvider(provider)",B公司的安全组件通过 Webapp classloader 加载的BouncyCastleProvider 1.5版 自然就注册不进去了, 所以初始化失败,报了本文开始提的异常.

 

解决办法

将A 公司使用的BouncyCastleProvider 1.3升级为1.5, 问题就解决了.

 

问题总结

我们都知道, java的classloader相当于一个命名空间, 当要加载一个类时, 会通过双亲委派机制,先让父加载器加载,加载不成功才由自己加载, 而与兄弟加载器是隔离的.

所以当发现此类问题时, 可以通过"obj.getClass().getClassLoader()"先看看到底由哪个加载器加载的. 在依次找,是哪个类加载器出了问题.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息