在串接API时,遇到最大的坎就是Message内文加密了,
就让我们来试看看罗~
项目 | 说明 |
---|---|
产出JSON讯息内文 | 即要送出的讯息内文(JSON) |
HashID | 由四组 Hash 值透过两两 XOR 位元运算再相加的32 位元字串。 |
IV值 | Nonce 值经过 SHA256 运算後取右边 16 位元字串 。 |
有上一篇的经验,IV计算就显得非常亲切,步骤如下:
sha256 = hashlib.sha256()
sha256.update(NonceValue.encode('utf-8'))
SHAValue = sha256.hexdigest().upper()
print(SHAValue)
IVValue=SHAValue[-16:]
print(IVValue)
结果
CB6FA68E42B655AB
重头戏来罗,规格书显示:
将讯息内文以 AES CBC 方式加密,加密後的 Byte 以十六进制2位数字串相加。
因为对於实在是没有经验,直接针对关键字搜寻,下面是我最後参考的一篇文章,
Python AES/CBC/PKCS5Padding加解密
不过虽然使用以上程序,可以正常的加解密,但出来的加密内容,与范例不一样,因为不熟悉加解密的流程,看范例程序好像也没有太大头绪,大概是我PHP也不太会写,只好於线上搜寻相关问题了,
最後最後~突发奇想,想说找看看线上加密的网页,
参考如下
线上加解密网址
与网页上的程序结果一致,但不是我要的答案,这也是友人问我的问题,无法跟范例一致。
结果我发现线上加解密网站,多了一些选项,Output Text Format的选项,多了HEX选项,如下图,
绝大多数的线上范例,几乎都是base64的格式,
登登,果然改用HEX之後柳暗花明,终於找到答案了!!!!
规格书上若能说出是用HEX转码就省很多麻烦了~~
首先先安装以下套件
pip install pycryptodome
程序如下
from Crypto.Cipher import AES
class AESCrypt:
"""
AES/CBC/PKCS5Padding 加密
"""
def __init__(self, key,iv):
"""
使用金钥,加密模式进行初始化
:param key:
"""
if len(key) != 16 and len(key) !=32:
raise RuntimeError('金钥长度非16位 and 32 位!!!')
self.key = str.encode(key)
self.iv = str.encode(iv)
self.MODE = AES.MODE_CBC
self.block_size = 16
# 填充函数
# self.padding = lambda data: data + (self.block_size - len(data) % self.block_size) * chr(self.block_size - len(data) % self.block_size)
# 此处为一坑,需要现将data转换为byte再来做填充,否则中文特殊字元等会报错
self.padding = lambda data: data + (self.block_size - len(data.encode('utf-8')) % self.block_size) * chr(self.block_size - len(data.encode('utf-8')) % self.block_size)
# 截断函数
self.unpadding = lambda data: data[:-ord(data[-1])]
def aes_encrypt(self, plaintext):
"""
加密
:param plaintext: 明文
:return:
"""
try:
# 填充16位
padding_text = self.padding(plaintext).encode("utf-8")
# 初始化加密器
cryptor = AES.new(self.key, self.MODE, self.iv)
# 进行AES加密
encrypt_aes = cryptor.encrypt(padding_text)
# 进行HEX转码
encrypt_text = encrypt_aes.hex()
# # 进行BASE64转码
# encrypt_text = (base64.b64encode(encrypt_aes)).decode()
return encrypt_text
except Exception as e:
logging.exception(e)
def aes_decrypt(self, ciphertext):
"""
解密
:param ciphertext: 密文
:return:
"""
try:
# 密文必须是16byte的整数倍
# if len(ciphertext) % 16 != 0:
# raise binascii.Error('密文错误!')
# print(ciphertext)
cryptor = AES.new(self.key, self.MODE, self.iv)
# 进行BASE64转码
# plain_decode = base64.b64decode(ciphertext)
# 进行HEX转码
plain_decode = bytes.fromhex(ciphertext)
# print(type(plain_decode)) #byte
# 进行ASE解密
decrypt_text = cryptor.decrypt(plain_decode)
# 截取
plain_text = self.unpadding(decrypt_text.decode("utf-8"))
return plain_text
except UnicodeDecodeError as e:
logging.error('解密失败,请检查金钥是否正确!')
logging.exception(e)
except binascii.Error as e:
logging.exception(e)
except Exception as e:
logging.exception(e)
if __name__ == '__main__':
# 测试
send_message_ori = {
"ShopNo": "BA0026_001",
"OrderNo": "A201804270001",
"Amount": 50000,
"CurrencyID": "TWD",
"PayType": "A",
"ATMParam": {"ExpireDate": "20180502"},
"CardParam": {},
"PrdtName": "虚拟帐号订单",
"ReturnURL": "http://10.11.22.113:8803/QPay.ApiClient/Store/Return",
"BackendURL": "http://10.11.22.113:8803/QPay.ApiClient/AutoPush/PushSuccess",
}
cryptor = AESCrypt(hashID,IVValue)
jsonText=json.dumps(send_message_ori, ensure_ascii=False).replace(' ', "")
aes_encrypt_str = cryptor.aes_encrypt(jsonText).upper()
print(f'加密结果为: {aes_encrypt_str}')
aes_decrypt_str = cryptor.aes_decrypt(aes_encrypt_str)
print(f'解密结果为: {aes_decrypt_str}')
结果如附
加密结果为: 2C236A4E91DB2F7670E79BBCE3A626EB728916919012681FF92BE0B4BBF57F5519AF1A469A1D8710B202CB2C2F3C12A770788D825AD0F0A22AED518545A0D244AD0F9C37C7C693EFFABE78B606BCDAED6284902F7F522BBA85D9BE7EFEF46C6793FB6A5D6624C2642A74EB312034BEA931EE3A5F3C660F3ABAA9032949AE86DEFEB452545807561D282C7B7C8E9102CED1404B8B542BC09CE12FA38F335BE7F027AE74BDDBADDB1790B172EFBF1FD25524E2BB64A626EA44643D4BD490E348E926BB7A48D5FA939EEC5BE681009E7AC7FED1C8475B715891321406960675B5A216032CF8657A3CB2B2D0C7FF85027D70E1F2B5DD414373912E97FA6FB85E9AB89B118BC545583CC9AC503F8BAD73C185CB97B28313618021F9217A30278043EF728BB5C49D231C4A22279864F68194254BC624789F36CCDEE75861CFC667CD8E9E89F1DB04ABA0D26FEF24BFE0470488
解密结果为: {"ShopNo":"BA0026_001","OrderNo":"A201804270001","Amount":50000,"CurrencyID":"TWD","PayType":"A","ATMParam":{"ExpireDate":"20180502"},"CardParam":{},"PrdtName":"虚拟帐号订单","ReturnURL":"http://10.11.22.113:8803/QPay.ApiClient/Store/Return","BackendURL":"http://10.11.22.113:8803/QPay.ApiClient/AutoPush/PushSuccess"}
加解密的部分都搞定了,剩下呼叫永丰API的部分了
<<: Day6 - 下单函数使用,限价、市价、删单、改单怎麽写
>>: 从零开始学3D游戏设计:零件介面 Part.2 完成介面
微服务(Microservices) 微服务是一个低耦合的架构,可以通过以下方式实现重构一个单片应...
人生真的很奇妙 可能在某个时间轴曾经跟某个人的时间轴交错 但当下是不认识的 然後在几年过後又再次交...
当我们布署完Microsoft Defender for Endpoint 接下来当侦测到威胁时,系...
如果有从永丰银行API那边下载过C#版的丰收款QPay.SampleCode,应该能发现他们目前的专...
Day 30 Elastic Cloud挑战结束心得 前言 三十天其实一下子就过去了,这次比赛让我重...