• 反射解决微信开发加解密illegal key size,不需要修改JDK jar包


     在微信开发时,消息接口时,涉及到消息加密,抛出了 java.security.InvalidKeyException: Illegal key size 的异常,异常堆栈如下:

     

    按照网上的解决方案,都是要求替换JDK目录下两个jar包,

    对于一些生产系统 这种方式就不是很方便了,经过探索,发现一种方案,通过反射机制来解决

    查看JDK源码,Cihper.checkCryptoPermcheckCryptoPerm,代码如下

        private void checkCryptoPerm(CipherSpi var1, Key var2) throws InvalidKeyException {
            if (this.cryptoPerm != CryptoAllPermission.INSTANCE) {
                AlgorithmParameterSpec var3;
                try {
                    var3 = this.getAlgorithmParameterSpec(var1.engineGetParameters());
                } catch (InvalidParameterSpecException var5) {
                    throw new InvalidKeyException("Unsupported default algorithm parameters");
                }
    
                if (!this.passCryptoPermCheck(var1, var2, var3)) {
                    throw new InvalidKeyException("Illegal key size or default parameters");
                }
            }
        }

    其中主要的就是 this.cryptoPerm != CryptoAllPermission.INSTANCE ,找到cryptoPerm初始化的位置,有一个方法

        private void initCryptoPermission() throws NoSuchAlgorithmException {
            if (!JceSecurity.isRestricted()) {
                this.cryptoPerm = CryptoAllPermission.INSTANCE;
                this.exmech = null;
            } else {
                this.cryptoPerm = getConfiguredPermission(this.transformation);
                String var1 = this.cryptoPerm.getExemptionMechanism();
                if (var1 != null) {
                    this.exmech = ExemptionMechanism.getInstance(var1);
                }
    
            }
        }

    意思是,如果 JceSecurity.isRestricted() 返回true,则使用CryptoAllPermission.INSTANCE实例 否则需要进行key的校验,因此修改这个方法就行了

    isRestricted方法的内容如下:

    final class JceSecurity {
    
    private static final boolean isRestricted; //默认情况下为true
        static boolean isRestricted() {
            return isRestricted;
        }
    
    }

    isRestricted这是一个private static final变量,可通过反射的方式修改

    反射修改private field值的方法是

    Field field = Class.forName("类名").getDeclaredField("属性名");
    field.setAccessible(true);
    field.set(null,值); // 如果是static,第一个参数填null,否则填实例对象

    由于这个属性的final的,需要对Field.class再反射一次,从modifiers中去掉final属性:

    Field modifiersField = Field.class.getDeclaredField("modifiers");
    modifiersField.setAccessible(true);
    modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);

    完整的代码:

    //解决微信开发时,InvalidKeyException:illegal Key Size的问题

    //反射获取isRestrictedfield
    Field field = Class.forName("javax.crypto.JceSecurity").getDeclaredField("isRestricted");

    //这个field是 private static final的,需要找到这个field的modifiers,将final去掉,才能修改
    Field modifiersField = Field.class.getDeclaredField("modifiers");
    modifiersField.setAccessible(true);
    modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);

    //修改field
    field.setAccessible(true);
    field.set(null,false);

    执行完整的代码后,加密/解密正常,用微信企业号默认的SDK,测试加密通过

    import com.yomahub.liteflow.example.utils.WXBizMsgCrypt;
    
    import java.lang.reflect.Field;
    import java.lang.reflect.Modifier;
    
    public class Test {
        public static void main(String[] args) throws Exception {
    
            //解决微信开发时,InvalidKeyException:illegal Key Size的问题
    
            //反射获取isRestrictedfield
            Field field = Class.forName("javax.crypto.JceSecurity").getDeclaredField("isRestricted");
    
            //这个field是 private static final的,需要找到这个field的modifiers,将final去掉,才能修改
            Field modifiersField = Field.class.getDeclaredField("modifiers");
            modifiersField.setAccessible(true);
            modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
    
            //修改field
            field.setAccessible(true);
            field.set(null,false);
    
    
            String sToken = "QDG6eK";
            String sCorpID = "wx5823bf96d3bd56c7";
            String sEncodingAESKey = "jWmYm7qr5nMoAUwZRjGtBxmz3KA1tkAj3ykkR6q2B2C";
    
            WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(sToken, sEncodingAESKey, sCorpID);
    
    
            String sRespData = "<xml><ToUserName><![CDATA[mycreate]]></ToUserName><FromUserName><![CDATA[wx5823bf96d3bd56c7]]></FromUserName><CreateTime>1348831860</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[this is a test]]></Content><MsgId>1234567890123456</MsgId><AgentID>128</AgentID></xml>";
            String sReqTimeStamp = "1409659813";
    
            String sReqNonce = "1372623149";
            String result = wxcpt.EncryptMsg(sRespData,sReqTimeStamp,sReqNonce);
    
            System.out.println(result);
        }
    }
    View Code
  • 相关阅读:
    Vue和React组件diff更新影响范围对比
    ES6中import和CommonJS中require的区别
    MutationObserver监听DOM变化
    Mint UI中文官网
    为什么在浏览器不支持H265视频播放
    Google谷歌官网首页涂鸦记录
    windows键盘输入无效,键盘灯亮,打字不出字
    javascript实现跨域的方法汇总
    javascript中setInterval的用法
    浅谈Javascript数组的使用
  • 原文地址:https://www.cnblogs.com/xcr1234/p/15451907.html
Copyright © 2020-2023  润新知