在这篇文章中,介绍了如何使用飞天诚信的加密狗设备进行加密解密。但文章最后有个遗憾:需要借助官方给的 PHP 代码来进行解密。自己尝试了几次用 Python 实现,总是失败。
今天终于发现了解决之道。
依赖
需要安装 pycryptodome:
1
| pip3 install pycryptodome -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com
|
完整代码
等效于 PHP 的 openssl_public_decrypt,手动处理 RSA 运算和 PKCS#1 v1.5 padding(兼容 0x01 和 0x02 两种格式):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| from urllib.parse import unquote import base64 from Crypto.PublicKey import RSA
def check_rsa_code(encrypted_str: str) -> str: """ 使用公钥解密(等效于 PHP 的 openssl_public_decrypt) 适配 PKCS#1 v1.5 两种 padding 格式 (0x01/0x02)
:param encrypted_str: URL 编码 + Base64 编码的密文 :return: 解密后的明文字符串 """ public_key_pem = """-----BEGIN PUBLIC KEY----- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxx -----END PUBLIC KEY-----"""
encrypted_str = unquote(encrypted_str) encrypted_bytes = base64.b64decode(encrypted_str)
rsa_key = RSA.import_key(public_key_pem) n = rsa_key.n e = rsa_key.e
cipher_int = int.from_bytes(encrypted_bytes, byteorder="big") plain_int = pow(cipher_int, e, n)
k = (rsa_key.size_in_bits() + 7) // 8 plain_bytes = plain_int.to_bytes(k, byteorder="big")
if len(plain_bytes) > 2 and plain_bytes[0] == 0x00: if plain_bytes[1] == 0x01: sep_idx = plain_bytes.find(b"\x00", 2) if sep_idx > 0: plain_bytes = plain_bytes[sep_idx+1:] elif plain_bytes[1] == 0x02: sep_idx = plain_bytes.find(b"\x00", 2) if sep_idx > 0: plain_bytes = plain_bytes[sep_idx+1:] else: plain_bytes = plain_bytes.lstrip(b"\x00") else: plain_bytes = plain_bytes.lstrip(b"\x00")
return plain_bytes.decode("utf-8")
|
小结
这样就完全不再依赖 PHP 了。困扰了四年的问题,就这样解决了~