shikeying
2024-01-11 3b67e947e36133e2a40eb2737b15ea375e157ea0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
package com.walker.infrastructure.utils;
 
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.commons.codec.digest.DigestUtils;
 
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
/** 
* 功能:支付宝MD5签名处理核心文件,不需要修改
* 版本:3.3
* 修改日期:2012-08-17
* 说明:
* 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
* 该代码仅供学习和研究支付宝接口使用,只是提供一个
* */
 
public class MD5 {
 
    /**
     * MD5 32位转大写
     * @param plainText
     *            明文
     * @return 32位密文
     */
    public static String encryption(String plainText) {
        String re_md5 = StringUtils.EMPTY_STRING;
        try {
            MessageDigest md = MessageDigest.getInstance(MD5_NAME);
            md.update(plainText.getBytes());
            byte b[] = md.digest();
 
            int i;
 
            StringBuilder buf = new StringBuilder(StringUtils.EMPTY_STRING);
            for (int offset = 0; offset < b.length; offset++) {
                i = b[offset];
                if (i < 0)
                    i += 256;
                if (i < 16)
                    buf.append("0");
                buf.append(Integer.toHexString(i));
            }
 
            re_md5 = buf.toString().toUpperCase();
 
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("未找到MD5算法:" + e.getMessage(), e);
        }
        return re_md5;
    }
    
    /**
     * 签名字符串
     * @param text 需要签名的字符串
     * @param key 密钥
     * @param input_charset 编码格式
     * @return 签名结果
     */
    public static String sign(String text, String key, String input_charset) {
        text = text + key;
        return DigestUtils.md5Hex(getContentBytes(text, input_charset));
    }
    
    /**
     * 签名字符串
     * @param text 需要签名的字符串
     * @param sign 签名结果
     * @param key 密钥
     * @param input_charset 编码格式
     * @return 签名结果
     */
    public static boolean verify(String text, String sign, String key, String input_charset) {
        text = text + key;
        String mysign = DigestUtils.md5Hex(getContentBytes(text, input_charset));
        if(mysign.equals(sign)) {
            return true;
        }
        else {
            return false;
        }
    }
 
    /**
     * @param content
     * @param charset
     * @return
     * @throws SignatureException
     * @throws UnsupportedEncodingException 
     */
    private static byte[] getContentBytes(String content, String charset) {
        if (charset == null || StringUtils.EMPTY_STRING.equals(charset)) {
            return content.getBytes();
        }
        try {
            return content.getBytes(charset);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + charset);
        }
    }
 
    public static final char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
    public static final String MD5_NAME = "MD5";
    
    /**
     * 生成MD5摘要信息,目前该方法微信支付使用
     * @param buffer
     * @return
     */
    public final static String getMessageDigest(byte[] buffer) {
        try {
            MessageDigest mdTemp = MessageDigest.getInstance(MD5_NAME);
            mdTemp.update(buffer);
            byte[] md = mdTemp.digest();
            int j = md.length;
            char str[] = new char[j * 2];
            int k = 0;
            for (int i = 0; i < j; i++) {
                byte byte0 = md[i];
                str[k++] = hexDigits[byte0 >>> 4 & 0xf];
                str[k++] = hexDigits[byte0 & 0xf];
            }
            return new String(str);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    
    /**
     * 签名json数据
     * @param json 输入数据
     * @param key 给定的key
     * @return 返回签名后的字符串
     */
//    @Deprecated
//    public static String signJson(JSONObject json, String key){
//        if(json == null){
//            return null;
//        }
//        //过滤空值、sign与sign_type参数
//        Map<String, String> sParaNew = paraFilter((Map<String, Object>)json);
//        //获取待签名字符串
//        String preSignStr = createLinkString(sParaNew);
//        return MD5.sign(preSignStr, key, StringUtils.DEFAULT_CHARSET_UTF8);
//    }
    @Deprecated
    public static String signJson(String json, String key){
        if(json == null){
            return null;
        }
        //过滤空值、sign与sign_type参数
        try {
            Map map = JsonUtils.jsonStringToObject(json, Map.class);
            Map<String, String> sParaNew = paraFilter(map);
            //获取待签名字符串
            String preSignStr = createLinkString(sParaNew);
            return MD5.sign(preSignStr, key, StringUtils.DEFAULT_CHARSET_UTF8);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
 
    /**
     * 快速生成签名,通过fastjson直接生成序列化字符串,它可以按照a~z字母排序。
     * @param json
     * @param key
     * @return
     */
//    public static String signJsonFast(JSONObject json, String key){
//        if(json == null){
//            return null;
//        }
//        return MD5.sign(json.toJSONString(), key, StringUtils.DEFAULT_CHARSET_UTF8);
//    }
    public static String signJsonFast(String json, String key){
        if(StringUtils.isEmpty(json)){
            return null;
        }
        return MD5.sign(json, key, StringUtils.DEFAULT_CHARSET_UTF8);
    }
 
    /**
     * 验证签名过的json数据
     * @param json 待验证的json
     * @param sign 签名过的数据
     * @param md5Key 给定的key
     * @return 返回结果,true正确,false失败
     */
//    @Deprecated
//    public static boolean verifyJson(JSONObject json, String sign, String md5Key){
//        if(json == null){
//            return false;
//        }
//        return getMd5SignVeryfy((Map<String, Object>)json, sign, md5Key);
//    }
    @Deprecated
    public static boolean verifyJson(String json, String sign, String md5Key){
        if(StringUtils.isEmpty(json)){
            return false;
        }
        try {
            Map map = JsonUtils.jsonStringToObject(json, Map.class);
            return getMd5SignVeryfy(map, sign, md5Key);
        } catch (Exception e) {
            throw new RuntimeException("verifyJson:转换json字符串为Map出现异常:"+e.getMessage(), e);
        }
    }
 
    /**
     * 替换<code>verifyJson</code>方法。
     * 使用fastjson的自动排序功能,就能直接生成可用签名的字符串,无需考虑key的顺序问题,但fastjson版本必须1.2.5+
     * @date 2019-03-07
     * @param json
     * @param sign
     * @param md5Key
     * @return
     */
//    public static boolean verifyJsonFast(JSONObject json, String sign, String md5Key){
//        if(json == null){
//            return false;
//        }
//        json.remove(NAME_SIGN_2);
//        return MD5.verify(json.toJSONString(), sign, md5Key, StringUtils.DEFAULT_CHARSET_UTF8);
//    }
    public static boolean verifyJsonFast(String json, String sign, String md5Key){
        if(json == null){
            return false;
        }
        try {
            ObjectNode objectNode = JsonUtils.jsonStringToObjectNode(json);
            objectNode.remove(NAME_SIGN_2);
            return MD5.verify(JsonUtils.objectToJsonString(objectNode), sign, md5Key, StringUtils.DEFAULT_CHARSET_UTF8);
        } catch (Exception e) {
            throw new RuntimeException("verifyJsonFast:转换json字符串为对象异常:" + e.getMessage(), e);
        }
    }
 
    /**
     * 根据反馈回来的信息,生成签名结果
     * @param Params 通知返回来的参数数组
     * @param sign 比对的签名结果
     * @return 生成的签名结果
     */
    public static boolean getMd5SignVeryfy(Map<String, Object> Params, String sign, String md5Key) {
        //过滤空值、sign与sign_type参数
        Map<String, String> sParaNew = paraFilter(Params);
        //获取待签名字符串
        String preSignStr = createLinkString(sParaNew);
        //获得签名验证结果
        return MD5.verify(preSignStr, sign, md5Key, StringUtils.DEFAULT_CHARSET_UTF8);
    }
    
    /** 
     * 除去数组中的空值和签名参数
     * @param sArray 签名参数组
     * @return 去掉空值与签名参数后的新签名参数组
     */
    private static Map<String, String> paraFilter(Map<String, Object> sArray) {
        Map<String, String> result = new HashMap<String, String>();
        if (sArray == null || sArray.size() <= 0) {
            return result;
        }
 
        String value = null;
        for (String key : sArray.keySet()) {
            value = sArray.get(key).toString();
            if (StringUtils.isEmpty(value) || key.equalsIgnoreCase(NAME_SIGN_2)
                || key.equalsIgnoreCase(NAME_SIGN_TYPE)) {
                continue;
            }
            result.put(key, value);
        }
        return result;
    }
    
    /** 
     * 把数组所有元素,并按照“参数=参数值”的模式用“&”字符拼接成字符串
     * @param params 需要参与字符拼接的参数组
     * @return 拼接后字符串
     */
    public static String createLinkString(Map<String, String> params) {
        List<String> keys = new ArrayList<String>(params.keySet());
        Collections.sort(keys);
 
        StringBuilder result = new StringBuilder();
        String key = null;
        String value = null;
        for (int i = 0; i < keys.size(); i++) {
            key = keys.get(i);
            value = params.get(key);
            if(i > 0){
                result.append(StringUtils.CHAR_AND);
            }
            result.append(key).append(StringUtils.CHAR_EQUALS).append(value);
        }
        return result.toString();
    }
    
    public static final String NAME_SIGN_2 = "sign";
    private static final String NAME_SIGN_TYPE = "sign_type";
    
    public static void main(String[] args){
//        String key = "123456";
//        JSONObject input = new JSONObject();
//        input.put("name", "Mike");
//        input.put("age", 30);
//        input.put("amount", 600.2);
//        
//        String signStr = signJson(input, key);
//        System.out.println("签名内容 = " + signStr);
//        System.out.println("验证签名 = " + verifyJson(input, signStr, key));
        //签名内容 = 3d4d18461ebd93e20f8d73c888b94ee9
        //验证签名 = true
        
        System.out.println(MD5.encryption("123456"));
    }
}