Signature Asymmetric

Signature Asymmetricis a cryptographic method that uses public and private keys to create and verify signatures. The private key creates the signature, while the public key verifies it. In its implementation, creating a signature using a private key is applied to services with the Merchant -> Espay flow. In contrast, signature validation using a public key is implemented for services with the Espay -> Merchant flow.

  • SHA256withRSA is used to generate a signature with a private key.

X-SIGNATURE = base64Encode(SHA256withRSA(PrivateKey, StringToSign))
  • SHA256withRSA is used to validate signature with public key.
Base64Decode(X-SIGNATURE) = SHA256withRSA(PublicKey, StringToSign)
  • StringToSign
StringToSign = HTTPMethod+”:”+RelativeUrl+”:”+ Lowercase((SHA-256(MinifyJson(RequestBody))))+”:”+Timestamp 

Signature Asymmetric Component

Component Description
HTTP Method
HTTP Method.

Example:
POST, DELETE
Relative URL
API URL path of the service you are using.

Example:
  • API URL:
    https://sandbox-api.espay.id/api/v1.0/qr/qr-mpm-generate
  • Relative URL:
    /api/v1.0/qr/qr-mpm-generate
Request Body
Request Body of the service in JSON format.
Timestamp
Customer's current local date and time, same as X-TIMESTAMP Header.

Example:
yyyy-MM-ddThh:mi:ssTZD

Format:
2023-08-31T07:49:28+07:00
You can create private and public keys in PKCS#1 format using SSL for production needs and use the available examples for development needs.

Example of generate private key and public key with PKCS#1 format

With openSSL 1.1.1(PKCS#1):

openssl genrsa -out private.pem 2048

openssl rsa -in private.pem -pubout > public.pub

Example of public key format PKCS#1


-----BEGIN PUBLIC KEY----- 
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2O9xDMTBiZ5oOy3LBVn6 
TerxWMHEwxl6gr0SX1dRt4be5vq2voFMoCHokeowqpeU5ZQi0EM36W7Q1K8hH6KR 
jdNqhdIHyMh7X0yhVJTQ3Fz9QcjBfeMwoovmIYHP+U08GKz7j99VojSSriYvzT1m 
PdwvTuAdFT3QEXfgdMLKQCjtXF/eyg2Q+xCYJALv+zeaPlsu00RO3TM5NGaCSbFC 
oF/xa4IOfV+215beBvl1fUhW6mkEo7gdhK8T0ddk5bInEJs3YzDwQNtAutLEFVot 
EKX2ETqIk8S1H7Pou7tSo73O0fFGaSBhG610bKIb9lLTXCQYJKk8bygPaL3aoT+5 
QwIDAQAB
-----END PUBLIC KEY-----
Example of a PKCS#1 format private key

-----BEGIN RSA PRIVATE KEY----- 
MIIEpAIBAAKCAQEA2O9xDMTBiZ5oOy3LBVn6TerxWMHEwxl6gr0SX1dRt4be5vq2 
voFMoCHokeowqpeU5ZQi0EM36W7Q1K8hH6KRjdNqhdIHyMh7X0yhVJTQ3Fz9QcjB 
feMwoovmIYHP+U08GKz7j99VojSSriYvzT1mPdwvTuAdFT3QEXfgdMLKQCjtXF/e 
yg2Q+xCYJALv+zeaPlsu00RO3TM5NGaCSbFCoF/xa4IOfV+215beBvl1fUhW6mkE 
o7gdhK8T0ddk5bInEJs3YzDwQNtAutLEFVotEKX2ETqIk8S1H7Pou7tSo73O0fFG 
aSBhG610bKIb9lLTXCQYJKk8bygPaL3aoT+5QwIDAQABAoIBAQDTSPIcc43kUWpH 
KSSxQ59sQEVsIt1W//u4VhoMzekDDNMQuGNATIKq/Bud8jAQFq6oo4z8tltAefPf 
Eer6+sU1ExKO369BOTIf8Wy4CnEaD1+CsNrzl1EJH6S2Qc6jizva9K/WwriO0RGD 
mCG6jfCEk21oLxNkWt3KBa2RSx7dOLO+ct07jtRbfYCVCAezyx6fWxLJ6eVmGZXM 
kOhAr9tQ6IC3v/iQgA00LNPXR+X12obcmNXtcng5uHffeZNr6tmpLpXTYLdwZlwl 
FINuTGpPjp1yy6q6GQYphF51ywRFN17g8NoVHLXDAfnrmB1lgtbC3nSiAvqEq2c6 
XQkAIZbBAoGBAPgQDtG7RJ/Wdo5ra9HMgceVqDQgrdY4vw4cnV4NVGSBGn8jNhk7 
YrJ8siJbLxqi5cPwJzu7xS8krKyt3vBY8AFKvVJ9yZ06VVL4d2LvWr50ym/zshnC 
w1WlKhcuyaqP6MCiC6pZNA5LR1AN6hK2B1ZnmSrvDkg+MZtGTAxJrF6TAoGBAN/g 
aVtaHuw1Zh2ixRfUjjQ4YMSxt/68DnmAJemmWQysvFsTZLfy87KLenmLABnG9qke 
sOLD/vC7h5s5G9+vN4JMbmTYGBYp0VW5wWaC7Nw8cskgsmb7BZ+K7HsQbmtxh9Nu 
BeQqdmQHZvLQ6wgY+0QTy/1KTUPwxLztyJttGjiRAoGAQEkpDgFSD3osz0vXbU9q 
cqa+KIQviMy79pRD1BPwQvuSOlCNvIw/T7IxF+Y5ltWQZe7evAQ1XbpLZZTJqc/i 
ovMTjUU78psjcZUim2kcQy9RJyIojbSDmrZq6gceDC2vS/yyuTrU2r93g6+XcbHq 
xOGkOBQrx10Wzf6xxp1xJjECgYBfSk6t4nsdAVGYtap8jS2GDqUps5dkZrkmgCQj 
AnoOygtWHLgXD+MokPOtfjupvSVKMNULgG8oGjoLGNDDcfoHjO7EH7KI5H3Epk8q 
ifm1eElHUJJ/AMOQ9/nWG9VUCDvPA5qgVm6T/w6TtdcEWFXC0UZXZmPi0j17SR7F 
AThS8QKBgQCCyPFJzwGIP99PcakQ38oFcoU8u/ahb0ghgJfSgK+K/ChXSyfbq5zt 
jRkj6UWLa3plYX3po9h0Yp6f2IxnbOa3VK6fPkcSvBxhgK3RrugPerUJzFEPd3k4 
GTqOBXtXO6N7zEMYxZxv0SgrV24LPfPz0aPObDeH6F0kuzXjanopIw== 
-----END RSA PRIVATE KEY-----

Generate Signature with Private Key

The following are the steps to generate a signature with a private key:

  1. Create StringToSign Component

  • Minify Request Body.
MinifyJson(RequestBody))
Example:
Format before minify
{
  "partnerReferenceNo": "DIGORDER000001",
  "merchantId": "SGWDIGALLERY",
  "subMerchantId": "fd322d0f036c8443d6904973c1a329bd", 
  "amount": {
    "value": "10000.00",
    "currency": "IDR"
  },
  "urlParam": {
    "url": "https://yourthankyoupage.com",
    "type": "PAY_RETURN",
    "isDeeplink": "N"
  },
  "validUpTo": "2023-12-23T07:44:11+07:00",
  "pointOfInitiation": "Website",
  "payOptionDetails": {
    "payMethod": "014",
    "payOption": "BCAATM",
    "transAmount": {
      "value": "10000.00",
      "currency": "IDR"
    },
    "feeAmount": {
      "value": "10000.00",
      "currency": "IDR"
    }
  },
  "additionalInfo": {
    "payType": "REDIRECT",
    "userId": "425666",
    "userName": "Agung Setiadi Putra",
    "userEmail": "agung@agung.com",
    "userPhone": "082231838297",
    "buyerId": "12345678"
  }
}

Format after minify
{"partnerReferenceNo":"DIGORDER000001","merchantId":"SGWDIGALLERY","subMerchantId":"fd322d0f036c8443d6904973c1a329bd","amount":{"value":"10000.00","currency":"IDR"},"urlParam":{"url":"https://yourthankyoupage.com","type":"PAY_RETURN","isDeeplink":"N"},"validUpTo":"2023-12-23T07:44:11+07:00","pointOfInitiation":"Website","payOptionDetails":{"payMethod":"014","payOption":"BCAATM","transAmount":{"value":"10000.00","currency":"IDR"},"feeAmount":{"value":"10000.00","currency":"IDR"}},"additionalInfo":{"payType":"REDIRECT","userId":"425666","userName":"Agung
Setiadi Putra","userEmail":"agung@agung.com","userPhone":"082231838297","buyerId":"12345678"}}
  • Encrypt the minified request body using SHA-256

(SHA-256(MinifyJson(RequestBody)))
Example:
Format before encryption
{"partnerReferenceNo":"DIGORDER000001","merchantId":"SGWDIGALLERY","subMerchantId":"fd322d0f036c8443d6904973c1a329bd","amount":{"value":"10000.00","currency":"IDR"},"urlParam":{"url":"https://yourthankyoupage.com","type":"PAY_RETURN","isDeeplink":"N"},"validUpTo":"2023-12-23T07:44:11+07:00","pointOfInitiation":"Website","payOptionDetails":{"payMethod":"014","payOption":"BCAATM","transAmount":{"value":"10000.00","currency":"IDR"},"feeAmount":{"value":"10000.00","currency":"IDR"}},"additionalInfo":{"payType":"REDIRECT","userId":"425666","userName":"Agung
Setiadi Putra","userEmail":"agung@agung.com","userPhone":"082231838297","buyerId":"12345678"}}
Format after encryption
f6bbc08be6997d4bd02af5254e3f934f9ed908fb7724d2e8cf98b178158a2b7a
  • Change the request body encrypted with SHA-256 to Hex Encode and Lowercase.

HexEncode is optional, but use it if the SHA-256 returns a binary stream.

Using HexEncode
Lowercase(HexEncode(SHA-256(MinifyJson(RequestBody))))
Not using HexEncode
Lowercase((SHA-256(MinifyJson(RequestBody))))
Example:
Format before HexEncode dan Lowercase
f6bbc08be6997d4bd02af5254e3f934f9ed908fb7724d2e8cf98b178158a2b7a
Format after lowercase (Not using HexEncode)
f6bbc08be6997d4bd02af5254e3f934f9ed908fb7724d2e8cf98b178158a2b7a

  1. Generate StringToSign

To create a StringToSign, combine all components using a colon “:”.
StringToSign

HTTPMethod+”:”+RelativeUrl+”:”+ Lowercase(HexEncode(SHA-256(MinifyJson(RequestBody))))+”:”+Timestamp
Example:
StringToSign Format
POST:/apimerchant/v1.0/debit/payment-host-to-host:f6bbc08be6997d4bd02af5254e3f934f9ed908fb7724d2e8cf98b178158a2b7a:2024-03-14T07:49:28+07:00

  1. Generate X-Signature with private key

X-SIGNATURE = base64Encode(SHA256withRSA(PrivateKey, StringToSign))
Example:
X-Signature Format
D/QV3mN8i19xZRTkOW5sdn5XtrXoT8EmepDRzaGHheT+qnnzrZlEKCBic6M5sQyj6Hp8jFSY4PCsMm7lJQFRLiGPdYf/rDPFsa/ai1MnoUoMKUFSmQHUmjAAhbQjkdNWKjoSG+xTTmyEzsBz6/P6ijWMBDTZWPIb3/qaN6oxcnhw2RLOCyCZlXwBeP6RMc3Gz1wilRGQ5jqeebQVGgUJjqAGLM/cVIjG0fXmQAmsG0g3XA7e63qW0M6am8zXHPtumRF5X4JN0CSRcV9QjvLvH21vcnYhuixebzr5dnnoroXL/aE/ptfrb79Ou0dwqRsQBCqZhwFssSFRPDhzqsZWIw==

Try It!

You can enter data using the input provided. After that, you submit and see the results!

Request

Value

Response

Validasi Signature with Public Key

The following are the steps for validating a signature with a public key:
  1. Decode X-Signature Header
Example:
X-Signature Format
rgfRxIG62kOVexmBsrHnl87aW1lS+JtvMUa9pF8yhHb+m1Rv63LzFFC50FTzZMhZIarrI4Tff4Q3RhvMP5nLEMwOamnVPHtYnIY9Xjvudz3AitjUU1010dGOn7vt8ojY8K4kN+extwGuxmmPePbYksy4UGs8Ll8SfwksOKgygzFy+AttZY2s2duAt8tD/D+q576j62CyOVRvMVysXVWCRnYxPBa8D9hUj+M47yxdYN21RteSkQjB90fBXAVeBeikOzosDflaO2PH80grbmKSV5hzF9Z48ABnDxkwFG7PG8cqK1XRde34aXFYsI+sXCQDLZ6Y3TWBA/iWfn1lx08T3g==
X-Signature format after Base64Decode
āC{[YRo1F_2vTorPTdY!#7F?ji<{X=^;w=S]5ю$7籷ix̸ؒPk<._ ,821r meۀC?羣`9To1\]UFv1<T8,]`ݵFגG\^;:,
Z;cH+nbWsx�g0n*+UuiqX\$-5~}eO
  1. Create StringToSign Component
  • Minify Request Body.
MinifyJson(RequestBody))
Example:
Format before minify
{
  "partnerServiceId": " Espay",
  "customerNo": "SGWDIGALLERY",
  "virtualAccountNo": "DIGORDER000002",
  "trxDateInit": "2024-06-17T21:45:46+0700",
  "inquiryRequestId": "710c1836-eddf-49d1-8234-f11e93750fdd"
}
Format after minify
{"partnerServiceId":" Espay","customerNo":"SGWDIGALLERY","virtualAccountNo":"DIGORDER000002","trxDateInit":"2024-06-17T21:45:46+0700","inquiryRequestId":"710c1836-eddf-49d1-8234-f11e93750fdd"}
  • Encrypt the minified request body using SHA-256

(SHA-256(MinifyJson(RequestBody)))
Example:
Format before encryption
{"partnerServiceId":" Espay","customerNo":"SGWDIGALLERY","virtualAccountNo":"DIGORDER000002","trxDateInit":"2024-06-17T21:45:46+0700","inquiryRequestId":"710c1836-eddf-49d1-8234-f11e93750fdd"}
Format after encryption
33578ff224ac535c2be314623a3ba420f6b965f4570ec9bbb8af17ac8dbd6468
  • Change the request body encrypted with SHA-256 to Hex Encode and Lowercase.

HexEncode is optional, but use it if the SHA-256 returns a binary stream.

Using HexEncode
Lowercase(HexEncode(SHA-256(MinifyJson(RequestBody))))
Not using HexEncode
Lowercase((SHA-256(MinifyJson(RequestBody))))
Example:
Format before HexEncode dan Lowercase
33578ff224ac535c2be314623a3ba420f6b965f4570ec9bbb8af17ac8dbd6468
Format after lowercase (Not using HexEncode)
33578ff224ac535c2be314623a3ba420f6b965f4570ec9bbb8af17ac8dbd6468
  1. Generate StringToSign
To create a StringToSign, combine all components using a colon “:”.

StringToSign

HTTPMethod+”:”+RelativeUrl+”:”+ Lowercase(HexEncode(SHA-256(MinifyJson(RequestBody))))+”:”+Timestamp

Example:
StringToSign Format
POST:/api/webhooks/epsay/v1.0/transfer-va/inquiry.php:33578ff224ac535c2be314623a3ba420f6b965f4570ec9bbb8af17ac8dbd6468:2024-06-17T21:45:46+0700
  1. Generate X-Signature with public key
X-SIGNATURE =
Base64Decode(X-SIGNATURE) = SHA256withRSA(PublicKey, StringToSign)
Example:
Signature validation format
1

Try It!

Anda bisa coba masukkan data sesuai dengan input yang telah disediakan. Setelah itu Anda submit dan lihat hasilnya!

Request

Value

Response



PHP - Generate Signature

$stringToSign = $http_method.':'.$endpoint_url.':'.strtolower((hash('sha256', json_encode(json_decode($_POST['bodyRequest']),JSON_UNESCAPED_SLASHES)))).':'.$timestamp;

openssl_sign($stringToSign, $signature, $privKey, 'sha256WithRSAEncryption');      
            



PHP - Signature Validation

// Decode X-Signature
$requestSignature = base64_decode($xSignature);

// String to Sign
$stringToSign = $http_method.':'.$endpoint_url.':'.strtolower((hash('sha256', json_encode(json_decode($_POST['bodyRequest']),JSON_UNESCAPED_SLASHES)))).':'.$timestamp;

// Signature validation
$signVerify = openssl_verify($stringToSign, $requestSignature, $publicKey, 'sha256WithRSAEncryption');

          
Scroll to Top