最初目的是验证参数签名。
由于因为 sign 太长,超出了微信 URL Link 的自定义参数长度限制。最终没有采用此算法
- sha1 的目的是降低明文长度
"""
RSA with SHA1 签名和验证
"""
import hashlib
import random
import string
from typing import cast
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding, rsa
def sha1(data: bytes) -> bytes:
return hashlib.sha1(data).digest()
def generate_rsa_keys():
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=1024,
backend=default_backend(),
)
public_key = private_key.public_key()
private_pem = private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption(),
)
public_pem = public_key.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo,
)
return private_pem, public_pem
hash_algorithm = hashes.SHA1()
def sign_rsa(private_key: bytes, data: bytes):
# 加载私钥
pk = cast(rsa.RSAPrivateKey, serialization.load_pem_private_key(private_key, None))
# 对数据进行签名
signature = pk.sign(data, padding.PKCS1v15(), hash_algorithm)
return signature
def verify_rsa(public_key: bytes, data: bytes, signature: bytes):
pk = cast(rsa.RSAPublicKey, serialization.load_pem_public_key(public_key))
try:
pk.verify(signature, data, padding.PKCS1v15(), hash_algorithm)
return True
except Exception:
return False
def _test_rsa_sign_verify():
private_key, public_key = generate_rsa_keys()
print("private_key", private_key)
print("public_key", public_key)
for _ in range(10):
word_len = random.randint(10, 100)
word = "".join(random.choices(string.ascii_letters + string.digits, k=word_len))
word_sha1 = sha1(word.encode())
signature = sign_rsa(private_key, word_sha1)
signature_hex = signature.hex()
raw_signature = bytes.fromhex(signature_hex)
print("signature", len(signature_hex), signature_hex)
assert verify_rsa(public_key, word_sha1, raw_signature)
assert not verify_rsa(public_key, word_sha1 + b"1", raw_signature)
print("pass")
if __name__ == "__main__":
_test_rsa_sign_verify()