- 背景
- md5withRSA加签和验签名原理简单介绍
- 总结
我需要测试open API提供给第三方的查询接口,本身接口没有什么难度,由于安全规范,需要验证数字签名,该接口要求每次请求传入10位之内的随机数,当前的时间戳,以及用户的邮箱,拼接而成的字符串用于生成数字签名,比如:nonce=99999923×tamp=1632747148774&userName=qyzhg113@core.qyzhg.com,通过md5withRSA算法加密生成的字符串,放在query请求参数中,服务器那边做验证签名,因为每次都有时间戳,和随机数的校验,所以用postman不好测试(postman应该可以用js写,奈何本人不会js),所以用python 来实现,本身也是做一个记录。
md5withRSA加签和验签名原理简单介绍此处不讨论加密算法的原理,本人数学不咋样,就不献丑了,来说一说,通常加签和验签的流程。
1.约定公钥和私钥,RSA算法会生成一对公钥和私钥,暴露接口一方会提供私钥给使用接口的一方,公钥和私钥不清楚的可以自行百度,这里不做过多说明
例子:
test_private_key = ''' MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAL0CpOl9vtJqj9t8osGZagTPi5lm5IUal8yyZbK27J2iwqhocfCTxPns3VfGgqnJerrUQAKBYk1oQ61aA7aJ0flxEtG2IcH2lF3WmqvDLP9BHJQtXRs/oQdEniz9Im3SYNU5rR0c5owJk1P0HC8Sume1UlbFPJOiPl9PUZk01DBnAgMBAAECgYBAg0OIkqvsJAUgFGV1EQkXxUNPw8fiCpaffpCptDgFAgXQ931UcQt9hrRx/kag7y0d0c5bTJAh/aGD7MJxro7lLqbsSs5GAW6h4E6a7bJKWq3z61figwO/7SY2Ym9/NzaWCUo+CZosdDDwv3yTkqZ5ZeZZ409CG+5YEgpODAvjWQJBAPoGvf8F706hmSzYX/PHRVju1FAcgwxhrM7kUyuUNSCeqBfGO6KaFo7PiRm2+xtrvlLZt1s2l5sLYiF+WrHhx20CQQDBhrRaI6crsGYHrX+64AJWxiLpiM93ZVxlJyOMKHNIGDN5W1u0r4VlASWFs/Z2EKTTU874NQE4wn2L6rRIK06jAkA2dqmEmAJdGo6HWkrsi4frq3rMSKmzVMOT/eCwKYS5KlZrd18eOHqZeVPgKh/hBUNcQNjUIbw8peomaaPQA+KxAkEAivxOLGpsldDjBeKR2EknBODZk/UAYtQ17iOUwQUP/hf7Z8235+UinS6cnxBnEdXUOj13aATRMs1jUwgln6sSlwJBAOQeTxCeKx/Dj9660/nZgek8ez3kcshK+mlz04kIQzG+XSzE3G9joYMYoLz/CIc+xyYXCqqasL/h2hOpB/kj0kI= ''' test_public_key = ''' MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC9AqTpfb7Sao/bfKLBmWoEz4uZZuSFGpfMsmWytuydosKoaHHwk8T57N1XxoKpyXq61EACgWJNaEOtWgO2idH5cRLRtiHB9pRd1pqrwyz/QRyULV0bP6EHRJ4s/SJt0mDVOa0dHOaMCZNT9BwvErpntVJWxTyToj5fT1GZNNQwZwIDAQAB '''
2.使用私钥生成签名,这里用到Cypto库,具体代码实现如下
from string import Template
import time
from faker import Faker
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import MD5
import base64
import urllib.parse
import requests
test_private_key = '''
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAL0CpOl9vtJqj9t8osGZagTPi5lm5IUal8yyZbK27J2iwqhocfCTxPns3VfGgqnJerrUQAKBYk1oQ61aA7aJ0flxEtG2IcH2lF3WmqvDLP9BHJQtXRs/oQdEniz9Im3SYNU5rR0c5owJk1P0HC8Sume1UlbFPJOiPl9PUZk01DBnAgMBAAECgYBAg0OIkqvsJAUgFGV1EQkXxUNPw8fiCpaffpCptDgFAgXQ931UcQt9hrRx/kag7y0d0c5bTJAh/aGD7MJxro7lLqbsSs5GAW6h4E6a7bJKWq3z61figwO/7SY2Ym9/NzaWCUo+CZosdDDwv3yTkqZ5ZeZZ409CG+5YEgpODAvjWQJBAPoGvf8F706hmSzYX/PHRVju1FAcgwxhrM7kUyuUNSCeqBfGO6KaFo7PiRm2+xtrvlLZt1s2l5sLYiF+WrHhx20CQQDBhrRaI6crsGYHrX+64AJWxiLpiM93ZVxlJyOMKHNIGDN5W1u0r4VlASWFs/Z2EKTTU874NQE4wn2L6rRIK06jAkA2dqmEmAJdGo6HWkrsi4frq3rMSKmzVMOT/eCwKYS5KlZrd18eOHqZeVPgKh/hBUNcQNjUIbw8peomaaPQA+KxAkEAivxOLGpsldDjBeKR2EknBODZk/UAYtQ17iOUwQUP/hf7Z8235+UinS6cnxBnEdXUOj13aATRMs1jUwgln6sSlwJBAOQeTxCeKx/Dj9660/nZgek8ez3kcshK+mlz04kIQzG+XSzE3G9joYMYoLz/CIc+xyYXCqqasL/h2hOpB/kj0kI=
'''
test_public_key = '''
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC9AqTpfb7Sao/bfKLBmWoEz4uZZuSFGpfMsmWytuydosKoaHHwk8T57N1XxoKpyXq61EACgWJNaEOtWgO2idH5cRLRtiHB9pRd1pqrwyz/QRyULV0bP6EHRJ4s/SJt0mDVOa0dHOaMCZNT9BwvErpntVJWxTyToj5fT1GZNNQwZwIDAQAB
'''
# 获取时间戳
def get_timestamp():
return int(time.time() * 1000)
# 获取6位随机数
def get_nonce():
fake = Faker()
return fake.random_int(min=100000, max=999999)
# 将字符串使用MD5进行加密
def my_hash(data):
return MD5.new(data.encode('utf-8'))
# 使用约定的私钥生成签名
def rsa_sign(data):
private_key_bytes = base64.b64decode(test_private_key)
pri_key = RSA.importKey(private_key_bytes)
signer = PKCS1_v1_5.new(pri_key)
hash_obj = my_hash(data)
signature = base64.b64encode(signer.sign(hash_obj))
return signature
# 使用约定的公钥验证签名
def rsa_verify(signature, data):
public_key_bytes = base64.b64decode(test_public_key)
pub_key = RSA.importKey(public_key_bytes)
hash_obj = my_hash(data)
verifier = PKCS1_v1_5.new(pub_key)
return verifier.verify(hash_obj, base64.b64decode(signature))
例子:
待加密的字符串:
test_data = "apiCode=fa4e05682c474619d29cbf3df4a9f69a&entCode=0fe827b0ce0c2f1249642119bc3efcdb&nonce=99999923×tamp=1632747148774&userName=qyzhg113@core.qyzhg.com"
使用md5做一次加密
# 将字符串使用MD5进行加密
def my_hash(data):
return MD5.new(data.encode('utf-8'))
将生成的加密数据,再通过rsa的私钥生成签名
# 使用约定的私钥生成签名,注意我这里已经直接调用了md5了
def rsa_sign(data):
private_key_bytes = base64.b64decode(test_private_key)
pri_key = RSA.importKey(private_key_bytes)
signer = PKCS1_v1_5.new(pri_key)
hash_obj = my_hash(data)
signature = base64.b64encode(signer.sign(hash_obj))
return signature
生成的签名结果,
HuCYD1zwCtqUEM2rgFBCVO5gCiDNplaoenArlCA7AGgowXAjiMjCesUuNJZN7I24R+Zq70S2za4Nf7/LfDHa0ajP6rnaA1rXQyhy6ymMzknSAI0Bn9dafmKGCE3fFUt/2e46lGHZFpT3JXgpmEkNczZeMo5iTA+/VKhdGoofOHc=
3.服务器收到你的请求中传递的签名,进行验证签名操作
# 使用约定的公钥验证签名
def rsa_verify(signature, data):
public_key_bytes = base64.b64decode(test_public_key)
pub_key = RSA.importKey(public_key_bytes)
hash_obj = my_hash(data)
verifier = PKCS1_v1_5.new(pub_key)
return verifier.verify(hash_obj, base64.b64decode(signature))
test_data = "apiCode=fa4e05682c474619d29cbf3df4a9f69a&entCode=0fe827b0ce0c2f1249642119bc3efcdb&nonce=99999923×tamp=1632747148774&userName=qyzhg113@core.qyzhg.com" print(rsa_verify(rsa_sign(test_data), test_data)) 结果: True总结



