Appearance
1.2 签名示例代码
1.2.1 JAVA版本
Java
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.*;
import java.util.Base64;
public class Demo {
private static final String AES_KEY = "1234567812345678";
private static final String PRIVATE_KEY_PEM =
"-----BEGIN PRIVATE KEY-----\n" +
"MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAOXcXDlUfioHYK8x\n" +
"+PTip8W9bwh9fWmTT9gXQGVo+91UQ0V/uZe1eR/PZrsW3GgZEqA3qavj2xSg/q+i\n" +
"o8isZ2zm7qrzY0zvuCJ/ZTnqi1aGzlB2oH4CIq0nUtck/LeWS3Z5OQVQLB0FglRq\n" +
"atZ/feqdBsqgqqwfggMVZI6A6w2PAgMBAAECgYACT7Pxs6LNI2PafyMkuz66o0wB\n" +
"htmC/UM5RgqUuniF4joG8eDY4K9GHZzH1tQCi/X+/HBNVS43x+Knu3fwJaOolMzc\n" +
"WagAW8csDXrT9M1XxfXiw/X/rKoit6Z60z+2OPO/XozR2MuP9Z6MYrLHRvD3RySD\n" +
"rPK7ccogj3IJZ/4iUQJBAPYSb6Th2sb24flS8pxTgHMaBUeoRklnUMFW3UzpjsQV\n" +
"uVGfr+P3RcqpWGh+9IqhFdMoVDmnUnr4Om712GIOJvcCQQDvInxeS9TqZNzSpVaZ\n" +
"du7SL4tXEsZrgCpehtzQfEBCfReNTdEa25aseKSBqdpLyO8pgz5IjeFnU6ahifY0\n" +
"y7ApAkEA2A6R9nzUglQtT6QUH0x2ARo8vpEyvaq4Tjn971U3JFZKtC942bm4jtwo\n" +
"IwAtqTcNGa1UXpbapdwkOl8kEdyJOwJAQ0cKgmUHQ+KYldLaaFajnhKuOxMXK8tl\n" +
"IC8FFMrAMXSMGb8Y41uAKonOjoRA3C1ty9oWvcbc8XsBWFU+JWBg8QJBAJ1xeRPh\n" +
"SdYwi7GHNPQ4JruaYvrnBRK7XqYqHRBSMb8IFpDjWEoKJhr/rDoE/Z9x+pwgLsSM\n" +
"OsfW8fVMcwILSqg=\n" +
"-----END PRIVATE KEY-----\n";
private static final String PUBLIC_KEY_PEM =
"-----BEGIN PUBLIC KEY-----\n" +
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDl3Fw5VH4qB2CvMfj04qfFvW8I\n" +
"fX1pk0/YF0BlaPvdVENFf7mXtXkfz2a7FtxoGRKgN6mr49sUoP6voqPIrGds5u6q\n" +
"82NM77gif2U56otWhs5QdqB+AiKtJ1LXJPy3lkt2eTkFUCwdBYJUamrWf33qnQbK\n" +
"oKqsH4IDFWSOgOsNjwIDAQAB\n" +
"-----END PUBLIC KEY-----\n";
public static void main(String[] args) {
Map<String, Object> params = new LinkedHashMap<String, Object>();
params.put("username", "momo");
params.put("orderNo", "SH20220113111929");
String channelCode = "kld8956spceq";
String method = "userVerify";
String nonce = "5K8264ILTKCH16CQ2502SI8ZNMTM67VS";
String timestamp = "1568945678";
try {
String bizData = buildBizData(params, AES_KEY);
String signature = sign(bizData, channelCode, method, nonce, timestamp);
System.out.println(signature);
if (check(bizData, channelCode, method, nonce, timestamp, signature)) {
System.out.println("验签成功");
} else {
System.out.println("验签失败");
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// BuildBizData 加密入参
static String buildBizData(Map<String, Object> params, String aesKey) throws Exception {
String rawJson = toJsonSorted(params);
return aesEcbEncryptBase64(rawJson.getBytes(StandardCharsets.UTF_8), aesKey);
}
// Sign 返回签名
static String sign(String bizData, String channelCode, String method, String nonce, String timestamp) {
try {
String paramsStr = String.format("biz_data=%s&channel_code=%s&method=%s&nonce=%s×tamp=%s", bizData, channelCode, method, nonce, timestamp);
RSAPrivateKey privateKey = loadPrivateKeyFromPem(PRIVATE_KEY_PEM);
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(paramsStr.getBytes(StandardCharsets.UTF_8));
byte[] sig = signature.sign();
return Base64.getEncoder().encodeToString(sig);
} catch (Exception e) {
return "";
}
}
// Check 校验签名
static boolean check(String bizData, String channelCode, String method, String nonce, String timestamp, String signatureBase64) {
try {
String paramsStr = String.format("biz_data=%s&channel_code=%s&method=%s&nonce=%s×tamp=%s", bizData, channelCode, method, nonce, timestamp);
RSAPublicKey publicKey = loadPublicKeyFromPem(PUBLIC_KEY_PEM);
Signature verifier = Signature.getInstance("SHA256withRSA");
verifier.initVerify(publicKey);
verifier.update(paramsStr.getBytes(StandardCharsets.UTF_8));
byte[] sig = Base64.getDecoder().decode(signatureBase64);
return verifier.verify(sig);
} catch (Exception e) {
System.out.println(e.getMessage());
return false;
}
}
static String aesEcbEncryptBase64(byte[] rawData, String key) throws Exception {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] encryptData = cipher.doFinal(rawData);
return Base64.getEncoder().encodeToString(encryptData);
}
private static RSAPrivateKey loadPrivateKeyFromPem(String pem) throws Exception {
String normalized = pem.replace("-----BEGIN PRIVATE KEY-----", "")
.replace("-----END PRIVATE KEY-----", "")
.replaceAll("\\s", "");
byte[] keyBytes = Base64.getDecoder().decode(normalized);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
}
private static RSAPublicKey loadPublicKeyFromPem(String pem) throws Exception {
String normalized = pem.replace("-----BEGIN PUBLIC KEY-----", "")
.replace("-----END PUBLIC KEY-----", "")
.replaceAll("\\s", "");
byte[] keyBytes = Base64.getDecoder().decode(normalized);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
return (RSAPublicKey) keyFactory.generatePublic(keySpec);
}
// Minimal stable JSON: sort keys lexicographically like Go's encoding/json for maps
private static String toJsonSorted(Map<String, Object> map) {
List<String> keys = new ArrayList<String>(map.keySet());
Collections.sort(keys);
StringBuilder sb = new StringBuilder();
sb.append('{');
boolean first = true;
for (String k : keys) {
if (!first) sb.append(',');
first = false;
sb.append('"').append(escapeJson(k)).append('"').append(':');
Object v = map.get(k);
if (v == null) {
sb.append("null");
} else {
sb.append('"').append(escapeJson(String.valueOf(v))).append('"');
}
}
sb.append('}');
return sb.toString();
}
private static String escapeJson(String s) {
StringBuilder out = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
switch (c) {
case '"': out.append("\\\""); break;
case '\\': out.append("\\\\"); break;
case '\b': out.append("\\b"); break;
case '\f': out.append("\\f"); break;
case '\n': out.append("\\n"); break;
case '\r': out.append("\\r"); break;
case '\t': out.append("\\t"); break;
default:
if (c < 0x20) {
out.append(String.format("\\u%04x", (int) c));
} else {
out.append(c);
}
}
}
return out.toString();
}
}1.2.2 GO版本
go
package main
import (
"bytes"
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"encoding/json"
"encoding/pem"
"fmt"
"github.com/forgoer/openssl"
)
var aesKey = "1234567812345678"
var privateKey = []byte(`
-----BEGIN PRIVATE KEY-----
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAOXcXDlUfioHYK8x
+PTip8W9bwh9fWmTT9gXQGVo+91UQ0V/uZe1eR/PZrsW3GgZEqA3qavj2xSg/q+i
o8isZ2zm7qrzY0zvuCJ/ZTnqi1aGzlB2oH4CIq0nUtck/LeWS3Z5OQVQLB0FglRq
atZ/feqdBsqgqqwfggMVZI6A6w2PAgMBAAECgYACT7Pxs6LNI2PafyMkuz66o0wB
htmC/UM5RgqUuniF4joG8eDY4K9GHZzH1tQCi/X+/HBNVS43x+Knu3fwJaOolMzc
WagAW8csDXrT9M1XxfXiw/X/rKoit6Z60z+2OPO/XozR2MuP9Z6MYrLHRvD3RySD
rPK7ccogj3IJZ/4iUQJBAPYSb6Th2sb24flS8pxTgHMaBUeoRklnUMFW3UzpjsQV
uVGfr+P3RcqpWGh+9IqhFdMoVDmnUnr4Om712GIOJvcCQQDvInxeS9TqZNzSpVaZ
du7SL4tXEsZrgCpehtzQfEBCfReNTdEa25aseKSBqdpLyO8pgz5IjeFnU6ahifY0
y7ApAkEA2A6R9nzUglQtT6QUH0x2ARo8vpEyvaq4Tjn971U3JFZKtC942bm4jtwo
IwAtqTcNGa1UXpbapdwkOl8kEdyJOwJAQ0cKgmUHQ+KYldLaaFajnhKuOxMXK8tl
IC8FFMrAMXSMGb8Y41uAKonOjoRA3C1ty9oWvcbc8XsBWFU+JWBg8QJBAJ1xeRPh
SdYwi7GHNPQ4JruaYvrnBRK7XqYqHRBSMb8IFpDjWEoKJhr/rDoE/Z9x+pwgLsSM
OsfW8fVMcwILSqg=
-----END PRIVATE KEY-----
`)
var publicKey = []byte(`
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDl3Fw5VH4qB2CvMfj04qfFvW8I
fX1pk0/YF0BlaPvdVENFf7mXtXkfz2a7FtxoGRKgN6mr49sUoP6voqPIrGds5u6q
82NM77gif2U56otWhs5QdqB+AiKtJ1LXJPy3lkt2eTkFUCwdBYJUamrWf33qnQbK
oKqsH4IDFWSOgOsNjwIDAQAB
-----END PUBLIC KEY-----
`)
func main() {
params := map[string]interface{}{
"username": "momo",
"orderNo": "SH20220113111929",
}
channelCode := "kld8956spceq"
method := "userVerify"
nonce := "5K8264ILTKCH16CQ2502SI8ZNMTM67VS"
timestamp := "1568945678"
bizData, err := BuildBizData(params, aesKey)
if err != nil {
panic(err)
}
signature := Sign(bizData, channelCode, method, nonce, timestamp)
fmt.Println(signature)
if Check(bizData, channelCode, method, nonce, timestamp, signature) {
fmt.Println("验签成功")
} else {
fmt.Println("验签失败")
}
}
// BuildBizData 加密入参
func BuildBizData(params map[string]interface{}, aesKey string) (string, error) {
rawData, err := json.Marshal(params)
if err != nil {
return "", err
}
return AesEcbEncryptBase64(rawData, aesKey)
}
// Sign 返回签名
func Sign(bizData, channelCode, method, nonce, timestamp string) string {
paramsStr := fmt.Sprintf("biz_data=%s&channel_code=%s&method=%s&nonce=%s×tamp=%s", bizData, channelCode, method, nonce, timestamp)
messageBuffer := bytes.NewBufferString(paramsStr)
hash := sha256.New()
_, _ = hash.Write(messageBuffer.Bytes())
digest := hash.Sum(nil)
// pem解码
block, _ := pem.Decode(privateKey)
var rsaPrivateKey interface{}
// x509解码
rsaPrivateKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return ""
}
signature, err := rsa.SignPKCS1v15(rand.Reader, rsaPrivateKey.(*rsa.PrivateKey), crypto.SHA256, digest)
if err != nil {
return ""
}
return base64.StdEncoding.EncodeToString(signature)
}
// Check 校验签名
func Check(bizData, channelCode, method, nonce, timestamp, signature string) bool {
paramsStr := fmt.Sprintf("biz_data=%s&channel_code=%s&method=%s&nonce=%s×tamp=%s", bizData, channelCode, method, nonce, timestamp)
messageBuffer := bytes.NewBufferString(paramsStr)
hash := sha256.New()
_, _ = hash.Write(messageBuffer.Bytes())
digest := hash.Sum(nil)
// pem解码
block, _ := pem.Decode(publicKey)
// x509解码
publicKeyInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
fmt.Println(err)
return false
}
sig, err := base64.StdEncoding.DecodeString(signature)
if err != nil {
fmt.Println(err)
return false
}
// 类型断言
pk := publicKeyInterface.(*rsa.PublicKey)
if err := rsa.VerifyPKCS1v15(pk, crypto.SHA256, digest, sig); err != nil {
fmt.Println(err)
return false
}
return true
}
func AesEcbEncryptBase64(rawData []byte, key string) (string, error) {
encryptData, err := openssl.AesECBEncrypt(rawData, []byte(key), openssl.PKCS5_PADDING)
if err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(encryptData), nil
}