Skip to main content

Appendix 1

Security Control​

Merchant and PayMaster share a SECRET KEY, used by both parties to create a Secure Hash Value for the transaction data.

  • Obtain the Secret Key from the PayMaster Gateway.

The Secure Hash is a hexadecimal-encoded SHA-256 HMAC (or MD5 HMAC) of the concatenation of all fields in the Message Header and Data Content (excluding trailer fields), followed by the secret key.


Request Page t002_SHV​

Before calling PayMaster, the Merchant must generate t002_SHV for the request message and append t001_SHT and t002_SHV as trailer fields.

Step 1 : Build the request string (without trailer)​

Concatenate header and data fields in ascending field-ID order. Separate each name=value pair with &. Do not include t001_SHT or t002_SHV.

Example DuitNow Pay payment request (0880):

Request message without trailer fields
h001_MTI=0880&h002_VNO=06&h003_TDT=20260824&h004_TTM=12432905&f001_MID=120567801561128&f003_ProcCode=000000&f006_TxnDtTm=20010831124329&f007_TxnAmt=000000057080&f010_CurrCode=458&f019_ExpTxnAmt=2&f249_TxnCh=WEB&f253_CntyCode=MY&f256_FICode=RPP&f260_ServID=FNX&f263_MRN=2012121912345&f264_Locale=en&f268_CHName=Thomson&f275_RURL_DD=https://www.megastore.com/dd/done.jsp&f278_EMailAddr=thomson8899@yahoo.com&f279_HP=60128888888&f285_IPAddr=11.11.88.88&f352_AcqBank=FNXSMYNB

Step 2 : Append the Secret Key​

Append the Secret Key to the string from Step 1:

Request Message without Trailer Fields + Secret Key

Step 3 : Generate the hash value​

Encode the string using the algorithm specified in t001_SHT. In this example, SHA-256 HMAC (SH2) is used. Set the result as t002_SHV, then append the trailer fields to the request.

In this example:

  • Assuming secret key is 00112233445566778899AABBCCDDEEFF, the hash value is 6C825DC0E39F2917A8BC34A45F5BAF6EDDF7353446C19D3CC6296E6F3A962892.

Final request trailer:

t001_SHT=SH2&t002_SHV=6C825DC0E39F2917A8BC34A45F5BAF6EDDF7353446C19D3CC6296E6F3A962892

Sample Code (Generate)​

public void reqPayment() throws Exception {

String secretKey = "00112233445566778899AABBCCDDEEFF";

String request =
"h001_MTI=0880&h002_VNO=06&h003_TDT=20260824&h004_TTM=12432905"
+ "&f001_MID=120567801561128&f003_ProcCode=000000"
+ "&f006_TxnDtTm=20010831124329&f007_TxnAmt=000000057080"
+ "&f010_CurrCode=458&f019_ExpTxnAmt=2&f249_TxnCh=WEB"
+ "&f253_CntyCode=MY&f256_FICode=RPP&f260_ServID=FNX"
+ "&f263_MRN=2012121912345&f264_Locale=en&f268_CHName=Thomson"
+ "&f275_RURL_DD=https://www.megastore.com/dd/done.jsp"
+ "&f278_EMailAddr=thomson8899@yahoo.com&f279_HP=60128888888"
+ "&f285_IPAddr=11.11.88.88&f352_AcqBank=FNXSMYNB"
+ secretKey;

SecretKeySpec byteSecretKey = new SecretKeySpec(secretKey.getBytes(), "HmacSHA256");
Mac sha256_MAC = Mac.getInstance("HmacSHA256");
sha256_MAC.init(byteSecretKey);

String hashed = this.bytesToHex(sha256_MAC.doFinal(request.getBytes())).toUpperCase();

System.out.println(hashed);
// 6C825DC0E39F2917A8BC34A45F5BAF6EDDF7353446C19D3CC6296E6F3A962892
}

public String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}

Response Page t002_SHV​

The payment response message includes t001_SHT and t002_SHV. The Merchant shall use these two values to verify the response message sent by PayMaster to ensure that the data has not been tampered with.

To verify this, the Merchant should remove the Trailer Fields (t001_SHT and t002_SHV) from the response message, append the remaining message with the Merchant's Secret Key, and then encode the string using the SHA-256 HMAC hashing algorithm.

Once the encoded result is obtained, compare it with the value in t002_SHV.

  • The values must be equal.

Example​

Step 1 : Remove trailer fields​

Remove the trailer fields from the response message returned by the PayMaster Gateway.

Example DuitNow Pay payment response (0890):

Before removing the trailer values
h001_MTI=0890&h002_VNO=06&h003_TDT=20260824&h004_TTM=12432905&f001_MID=120567801561128&f003_ProcCode=000000&f006_TxnDtTm=20120831124329&f007_TxnAmt=000000057080&f010_CurrCode=458&f019_ExpTxnAmt=2&f254_DDRespCode=00&f256_FICode=RPP&f257_PGRN=AJ789EG07S0012012022&f258_TxnStatDetCde=0000&f259_TxnStatMsg=OK&f260_ServID=FNX&f263_MRN=2012121912345&f277_DDRN=DD200108301234&f286_OrgDDRespCode=00&f407_PayerAccType=TBH&t001_SHT=SH2&t002_SHV=0978A771F4F3395B00455BFBD7ADF732A09DBCFF65DE773009940DAA113248FC
After removing the trailer values
h001_MTI=0890&h002_VNO=06&h003_TDT=20260824&h004_TTM=12432905&f001_MID=120567801561128&f003_ProcCode=000000&f006_TxnDtTm=20120831124329&f007_TxnAmt=000000057080&f010_CurrCode=458&f019_ExpTxnAmt=2&f254_DDRespCode=00&f256_FICode=RPP&f257_PGRN=AJ789EG07S0012012022&f258_TxnStatDetCde=0000&f259_TxnStatMsg=OK&f260_ServID=FNX&f263_MRN=2012121912345&f277_DDRN=DD200108301234&f286_OrgDDRespCode=00&f407_PayerAccType=TBH

Step 2 : Append the Secret Key to the response message​

Append the Secret Key to the response message after removing the trailer fields. This will result in a string formatted as Response Message without Trailer Fields + Secret Key. Encode this string using the algorithm specified in t001_SHT. In this example, SHA-256 is used.

Step 3 : Compare the encoding result with the hash value​

Compare the encoded result with the hash value in t002_SHV. The two values must match.

In this example:

  • Assuming secret key is 00112233445566778899AABBCCDDEEFF, the hash value is 0978A771F4F3395B00455BFBD7ADF732A09DBCFF65DE773009940DAA113248FC.

The Merchant MUST reject any non-matching results and report them to PayMaster.

Sample Code (Verify)​

public void resPayment() throws Exception {

String secretKey = "00112233445566778899AABBCCDDEEFF";

String response =
"h001_MTI=0890&h002_VNO=06&h003_TDT=20260824&h004_TTM=12432905"
+ "&f001_MID=120567801561128&f003_ProcCode=000000"
+ "&f006_TxnDtTm=20120831124329&f007_TxnAmt=000000057080"
+ "&f010_CurrCode=458&f019_ExpTxnAmt=2&f254_DDRespCode=00"
+ "&f256_FICode=RPP&f257_PGRN=AJ789EG07S0012012022"
+ "&f258_TxnStatDetCde=0000&f259_TxnStatMsg=OK&f260_ServID=FNX"
+ "&f263_MRN=2012121912345&f277_DDRN=DD200108301234"
+ "&f286_OrgDDRespCode=00&f407_PayerAccType=TBH"
+ secretKey;

SecretKeySpec byteSecretKey = new SecretKeySpec(secretKey.getBytes(), "HmacSHA256");
Mac sha256_MAC = Mac.getInstance("HmacSHA256");
sha256_MAC.init(byteSecretKey);

String hashed = this.bytesToHex(sha256_MAC.doFinal(response.getBytes())).toUpperCase();

System.out.println(hashed.equalsIgnoreCase(
"0978A771F4F3395B00455BFBD7ADF732A09DBCFF65DE773009940DAA113248FC"));
}

public String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}