当前位置:网站首页>Wechat refund callback decryption req_ Illegal key size or default parameters

Wechat refund callback decryption req_ Illegal key size or default parameters

2020-12-06 09:02:05 osc_ 5l7bcj86

Step on the pit 1: Wechat refund involves certificate issues

Put the certificate file in resource Under the folder ,

use spring Read the certificate file by reading the configuration file , No problem in the local computer unit test , The later discovery is through jenkins Package it to the test service because maven The reason for the plug-in changed the certificate file , The resulting error reporting solution

stay pom Add plug-in to file

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-resources-plugin</artifactId>
    <configuration><encoding>UTF-8</encoding>
        <!--  The filter suffix is pem、pfx,pkcs12,jks Certificate file for  -->
        <nonFilteredFileExtensions>
            <nonFilteredFileExtension>pkcs12</nonFilteredFileExtension>
            <nonFilteredFileExtension>jks</nonFilteredFileExtension>
            <nonFilteredFileExtension>cer</nonFilteredFileExtension>
            <nonFilteredFileExtension>pem</nonFilteredFileExtension>
            <nonFilteredFileExtension>pfx</nonFilteredFileExtension>
        </nonFilteredFileExtensions>
    </configuration>
</plugin>

such As soon as the problem is solved .

Step on the pit 2 :  Refund successful wechat callback through AES Decrypt req_info Information issues

The following is the introduction in the wechat document

After wechat refund is successful , For the sake of network security , Wechat will encrypt the returned field information To req_info This field is returned to us , After we get the data, we have to decrypt it to get the corresponding refund number, and then deal with our own business internally

Wechat official gave the decryption document introduction, but there is no corresponding demo , And then it's time to step on the pit , Here is my record of stepping on the pit

private final static String[] hexDigits = {"0", "1", "2", "3", "4", "5", "6", "7",
        "8", "9", "a", "b", "c", "d", "e", "f"};

// Key algorithm 
private static final String ALGORITHM = "AES";

// Encryption and decryption algorithm / Working mode / fill style 
private static final String ALGORITHM_MODE_PADDING = "AES/ECB/PKCS7Padding";

/**
 * API secret key 
 */
private static final String SERVICE_KEY = Configuration.readConfigString("service.key", "config");

/**
 *  Generate key   WeChat key
 */
private static SecretKeySpec key = new SecretKeySpec(MD5Encode(SERVICE_KEY).toLowerCase().getBytes(), ALGORITHM);

If you just execute the above code , The code will throw an exception

At this point, we need to add this code to the code So the subcode is perfectly executed , But there's a downside to this approach , Because every decryption will new One

BouncyCastleProvider, If this object is created too much, it will cause memory overflow of virtual machine , Now we make an improvement , Put the above code in a static code block 

Write it like this

Here is the complete code for the decryption process

 private static final Logger log = Logger.getLogger(RefundNotifyDecryptionUtil.class);


    private final static String[] hexDigits = {"0", "1", "2", "3", "4", "5", "6", "7",
            "8", "9", "a", "b", "c", "d", "e", "f"};

    // Key algorithm 
    private static final String ALGORITHM = "AES";

    // Encryption and decryption algorithm / Working mode / fill style 
    private static final String ALGORITHM_MODE_PADDING = "AES/ECB/PKCS7Padding";

    /**
     * API secret key 
     */
    private static final String SERVICE_KEY = Configuration.readConfigString("service.key", "config");

    /**
     *  Generate key  
     */
    private static SecretKeySpec key = new SecretKeySpec(MD5Encode(SERVICE_KEY).toLowerCase().getBytes(), ALGORITHM);

    static{
        if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null){
            Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
        }

    }

    /**
     * AES Decrypt 
     *
     * @param base64Data
     * @return
     * @throws Exception
     */
    public static String decryptData(String base64Data) throws Exception {
        String result = "";
        try {
            Cipher cipher = Cipher.getInstance(ALGORITHM_MODE_PADDING);
            cipher.init(Cipher.DECRYPT_MODE, key);
            result = new String(cipher.doFinal(Base64.getDecoder().decode(base64Data)));
        }catch (Exception e){
            log.info(e.getMessage());
        }

        return result;
    }


    public static void main(String[] args) throws Exception {
        // Decrypt 
        String req_info="FKV8RBK9Ws3gmFQvOBKQclyUgIkvCh7+qge1BbQ/xLTPFkIfUKbzq6XvUPLSSCvsLRVUlO/wkK7Y4RqUK0ve44tpLebYhYhqQXAGUdXrOaPiv5Ttv6codaL+6qCPIY4Vu8M2wcpXSLakofe7LvD/Hvg6Mo9Z05+MXzUX8/LwMQ0hen8ZioNrQjzGuDv9p8pT+e3oCT+PXHyshREMGSm5vm0zr9qFndWsqFwivZ23aEQQzb7CpjvzRpXLEsaySragqNfyJlP5VnaFeIonTWU9jSlruCRHytqfct6iuUj3tUoyLDRXFQPIfZM7ZuP32nan77KNIdsf0HOFcGVeUq/jHdJ4XsIPYV/+8MYOBvaRRp90kVYHFws1DNQGkfwxcqJtsM+vx35hjlQBZjWOKMu2aNqKzhiIU0Tj9duuX5XXgzx1syzlc664woFlf42hngNr5e9kruhp85L6K94H/cuYVYaYZbQj3PCHga9ebGjXEnHw0LgXwqUgC3dfOZ+uPBixYUO2zQS1UPYr3b1aUIDnK5sJzO6BcOtcCAp2tehJtIBKsj5ooLmvRP1zoXqiKdtyiGCN2vHRYpyLzbGiALAnKQMTdOcJhAMSELIVAxNkeUGPcKTbQVS71QIYxwWUNqB2n1uZg6VbM2MKUhj50iYIMstatjsC6YfR161Dsl53A9H4UHMwWAb1zptHtoyvRhXKeCF9vEzBfQ5QEY+1LX8wxektxFgMepbzlF9HtBx6/Ulzyx4WepUA2uV5RvsUrYkjXdZM2AGtrvSJer6Uu9uZl5rUdGbcL0uEIAApbMRFzpJ1OhWcRP/yQWWEO4O0c9kVgSKTcnqkmZMi8aDn6xE0E44880lg0t0ZQn0dYeFP8oxH6TWW7+mjuUpvRkqw/N0UaGcH/NiTozyp8Z0ZKSm/46ykeR0khZQl3H7RZIBRqpJfq1B04vQcN9ygtfY3sxV1mQGfOJ72wHRyTpdbNSqczZl2ANwjqanUCD4V4+tMrYaUUkc+JyW8/vKyyLP6GwMqdbD5re5hn9U6GV/mB1c0ZpruiN90ilNX1ZU4X1o+ZSY907bAqCueaqxvsfadiaRY";
        //String req_info = "m4NnwrtY0jhpDgNp65H1V/0OWMtSoTYhhY89MHbflhmnaHq9ZKjx9ABq6Jpg4SccA876HVy7J9P85NpdvCMNGInZ4fANDRE+YfZe4HeF+bbFj6JETcEFPpE9YW+bTbC0D+gl/otScJfvB2QUK7+EeBGPHN1EWX9zbr2Gw6AUaORdFk3mGxV5dtjuwWQrv5juzkXDs33Z2dUMslO+i3j0cTDHqwS4hptx2j6h2HvzgzltFbjo7nysU+4rArqJvrGW/9r18e1St9XgG21NALqixfaSmqetOR4zLVL4/+z3CEz8cg5r+/4GUOTf3XFmLCZ/wEkRQhKRNVibG0NFfiG3KnqArMJ/dheQHCd7qL+XX/ZV6tj8RLMgL7R6hOiR03Ljyikdxq9M3K9CTYgf03pHJd3geXX1LgXrLxc1flL6NW+zD3ZayGYpr1WpLsSMG7z8W5j1pme6cRj3n2+CwSFnOnOkxaFuLKoJAJIqM3gbC0eN++vY73RKphlI4zZqg6o5s3MXI6ju1yoi/ZQ+XbTg2JttsdbU0aySernKwkt0rYMf0j/Mcvo2axgHbI3w/iTm141WxHUjkQ+ga2X1pOWdGifGhSmMP8oGaA/WD5MAsK1qXX0eFvUWS/PTauCSTWq5Cmr8loA/KL3jgvB0nyR4mfccB+tPy4Ny7kzOlr/VNeb0ULf96R0AWFWCtdt8AmujAP0DYiM5FSmYLI0XRhpSDjnEbBM8+isNE1GlAVR3NzzemwQORihScovpAktbRSN/d3N+NgTjSoVDiJvCOxCs3thX9qt9iwYbA+/X/gv8lza2FZyIzwkQxGRcYl8JWKpXzNW8EWUNVnSLdHvQttDeV3CvgP/x579RGd6whyFYS6AaI0qw7oTjCFh2EHS/VzGvFuv166ZlVIJ4MNvg79O9h63ZOSE1LzVqEsVh8fDCfM2GgJ9aUdl95Djgunit4yIZOdoigR3f/BEHKrYCEham11rYohaAXs4XAXWihsV3WD5j4G/P+txvjAwujvf4HDwzHgFsmSml013U2mUiy+v4zw==";
        String B = decryptData(req_info);
        System.out.println(B);
//        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
//
//        // encryption 
//        String str = "<root>"+
//                "<out_refund_no><![CDATA[2531340110812300]]></out_refund_no>"+
//                "<out_trade_no><![CDATA[2531340110812100]]></out_trade_no>"+
//                "<refund_account><![CDATA[REFUND_SOURCE_RECHARGE_FUNDS]]></refund_account>"+
//                "<refund_fee><![CDATA[1]]></refund_fee>"+
//                "<refund_id><![CDATA[50000505542018011003064518841]]></refund_id>"+
//                "<refund_recv_accout><![CDATA[ Pay the user change ]]></refund_recv_accout>"+
//                "<refund_request_source><![CDATA[API]]></refund_request_source>"+
//                "<refund_status><![CDATA[SUCCESS]]></refund_status>"+
//                "<settlement_refund_fee><![CDATA[1]]></settlement_refund_fee>"+
//                "<settlement_total_fee><![CDATA[1]]></settlement_total_fee>"+
//                "<success_time><![CDATA[2018-01-10 10:31:24]]></success_time>"+
//                "<total_fee><![CDATA[1]]></total_fee>"+
//                "<transaction_id><![CDATA[4200000052201801101409025381]]></transaction_id>"+
//                "</root>";
//        System.out.println(encryptData(str));
//        Map<String, String> result_map = XmlUtils.XmlToMap1("<root><out_refund_no><![CDATA[2531340110812300]]></out_refund_no><out_trade_no><![CDATA[2531340110812100]]></out_trade_no><refund_account><![CDATA[REFUND_SOURCE_RECHARGE_FUNDS]]></refund_account><refund_fee><![CDATA[1]]></refund_fee><refund_id><![CDATA[50000505542018011003064518841]]></refund_id><refund_recv_accout><![CDATA[ Pay the user change ]]></refund_recv_accout><refund_request_source><![CDATA[API]]></refund_request_source><refund_status><![CDATA[SUCCESS]]></refund_status><settlement_refund_fee><![CDATA[1]]></settlement_refund_fee><settlement_total_fee><![CDATA[1]]></settlement_total_fee><success_time><![CDATA[2018-01-10 10:31:24]]></success_time><total_fee><![CDATA[1]]></total_fee><transaction_id><![CDATA[4200000052201801101409025381]]></transaction_id></root>");

//        System.out.println(result_map);
    }


    /**
     * AES encryption 
     *
     * @param data
     * @return
     * @throws Exception
     */
    public static String encryptData(String data) throws Exception {
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
        //  Create a cipher 
        Cipher cipher = Cipher.getInstance(ALGORITHM_MODE_PADDING);
        //  initialization 
        cipher.init(Cipher.ENCRYPT_MODE, key);
        return Base64Util.encode(cipher.doFinal(data.getBytes()));
    }


    /**
     * MD5 code 
     * @param origin  Original string 
     * @return  after MD5 The result of encryption 
     */
    public static String MD5Encode(String origin) {
        String resultString = null;
        try {
            resultString = origin;
            MessageDigest md = MessageDigest.getInstance("MD5");
            resultString = byteArrayToHexString(md.digest(resultString.getBytes()));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resultString;
    }

    private static String byteToHexString(byte b) {
        int n = b;
        if (n < 0) {
            n = 256 + n;
        }
        int d1 = n / 16;
        int d2 = n % 16;
        return hexDigits[d1] + hexDigits[d2];
    }

    /**
     *  Convert byte array to 16 Hexadecimal string 
     * @param b  Byte array 
     * @return 16 Hexadecimal string 
     */
    public static String byteArrayToHexString(byte[] b) {
        StringBuilder resultSb = new StringBuilder();
        for (byte aB : b) {
            resultSb.append(byteToHexString(aB));
        }
        return resultSb.toString();
    }

POM This dependency should be added to the file

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-ext-jdk16</artifactId>
    <version>1.46</version>
</dependency>

Through the above methods, you will find that the local code can be decrypted successfully . But the pit continues to come back , After the code is released to the test server, decryption is not successful He will throw an exception when executing the decryption code. The exception message is

Illegal key size or default parameters

Next, we solve the problem of the test server , The reason for this problem is Maybe it's on the server jdk The version is too low to support key by 256 The way to decrypt Then we need to modify and replace jre The two inside jar Package file

\jre\lib\security Next two documents

Replace these two files , Of course, make a backup of the original two before replacing In case of other problems

Pay attention to download the corresponding version of your server jar package Here is the download address

Encryption and decryption exception handling method
Alibaba edited this page on 24 Dec 2019 · 5 revisions 
If it appears in the process of encryption and decryption java.security.InvalidKeyException: Illegal key size, You need to download something :
JRE/JDK 6:http://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html 
JRE/JDK 7:http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html 
JRE/JDK 8u151 The previous version :http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html 
If installed JRE, Put two jar Files in $JAVA_HOME/lib/security Overwrite the original file in the directory
If installed JDK, Put two jar Files in $JAVA_HOME/jre/lib/security Overwrite the original file in the directory
If the tool is used, it may have built-in JRE, You need to put two under the directory of the tool reference jar Files in /jre/lib/security Overwrite the original file in the directory
JRE/JDK 8u151 Later versions have built-in unlimited permission policy files , Just put the $JAVA_HOME/jre/lib/security/java.security In the document #crypto.policy=unlimited Just uncomment








Replace two jar After the file, we need to refresh the environment variables

source /etc/profile

After the above operation is completed Restart the server and continue with a refund   We found that the decryption code is normal , Correctly analyzed the encrypted information returned by wechat   I'm so happy

Sharing is over , If there is any deficiency, I hope you can give me some advice

 

 

 

版权声明
本文为[osc_ 5l7bcj86]所创,转载请带上原文链接,感谢
https://chowdera.com/2020/12/20201206085959956g.html