cer格式证书转公钥
openssl x509 -inform der -in 20KFT.cer -noout -pubkey > test.pub
大致验签代码如下:
In [46]: raw='callerIp=10.37.20.46&language=zh_CN&orderNo=20190318083116287&payAmount=19&
...: payResult=2&payType=2&phone=13425454548&rechargeAmount=20&transTime=201903180831
...: 16'
In [47]: signature = 'AvQDPQqKXKsrPE10Gvv6QDlcrWg437J9WLIOPTdBt4cqws6DnX8nCFztnVE8U/eln4o
...: +78JtjIPOsHKg9B2+uHMGiznxlMRggyVTyI1ki/7igxstKfz6WIZIjqBMhqjxWSw/AOeQ8y95ZNofeo1
...: LhSZQDebzbGcTxb9x6uCSh/G6k2TlPLA3HTqZUjZIuWRp5QmtXxnrokUrQPjhXv61SvheFJPxR2Od5Vm
...: tC08IRx+oCAZ96lRmneURFm/lO3d0Rr7NR+kemviqcbKX3CN6s1uWEwiXMzqy8jobsVdcqzyHjct17mx
...: kClL+uawSVAEx6zr2AT9tCrxrHuR+tmSc2Q=='
In [48]: pub=RSA.import_key(Path('test.pub').read_text())
In [53]: PKCS1_v1_5.new(pub).verify(SHA1.new(raw.encode()), b64decode(signature))
Out[53]: True
封装成函数:
import binascii
from base64 import b64decode, b64encode
from pathlib import Path
from urllib.parse import unquote
# pip install pycryptodomex
from Cryptodome.Hash import SHA1
from Cryptodome.PublicKey import RSA
from Cryptodome.Signature import PKCS1_v1_5
def build_raw(origin: dict) -> str:
data = {k: v for k, v in origin.items() if v and not k.startswith("signature")}
return "&".join(f"{k}={v}" for k, v in sorted(data.items()))
def do_verify(raw: str, signature: bytes, pub: str) -> bool:
pkc = PKCS1_v1_5.new(RSA.importKey(pub))
return pkc.verify(SHA1.new(raw.encode()), signature)
def verify_sign(recv: dict, pub_filename: str = "pub.pem") -> bool:
pub = Path(pub_filename).read_bytes().decode()
signature = unquote(recv["signatureInfo"]).encode()
try:
signature = b64decode(signature)
except binascii.Error:
...
return do_verify(build_raw(recv), signature, pub)
如果公钥是固定的,则直接把公钥对象写成常量更佳:
from base64 import b64decode
from pathlib import Path
from urllib.parse import unquote
from Cryptodome.Hash import SHA1
from Cryptodome.PublicKey import RSA
from Cryptodome.Signature import PKCS1_v1_5
PUB_PKC = PKCS1_v1_5.new(RSA.importKey(Path("pub.pem").read_text()))
def build_raw(origin: dict) -> str:
data = {k: v for k, v in origin.items() if v and not k.startswith("signature")}
return "&".join(f"{k}={v}" for k, v in sorted(data.items()))
def verify_sign(recv: dict) -> bool:
sha_obj = SHA1.new(build_raw(recv).encode())
return PUB_PKC.verify(sha_obj, b64decode(unquote(recv["signatureInfo"])))