本文的目標是將如 Message
欄位的內文使用 AES 加密機制將其進行加密,並轉換成如下圖所示的 16 進制字串。
圖 7-1: 各欄位資料範例
AES 加密機制
在筆者本身串接各家金流的經驗中,AES (advanced encryption standard) 區塊加密法最常見到的,其中加密模式又以 ECB 與 CBC 使用頻率最高。ECB 是最簡單的加密模式,不需要 IV 值,大部分廠商在安全要求更嚴謹的資料上會使用 CBC 加密模式。
本系列的永豐金收款系統正是使用 CBC 加密模式。
CBC 加密模式需要一個初始化向量 (initialization vector) 來對其第一個區塊加鹽,也就是我們在 Day 6 產生的 IV 值。
依賴套件
在 PHP 中使用 AES-CBC 加密模式是使用 openssl_encrypt
函式,如果執行時發生找不到函式的錯誤,可以先使用 php -m
指令確認一下有無安裝 OpenSSL 擴展。如果沒有的話則必須先安裝唷!
圖 7-2: CLI 指令範例 php -m
如上圖紅箭頭標示,找到的話表示您的 PHP 版本已安裝 OpenSSL。
加密實作
在使用 openssl_encrypt 函式時有三個參數我們必須提供。請見以下說明。
Message 加密要件
圖 7-3: Message 欄位要件,文件第 22 頁
(1) JSON 訊息內文
圖 7-4: 範例 - 建立訂單的資料結構
JSON 訊息內文為要傳送給 API 的資料結構,作為 openssl_encrypt 函式的第一個參數。
(2) HashId
openssl_encrypt 函式的第三個參數,作為加密的 key。
取得方法參閱 Day 3 - 安全簽章: HashId 計算。
(3) IV
openssl_encrypt 函式的第四個參數。
取得方法參閱 Day 6 - 產生內文加密所需的 IV 值。
範例
圖 7-5: PHP SDK - aesEncrypt 方法
本範例是 PHP SDK 中用來進行 AES-CBC 加密的方法。
第13行 為使用 PHP 函式 openssl_encrypt 進行加密。
第14行 將加密後產生的 binary string 轉成 HEX,接著轉成大寫字元。
驗證加密結果
圖 7-6: 加密測試網頁
API 文件第 22 頁提供兩個線上測試工具來驗證加密是否正確。
網址 | |
---|---|
加密 | https://sandbox.sinopac.com/QPay.ApiClient/Calc/Encrypt |
解密 | https://sandbox.sinopac.com/QPay.ApiClient/Calc/Descrypt |
在筆者進行線上工具測試時,發現程式的加密程式碼算出來的結果和線上測試工具的結果不同,再進一步比對輸入的 JSON 字串,發現必須要一模一樣,多一個空格、斷行或者跳脫字元都不行。
例如,單純使用 json_encode 函式將陣列轉換成 JSON 字串時,中文字會被編碼,反斜線也被加了跳脫字元,因此在測試的時候可以考慮以下兩個方法之一:
(1) json_encode 加上旗標
可以在 json_encode 函式加上旗標值讓 JSON 字串的輸出和我們貼到測試網頁的一致,不然加密後的結果會不一樣喔!
關於 json_encode 的旗標值可參閱 PHP 官方手冊 這一頁。
圖 7-7: json_encode 加上 flag 差異
上圖是使用 json_encode 將陣列轉成 JSON 字串有無使用旗標的差異,標市示綠色螢光色是中文字被轉成 Unicode 編碼字符,標市示黃色螢光色是反斜線也被加了跳脫字元。經由此圖可以一眼看出其中的差別。
常數名 | 旗標值 | 說明 |
---|---|---|
JSON_UNESCAPED_UNICODE | 256 | 不把中文字轉成 Unicode 編碼字符 |
JSON_UNESCAPED_SLASHES | 64 | 不把反斜線加上跳脫字元 \ |
JSON_FORCE_OBJECT | 16 | 會把空陣列 [] 轉成 {} |
以上是一些可以參考使用的旗標常數,總而言之,程式轉出來的 JSON 字串要和網頁上的一樣就對了。
(2) 使用程式產生的 JSON 字串
另外一個方法是,使用程式產生的 JSON 字串貼到測試網頁上的輸入框。雖然中文字被轉碼,也會有跳脫字元,不過只要兩邊的字串是完全一致,加密後的結果就會一樣。
流程總結
今天的文章完成了發送請求給 Order
API 需要的 Message 欄位,其它需要的欄位也已取得,明天的進度就來建立我們第一筆的測試訂單吧!
留言