跳到主要内容

附录 1

安全控制

响应页面 SHValue

商户和 PayMaster 将共享一个用于创建交易数据的 密钥

  • 密钥应从 PayMaster 网关获取。

支付响应消息将包括 SHAlgorithmTypeSHValue。商户应使用这两个值验证 PayMaster 发送的响应消息,以确保数据未被篡改。

为了验证,商户需要从响应消息中删除尾部字段(t001_SHTt002_SHV),将消息附加上商户密钥,然后使用 SHA-256 HMAC 哈希算法对字符串进行编码。

一旦获得编码结果,将其与 SHValue 中的值进行比较。

  • 两个值必须相等。

示例 1

步骤 1:删除尾部字段

从 PayMaster 网关返回的响应消息中删除尾部字段(最后两行)。

删除尾部值之前
h001_MTI=0290&h002_VNO=06&h003_TDT=20230811&h004_TTM=16241856&f001_MID=000010000012639&f004_PAN=545301XXXXXX5323&f005_ExpDate=2710&f006_TxnDtTm=20230811162418&f007_TxnAmt=000000000100&f009_RespCode=00&f010_CurrCode=458&f011_AuthIDResp=774585&f019_ExpTxnAmt=2&f023_RRN=322382167159&f024_OrgRespCode=00&f254_DDRespCode=00&f256_FICode=&f257_PGRN=230811162420AC069FNX&f258_TxnStatDetCde=0000&f259_TxnStatMsg=SUCCESS&f260_ServID=FNX&f261_HostID=&f262_SessID=&f263_MRN=20230811162418FNX&f270_ORN=&f277_DDRN=&f283_UPP_PM=00&f286_OrgDDRespCode=22&f350_CrdTyp=MST&f352_AcqBank=&f353_IPPTenure=&f325_ECommMercInd=1&f339_TokenFlg=N&f344_MercCustId=&f346_Token=&f347_TokenShrtNm=&f348_MaskPAN=&f365_POSEnvFlg=&t001_SHT=SH2&t002_SHV=FC63B34696B77153044E6D353D0241088A44EC13CCF5C414FFC30CE815C96614
删除尾部字段之后
h001_MTI=0290&h002_VNO=06&h003_TDT=20230811&h004_TTM=16241856&f001_MID=000010000012639&f004_PAN=545301XXXXXX5323&f005_ExpDate=2710&f006_TxnDtTm=20230811162418&f007_TxnAmt=000000000100&f009_RespCode=00&f010_CurrCode=458&f011_AuthIDResp=774585&f019_ExpTxnAmt=2&f023_RRN=322382167159&f024_OrgRespCode=00&f254_DDRespCode=00&f256_FICode=&f257_PGRN=230811162420AC069FNX&f258_TxnStatDetCde=0000&f259_TxnStatMsg=SUCCESS&f260_ServID=FNX&f261_HostID=&f262_SessID=&f263_MRN=20230811162418FNX&f270_ORN=&f277_DDRN=&f283_UPP_PM=00&f286_OrgDDRespCode=22&f350_CrdTyp=MST&f352_AcqBank=&f353_IPPTenure=&f325_ECommMercInd=1&f339_TokenFlg=N&f344_MercCustId=&f346_Token=&f347_TokenShrtNm=&f348_MaskPAN=&f365_POSEnvFlg=

步骤 2:将密钥附加到响应消息

在删除尾部字段之后,将密钥附加到响应消息。您将得到一个没有尾部字段 + 密钥的响应消息字符串。使用 SHAlgorithmType 中指定的算法对字符串进行编码。在这个例子中,使用 SHA-256

步骤 3:将编码结果与哈希值比较

将编码结果与 SHValue 中的哈希值进行比较。两者 必须 相匹配。

在这个例子中:

  • 假设密钥为 00112233445566778899AABBCCDDEEFF,哈希值为 E73CEDA9D9A8D1AAF59BDB919EF7C82D52671A4B457CE816BCE91AFF31485259
危险

商户必须拒绝不匹配的结果并向 PayMaster 报告。

示例代码

public void resPayment() throws Exception {

String secretKey = "B96856FA91749A259F71340E3C6BC3478524320F218587D22071A35DD4E7BXXX";

String response = "h001_MTI=0290&h002_VNO=06&h003_TDT=20230811&h004_TTM=16241856&f001_MID=000010000012639&
f004_PAN=545301XXXXXX5323&f005_ExpDate=2710&f006_TxnDtTm=20230811162418&f007_TxnAmt=000000000100&f009_Resp
Code=00&f010_CurrCode=458&f011_AuthIDResp=774585&f019_ExpTxnAmt=2&f023_RRN=322382167159&f024_OrgRespCode=0
0&f254_DDRespCode=00&f256_FICode=&f257_PGRN=230811162420AC069FNX&f258_TxnStatDetCde=0000&f259_TxnStatMsg=S
UCCESS&f260_ServID=FNX&f261_HostID=&f262_SessID=&f263_MRN=20230811162418FNX&f270_ORN=&f277_DDRN=&f283_UPP_
PM=00&f286_OrgDDRespCode=22&f350_CrdTyp=MST&f352_AcqBank=&f353_IPPTenure=&f325_ECommMercInd=1&f339_TokenFl
g=N&f344_MercCustId=&f346_Token=&f347_TokenShrtNm=&f348_MaskPAN=&f365_POSEnvFlg=" + 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()));

System.out.println(hashed.equalsIgnoreCase("FCXX3469XX7715304XX6XX53XX241088XX4EXX3CCXXC41XXFXX0CXX15XX6614"));
}

public String bytesToHex(byte[] bytes) {

StringBuilder sb = new StringBuilder();
byte[] var6 = bytes;
int var5 = bytes.length;

for(int var4 = 0; var4 < var5; ++var4) {
byte b = var6[var4];
sb.append(String.format("%02x", b));
}

return sb.toString();// 31
}

示例 2

Portal 用户 ID (PortalUserID) 的加密算法是 Triple DES 在 ECB 模式下,如以下步骤所示:

  • 加密密钥与安全哈希密钥相同。

参数

  • Portal 用户 ID > 7180024846
  • 加密密钥 > 00112233445566778899AABBCCDDEEFF

步骤 1:取密钥值

对加密密钥进行消息摘要,并将前 24 字节作为密钥。

MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] digestOfPassword = md.digest(encryptionKey.getBytes("utf-8"));
byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);

十六进制表示的密钥 > 20AFF5A341131D58C07A76E062D895E0968727664B8769B7

步骤 2:初始化密码对象

使用密钥初始化密码对象。

SecretKey key = new SecretKeySpec(keyBytes, "DESede");
Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, key);

步骤 3:填充 Portal 用户 ID

填充 Portal 用户 ID 并返回为字符串。

PortalUserID = padStringByMultiplier(customerID,8);

public static String padStringByMultiplier(String in, int multiplier) {
byte[] dest = null;
while (in.length() % multiplier != 0) {
int finalLength = in.length() + 1;
dest = new byte[finalLength]; byte[] src = in.getBytes();
System.arraycopy(src,0,dest,0,Math.min(src.length,dest.length));
Arrays.fill(dest, src.length, dest.length, (byte) 0x20);
in = new String(dest);
} return in;
}

步骤 4:加密填充的 Portal 用户 ID

使用 Triple DES(使用 ECB 模式)加密填充的 Portal 用户 ID。

byte[] plainTextBytes = customerID.getBytes("utf-8");
byte[] buf = cipher.doFinal(plainTextBytes);

十六进制表示的加密 PortalUserID > 20AFF5A341131D58C07A76E062D895E0968727664B8769B7

步骤 5:编码加密的 Portal 用户 ID

对步骤 4 中的加密 PortalUserID 进行 Base64 编码。

byte[] plainTextBytes = customerID.getBytes("utf-8");
byte[] buf = cipher.doFinal(plainTextBytes);

十六进制表示的加密 PortalUserID > 20AFF5A341131D58C07A76E062D895E0968727664B8769B7

最终值

最终输出值将为:

O5ACzHbvQNm3iNAwdvi1Sg==

编程指南

加载 Java 密钥库文件

Password > mystorepassword

keyStoreFile > mykeystore.jks

KeyStore keystore = KeyStore.getInstance("JKS");
char[] storePass = password.toCharArray();
FileInputStream fileInputStream = new FileInputStream(keyStoreFile);
keystore.load(fileInputStream, storePass);
fileInputStream.close();

从 Java 密钥库文件获取私钥

alias > mySignCert

KeyStore.ProtectionParameter keyPass = new KeyStore.PasswordProtection(storePass);
KeyStore.PrivateKeyEntry privKeyEntry = (KeyStore.PrivateKeyEntry)keystore.getEntry(alias, keyPass);
PrivateKey privateKey = privKeyEntry.getPrivateKey();