发生背景:我们使用了javax的KeyGenerator去生成密钥,然后使用的算法是国密SM4;同时也使用了GmSSL去与其他服务通讯。
问题:生成密钥的时候报错了
排查过程:
1、在报错的地方追源码进去,然后发现是在sun.security.jca.GetInstance getService(String var0,String var1,String var2)这个方法报出来的
2、进一步找原因,发现在上图圈起来的var3.getService方法中,从legacyMap中去获取该provider提供了哪些支持的算法,通过把所有支持的算法拉出来看了后发现这里面根本不支持任何国密SM的算法,因此爆出了上面的问题。
3、想着在我们引入GmSSL之前没有这个问题,因此怀疑是GmSSL引入了某个提供者的包导致了冲突,然后发现其实这个包没有引入其他包
4、继续追源码,又回到上面的getService方法中排查,var3是获取到的提供者,也就是说下面是从提供者中去获取的service,没有找到我们要的算法,因此认为提供者有问题。
5、查看对比使用GmSSL前后这里的提供者列表区别,这里提供者列表的加载不是getProviderList()方法,而是后面的getProvider(var2)方法,追进去发现又去调用了一个获取提供者配置的方法,是读取的这里面的数组对象。
这里面存了所有加载进来的提供者,然后发现了导致我们报错的这个提供者是org.bc.jce.provider.BouncyCastleProvider
6、因为追源码的时候分别记录了出问题前和出问题后的调用流程记录,因此发现就是注入的这个提供者的包名不一样了,这就很明显了,是因为引入了GmSSL出的问题,那么就是GmSSL也向Security添加了这个提供者,但是添加的是1.48的版本,这个版本是不支持任何国密SM相关算法的,下面放一张追源码流程的对比图
7、解决:既然GmSSL也添加了这个提供者,但是是低版本的,那么将其替换成高版本应该就可以解决
加了一句这个代码,问题解决。下方那行代码,new BouncyCastleProvider()是简写的,因为上面已经导入了这个包了。完整的应该是 org.bouncycastle.jce.provider.BouncyCastleProvider
8、问题解决