圖 3-1: 各欄位資料範例
經過前一篇文章的示範,我們使用 Postman 的測試拿到了 Nonce 值。如上圖,Nonce
是我們發送給豐支付 API 的請求中,其中一個欄位而已。其它例如 Version
是固定值,ShopNo
是官方配給給我們的店家代碼,Sign
和 Message
則是另外兩個我們要產生的欄位資料。
產生安全簽章 Sign 的文件說明在第 17 頁。
圖 3-2: 文件條目,第五章節第四段。
安全簽章是由資料欄位的網址編碼查詢字串 (URL-encoded query string)加上 Nonce 再加上 HashId 之後,再經過 SHA256 編碼產生。
圖 3-3: 文件條目,第五章節第四段第二條。
HashId 是由永豐技術客服給我們的四組雜湊值計算而成。這四組雜湊值各有代號,分別為 A1、A2、B1、B2 如下範例:
代號 | 雜湊值 |
---|---|
A1 | 4D9709D699CA40EE |
A2 | 5A4FEF83140C4E9E |
B1 | BC74301945134CB4 |
B2 | 961F67F8FCA44AB9 |
手冊上是這樣描述的:
圖 3-4: API手冊 - HashId 說明
使用 A1 與 A2 這一對雜湊值進行按位運算 (bitwise operation),採用「按位元或 」運算。B1 與 B2 也進行同樣的運算,取得算出來的字串後,兩者相加則為 HashId。
位元運算符的的說明在 PHP 官方手冊這一段有詳細說明,並有一個範例關於兩個數值使用 XOR,如下:
<?php
echo 12 ^ 9; // Outputs '5' (int)
^
符號為位元運算符,將 12 及 9 以「按位元或」(XOR, Exclusive-Or) 進行運算。
使用 PHP 的朋友,永豐金技術客服已有提供 PHP 的範例函式可直接使用,或者可以使用筆者在稍候章節釋出的非官方版本 SDK。
非使用 PHP 的朋友,實作上,則是將 A1 的字串 4D9709D699CA40EE 分成 4D, 96, 09, D6, 99, CA, 40, EE 八組 16 進位的 HEX 值
A2 的字串 5A4FEF83140C4E9E 分成的 5A, 4F, EF, 83, 14, 0C, 4E, 9E 八組 16 進位的 HEX 值。
B1 及 B2 也是一樣。
代號 | 雜湊值 | 分組(HEX, 16 進位) |
---|---|---|
A1 | 4D9709D699CA40EE | 4D, 97, 09, D6, 99, CA, 40, EE |
A2 | 5A4FEF83140C4E9E | 5A, 4F, EF, 83, 14, 0C, 4E, 9E |
B1 | BC74301945134CB4 | BC, 74, 30, 19, 45, 13, 4C, B4 |
B2 | 961F67F8FCA44AB9 | 96, 1F, 67, F8, FC, A4, 4A, B9 |
接著將 HEX 轉成 10 進位數字如下:
代號 | 雜湊值 | 分組(10 進位) |
---|---|---|
A1 | 4D9709D699CA40EE | 77, 151, 9, 214, 153, 202, 64, 238 |
A2 | 5A4FEF83140C4E9E | 90, 79, 239, 131, 20, 12, 78, 158 |
B1 | BC74301945134CB4 | 188, 116, 48, 25, 69, 19, 76, 180 |
B2 | 961F67F8FCA44AB9 | 150, 31, 103, 248, 252, 164, 74, 185 |
可使用的 PHP 原生函式為 base_convert
。
圖 3-5: base_convert 用法說明
再跑迴圈去計算 A1[0] ^ A2[0]
、A1[1] ^ A2[1]
以此類推。
例如:
<?php
echo 77 ^ 90; // Outputs '23' (int)
echo 151 ^ 79; // Outputs '216' (int)
- | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|---|---|
A1 | 77 | 151 | 9 | 214 | 153 | 202 | 64 | 238 |
A2 | 90 | 79 | 239 | 131 | 20 | 12 | 78 | 158 |
A1 ^ A2 | 23 | 216 | 230 | 85 | 141 | 198 | 14 | 112 |
- | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|---|---|
B1 | 188 | 116 | 48 | 25 | 69 | 19 | 76 | 180 |
B2 | 150 | 31 | 103 | 248 | 252 | 164 | 74 | 185 |
B1 ^ B2 | 42 | 107 | 87 | 225 | 185 | 183 | 6 | 13 |
最後再把結果轉回 HEX 字串,組合起來即可。
- | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|---|---|
Decimal | 23 | 216 | 230 | 85 | 141 | 198 | 14 | 112 |
HEX | 17 | d8 | e6 | 55 | 8d | c6 | 0e | 70 |
- | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|---|---|
Decimal | 42 | 107 | 87 | 225 | 185 | 183 | 6 | 13 |
HEX | 2a | 6b | 57 | e1 | b9 | b7 | 06 | 0d |
A1 與 A2 的結果字串與 B1 與 B2 的結果字串組合起來即為 HashId。
對了,別忘了把字串轉為大寫唷。結果:
17D8E6558DC60E702A6B57E1B9B7060D
本文更新於筆者的 TerryL 部落格,Day 3 - 安全簽章: HashId 計算,有興趣可前往閱讀及討論。