python RSA rsa 加密、解密、签名、验签 密钥文件讲解说明
RSA公私钥生成地址
http://www.metools.info/code/c80.html
在线RSA PKCS#1、PKCS#8公钥格式转换工具
http://www.metools.info/code/c85.html
1.从PFX文件 提取 公钥、私钥 方法一
2.从PFX文件 提取 公钥、私钥 方法二
1、提取密钥对(如果pfx证书已加密,会提示输入密码。)
openssl pkcs12 -in 1.pfx -nocerts -nodes -out 1.key
2、从密钥对提取私钥
openssl rsa -in 1.key -out 1_pri.key
3、从密钥对提取公钥
openssl rsa -in 1.key -pubout -out 1_pub.key
3.使用openssl将RSA的X.509公钥转成PKCS#1标准
3.1 确定RSA公钥标准
假如公钥是以X.509标准导出,以PEM格式存储,那么形式如下:
-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----
假如公钥是以PKCS#1标准导出,以PEM格式存储,那么形式如下:
-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----
3.2使用openssl将X.509转成PKCS#1
openssl rsa -pubin -in x509_public.key -RSAPublicKey_out > rsa_public.key
4.Python RAS 加密、解密、签名、验签
python中用于RSA加解密的库有好久个,本文主要讲解rsa 库对于RSA加密、解密、签名、验签的知识点。
推荐使用rsa库
加密是为了保证传输内容隐私,签名是为了保证消息真实性。
服务器存私钥,客户端存公钥。(服务器和客户端关系可以考虑为 1:N)
客户端往服务器传输内容,更多考虑是隐私性,所以公钥签名、私钥解密。
服务器往客户端传输内容,更多考虑真实性,所以私钥签名,公钥验签。
消息的摘要生的算法常用的是MD5或者SHA1,消息内容不一样,生成的摘要信息一定不一样。
真实性的考虑一方面是内容由私钥拥有者发出,另一方面内容在传输过程中没有改变过,所以签名的对象是传输信息生成的消息摘要(摘要内容短,签名也会快些)。
每次加密的长度需要小于密钥长度-特殊位(128位公钥,最长可加密128-11=117位明文)。
每次解密的长度需要小于密钥的长度(128位私钥解密,解密密文长度需要小于等于128位)。
如果加解密内容过长,就需要分段加密、解密。
PEM格式的密钥为base64位文本格式。
# -*- coding: UTF-8 -*- # ! /usr/bin/env python import base64 import rsa from rsa import common # 使用 rsa库进行RSA签名和加解密 class RsaUtil(object): PUBLIC_KEY_PATH = '/tmp/gbzj/public_key.pem' # 公钥 PRIVATE_KEY_PATH = '/tmp/gbzj/private_key.pem' # 私钥 # 初始化key def __init__(self, company_pub_file=PUBLIC_KEY_PATH, company_pri_file=PRIVATE_KEY_PATH): if company_pub_file: self.company_public_key = rsa.PublicKey.load_pkcs1_openssl_pem(open(company_pub_file).read()) if company_pri_file: self.company_private_key = rsa.PrivateKey.load_pkcs1(open(company_pri_file).read()) def get_max_length(self, rsa_key, encrypt=True): """加密内容过长时 需要分段加密 换算每一段的长度. :param rsa_key: 钥匙. :param encrypt: 是否是加密. """ blocksize = common.byte_size(rsa_key.n) reserve_size = 11 # 预留位为11 if not encrypt: # 解密时不需要考虑预留位 reserve_size = 0 maxlength = blocksize - reserve_size return maxlength # 加密 支付方公钥 def encrypt_by_public_key(self, message): """使用公钥加密. :param message: 需要加密的内容. 加密之后需要对接过进行base64转码 """ encrypt_result = b'' max_length = self.get_max_length(self.company_public_key) while message: input = message[:max_length] message = message[max_length:] out = rsa.encrypt(input, self.company_public_key) encrypt_result += out encrypt_result = base64.b64encode(encrypt_result) return encrypt_result def decrypt_by_private_key(self, message): """使用私钥解密. :param message: 需要加密的内容. 解密之后的内容直接是字符串,不需要在进行转义 """ decrypt_result = b"" max_length = self.get_max_length(self.company_private_key, False) decrypt_message = base64.b64decode(message) while decrypt_message: input = decrypt_message[:max_length] decrypt_message = decrypt_message[max_length:] out = rsa.decrypt(input, self.company_private_key) decrypt_result += out return decrypt_result # 签名 商户私钥 base64转码 def sign_by_private_key(self, data): """私钥签名. :param data: 需要签名的内容. 使用SHA-1 方法进行签名(也可以使用MD5) 签名之后,需要转义后输出 """ signature = rsa.sign(data, priv_key=self.company_private_key, hash_method='SHA-256') # 加密方式Use 'MD5', 'SHA-1', 'SHA-224', SHA-256', 'SHA-384' or 'SHA-512' return base64.b64encode(signature) def verify_by_public_key(self, message, signature): """公钥验签. :param message: 验签的内容. :param signature: 对验签内容签名的值(签名之后,会进行b64encode转码,所以验签前也需转码). """ signature = base64.b64decode(signature) return rsa.verify(message, signature, self.company_public_key) message = 'appId=f334fdgd&bizContent={"authCode":"4196a49571e747259028fa25df330604b4f6d301"}×tamp=2022-08-01 10:20:08' print("明文内容:>>> ") print(message) rsaUtil = RsaUtil() encrypy_result = rsaUtil.encrypt_by_public_key(message) print("加密结果:>>> ") print(encrypy_result) decrypt_result = rsaUtil.decrypt_by_private_key(encrypy_result) print("解密结果:>>> ") print(decrypt_result) sign = rsaUtil.sign_by_private_key(message) print("签名结果:>>> ") print(sign) print("验签结果:>>> ") print(rsaUtil.verify_by_public_key(message, sign))