API Signature Generate

# Unified signature generation rules

Only the parameter value participates in the signature, the Key (parameter name) is only sorted and does not participate in the signature calculation

  1. Sort the Key (parameter name) of all non-empty parameters according to ASCII
  2. According to the order of Key (parameter name), take the parameter values one by one for parallel splicing, and use the RSA algorithm to calculate the string to calculate the signature string

# Example description

  • Example Parameters
Parameters Example
merchantCode S82023000000000000001
orderType 0
method qrPay
orderNum T13748238583
payMoney 100
notifyUrl http://notifyUrl
dateTime 2099-99-99 01:01:01
  • Splicing strings
  1. First sort the Key (parameter name) according to ASCII
  2. Then sort the values according to Key (parameter name) and concatenate them into a string.

StrA = 2099-99-99 01:01:01S82023000000000000001qrPayhttp://notifyUrlT137482385830100

  • Calculate Signature
  1. Use the key pair you configured in TopPay Merchant Backend
  2. Use your private key to perform encryption calculation RSA(StrA) to obtain the final signature string

Sign = IMLn23c4orM+7pZhHoRmbjrol4X33jeAqFxbZuQ+pnznBIGhb6 ...

# Code Example

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;

/**
 * <p>
 *  TopPay RSA signatureToolClass
 * </p>
 *
 * @author TopPay
 */
public class TopPayRequestUtil {

  /**
   * VERIFY SIGNATURE
   * @param params
   * @return
   */
  public static boolean verifySign(JsonObject params, String publickey) throws InvalidKeySpecException, NoSuchAlgorithmException {
    String platSign = params.remove("platSign").getAsString(); // sign
    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);
  }

  /**
   * PRIVATE KEY ENCRYPTION
   * @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("ENCRYPTED STRING[" + data + "]Encountered an exception", e);
    }
  }

  /**
   * PUBLIC KEY DECRYPTION
   * @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("When attempting to encrypt the string [" + data + "], an exception occurred.", e);
    }
  }

  /**
   * GET PRIVATE KEY
   * @param privateKey KEY STRING (BASE 64 ENCODED)
   */
  public static RSAPrivateKey getPrivateKey(String privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
    //Obtain the private key object through the Key command encoded by PKCS 8
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey));
    RSAPrivateKey key = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec);
    return key;
  }

  /**
   * GET PUBLIC KEY
   * @param publicKey KEY STRING (BASE 64 ENCODED)
   */
  public static RSAPublicKey getPublicKey(String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
    //Obtain the public key object through the Key command encoded by X509
    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("An exception occurred while encrypting or decrypting data with a threshold of [" + 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");//SENDING JSON DATA NEEDS TO SET CONTENT TYPE
    post.setEntity(s);
    HttpResponse res = client.execute(post);
    if(res.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
      return EntityUtils.toString(res.getEntity());// RETURN JSON FORMAT

    }
    return null;
  }
}


<?php
header('Content-Type: text/html; charset=utf-8');
class Rsa
{
    public function __construct($platPublicKey, $mchPrivateKey){
        // Read public and private keys from file
       $this->publicKey = openssl_pkey_get_public(file_get_contents($publicKeyPath));
        if (!$this->publicKey) {
            die('Load public key error');
        }
        $this->privateKey = openssl_pkey_get_private(file_get_contents($privateKeyPath));
        if (!$this->privateKey) {
            die('Load private key error');
        }
    }

    //Private key encrypted data
    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); // The signed data is base64 encoded for transmission
    }

    //Public key decrypts signed data
    public function public_key_decrypt($encryptedData){
        $encryptedData = base64_decode($encryptedData); // Decode the received signature
        if ($encryptedData === false) {
            echo "Failed to base64 decode the data.\n";
            return false;
        }
        if (openssl_public_decrypt($encryptedData, $decrypted, $this->publicKey)) {
            return $decrypted; // Decryption is successful and the decrypted data is returned.
        } else {
            // Print all OpenSSL error messages
            while ($msg = openssl_error_string()) {
                echo "OpenSSL Error: $msg\n";
            }
            return false; //Decryption failed
        }
    }
}

//The following code is debugging code
//Please note: Use the merchant’s private key to request data encryption, and use the platform’s public key to decrypt the notification.
//Merchant private key
$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-----';
//Platform public key
$platPublicKey = '-----BEGIN PUBLIC KEY-----'."\n".'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCvGQXHktEoCrQ/EnMceY4QVc15KHyvW1ePyYmSqZJC99u4gcdbzYYuunw7kqsdIKWSjPV6q/4cc8665ZOFuUH8W8iFMdOmuGO0QRUIvif09hhyWyaM7IpPMlU2+oydAWWjgc8JFmDZt1dWbMuaOS9Rw959wUOoQpbQK4yD37Bj0wIDAQAB'."\n".'-----END PUBLIC KEY-----';
//Call the encryption and decryption tool class
$encryptionTool = new Rsa($platPublicKey, $mchPrivateKey);
$merchantCode = 'S820230414142102000000';
$orderType = '0';
$orderNum = 'TEST202404121503';
$money = '22.00';
$name = 'สวัสดี สวัสดี';
$name_en = 'test';
$dateTime = date("YmdHis",time());
$params = array(
    'merchantCode' => $merchantCode,
    'orderType' => $orderType,
    'orderNum' => $orderNum,
    'money' => $money,
    'dateTime' => $dateTime,
    'name' => $name,
    'name_en' => $name_en,

);
//Data sorting and splicing
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 structure
        /// </summary>
        public struct RSAKEY
        {
            /// <summary>
            /// Public key
            /// </summary>
            public string PublicKey
            {
                get;
                set;
            }
            /// <summary>
            /// Private key
            /// </summary>
            public string PrivateKey
            {
                get;
                set;
            }
        }
        public RSAKEY GetKey()
        {
            //Constructor for RSA key pairs
            RsaKeyPairGenerator keyGenerator = new RsaKeyPairGenerator();

            //RSA key constructor parameters
            RsaKeyGenerationParameters param = new RsaKeyGenerationParameters(
                Org.BouncyCastle.Math.BigInteger.ValueOf(3),
                new Org.BouncyCastle.Security.SecureRandom(),
                1024,   //Key length
                25);
            //Initialize key constructor with parameters
            keyGenerator.Init(param);
            //Generate key pair
            AsymmetricCipherKeyPair keyPair = keyGenerator.GenerateKeyPair();
            //Get the public key and secret key
            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);     //Here you can also read from the stream and import from local
            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);  //Here you can also read from the stream and import from local
            // 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)
        {
            //Asymmetric encryption algorithm, used for encryption and decryption
            IAsymmetricBlockCipher engine = new Pkcs1Encoding(new RsaEngine());
            //encryption
            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("Ciphertext (base64 encoded):" + 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(" ", "");
            //Asymmetric encryption algorithm, used for encryption and decryption
            IAsymmetricBlockCipher engine = new Pkcs1Encoding(new RsaEngine());

            //Decrypt

            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>
        /// Verify signature
        /// </summary>
        /// <param name="?"></param>
        /// <returns></returns>
        public bool verifySign(Dictionary<string, object> dict, string publickey)
        {
            string platSign = dict["platSign"].ToString().Trim(); // sign
            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 //Public key address
	PriPath string //Private key address
	Pub64   string //The public key body does not include header and tail
	Pri64   string //The private key body does not include header and tail
}

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)
}

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

// Private key decryption
func (r *Cryptor) Decrypt(cipherText []byte) []byte {
	r.loadPriKey()
	plainText, _ := rsa.DecryptPKCS1v15(rand.Reader, r.pri, cipherText)
	return plainText
}

// Signature default SHA512
func (r *Cryptor) Sign(data []byte) []byte {
	return r.SignWithHash(data, sha512.New(), crypto.SHA512)
}

// Signature specifies the Hash algorithm. The hash and hashType should be kept consistent.
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
}

// Signature verification default SHA512
func (r *Cryptor) Verify(data []byte, sign []byte) error {
	return r.VerifyWithHash(data, sign, sha512.New(), crypto.SHA512)
}

// Verify the signature. Specify the Hash algorithm. The hash and hashType must be consistent.
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
}

// Private key encryption
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
}

// Public key decryption
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
}

// Private key to encrypt or decrypt 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
		}
	}
}

// Public key encryption or decryption 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
		}
	}
}

// Public key decryption
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
}

// Copied from 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
}

// Private key encryption
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
}

// Copied from 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
}

// Copied from 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
}

// Copied from 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

# Generate RSA key pair
rsa_key = RSA.gen_key(2048, 65537)

# Data to be encrypted
data_to_encrypt = b'Hello, RSA!'

# Encrypt data using private key
encrypted_data = rsa_key.private_encrypt(data_to_encrypt, RSA.pkcs1_padding)

# Decrypt data using public key
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');

//This public and private key is for example only. When connecting business, please use the real key pair.
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-----`;


//Encrypt message using private key
function encryptWithPrivateKey(data) {
    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
        );
        encryptedBuffer = Buffer.concat([encryptedBuffer, encryptedBlock]);
        offset += block.length;
    }
    return encryptedBuffer.toString('base64');
}



//Decrypt data using public key
function decryptWithPublicKey(signature) {
   const decryptedData = crypto.publicDecrypt(
    {
      key: publicKey,
      padding: crypto.constants.RSA_PKCS1_PADDING,
    },
    Buffer.from(signature, 'base64') //Decode Base64 encoded encrypted data
  );
  return decryptedData.toString();
}

//Export encryption functions for use in other files
module.exports = {
    encryptWithPrivateKey,
    decryptWithPublicKey,
}