shop_platform - 串接藍新金流:TradeInfo
(本文使用的語言為 python 3)
文件:藍新金流 > API 文件下載 > 多功能收款 MPG。我下載時,版本是 1.6
TradeInfo 是什麼
根據文件第 33 頁的第一個表格,需要傳送給藍新金流的參數共有四個,其中一個就是 TradeInfo:
需要放進 TradeInfo 裡的參數欄位,如文件第 33~37 頁所列。準備好這些參數欄位後,要幫這些參數欄位加密,加密後的結果,才是要傳送給藍新金流的 TradeInfo。
加密
根據文件第 65~66 頁,可以看到,要先把參數欄位整理成 query string 的格式,才進行 AES 加密。AES 加密採用 CBC 模式,padding 的 blocksize 是 32。然後把加密後的結果轉成 16 進位。test case 為:
data = {
'MerchantID': 3430112,
'RespondType': 'JSON',
'TimeStamp': 1485232229,
'Version': 1.4,
'MerchantOrderNo': 'S_1485232229',
'Amt': 40,
'ItemDesc': 'UnitTest'
}
Key = '12345678901234567890123456789012'
IV = '1234567890123456'
expect_output = 'ff91c8aa01379e4de621a44e5f11f72e4d25bdb1a18242db6cef9ef07d80b0165e476fd1d9acaa53170272c82d122961e1a0700a7427cfa1cf90db7f6d6593bbc93102a4d4b9b66d9974c13c31a7ab4bba1d4e0790f0cbbbd7ad64c6d3c8012a601ceaa808bff70f94a8efa5a4f984b9d41304ffd879612177c622f75f4214fa'
query string 格式
將不同的 key-value pair 用 & 隔開,key 和 value 之間用 = 隔開。像這樣:key1=value1&key2=value2
。
也就是說,test case 中的 data 轉換成 query string 格式後會長這樣:
MerchantID=3430112&RespondType=JSON&TimeStamp=1485232229&Version=1.4&MerchantOrderNo=S_1485232229&Amt=40&ItemDesc=UnitTest
data 轉 query string 實作:
from typing import Dict
def query_string_encode(data: Dict) -> str:
key_value_pairs = []
for key, value in data.items():
key_value_pairs.append(f'{key}={value}')
return '&'.join(key_value_pairs)
AES 加密
密鑰(key)和初始向量(iv),會在註冊藍新金流帳號時拿到。密鑰是英文大小寫和數字組成的,共有 32 個字。我目前的猜測是,這組密鑰轉成 ASCII 編碼的話,ASCII 編碼中的每個字元大小是 8 bits (= 1 byte),那麼 32 個字的密鑰,就是 32 * 8 bits = 256 bits,所以會被歸類在 AES 256 加密。
搜尋怎麼用 python 完成 AES 加密,查詢到的套件有 PyCrypto(已經停止維護,網友不推薦使用)、Pycryptodome(或者又叫 Pycryptodomex,結尾多一個 x)。似乎比較多人在用 Pycryptodome,最後使用 Pycryptodome。
AES 加密實作:
from typing import Dict, Union
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
def aes_encrypt(data: str,
key: bytes = HashKey.encode('ascii'),
iv: bytes = HashIV.encode('ascii')) -> str:
cipher = AES.new(key, AES.MODE_CBC, iv=iv)
ciphered_data = cipher.encrypt(pad(data.encode('utf8'), block_size=32))
return ciphered_data.hex()
有些參數只接受二進制或 bytearray 類型的資料,所以我用 string.encode()
函式將字串轉成二進制。因為我使用的 data 中可能有中文,所以是用 utf-8 的編碼方式轉成二進制資料。
PyCharm 一直提醒我:Package containing module 'Crypto' is not listed in the project requirements。看了幾篇關於 crypto、pycrypto、pycryptodome 、pycryptodomex 這幾個套件之間到底是什麼關係的文章後,我目前的理解是:
crypto 是 cli 用的。
pycrypto 多年前已停止維護,繼任者是 pycryptodome。
pycryptodome 和 pycryptodomex 功能是一樣的,他們之間的差別在於安裝的位置不同。前者會把套件安裝在 Crypto package 裡面,和 pycrypto 的安裝位置相同,所以 pycrypto 和 pycryptodome 不能並存;而後者則是安裝在 Cryptodome package 裡面,所以能夠和 pycrypto 並存。
我想,既然我的 Pipfile 裡面已經有寫「pycryptodome = "*"」,我的程式碼應該不會壞掉,所以就不管這個警告了。如果有人真的不喜歡這個警告,那麼我推測,不要安裝 pycryptodome,改成安裝 pycryptodomex 應該就可以解決了。
commit
參考資料
Comments
Post a Comment