Skip to content

Signature & Verification

See also: API Environments

Common Signature Steps

  1. Let all sent or received fields be set M.
  2. Sort non-empty parameters in M by parameter name in ASCII ascending order (dictionary order).
  3. Concatenate them as URL key-value pairs (key1=value1&key2=value2...) into stringA.

Sign & Verify

  • Sign with the merchant private key: sign = RSAUtils.createSign(stringA, merchantPrivateKey)
  • Verify with the platform public key: isPass = RSAUtils.verifySign(stringA, platformPublicKey)

Important Rules

  1. Sort parameter names by ASCII (dictionary order).
  2. Empty values do not participate in signing, including empty string, 0, 0.0, null, false, and string '0'.
  3. In stringA, both names and values use raw values (no URL encoding).
  4. Signature algorithm: OPENSSL_ALGO_SHA256 (merchant private key signs; platform public key verifies).
  5. Remove trailing zeros after decimal points in request values before signing, for example 101.00101, 11.2011.2; 13.33 stays unchanged.
  6. This is RSA signing, not RSA encryption.

Parameter Sorting Example

json
{
 "appId": 10001,
 "mchOrderNo": "order_1662098266",
 "bankCode": "CLABE",
 "amount": 1200,
 "notifyUrl": "http://www.domain.com/notify",
 "name": "Gary Williams",
 "phone": "88123456789",
 "email": "test@gmail.com",
 "currentTime": 1662098266,
 "sign": "AFEleaq1Hpr3jzEqy7rnDhZyrB8JfR2380sU2aTs4jA82ULV/eRuieoO9STzVLSM+wr/J/+2x30rWvNJ+xYLe99TZBVwHtzlU+p7+1ie4mq8YNfhUlXGiWPI/9x7AuHmRH5iCP0+kgnhqWk7h+5ye+s330nKC+BUPlGlCaCaBnY=",
 "payer": {
 "name": "xxxx",
 "cpf": "xxxdsahfu"
 }
}

Sorted stringA:

text
amount=1200&appId=10001&bankCode=CLABE&currentTime=1662098266&email=test@gmail.com&mchOrderNo=order_1662098266&name=Gary Williams&notifyUrl=http://www.domain.com/notify&phone=88123456789&payer=Array

Signature Examples

PHP Example

php
class SignUtils
{
 /**
 * Create signature with private key
 * @param array $params
 * @param string $privateKey
 * @return string
 */
 public static function createSign(array $params, string $privateKey): string
 {
 $signString = self::getSignString($params);
 $privateKey = '-----BEGIN PRIVATE KEY-----' . "\n" . $privateKey . "\n" . '-----END PRIVATE KEY-----';
 // Convert to OpenSSL key; private key must not have been converted via PKCS#8
 $res = openssl_get_privatekey($privateKey);
 // Call OpenSSL signing to generate $sign
 openssl_sign($signString, $sign, $res, OPENSSL_ALGO_SHA256);
 // Release resources
 openssl_free_key($res);
 return base64_encode($sign);
 }

 /**
 * Verify signature with public key
 * @param array $params
 * @param string $pubKey
 * @return bool
 */
 public static function verifySign(array $params, string $pubKey): bool
 {
 $sign = $params['sign'] ?? '';
 $signString = self::getSignString($params);
 $pubKey = '-----BEGIN PUBLIC KEY-----' . "\n" . $pubKey . "\n" . '-----END PUBLIC KEY-----';
 // Convert to OpenSSL public key format
 $res = openssl_get_publickey($pubKey);
 // Call OpenSSL verify; returns bool
 $result = (bool)openssl_verify($signString, base64_decode($sign), $res, OPENSSL_ALGO_SHA256);
 // Release resources
 openssl_free_key($res);
 return $result;
 }

 /**
 * @note Build the pre-sign string
 * @param array $params
 * @return string
 */
 private static function getSignString(array $params): string
 {
 unset($params['sign']);
 ksort($params);
 $string = '';
 if (!empty($params)) {
 $array = array();
 foreach ($params as $key => $value) {
 if (!empty($value)) {
 $array[] = $key . '=' . $value;
 }
 }
 $string = implode("&", $array);
 }
 return $string;
 }
}

Python Example

python
import base64
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA256

## Requires pycryptodome

class SignUtils:
 @staticmethod
 def create_sign(params, private_key):
 sign_string = get_sign_string(params)
 private_key = f'-----BEGIN PRIVATE KEY-----
{private_key}
-----END PRIVATE KEY-----'
 res = RSA.import_key(private_key)
 sign = PKCS1_v1_5.new(res).sign(SHA256.new(sign_string.encode()))
 return base64.b64encode(sign).decode()

 @staticmethod
 def verify_sign(params, pub_key):
 sign = params.get('sign')
 sign_string = get_sign_string(params)
 pub_key = f'-----BEGIN PUBLIC KEY-----
{pub_key}
-----END PUBLIC KEY-----'
 res = RSA.import_key(pub_key)
 try:
 PKCS1_v1_5.new(res).verify(SHA256.new(sign_string.encode()), base64.b64decode(sign))
 return True
 except (ValueError, TypeError):
 return False

 @staticmethod
 def get_sign_string(params):
 sorted_params = sorted(params.items(), key=lambda x: x[0])
 array = []
 for key, value in sorted_params:
 if value:
 array.append(f"{key}={value}")
 return '&'.join(array)

Transafe Developer Documentation