API Authentication
Spiral PG is using RSA digital signature for API authentication.
Key Pair Generation
Spiral will provide a public key to verify the message sending by spiral. Vice versa, merchants are needed to provide the public key to Spiral portal first and signed the request message by its private key.
As time and merchant reference is used as the payload of the signing, a signature can only be used for a single transaction and be valid for a short period of time.
You can follow below steps to generate key pair by OpenSSL:
1. Execute `openssl genrsa -out clientId_private_key.pem 2048` to get merchant’s private key. (Private should be used by the merchant’s web system) 2. Execute `openssl rsa -in clientId_private_key.pem -pubout > clientId_public_key.pem` to get merchant’s public key. (Public key to be shared to EFT and import to Spiral portal)
|
Signing Message
The signing message is formatted by below 3 data elements:
Date element |
Description |
clientId |
Client ID, assigned by Spiral |
MerchantRef |
Merchant Reference, the value is unique for every |
Datetime |
The UTC time in %Y-%m-%d’T’%H:%M:%S’Z’ format |
How to sign
To create a Spiral-Client-Signature:
- Construct a payload by concatenating the following items in order: client ID, merchant reference and Spiral-Request-Datetime
- Use the client’s private key to create a signature for the payload using SHA256withRSA algorithm
- Base64 encode the signature bytes to get the signature string
Payload Example:
Client ID: 000000000000001
Merchant reference: 123456789012
Spiral-Request-Datetime: 2020-08-01T10:22:34Z
Resulting Payload: 0000000000000011234567890122020-08-01T10:22:34Z
Signature creation sample Code:
- php
- Node.js
- .net (framework 4.5)
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);
}
How to verify
Construct a payload by concatenating the following items in order: client ID, merchant reference and Spiral-Request-Datetime
Base64 decode the signature string to get the signature bytes
Verify the signature against the payload, decoded signature and Spiral PG’s public key using SHA256withRSA algorithm
Signature verification sample code:
- php
- Node.js
- .net (framework 4.5)
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);
}
You can verify the result of the signature signing using below tool.