微信退款通知(回調) req_info解密 錯誤彙總(待完成)-08-26

問題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具體加密過程:?????

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章