Spiral網關使用RSA數碼簽署作為API驗證方法。

產生公/私鑰

Spiral會提供一組公鑰給商戶,以用作校驗由Spiral發出的API。相對地,商戶亦同樣要提供一組公鑰給Spiral系統,並使用其私鑰上簽署由商戶發出的API。

你可以用以下 OpenSSL 指令去產生公/私鑰:

1. 執行`openssl genrsa -out clientId_private_key.pem 2048` 以獲取商戶的私鑰。 (用作簽署API)

2. 執行`openssl rsa -in clientId_private_key.pem -pubout > clientId_public_key.pem` 以獲取商戶的公鑰。 (在Spiral網站中導入) 

簽署API訊息

作為簽署內容的payload由下列三部份組成:

資料元素

描述

clientId

Client ID, 由Spiral 指發

MerchantRef

商戶參考號,每單交易均要有不同值

(可以考慮由商戶本身的訂單號加上第幾次嘗試支付去組成)

Datetime

訊息組成的時間,使用UTC 時區, ISO格式 %Y-%m-%d’T’%H:%M:%S’Z’ 
請留意UTC和香港有8小時差別, e.g.  2021-01-17T11:39:51+08:00 (HKT) 則應使用 2021-01-17T03:39:51Z

如何簽署

產生Spiral-Client-Signature:

  1. 使用client ID, merchant reference and Spiral-Request-Datetime的順序去構成一個payload。
  2. 使用SHA256 with RSA 及商戶自己的私鑰去簽署payload。
  3. 用Base64 去將簽署後的位元組編碼成為字串。

Payload 範例:

Client ID: 000000000000001

Merchant reference: 123456789012

Spiral-Request-Datetime: 2020-08-01T10:22:34Z
結果Payload: 0000000000000011234567890122020-08-01T10:22:34Z

 

產生簽署的範例源碼:

define(“ClientPrivateKey”, “file://./Cert/custpri.pem”);

public function signing($cliendId, $merchantRef){
  $now = new Datetime(“now”);
  $now->setTimeZone(new DateTimeZone(‘UTC’));
  $request_datetime = $now->format(‘Y-m-d\TH:i:s\Z’);
  $payload = $cliendId . $merchantRef . $request_datetime;

  $pkeyid = openssl_pkey_get_private(ClientPrivateKey);
  openssl_sign($payload, $signature, $pkeyid, OPENSSL_ALGO_SHA256);

  return $signature;
}

var clientPrivateKey = ‘/Cert/custpri.pem’;

function signing(clientId, merchantRef) {
  const crypto = require(‘crypto’);
  const sign = crypto.createSign(‘SHA256’);
  const fs = require(‘fs’);

  var isoTime = d.toISOString();
  isoTime = isoTime.replace(/\.\d+/, “”);
  sign.write(clientId + merchantRef + isoTime);
  sign.end();

  const key = fs.readFileSync(clientPrivateKey);
  return sign.sign(key, ‘base64’);
}

const String clientPrivateKey = @”C:\cert\custpri.xml”;

static String RSA_Sha256_Signature(String clientId, String merchantRef)
{
  // Using private key in XML format, there are online tool available to convert pem into xml format
  // e.g.: https://the-x.cn/en-us/certificate/PemToXml.aspx
  RSACryptoServiceProvider rsa = new  RSACryptoServiceProvider();
  rsa.FromXmlString(File.ReadAllText(clientPrivateKey));

  ASCIIEncoding encoder = new ASCIIEncoding();
  byte[] binData = encoder.GetBytes(clientId + merchantRef + isoTime);
  byte[] binSignature = rsa.SignData(binData, CryptoConfig.CreateFromName(“SHA256”));
return Convert.ToBase64String(binSignature);
}

如何校驗

  1. 使用client ID, merchant reference and Spiral-Request-Datetime的順序去構成一個payload。
  2. 用Base64 去將回覆訊息的簽署字串轉位元組。
  3. 使用SHA256 with RSA 及Spiral提供的公鑰去校驗payload及簽署位元組。

校驗簽署的範例源碼:


define(“SpiralPublicKey”, “file://./Cert/spiralpub.pem”);

// check server signature
public function verify($clientId, $merchantRef, $requestDateTime, $signature)
{
  $pubkeyid = openssl_pkey_get_public(SpiralPublicKey);
  $server_sig_payload = $clientId .   $merchantRef . $requestDateTime;
  $ok = openssl_verify($server_sig_payload, base64_decode($signature), $pubkeyid, OPENSSL_ALGO_SHA256);
  return ($ok == 1);
}

var spiralPublicKey = ‘/Cert/spiralpub(UAT).pem’;

function verifying(clientId, merchantRef, dateTime, signature) {
  const crypto = require(‘crypto’);
  const verify = crypto.createVerify(‘SHA256’);
  const fs = require(‘fs’);

  verify.write(clientId + merchantRef + dateTime);
  verify.end();

  const key = fs.readFileSync(spiralPublicKey);
  return verify.verify(key, signature, ‘base64’);
}

const String clientPrivateKey = @”C:\cert\spiralpub.xml”;

static bool RSA_Sha256_Verify(String clientId, String merchantRef, String isoTime, String signature)
{
  // Using XML format, there are online tool available to convert pem into xml format
  // e.g.: https://the-x.cn/en-us/certificate/PemToXml.aspx
  RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
  rsa.FromXmlString(File.ReadAllText(fileName));

  ASCIIEncoding encoder = new ASCIIEncoding();
  byte[] binData = encoder.GetBytes(clientId + merchantRef + isoTime);
  byte[] binSignature = Convert.FromBase64String(signature);
  return rsa.VerifyData(binData, CryptoConfig.CreateFromName(“SHA256”), binSignature);
}

下面的工具可以產生簽署,用作檢查程序的簽署結果。

Signature Calculation Checking Tool

Client ID:
(The value is given during account creation.)

Merchant Refernce:
(This value is unique for every transaction, sometimes it is constructed by invoice number + the number of payment attempts.)

Time:
(In ISO format, UTC+0)

Private Key:

Signature: