Python Signature & Verification Example
In API requests, to ensure data integrity and security, we use the RSA signature mechanism to encrypt and sign requests, and verify signatures on the receiving end.
This example provides a SignatureHandler class for generating signatures and verifying signatures
python
import base64
import json
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.serialization import (
load_pem_private_key,
load_pem_public_key,
)
class SignatureHandler:
def __init__(self, key: str, key_type: str = "private"):
"""
Initialize signature/verification class
:param key: Private or public key content (without headers and footers)
:param key_type: Key type, "private" for private key, "public" for public key
"""
if key_type == "private":
pem_key = (
"-----BEGIN PRIVATE KEY-----\n"
+ "\n".join(key[i:i + 64] for i in range(0, len(key), 64))
+ "\n-----END PRIVATE KEY-----"
)
self.key = load_pem_private_key(pem_key.encode(), password=None)
self.is_private = True
elif key_type == "public":
pem_key = (
"-----BEGIN PUBLIC KEY-----\n"
+ "\n".join(key[i:i + 64] for i in range(0, len(key), 64))
+ "\n-----END PUBLIC KEY-----"
)
self.key = load_pem_public_key(pem_key.encode())
self.is_private = False
else:
raise ValueError("Invalid key_type. Must be 'private' or 'public'.")
def generate_signature(self, merchant_id: str, timestamp: str, timezone: str, body: dict) -> str:
"""
Generate signature
:param merchant_id: Merchant ID
:param timestamp: Timestamp
:param timezone: Timezone
:param body: Request body string
:return: Generated signature (Base64 encoded string)
"""
if not self.is_private:
raise ValueError("Key must be private to generate signature.")
# Assemble signature content
body_str = json.dumps(body, separators=(",", ":"), ensure_ascii=False)
# Assemble signature content
sign_content = f"{merchant_id}.{timestamp}.{timezone}.{body_str}"
# Generate signature
signature = self.key.sign(
sign_content.encode(),
padding.PKCS1v15(),
hashes.SHA256(),
)
# Return Base64 encoded signature string
return base64.b64encode(signature).decode()
def verify_signature(self, merchant_id: str, timestamp: str, timezone: str, body: dict,
received_signature: str) -> bool:
"""
Signature verification method
:param merchant_id: Merchant ID
:param timestamp: Timestamp
:param timezone: Timezone
:param body: Request body string
:param received_signature: Signature sent by client (Base64 encoded string)
:return: Verification result, True for success, False for failure
"""
if self.is_private:
raise ValueError("Key must be public to verify signature.")
body_str = json.dumps(body, separators=(",", ":"), ensure_ascii=False)
# Assemble signature content
sign_content = f"{merchant_id}.{timestamp}.{timezone}.{body_str}"
try:
# Decode received signature
decoded_signature = base64.b64decode(received_signature)
# Verify signature
self.key.verify(
decoded_signature,
sign_content.encode(),
padding.PKCS1v15(),
hashes.SHA256(),
)
return True
except Exception as e:
return False