美文网首页
微信退款通知(回调) req_info解密 错误汇总(待完成)-

微信退款通知(回调) req_info解密 错误汇总(待完成)-

作者: 封_绝 | 来源:发表于2019-08-27 14:22 被阅读0次

问题1:

NoSuchProviderException No such provider: BC?

原因:不能使用没有添加解密包,虽然import了Bouncy Castle,但是从来没有添加到使用到
解决方法:在security中添加provider

        Security.addProvider(new BouncyCastleProvider());

解决来源:https://stackoverflow.com/questions/3711754/why-java-security-nosuchproviderexception-no-such-provider-bc

问题2:

java.security.InvalidKeyException: Illegal key size or default parameters.

解决办法:因为原来的jce中的cipher类不支持PKCS7Padding,所以需要下载Java Cryptography Extension,并且覆盖jre中security中的两个文件。
官方下载地址
解决来源1
问题详解

问题3:

javax.crypto.BadPaddingException: pad block corrupted
    at org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher$BufferedGenericBlockCipher.doFinal(Unknown Source)
    at org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher.engineDoFinal(Unknown Source)
    at javax.crypto.Cipher.doFinal(Cipher.java:2165)
    at com.newlife.s4.util.AES256Util.wxInfoDecrypt(AES256Util.java:102)
    at com.newlife.s4.util.AES256Util.main(AES256Util.java:119)
Disconnected from the target VM, address: '127.0.0.1:14544', transport: 'socket'

Process finished with exit code 0

错误可能:
(√)1.SecureRandom 产生随机数问题
原代码如下:

    /**
     * 解密步骤如下:
     * (1)对加密串A做base64解码,得到加密串B
     * (2)对商户key做md5,得到32位小写key* ( key设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置 )
     * (3)用key*对加密串B做AES-256-ECB解密(PKCS7Padding)
     *
     * @param keyStr  (md5得到的字符串)
     * @param content (解密内容)
     * @return
     */
    public static byte[] wxInfoDecrypt(String keyStr, byte[] content) throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, BadPaddingException, IllegalBlockSizeException, InvalidKeyException, UnsupportedEncodingException {
        //通过md5得到的字符串,放入key生成器,生成key

        SecureRandom secureRandom = new SecureRandom(keyStr.getBytes());
        KeyGenerator keygen = KeyGenerator.getInstance("AES");
        keygen.init(256, secureRandom);
        SecretKey secretKey = keygen.generateKey();
        //返回基本编码格式的密钥
        byte[] enCodeFormat = secretKey.getEncoded();
        //根据给定的字节数组构造一个密钥。enCodeFormat:密钥内容;"AES":与给定的密钥内容相关联的密钥算法的名称
        SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
//        SecretKeySpec key = new SecretKeySpec(keyStr.getBytes(), "AES");

        //解密,添加BouncyCastle
        Security.addProvider(new BouncyCastleProvider());
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
        cipher.init(Cipher.DECRYPT_MODE, key);
        byte[] decryptContent = cipher.doFinal(content);

        //返回xml byte
        return decryptContent;
    }

修改后可运行代码:

    public static byte[] wxInfoDecrypt(String keyStr, byte[] content) throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, BadPaddingException, IllegalBlockSizeException, InvalidKeyException, UnsupportedEncodingException {
        SecretKeySpec key = new SecretKeySpec(keyStr.getBytes(), "AES");

        //解密,添加BouncyCastle
        Security.addProvider(new BouncyCastleProvider());
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
        cipher.init(Cipher.DECRYPT_MODE, key);
        byte[] decryptContent = cipher.doFinal(content);

        //返回xml byte
        return decryptContent;
    }

?????不太明白??????

(不详)2.多用户并发操作问题:https://blog.csdn.net/yszd2017/article/details/78422608

(×)3.解密内容长度问题:密钥有长度限制,但是内容并没有明确说明,应该是没有的,因为AES是对称分组编码,使用相同的密钥进行加密,然后将内容进行分组,再对每一组进行加密

(不详)4.As Yann Ramin said, using String is a failure for cipher in/output. This is binary data that
can contain 0x00
can contain values that are not defined or mapped to strange places in the encoding used
https://stackoverflow.com/questions/4560461/decryption-error-pad-block-corrupted

(×)5.编码问题 wx的是ISO-8859-1编码,我们正常的是utf-8编码
在微信社区看到用的都是utf-8编码
编码问题提问与非官方回答
官方回答,但是不知道是说签名还是解密
自己尝试时也不太明白
代码如下:

            //本地使用的是utf-8编码,如果微信用的是iso-8859-1,那么粘贴过来使用的是哪种编码呢?
            if (Arrays.equals(reqInfoStr.getBytes(StandardCharsets.ISO_8859_1), reqInfoStr.getBytes(StandardCharsets.UTF_8))){
                System.out.println("ISO_8859_1 和 UTF_8 de Bytes相等");
            }

            //base64解码
            byte[] reqInfoByte = java.util.Base64.getDecoder().decode(reqInfoStr.getBytes(StandardCharsets.ISO_8859_1));
            byte[] reqInfoByteUtf8 = java.util.Base64.getDecoder().decode(reqInfoStr.getBytes(StandardCharsets.UTF_8));
            if(Arrays.equals(reqInfoByte, reqInfoByteUtf8)){
                System.out.println("Base64解码出来 ISO_8859_1 和 UTF_8 相等");
            }

            //apache 的md5返回的是全小写字符串,MD5Util是 全大写的
            String md5Key = Objects.requireNonNull(MD5Util.MD5(mchKey)).toLowerCase();
            String apacheMd5Key = Objects.requireNonNull(DigestUtils.md5Hex(mchKey));
            if(md5Key.equals(apacheMd5Key)){
                System.out.println("apacheMD5 he utilMD5 结果一致,除了大小写");
            }

输出结果:
ISO_8859_1 和 UTF_8 de Bytes相等
Base64解码出来 ISO_8859_1 和 UTF_8 相等
apacheMD5 he utilMD5 结果一致,除了大小写

为什么呢?看一下ISO_8859_1 和 UTF_8的异同
UTF-8 is a multibyte encoding that can represent any Unicode character. ISO 8859-1 is a single-byte encoding that can represent the first 256 Unicode characters. Both encode ASCII exactly the same way.来源
UTF-8是不定长编码,ISO-8859-1是单字符编码,如果仅有字母或者数字,则一致?详解1 详解2

(×)6.MD5加密方式问题,如果使用apache的commons-codec就可以 问题提出来源
概念:一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。
密码散列函数(英语:Cryptographic hash function),又译为加密散列函数密码散列函数加密散列函数,是散列函数的一种。它被认为是一种单向函数,也就是说极其难以由散列函数输出的结果,回推输入的数据是什么。这样的单向函数被称为“现代密码学的驮马”。这种散列函数的输入数据,通常被称为消息(message),而它的输出结果,经常被称为消息摘要(message digest)或摘要(digest)。

所以md5就是对其做散列函数。并不算是加密算法
作用:像https、U盾等就是通过这样的机制保证数据的私密性和完整性,用来在公共网络中确认对方身份,确保数据在公共网络中不被人监听和篡改(即使别人截获了你的数据,他也不可能在短时间内破解;而且如果数据被篡改,通过哈希就可以发现)。 https://www.zhihu.com/question/19984234

md5具体加密过程:?????

相关文章

网友评论

      本文标题:微信退款通知(回调) req_info解密 错误汇总(待完成)-

      本文链接:https://www.haomeiwen.com/subject/wkqrectx.html