API签名生成

# 签名统一生成规则

只有参数值参与签名, Key(参数名) 只进行排序,不参与签名计算

  1. 将所有非空参数的 Key(参数名) 按照 ASCII 排序
  2. 按 Key(参数名) 的顺序,逐个取参数值进并行拼接后,采用 RSA 算法对字符串计算,算出签名字符串

# 示例说明

  • 示例参数
参数 示例
merchantCode S820211021094748000001
method BCA
orderNum T1642592278863
payMoney 10000
productDetail Test Pay
notifyUrl your notify url
dateTime 20221202125813
name JackMa
expiryPeriod 1440
email [email protected]
phone 082122965511
  • 拼接字符串
  1. 首先把 Key (参数名) 按照ASCII排序
  2. 然后根据 Key (参数名) 排序后顺序取值并拼接成字符串

strA = 20221202125813test@email.com1440S820211021094748000001BCAJackMayour notify urlT164259227886310000082122965511Test Pay

  • 计算签名
  1. 使用您在 TopPay商户后台 配置的密钥对
  2. 用您的 私钥(privateKey) 进行加密计算RSA(StrA)获取到最终的签名字符串

Sign = IMLn23c4orM+7pZhHoRmbjrol4X33jeAqFxbZuQ+pnznBIGhb6 ...

# 代码示例

import com.google.gson.JsonObject;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.apache.tomcat.util.http.fileupload.IOUtils;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * TopPay RSA签名工具类
 * 
 * Author: TopPay
 */
public class TopPayRequestUtil {

  /**
   * 验证签名
   * 
   * @param params
   * @return
   */
  public static boolean verifySign(JsonObject params, String publickey) throws InvalidKeySpecException, NoSuchAlgorithmException {
    String platSign = params.remove("platSign").getAsString(); // 签名
    List<String> paramNameList = new ArrayList<>(params.keySet());
    Collections.sort(paramNameList);

    StringBuilder stringBuilder = new StringBuilder();
    for (String name : paramNameList) {
      stringBuilder.append(params.get(name).getAsString());
    }
    System.out.println("keys:" + stringBuilder);

    String decryptSign = publicDecrypt(platSign, getPublicKey(publickey));
    System.out.println("decryptSign:" + decryptSign);
    
    return stringBuilder.toString().equals(decryptSign);
  }

  /**
   * 私钥加密
   * 
   * @param data
   * @param privateKey
   * @return
   */
  public static String privateEncrypt(String data, RSAPrivateKey privateKey) {
    try {
      Cipher cipher = Cipher.getInstance("RSA");
      cipher.init(Cipher.ENCRYPT_MODE, privateKey);
      return Base64.encodeBase64String(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes("UTF-8"), privateKey.getModulus().bitLength()));
    } catch (Exception e) {
      throw new RuntimeException("加密字符串[" + data + "]时遇到异常", e);
    }
  }

  /**
   * 公钥解密
   * 
   * @param data
   * @param publicKey
   * @return
   */
  public static String publicDecrypt(String data, RSAPublicKey publicKey) {
    try {
      Cipher cipher = Cipher.getInstance("RSA");
      cipher.init(Cipher.DECRYPT_MODE, publicKey);
      return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data), publicKey.getModulus().bitLength()),"UTF-8");
    } catch (Exception e) {
      throw new RuntimeException("解密字符串[" + data + "]时遇到异常", e);
    }
  }

  /**
   * 得到私钥
   * 
   * @param privateKey 密钥字符串(经过base64编码)
   */
  public static RSAPrivateKey getPrivateKey(String privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
    // 通过PKCS#8编码的Key指令获得私钥对象
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey));
    RSAPrivateKey key = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec);
    return key;
  }

  /**
   * 得到公钥
   * 
   * @param publicKey 密钥字符串(经过base64编码)
   */
  public static RSAPublicKey getPublicKey(String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
    // 通过X509编码的Key指令获得公钥对象
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKey));
    RSAPublicKey key = (RSAPublicKey) keyFactory.generatePublic(x509KeySpec);
    return key;
  }

  private static byte[] rsaSplitCodec(Cipher cipher, int opmode, byte[] datas, int keySize) {
    int maxBlock = 0;
    if (opmode == Cipher.DECRYPT_MODE) {
      maxBlock = keySize / 8;
    } else {
      maxBlock = keySize / 8 -11;
    }
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    int offSet = 0;
    byte[] buff;
    int i = 0;
    try {
      while (datas.length > offSet) {
        if (datas.length - offSet > maxBlock) {
          buff = cipher.doFinal(datas, offSet, maxBlock);
        } else {
          buff = cipher.doFinal(datas, offSet, datas.length - offSet);
        }
        out.write(buff, 0, buff.length);
        i++;
        offSet = i * maxBlock;
      }
    } catch (Exception e) {
      throw new RuntimeException("加解密阀值为[" + maxBlock + "]的数据时发生异常", e);
    }
    byte[] resultDatas = out.toByteArray();
    IOUtils.closeQuietly(out);
    return resultDatas;
  }

  public static String doPost(String url, String json) throws IOException {
    HttpClient client = new DefaultHttpClient();
    HttpPost post = new HttpPost(url);
    StringEntity s = new StringEntity(json);
    s.setContentEncoding("UTF-8");
    s.setContentType("application/json");//发送json数据需要设置contentType
    post.setEntity(s);
    HttpResponse res = client.execute(post);
    if (res.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
      return EntityUtils.toString(res.getEntity());// 返回json格式:
    }
    return null;
  }
}

<?php
header('Content-Type: text/html; charset=utf-8');
class Rsa{
  public function __construct($platPublicKey, $mchPrivateKey){
    // 从文件中读取公钥和私钥
    $this->publicKey = openssl_pkey_get_public($platPublicKey);
    if (!$this->publicKey) {
      die('Load public key error');
    }
    $this->privateKey = openssl_pkey_get_private($mchPrivateKey);
    if (!$this->privateKey) {
      die('Load private key error');
    }
  }

  //私钥加密数据
  public function pivate_key_encrypt($data){
    $crypto = '';
    foreach (str_split($data, 117) as $chunk) {
      openssl_private_encrypt($chunk, $encryptData, $this->privateKey);
      $crypto .= $encryptData;
    }
    return base64_encode($crypto); // 签名后的数据进行base64编码以便传输
  }

  //公钥解密签名数据
  public function public_key_decrypt($encryptedData){
    $encryptedData = base64_decode($encryptedData); // 解码收到的签名
    if ($encryptedData === false) {
      echo "Failed to base64 decode the data.\n";
      return false;
    }
    if (openssl_public_decrypt($encryptedData, $decrypted, $this->publicKey)) {
      return $decrypted; // 解密成功,返回解密后的数据
    } else {
      // 打印所有 OpenSSL 错误信息
      while ($msg = openssl_error_string()) {
        echo "OpenSSL Error: $msg\n";
      }
      return false; // 解密失败
    }
  }
}

//下述代码为调试代码
//请注意:请求数据加密使用商户私钥,解密通知使用平台公钥
//商户私钥
$mchPrivateKey = '-----BEGIN PRIVATE KEY-----'."\n".'MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAK8ZBceS0SgKtD8Scxx5jhBVzXkofK9bV4/JiZKpkkL327iBx1vNhi66fDuSqx0gpZKM9Xqr/hxzzrrlk4W5QfxbyIUx06a4Y7RBFQi+J/T2GHJbJozsik8yVTb6jJ0BZaOBzwkWYNm3V1Zsy5o5L1HD3n3BQ6hCltArjIPfsGPTAgMBAAECgYBtrMS7/zBXXm0MXKgRm+nqPXRYgY2n4RT1kY1EekaM/+d2qIOQ8ykrN8/9GJ9pvTs4kmZokja256sD0i0XQ7UaLXYp31jTU4HlNpB8ixiCQG0gvldZRlLlGEeCeNrCQXT88dqC9mmvR7FIvS1sUnDonMZXEtJC8HOL4L80P52P0QJBAN3aovKYaCtmbtmYc76U+CqxyijRCxqV1Cb6u+YFY423FrFG2hXhdVu8UmgV+VvgT5lh0VQyKzVqRIdwk1hwzW8CQQDKDB8alSSBgcaEhlQkuTUjz4TwnYa5UhDuwzIs9FC2QLbBMa5alUiJDVlqVc33WzAHmGBJPRtMnnsGlgPeQiXdAkEAw9GVfjeTyqrxMNLlZtSqb1TaMUjCWkbhKT6q1w7unkl6mCMHn8SPB9ejjQfIP5Yv7Bxw3bYieVVBA6MUCz4VtQJAKju8aK8SMWvyFhOKFR8Np42iKTWUSrqHxZDRtSngkSgXy2xaGJ8pyVQcA6kp43GRKZVFUynNwgdCig7jghrrlQJBANfIE+D+PcFLSC8pRmX0sPhTLbuSFORgRzvpovW/FGXonNRp/yPWgIdXzpJKb40IFbbPEPjZtHKRJwSWWBDEfuk='."\n".'-----END PRIVATE KEY-----';
//平台公钥
$platPublicKey = '-----BEGIN PUBLIC KEY-----'."\n".'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCvGQXHktEoCrQ/EnMceY4QVc15KHyvW1ePyYmSqZJC99u4gcdbzYYuunw7kqsdIKWSjPV6q/4cc8665ZOFuUH8W8iFMdOmuGO0QRUIvif09hhyWyaM7IpPMlU2+oydAWWjgc8JFmDZt1dWbMuaOS9Rw959wUOoQpbQK4yD37Bj0wIDAQAB'."\n".'-----END PUBLIC KEY-----';
//调用加解密工具类
$encryptionTool = new Rsa($platPublicKey, $mchPrivateKey);
$merchantCode = 'S820230414142102000012';
$orderType = '0';
$orderNum = 'TEST202404121503';
$money = '22.00';
$name = 'สวัสดี สวัสดี';
$name_ch = '测试';
$dateTime = date("YmdHis",time());
$params = array(
  'merchantCode' => $merchantCode,
  'orderType' => $orderType,
  'orderNum' => $orderNum,
  'money' => $money,
  'dateTime' => $dateTime,
  'name' => $name,
  'name_ch' => $name_ch,
);
//数据排序拼接
ksort($params);
$params_str = '';
foreach ($params as $key => $val) {
    $params_str = $params_str . $val;
}
$signature = $encryptionTool->pivate_key_encrypt($params_str);
$decryptedData = $encryptionTool->public_key_decrypt($signature);
echo "Data: " . $params_str . "<br>";
echo "Signature: " . $signature . "<br>";
echo "DecryptedData: " . $decryptedData . "<br>";
?>

using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Encodings;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.X509;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace demo.utils
{
  public class RSAForJava
  {

    public RSAForJava() 
    {

    }
    /// <summary>
    /// KEY 结构体
    /// </summary>
    public struct RSAKEY
    {
      /// <summary>
      /// 公钥
      /// </summary>
      public string PublicKey
      {
        get;
        set;
      }
      /// <summary>
      /// 私钥
      /// </summary>
      public string PrivateKey
      {
        get;
        set;
      }
    }

    public RSAKEY GetKey() {
      // RSA密钥对的构造器
      RsaKeyPairGenerator keyGenerator = new RsaKeyPairGenerator();

      // RSA密钥构造器的参数
      RsaKeyGenerationParameters param = new RsaKeyGenerationParameters(
        Org.BouncyCastle.Math.BigInteger.ValueOf(3),
        new Org.BouncyCastle.Security.SecureRandom(),
        1024, // 密钥长度
        25);
      // 用参数初始化密钥构造器
      keyGenerator.Init(param);
      // 产生密钥对
      AsymmetricCipherKeyPair keyPair = keyGenerator.GenerateKeyPair();
      // 获取公钥和密钥
      AsymmetricKeyParameter publicKey = keyPair.Public;
      AsymmetricKeyParameter privateKey = keyPair.Private;

      SubjectPublicKeyInfo subjectPublicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey);
      PrivateKeyInfo privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(privateKey);

      Asn1Object asn1ObjectPublic = subjectPublicKeyInfo.ToAsn1Object();

      byte[] publicInfoByte = asn1ObjectPublic.GetEncoded("UTF-8");
      Asn1Object asn1ObjectPrivate = privateKeyInfo.ToAsn1Object();
      byte[] privateInfoByte = asn1ObjectPrivate.GetEncoded("UTF-8");

      RSAKEY item = new RSAKEY()
      {
        PublicKey = Convert.ToBase64String(publicInfoByte),
        PrivateKey = Convert.ToBase64String(privateInfoByte)
      };
      return item;
    }
    private AsymmetricKeyParameter GetPublicKeyParameter(string s)
    {
      s = s.Replace("\r", "").Replace("\n", "").Replace(" ", "");
      byte[] publicInfoByte = Convert.FromBase64String(s);
      Asn1Object pubKeyObj = Asn1Object.FromByteArray(publicInfoByte);// 这里也可以从流中读取,从本地导入
      AsymmetricKeyParameter pubKey = PublicKeyFactory.CreateKey(publicInfoByte);
      return pubKey;
    }
    private AsymmetricKeyParameter GetPrivateKeyParameter(string s)
    {
      s = s.Replace("\r", "").Replace("\n", "").Replace(" ", "");
      byte[] privateInfoByte = Convert.FromBase64String(s);
      // Asn1Object priKeyObj = Asn1Object.FromByteArray(privateInfoByte);// 这里也可以从流中读取,从本地导入
      // PrivateKeyInfo privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(privateKey);
      AsymmetricKeyParameter priKey = PrivateKeyFactory.CreateKey(privateInfoByte);
      return priKey;
    }

    private static StreamReader GetStreamReader(string content)
    {
      byte[] bytes = Encoding.UTF8.GetBytes(content);
      var memory = new MemoryStream(bytes);
      var reader = new StreamReader(memory);
      return reader;
    }

    public string EncryptByPrivateKey(string s, string key)
    {
      // 非对称加密算法,加解密用
      IAsymmetricBlockCipher engine = new Pkcs1Encoding(new RsaEngine());
      // 加密
      try
      {
        engine.Init(true, GetPrivateKeyParameter(key));
        byte[] byteData = System.Text.Encoding.UTF8.GetBytes(s);

        byte[] result = new byte[] { };
        for (int i = 0, j = byteData.Length / 117 + (byteData.Length % 117 == 0 ? 0 : 1); i < j; i++)
        {
          byte[] getData = byteData.Skip(i * 117).Take(117).ToArray();
          byte[] ResultData = engine.ProcessBlock(getData, 0, getData.Length);
          result = result.Concat(ResultData).ToArray();
        }

        // var ResultData = engine.ProcessBlock(byteData, 0, byteData.Length);
        return Convert.ToBase64String(result);

        // Console.WriteLine("密文(base64编码):" + Convert.ToBase64String(testData) + Environment.NewLine);
      }
      catch (Exception ex)
      {
        return ex.Message;
      }
    }
    public string DecryptByPublicKey(string s, string key)
    {
      s = s.Replace("\r", "").Replace("\n", "").Replace(" ", "");
      // 非对称加密算法,加解密用
      IAsymmetricBlockCipher engine = new Pkcs1Encoding(new RsaEngine());
      // 解密
      try
      {
        engine.Init(false, GetPublicKeyParameter(key));
        byte[] byteData = Convert.FromBase64String(s);

        string all = "";

        for (int i = 0, j = byteData.Length / 128 + (byteData.Length % 128 == 0 ? 0 : 1); i < j; i++)
        {
          byte[] getData = byteData.Skip(i * 128).Take(128).ToArray();
          byte[] ResultData = engine.ProcessBlock(getData, 0, getData.Length);
          all += Encoding.UTF8.GetString(ResultData);
        }
        return all;
        // var ResultData = engine.ProcessBlock(byteData, 0, byteData.Length);
        // return System.Text.Encoding.UTF8.GetString(ResultData);
      }
      catch (Exception ex)
      {
        return ex.Message;
      }
    }

    /// <summary>
    /// 验证签名
    /// </summary>
    /// <param name="?"></param>
    /// <returns></returns>
    public bool verifySign(Dictionary<string, object> dict, string publickey)
    {
      string platSign = dict["platSign"].ToString().Trim(); // 签名
      List<string> paramNameList = new List<string>();
      foreach (string key in dict.Keys)
      {
        if (!"platSign".Equals(key))
        {
          paramNameList.Add(key);
        }
      }
      paramNameList.Sort();
      StringBuilder stringBuilder = new StringBuilder();
      for (int i = 0; i < paramNameList.Count; i++)
      {
        string name = paramNameList[i];
        stringBuilder.Append(dict[name]);
      }
      
      String decryptSign = "";
      try
      {
        decryptSign = DecryptByPublicKey(platSign, publickey);
      }
      catch (Exception ex)
      {
        Console.WriteLine(ex.Message);
      }

      if (!stringBuilder.ToString().Equals(decryptSign, StringComparison.OrdinalIgnoreCase))
      {
        return false;
      }
      return true;
    }
  }
}

package rsa_ext

import (
  "bytes"
  "crypto"
  "crypto/rand"
  "crypto/rsa"
  "crypto/sha512"
  "crypto/x509"
  "encoding/base64"
  "encoding/pem"
  "errors"
  "hash"
  "io"
  "io/ioutil"
  "math/big"
  "os"
)

var (
  ErrNoPubKey        = errors.New("no pub key input")
  ErrDuplicatePubKey = errors.New("duplicate pub key specify")
  ErrNoPriKey        = errors.New("no pri key input")
  ErrDuplicatePriKey = errors.New("duplicate pri key specify")
  ErrNoPem           = errors.New("no pem")
  ErrDataToLarge     = errors.New("message too long for RSA public key size")
  ErrDataLen         = errors.New("data length error")
  ErrDataBroken      = errors.New("data broken, first byte is not zero")
  ErrKeyPairDismatch = errors.New("data is not encrypted by the private key")
  ErrDecryption      = errors.New("decryption error")
)

type Cryptor struct {
  pub     *rsa.PublicKey
  pri     *rsa.PrivateKey
  PubPath string // 公钥地址
  PriPath string // 私钥地址
  Pub64   string // 公钥主题不含头尾
  Pri64   string // 私钥主体不含头尾
}

func NewCryptor() *Cryptor {
  return &Cryptor{}
}

func (r *Cryptor) loadPubKey() {
  if r.pub != nil {
    return
  }
  if r.PubPath == "" && r.Pub64 == "" {
    panic(ErrNoPubKey)
  }
  if r.PubPath != "" && r.Pub64 != "" {
    panic(ErrDuplicatePubKey)
  }
  var keyByte []byte
  if r.PubPath != "" {
    keyByte = ReadFile(r.PubPath)
    block, _ := pem.Decode([]byte(keyByte))
    if block == nil {
      panic(ErrNoPem)
    }
    keyByte = block.Bytes
  }
  if r.Pub64 != "" {
    var err error
    keyByte, err = base64.StdEncoding.DecodeString(r.Pub64)
    CheckErr(err)
  }
  publicKeyInterface, err := x509.ParsePKIXPublicKey(keyByte)
  if err != nil {
    publicKeyInterface, err = x509.ParsePKCS1PublicKey(keyByte)
    CheckErr(err)
  }
  r.pub = publicKeyInterface.(*rsa.PublicKey)
}

func (r *Cryptor) loadPriKey() {
  if r.pri != nil {
    return
  }
  if r.PriPath == "" && r.Pri64 == "" {
    panic(ErrNoPriKey)
  }
  if r.PriPath != "" && r.Pri64 != "" {
    panic(ErrDuplicatePriKey)
  }
  var keyByte []byte
  if r.PriPath != "" {
    keyByte = ReadFile(r.PriPath)
    block, _ := pem.Decode([]byte(keyByte))
    if block == nil {
      panic(ErrNoPem)
    }
    keyByte = block.Bytes
  }
  if r.Pri64 != "" {
    var err error
    keyByte, err = base64.StdEncoding.DecodeString(r.Pri64)
    CheckErr(err)
  }
  privateKey, err := x509.ParsePKCS8PrivateKey(keyByte)
  if err != nil {
    privateKey, err = x509.ParsePKCS1PrivateKey(keyByte)
    CheckErr(err)
  }
  r.pri = privateKey.(*rsa.PrivateKey)
}

// 公钥加密
func (r *Cryptor) Encrypt(plainText []byte) []byte {
  r.loadPubKey()
  cipherText, err := rsa.EncryptPKCS1v15(rand.Reader, r.pub, plainText)
  CheckErr(err)
  return cipherText
}

// 私钥解密
func (r *Cryptor) Decrypt(cipherText []byte) []byte {
  r.loadPriKey()
  plainText, _ := rsa.DecryptPKCS1v15(rand.Reader, r.pri, cipherText)
  return plainText
}

// 签名 默认SHA512
func (r *Cryptor) Sign(data []byte) []byte {
  return r.SignWithHash(data, sha512.New(), crypto.SHA512)
}

// 签名 指定Hash算法 hash和hashType要保持一直
func (r *Cryptor) SignWithHash(data []byte, h hash.Hash, hashType crypto.Hash) []byte {
  r.loadPriKey()
  h.Write([]byte(data))
  signature, err := rsa.SignPKCS1v15(rand.Reader, r.pri, hashType, h.Sum(nil))
  CheckErr(err)
  return signature
}

// 验签 默认sha512
func (r *Cryptor) Verify(data []byte, sign []byte) error {
  return r.VerifyWithHash(data, sign, sha512.New(), crypto.SHA512)
}

// 验签 指定Hash算法 hash和hashType要保持一直
func (r *Cryptor) VerifyWithHash(data []byte, sign []byte, h hash.Hash, hashType crypto.Hash) error {
  r.loadPubKey()
  h.Write(data)
  return rsa.VerifyPKCS1v15(r.pub, hashType, h.Sum(nil), sign)
}

func ReadFile(path string) []byte {
  file, err := os.Open(path)
  CheckErr(err)
  defer file.Close()
  info, err := file.Stat()
  CheckErr(err)
  buf := make([]byte, info.Size())
  _, err = file.Read(buf)
  CheckErr(err)
  return buf
}

// 私钥加密
func (r *Cryptor) PriEncrypt(input []byte) []byte {
  r.loadPriKey()
  output := bytes.NewBuffer(nil)
  err := priKeyIO(r.pri, bytes.NewReader(input), output, true)
  CheckErr(err)
  out, err := ioutil.ReadAll(output)
  CheckErr(err)
  return out
}

// 公钥解密
func (r *Cryptor) PubDecrypt(input []byte) []byte {
  r.loadPubKey()
  output := bytes.NewBuffer(nil)
  err := pubKeyIO(r.pub, bytes.NewReader(input), output, false)
  CheckErr(err)
  out, err := ioutil.ReadAll(output)
  CheckErr(err)
  return out
}

// 私钥加密或解密Reader
func priKeyIO(pri *rsa.PrivateKey, r io.Reader, w io.Writer, isEncrypt bool) (err error) {
  k := (pri.N.BitLen() + 7) / 8
  if isEncrypt {
    k = k - 11
  }
  buf := make([]byte, k)
  var b []byte
  size := 0
  for {
    size, err = r.Read(buf)
    if err != nil {
      if err == io.EOF {
        return nil
      }
      return err
    }
    if size < k {
      b = buf[:size]
    } else {
      b = buf
    }
    if isEncrypt {
      b, err = priKeyEncrypt(rand.Reader, pri, b)
    } else {
      b, err = rsa.DecryptPKCS1v15(rand.Reader, pri, b)
    }
    if err != nil {
      return err
    }
    if _, err = w.Write(b); err != nil {
      return err
    }
  }
}

// 公钥加密或解密Reader
func pubKeyIO(pub *rsa.PublicKey, in io.Reader, out io.Writer, isEncrytp bool) (err error) {
  k := (pub.N.BitLen() + 7) / 8
  if isEncrytp {
    k = k - 11
  }
  buf := make([]byte, k)
  var b []byte
  size := 0
  for {
    size, err = in.Read(buf)
    if err != nil {
      if err == io.EOF {
        return nil
      }
      return err
    }
    if size < k {
      b = buf[:size]
    } else {
      b = buf
    }
    if isEncrytp {
      b, err = rsa.EncryptPKCS1v15(rand.Reader, pub, b)
    } else {
      b, err = pubKeyDecrypt(pub, b)
    }
    if err != nil {
      return err
    }
    if _, err = out.Write(b); err != nil {
      return err
    }
  }
}

// 公钥解密
func pubKeyDecrypt(pub *rsa.PublicKey, data []byte) ([]byte, error) {
  k := (pub.N.BitLen() + 7) / 8
  if k != len(data) {
    return nil, ErrDataLen
  }
  m := new(big.Int).SetBytes(data)
  if m.Cmp(pub.N) > 0 {
    return nil, ErrDataToLarge
  }
  m.Exp(m, big.NewInt(int64(pub.E)), pub.N)
  d := leftPad(m.Bytes(), k)
  if d[0] != 0 {
    return nil, ErrDataBroken
  }
  if d[1] != 0 && d[1] != 1 {
    return nil, ErrKeyPairDismatch
  }
  var i = 2
  for ; i < len(d); i++ {
    if d[i] == 0 {
      break
    }
  }
  i++
  if i == len(d) {
    return nil, nil
  }
  return d[i:], nil
}

// 从crypto/rsa复制
func leftPad(input []byte, size int) (out []byte) {
  n := len(input)
  if n > size {
    n = size
  }
  out = make([]byte, size)
  copy(out[len(out)-n:], input)
  return
}

// 私钥加密
func priKeyEncrypt(rand io.Reader, priv *rsa.PrivateKey, hashed []byte) ([]byte, error) {
  tLen := len(hashed)
  k := (priv.N.BitLen() + 7) / 8
  if k < tLen+11 {
    return nil, ErrDataLen
  }
  em := make([]byte, k)
  em[1] = 1
  for i := 2; i < k-tLen-1; i++ {
    em[i] = 0xff
  }
  copy(em[k-tLen:k], hashed)
  m := new(big.Int).SetBytes(em)
  c, err := decrypt(rand, priv, m)
  if err != nil {
    return nil, err
  }
  copyWithLeftPad(em, c.Bytes())
  return em, nil
}

// 从crypto/rsa复制
var bigZero = big.NewInt(0)
var bigOne = big.NewInt(1)

func decrypt(random io.Reader, priv *rsa.PrivateKey, c *big.Int) (m *big.Int, err error) {
  if c.Cmp(priv.N) > 0 {
    err = ErrDecryption
    return
  }
  var ir *big.Int
  if random != nil {
    var r *big.Int

    for {
      r, err = rand.Int(random, priv.N)
      if err != nil {
        return
      }
      if r.Cmp(bigZero) == 0 {
        r = bigOne
      }
      var ok bool
      ir, ok = modInverse(r, priv.N)
      if ok {
        break
      }
    }
    bigE := big.NewInt(int64(priv.E))
    rpowe := new(big.Int).Exp(r, bigE, priv.N)
    cCopy := new(big.Int).Set(c)
    cCopy.Mul(cCopy, rpowe)
    cCopy.Mod(cCopy, priv.N)
    c = cCopy
  }
  if priv.Precomputed.Dp == nil {
    m = new(big.Int).Exp(c, priv.D, priv.N)
  } else {
    m = new(big.Int).Exp(c, priv.Precomputed.Dp, priv.Primes[0])
    m2 := new(big.Int).Exp(c, priv.Precomputed.Dq, priv.Primes[1])
    m.Sub(m, m2)
    if m.Sign() < 0 {
      m.Add(m, priv.Primes[0])
    }
    m.Mul(m, priv.Precomputed.Qinv)
    m.Mod(m, priv.Primes[0])
    m.Mul(m, priv.Primes[1])
    m.Add(m, m2)

    for i, values := range priv.Precomputed.CRTValues {
      prime := priv.Primes[2+i]
      m2.Exp(c, values.Exp, prime)
      m2.Sub(m2, m)
      m2.Mul(m2, values.Coeff)
      m2.Mod(m2, prime)
      if m2.Sign() < 0 {
        m2.Add(m2, prime)
      }
      m2.Mul(m2, values.R)
      m.Add(m, m2)
    }
  }
  if ir != nil {
    m.Mul(m, ir)
    m.Mod(m, priv.N)
  }

  return
}

// 从crypto/rsa复制
func modInverse(a, n *big.Int) (ia *big.Int, ok bool) {
  g := new(big.Int)
  x := new(big.Int)
  y := new(big.Int)
  g.GCD(x, y, a, n)
  if g.Cmp(bigOne) != 0 {
    return
  }
  if x.Cmp(bigOne) < 0 {
    x.Add(x, n)
  }
  return x, true
}

// 从crypto/rsa复制
func copyWithLeftPad(dest, src []byte) {
  numPaddingBytes := len(dest) - len(src)
  for i := 0; i < numPaddingBytes; i++ {
    dest[i] = 0
  }
  copy(dest[numPaddingBytes:], src)
}

func CheckErr(err error) {
  if err != nil {
    panic(err)
  }
}

from M2Crypto import RSA

# 生成RSA密钥对
rsa_key = RSA.gen_key(2048, 65537)

# 待加密的数据
data_to_encrypt = b'Hello, RSA!'

# 使用私钥加密数据
encrypted_data = rsa_key.private_encrypt(data_to_encrypt, RSA.pkcs1_padding)

# 使用公钥解密数据
try:
  decrypted_data = rsa_key.public_decrypt(encrypted_data, RSA.pkcs1_padding)
  print("Decrypted data:", decrypted_data)
except RSA.RSAError as e:
  print("RSAError:", e)

const crypto = require('crypto');

const nodeRSA = require('node-rsa');

// 该公私钥仅供示例,业务对接时,请使用真实密钥对
const privateKey = `-----BEGIN PRIVATE KEY-----
MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAKGFQO+Gu+a1Vc08jsYL7v2dKIitgAeFPSNDOyNBUnbH3IFFfk0lNGHZQ45pvicFMARshBDzR7jJynl/F+JYkQBoqFQIRVsEHMWkq3+3QapCjknNq+H2Vnd41swxaWy3lNTgN532ia04LBghWxCJo4/ZMBsUX8qCSTer1lvSsFkXAgMBAAECgYA7hPUWztly/KNvi78477DTuBP1uamSG+EZm26xYSLYLnHtGQSfvPP+kqc4VXMCwgCdwLcx39QwHfwEpXbRq71SiUHiiwaZncNIWLFiUzy23DDc6GlP5VPp/bCMWrIukE0zp4a4Il7Uq7smDAM1oZFv44PMJfX52iFdmO1DSKX0YQJBANOwqgt6AjVuBZErpe5bZdZAxXFR3utc2hcQza4XmK1bxrKK3IfK7qslyGc+OrW5HzCzBQM3M5tGAPmFDmalMg8CQQDDVEV29muQ9R1cLcAVMLPNeBkMwukLO0J/iJ4JN+hS8bcOdpdQ8pyaNqbUMpHkYKP0PhS2dcieAVRlVAj8mVB5AkBNH+9EESae2r/SfSmOJuR6Y8zLlX13GLQodSnKhLRObMJ+qBLism+0ESbrXoO7U3/mmUJ5QnJd3upZ/j0Z7pPHAkBQOXtyWdFiLxpI8s1yppciq9H2CNO4djVgthbaiGjWMErUGOcbKxogyJOKkd6T4xFTzm+pZQTpyHgGShaK0NlZAkBMst7KZNxDMwRTImCCi03GU42uKfpzK9pK3cjyU2eYftNXAfEmfB49uxXW839m9vYQvJBltYUbbsLsMdJBkrNT
-----END PRIVATE KEY-----`;

const publicKey = `-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQChhUDvhrvmtVXNPI7GC+79nSiIrYAHhT0jQzsjQVJ2x9yBRX5NJTRh2UOOab4nBTAEbIQQ80e4ycp5fxfiWJEAaKhUCEVbBBzFpKt/t0GqQo5Jzavh9lZ3eNbMMWlst5TU4Ded9omtOCwYIVsQiaOP2TAbFF/Kgkk3q9Zb0rBZFwIDAQAB
-----END PUBLIC KEY-----`;


// 使用私钥对消息进行加密(通常这是用于创建签名)
function encryptWithPrivateKey(data) {
  //将数据转换为Buffer
  const buffer = Buffer.from(data);
  // 加密块的最大大小
  const maxBlockSize = 117; 
  let offset = 0;
  let encryptedBuffer = Buffer.alloc(0);
  // 分块加密
    while (offset < buffer.length) {
    // 获取当前块
    const block = buffer.slice(offset, Math.min(offset + maxBlockSize, buffer.length));
    // 使用私钥进行加密
    const encryptedBlock = crypto.privateEncrypt(
      {
        key: privateKey,
        padding: crypto.constants.RSA_PKCS1_PADDING,
      },
      block
    );
    // 将加密后的块加到结果Buffer上
    encryptedBuffer = Buffer.concat([encryptedBuffer, encryptedBlock]);
    // 增加偏移量
    offset += block.length;
  }
  // 转换为Base64编码
  return encryptedBuffer.toString('base64');
}



// 使用公钥解密数据
function decryptWithPublicKey(signature) {
  const decryptedData = crypto.publicDecrypt(
    {
      key: publicKey,
      padding: crypto.constants.RSA_PKCS1_PADDING,
    },
    Buffer.from(signature, 'base64') // 解码Base64编码的加密数据
  );
  return decryptedData.toString();
}

// 导出加密函数供其他文件使用
module.exports = {
  encryptWithPrivateKey,
  decryptWithPublicKey,
}