支付宝对接RSA加解签及ILLEGAL_SIGN踩坑

ILLEGAL_SIGN踩坑记:需对sign值进行URLEncoder编码

RSA加解签

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
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;

import java.io.*;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

public class RSA {

private static final String SIGN_TYPE_RSA = "RSA";

private static final String SIGN_TYPE_RSA2 = "RSA2";

private static final String SIGN_ALGORITHMS = "SHA1WithRSA";

private static final String SIGN_SHA256RSA_ALGORITHMS = "SHA256WithRSA";

private static final int DEFAULT_BUFFER_SIZE = 8192;

/**
* RSA/RSA2 加签
* @param signType
* @param privateKey
* @param content
* @param charset
* @return
* @throws Exception
*/
public static String rsaSign(String signType, String privateKey, String content, String charset) throws Exception {
PrivateKey priKey = null;
Signature signature = null;
if (SIGN_TYPE_RSA.equals(signType)) {
priKey = getPrivateKeyFromPKCS8(SIGN_TYPE_RSA, new ByteArrayInputStream(privateKey.getBytes()));
signature = java.security.Signature.getInstance(SIGN_ALGORITHMS);
} else if (SIGN_TYPE_RSA2.equals(signType)) {
priKey = getPrivateKeyFromPKCS8(SIGN_TYPE_RSA, new ByteArrayInputStream(privateKey.getBytes()));
signature = java.security.Signature.getInstance(SIGN_SHA256RSA_ALGORITHMS);
} else {
throw new Exception("不是支持的签名类型: signType=" + signType);
}
signature.initSign(priKey);

if (StringUtils.isEmpty(charset)) {
signature.update(content.getBytes());
} else {
signature.update(content.getBytes(charset));
}

byte[] signed = signature.sign();

return new String(Base64.encodeBase64(signed));
}

/**
* 验签方法
*
* @param content 参数的合成字符串格式: key1=value1&key2=value2&key3=value3
* @param signType
* @param sign
* @param publicKey
* @param content
* @param charset
* @return
*/
public static boolean rsaVerify(String signType, String sign, String publicKey, String content, String charset) throws Exception {
java.security.Signature signature = null;
PublicKey pubKey = getPublicKeyFromX509("RSA", new ByteArrayInputStream(publicKey.getBytes()));
if (SIGN_TYPE_RSA.equals(signType)) {
signature = java.security.Signature.getInstance(SIGN_ALGORITHMS);
} else if (SIGN_TYPE_RSA2.equals(signType)) {
signature = java.security.Signature.getInstance(SIGN_SHA256RSA_ALGORITHMS);
} else {
throw new Exception("不是支持的签名类型: signType=" + signType);
}
signature.initVerify(pubKey);

if (StringUtils.isEmpty(charset)) {
signature.update(content.getBytes());
} else {
signature.update(content.getBytes(charset));
}

return signature.verify(Base64.decodeBase64(sign.getBytes()));
}

private static PrivateKey getPrivateKeyFromPKCS8(String algorithm, InputStream ins) throws Exception {
if (ins == null || StringUtils.isEmpty(algorithm)) {
return null;
}

KeyFactory keyFactory = KeyFactory.getInstance(algorithm);

byte[] encodedKey = readText(ins).getBytes();

encodedKey = Base64.decodeBase64(encodedKey);

return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encodedKey));
}

private static PublicKey getPublicKeyFromX509(String algorithm, InputStream ins) throws Exception {
KeyFactory keyFactory = KeyFactory.getInstance(algorithm);

StringWriter writer = new StringWriter();
io(new InputStreamReader(ins), writer, -1);

byte[] encodedKey = writer.toString().getBytes();

encodedKey = Base64.decodeBase64(encodedKey);

return keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
}

private static String readText(InputStream ins) throws IOException {
Reader reader = new InputStreamReader(ins);
StringWriter writer = new StringWriter();

io(reader, writer, -1);
return writer.toString();
}

private static void io(Reader in, Writer out, int bufferSize) throws IOException {
if (bufferSize == -1) {
bufferSize = DEFAULT_BUFFER_SIZE >> 1;
}

char[] buffer = new char[bufferSize];
int amount;

while ((amount = in.read(buffer)) >= 0) {
out.write(buffer, 0, amount);
}
}

}

ILLEGAL_SIGN解决

1
2
3
4
5
6
7
8
9
10
11
12
13
private String getSign(String signType, String signKey, String content, String inputCharset) {
String sign = "";
if ("MD5".equalsIgnoreCase(signType)) {
sign = MD5.sign(content, signKey, inputCharset);
} else if ("RSA".equalsIgnoreCase(signType) || "RSA2".equalsIgnoreCase(signType)) {
try {
sign = RSA.rsaSign(signType, privateKey, content, inputCharset);
sign = URLEncoder.encode(sign, inputCharset); //解决ILLEGAL_SIGN
} catch (Exception e) {
}
}
return sign;
}

MD5加解签

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
import org.apache.commons.codec.digest.DigestUtils;

import java.io.UnsupportedEncodingException;
import java.security.SignatureException;

public class MD5 {

/**
* 签名字符串
*
* @param text 需要签名的字符串
* @param key 密钥
* @param charset 编码格式
* @return 签名结果
*/
public static String sign(String text, String key, String charset) {
text = text + key;
return DigestUtils.md5Hex(getContentBytes(text, charset));
}

/**
* 签名字符串
*
* @param text 需要签名的字符串
* @param sign 签名结果
* @param key 密钥
* @param charset 编码格式
* @return 签名结果
*/
public static boolean verify(String text, String sign, String key, String charset) {
text = text + key;
String mySign = DigestUtils.md5Hex(getContentBytes(text, 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 || "".equals(charset)) {
return content.getBytes();
}
try {
return content.getBytes(charset);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + charset);
}
}

}

Powered by AppBlog.CN     浙ICP备14037229号

Copyright © 2012 - 2020 APP开发技术博客 All Rights Reserved.

访客数 : | 访问量 :