Skip to content

签名代码示例

本文档提供 Java、Node.js、PHP 三种语言的签名与验签完整代码示例。

Java 示例

java
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;

public class SignUtil {

    /**
     * 计算请求体 SHA256 摘要
     */
    public static String sha256Hex(String body) throws Exception {
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        byte[] hash = digest.digest(body.getBytes("UTF-8"));
        StringBuilder hexString = new StringBuilder();
        for (byte b : hash) {
            hexString.append(String.format("%02x", b));
        }
        return hexString.toString();
    }

    /**
     * 构造签名串
     */
    public static String buildSignString(String serviceId, String timestamp, String nonceStr, String bodyDigest) {
        return serviceId + "\n" + timestamp + "\n" + nonceStr + "\n" + bodyDigest;
    }

    /**
     * 生成 RSA 签名
     */
    public static String sign(String serviceId, String timestamp, String nonceStr, String body, String privateKey) throws Exception {
        // 1. 计算请求体摘要
        String bodyDigest = sha256Hex(body);

        // 2. 构造签名串
        String signString = buildSignString(serviceId, timestamp, nonceStr, bodyDigest);

        // 3. 生成签名
        byte[] keyBytes = Base64.getDecoder().decode(privateKey);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey key = keyFactory.generatePrivate(keySpec);

        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(key);
        signature.update(signString.getBytes("UTF-8"));

        return Base64.getEncoder().encodeToString(signature.sign());
    }

    /**
     * 验证签名
     */
    public static boolean verify(String serviceId, String timestamp, String nonceStr, String body, String publicKey, String sign) throws Exception {
        // 1. 计算请求体摘要
        String bodyDigest = sha256Hex(body);

        // 2. 构造签名串
        String signString = buildSignString(serviceId, timestamp, nonceStr, bodyDigest);

        // 3. 验证签名
        byte[] keyBytes = Base64.getDecoder().decode(publicKey);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey key = keyFactory.generatePublic(new java.security.spec.X509EncodedKeySpec(keyBytes));

        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initVerify(key);
        signature.update(signString.getBytes("UTF-8"));

        return signature.verify(Base64.getDecoder().decode(sign));
    }
}

Node.js 示例

javascript
const crypto = require('crypto');

/**
 * 计算请求体 SHA256 摘要
 */
function sha256Hex(body) {
  return crypto.createHash('sha256').update(body).digest('hex');
}

/**
 * 构造签名串
 */
function buildSignString(serviceId, timestamp, nonceStr, bodyDigest) {
  return `${serviceId}\n${timestamp}\n${nonceStr}\n${bodyDigest}`;
}

/**
 * 生成 RSA 签名
 */
function sign(serviceId, timestamp, nonceStr, body, privateKey) {
  // 1. 计算请求体摘要
  const bodyDigest = sha256Hex(body);

  // 2. 构造签名串
  const signString = buildSignString(serviceId, timestamp, nonceStr, bodyDigest);

  // 3. 生成签名
  return crypto
    .createSign('RSA-SHA256')
    .update(signString)
    .sign(privateKey, 'base64');
}

/**
 * 验证签名
 */
function verify(serviceId, timestamp, nonceStr, body, publicKey, sign) {
  // 1. 计算请求体摘要
  const bodyDigest = sha256Hex(body);

  // 2. 构造签名串
  const signString = buildSignString(serviceId, timestamp, nonceStr, bodyDigest);

  // 3. 验证签名
  return crypto
    .createVerify('RSA-SHA256')
    .update(signString)
    .verify(publicKey, sign, 'base64');
}

// 使用示例
const body = JSON.stringify({
  merchant_no: '1234567890',
  out_trade_no: '20240101120000',
  total_amount: 100
});

const serviceId = 'SVC1234567890';
const timestamp = '1704067200';
const nonceStr = 'abc123def456';

const privateKey = `-----BEGIN PRIVATE KEY-----
Your Private Key Here
-----END PRIVATE KEY-----`;

const signValue = sign(serviceId, timestamp, nonceStr, body, privateKey);
console.log('签名值:', signValue);

PHP 示例

php
<?php

class SignUtil {

    /**
     * 计算请求体 SHA256 摘要
     */
    public static function sha256Hex($body) {
        return hash('sha256', $body);
    }

    /**
     * 构造签名串
     */
    public static function buildSignString($serviceId, $timestamp, $nonceStr, $bodyDigest) {
        return $serviceId . "\n" . $timestamp . "\n" . $nonceStr . "\n" . $bodyDigest;
    }

    /**
     * 生成 RSA 签名
     */
    public static function sign($serviceId, $timestamp, $nonceStr, $body, $privateKey) {
        // 1. 计算请求体摘要
        $bodyDigest = self::sha256Hex($body);

        // 2. 构造签名串
        $signString = self::buildSignString($serviceId, $timestamp, $nonceStr, $bodyDigest);

        // 3. 生成签名
        $privateKey = openssl_pkey_get_private($privateKey);
        openssl_sign($signString, $sign, $privateKey, OPENSSL_ALGO_SHA256);

        return base64_encode($sign);
    }

    /**
     * 验证签名
     */
    public static function verify($serviceId, $timestamp, $nonceStr, $body, $publicKey, $sign) {
        // 1. 计算请求体摘要
        $bodyDigest = self::sha256Hex($body);

        // 2. 构造签名串
        $signString = self::buildSignString($serviceId, $timestamp, $nonceStr, $bodyDigest);

        // 3. 验证签名
        $publicKey = openssl_pkey_get_public($publicKey);
        $result = openssl_verify($signString, base64_decode($sign), $publicKey, OPENSSL_ALGO_SHA256);

        return $result === 1;
    }
}

// 使用示例
$body = json_encode([
    'merchant_no' => '1234567890',
    'out_trade_no' => '20240101120000',
    'total_amount' => 100
]);

$serviceId = 'SVC1234567890';
$timestamp = '1704067200';
$nonceStr = 'abc123def456';

$privateKey = file_get_contents('private_key.pem');
$signValue = SignUtil::sign($serviceId, $timestamp, $nonceStr, $body, $privateKey);
echo "签名值: " . $signValue . PHP_EOL;

米付科技版权所有,保留所有权利