💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[TOC] ### RSA 加密与签名介绍 RSA是一种非对称加密算法,简单理解就是两个密钥:一个公钥,一个私钥。 加密:公钥加密,私钥解密; 签名:私钥签名,公钥验签。 **用作加密时**,密文泄露是无所谓的(相对而言),重要的是用于解密的密钥必须安全,所以用不公开的私钥来解密,用公钥来加密; **用作签名时**,目的是防止别人伪造我的身份发信息,所以用私钥来签名,用公钥来验签。 #### python签名示例 `requirements.txt`: ```python pycryptodome==3.6.6 ``` `utils.py`: ```python from Crypto.PublicKey import RSA from Crypto.Signature import PKCS1_v1_5 from Crypto.Hash import MD5 import base64 def rsa_sign(encrData): privateKey = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAMJSignj27blOez6i6YCM1b4AC9CtgubD0B9gmTskENJNxzg9i59hCpIibkTg1rvMDdSuKFvlHtxkOgSID8Qgm1h3AxpMKpYT58FnApqY7img85xEZo+uNB1GHTbrhuCGQFf2P8U1hE01Y6miFsESsFTQ09BpNy+1wPKt/KbW75fAgMBAAECgYA/04iPkw4Z1tTd57Vyw4pFaJP28fyFd1rdHdx0ddc0opm9nI5/2q5MjSLfbW9ZsPKvWTZXoCSvHzAvabS5whx0aYpZlfWCd6QRNAuoaP0FSCWH/ty7I3nHQJK8LQQhP3nfekAfiyMpvGGK4KrderEP37/MG1202iycR4X6fZnMkQJBAPqaKChFYAqStADg3owoux5Gc3rAf2zRXIBZXPNEYgE0owpwtP2tYPdcIy9l01Yv1nIDr2O7x8JrbUOuNe/4/4sCQQDGggz4XHqZAwDBvea3g9FBCnojzyqQMtHO54TxL6NXIr7maBoBb0XCXuh6Uz2F7O8an1Bi/adQXVXUhvErG9b9AkBJhU6AuhG6KF4M3+wKnKyA7lRU0ALSTv3fXdhKOmaySdoHZxeCUQpgp7Re5HXDFFfKrVAYZ2/slw3ATGzgkWGPAkBW5b1px4n/i3n8VfY2paSntT9sh5bZUvXXfjALKNB3J4Wr9SxVLnG6ObPJQMEw7FxrKgyVmPZyTrlw9LWEKoa9AkBz9OU/BFhg9wIcHiFWQSOQdKQ4touyTF3T3EbROt34oXEhp1b3/eEGlwvNF2dUrfi39b5rKph63G6d3rxb+GVG" private_key_bytes = base64.b64decode(privateKey) priKey = RSA.importKey(private_key_bytes) # priKey = RSA.importKey(privateKey) signer = PKCS1_v1_5.new(priKey) hash_obj = MD5.new(encrData.encode('utf-8')) signature = base64.b64encode(signer.sign(hash_obj)) return signature if __name__ == '__main__': encrData = "Hello,Milton" print(rsa_sign(encrData)) ```` **注意内容**: 1. 密钥如果是读取自.pem文件,密钥会有开始行和结束行,叫做头标注信息和尾标注信息。常见的长这样: ``` '''-----BEGIN PRIVATE KEY----- #密钥内容# -----END PRIVATE KEY-----''' ``` 此时直接priKey = RSA.importKey(privateKey)(见被注释掉的部分)即可,不用对私钥进行base64解码; 2. 哈希算法可以采用MD5,也可以用别的比如SHA; <br> ### 参考例子 #### 公共参数定义 | 参数名 | 是否必须 | 描述 | | --- | --- | --- | | timestamp | 是 | 每个请求都要带上当前请求时间戳,单位秒 | | sign_type | 是 | 签名类型, RSA, 需要应用(应用自行生成)与平台各一套密钥对, 应用把公钥提供给平台在调用接口时验签, 平台把公钥提供给应用在接口回调时验签 | | sign | 是 | 请求签名, 签名规则: 将除sign参数外的所有非空参数按key进行ASCII字典升序排列, 再将排序后的参数(key=value)以&拼接起来, 生成类似: access_token=kdfdskl&timestamp=25684512565的字符串, 再经过urlencode,使用RSA私钥加密(加密算法: SHA256)并生成base64的签名字符串, 所有请求都需要签名。 | #### python 签名 业务工具类 `sign_utils.py`: ```python # -*-coding:utf-8-*- from urllib import parse import time import requests from Crypto.PublicKey import RSA import base64 from Crypto.Hash import SHA256 from Crypto.Signature import PKCS1_v1_5 import json def send_post_request(url, params_dict): """ 发送http post请求 :param url: 接口地址 :param params_dict:接口参数 :return: """ sign = coffee_rsa_sign(params_dict) params_dict['sign'] = sign.decode('utf8') resp = requests.post(url, data=params_dict) print("-" * 150) print("case_url:", resp.url) print("case_data:", json.dumps(params_dict, indent=4, ensure_ascii=False)) print("case_resp:", json.dumps(resp.json(), indent=4, ensure_ascii=False)) print("") return resp def rsa_sign(sign_raw, key_raw, encryption="SHA256"): """ RSA签名 :param sign_raw:待签名字符串 :param key_raw:签名私钥 :param encryption:签名算法,默认SHA256 :return: """ if encryption == "SHA256": # 将签名串哈希 SHA256 hash_obj = SHA256.new(sign_raw.encode('utf-8')) else: print("加密算法未指定") return False # 加载签名私钥 private_key = RSA.importKey(base64.b64decode(key_raw)) signer = PKCS1_v1_5.new(private_key) # 使用RSA私钥对签名串(必须先哈希)签名 signature = signer.sign(hash_obj) return signature def get_rsa_sign(params_dict): """ 获取业务API签名 :param params_dict:除了sign字段的所有其他参数字典 :return: """ # step0:将非空参数按key进行ASCII字典升序排列, 再将排序后的参数(key=value)以&拼接起来 key_lists = sorted(params_dict.keys()) sign_raw = "&".join(list(map(lambda key: key + "=" + str(params_dict.get(key)), key_lists))) # step1:将签名原串 urldecode sign_raw = parse.quote(sign_raw) # step2:RSA签名 key_raw = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAMJSignj27blOez6i6YCM1b4AC9CtgubD0B9gmTskENJNxzg9i59hCpIibkTg1rvMDdSuKFvlHtxkOgSID8Qgm1h3AxpMKpYT58FnApqY7img85xEZo+uNB1GHTbrhuCGQFf2P8U1hE01Y6miFsESsFTQ09BpNy+1wPKt/KbW75fAgMBAAECgYA/04iPkw4Z1tTd57Vyw4pFaJP28fyFd1rdHdx0ddc0opm9nI5/2q5MjSLfbW9ZsPKvWTZXoCSvHzAvabS5whx0aYpZlfWCd6QRNAuoaP0FSCWH/ty7I3nHQJK8LQQhP3nfekAfiyMpvGGK4KrderEP37/MG1202iycR4X6fZnMkQJBAPqaKChFYAqStADg3owoux5Gc3rAf2zRXIBZXPNEYgE0owpwtP2tYPdcIy9l01Yv1nIDr2O7x8JrbUOuNe/4/4sCQQDGggz4XHqZAwDBvea3g9FBCnojzyqQMtHO54TxL6NXIr7maBoBb0XCXuh6Uz2F7O8an1Bi/adQXVXUhvErG9b9AkBJhU6AuhG6KF4M3+wKnKyA7lRU0ALSTv3fXdhKOmaySdoHZxeCUQpgp7Re5HXDFFfKrVAYZ2/slw3ATGzgkWGPAkBW5b1px4n/i3n8VfY2paSntT9sh5bZUvXXfjALKNB3J4Wr9SxVLnG6ObPJQMEw7FxrKgyVmPZyTrlw9LWEKoa9AkBz9OU/BFhg9wIcHiFWQSOQdKQ4touyTF3T3EbROt34oXEhp1b3/eEGlwvNF2dUrfi39b5rKph63G6d3rxb+GVG" signature = rsa_sign(sign_raw, key_raw, "SHA256") # step3:对签名结果base64加密 signature = base64.b64encode(signature) return signature if __name__ == '__main__': params_dict = { 'app_id': '12996762', 'app_secret': '902ac71d8fdbdfc097f53070afbcaefb', 'platform': '1', 'timestamp': str(int(time.time())), 'sign_type': 'RSA', } # send_post_request("http://xx.x.xxx.net/oauth2/access_token", params_dict) sign = coffee_rsa_sign(params_dict) print(sign) ``` <hr style="margin-top:100px"> :-: ![](https://box.kancloud.cn/2ff0bc02ec938fef8b6dd7b7f16ee11d_258x258.jpg) ***微信扫一扫,关注“python测试开发圈”,了解更多测试教程!***