python RSA加密传输
由于前端使用HTTP协议, 因此产生了对于数据加密的需求, 由于JS和Python中RSA秘钥产生方式的差异,踩了不少坑, 在这里记录一下.
前端
var crypt = new JSEncrypt();
crypt.setKey(__YOUR_PUBLIC_KEY__); //仅支持pkcs8标准的秘钥文件
var text = 'test';
var enc = crypt.encrypt(text);
秘钥文件格式标准
'pkcs8标准'
# 密钥格式(公钥)
-----BEGIN PUBLIC KEY-----
# 密钥内容
-----END PUBLIC KEY-----
'pkcs1标准'
# 密钥格式(私钥)
-----BEGIN RSA PRIVATE KEY-----
# 私钥内容
-----END RSA PRIVATE KEY-----
后端
python 后端有两个rsa加密库可用,rsa 和 PyCrytodome
安装
pip install rsa
pip install pycryptodomex
这里我使用了PyCrytodome库,rsa用法更简单明了,只是我用了以后一直和前端的rsa加密库对不上。导致前端加密过得的密文,使用这个解不开。
import base64
import os
from Cryptodome.PublicKey import RSA
from Cryptodome.Cipher import PKCS1_OAEP, PKCS1_v1_5
class CryptoRsa:
def __init__(self,password):
self.rsa_public_key = None
self.rsa_private_key = None
self.password = password
def create_rsa_key(self,password=None,path = None):
"""
创建RSA密钥
步骤说明:
1、从 Crypto.PublicKey 包中导入 RSA,创建一个密码
2、生成 1024/2048 位的 RSA 密钥
3、调用 RSA 密钥实例的 exportKey 方法,传入密码、使用的 PKCS 标准以及加密方案这三个参数。
4、将私钥写入磁盘的文件。
5、使用方法链调用 publickey 和 exportKey 方法生成公钥,写入磁盘上的文件。
使用 PKCS1_v1_5,不要用 PKCS1_OAEP,PKCS1_v1_5对应的是PKCS8标准格式
使用 PKCS1_OAEP 的话,前端 jsencrypt.js 只支持PKCS8,加密的数据解密不了
"""
if not os.path.exists(path):
os.makedirs(path)
key = RSA.generate(1024)
encrypted_key = key.exportKey(passphrase=password, pkcs=8,protection="scryptAndAES128-CBC")
self.rsa_private_key = encrypted_key
with open(path +"rsa_private_key.pem", "wb") as f:
f.write(encrypted_key)
self.rsa_public_key = key.publickey().exportKey()
with open(path + "rsa_public_key.pem", "wb") as f:
f.write(self.rsa_public_key)
def rsa_encrypto(self,message,path=None,):
# 加载公钥
recipient_key = RSA.import_key(open(path + "rsa_public_key.pem").read())
cipher_rsa = PKCS1_v1_5.new(recipient_key)
msg = message.encode('utf8')
en_data = cipher_rsa.encrypt(msg)
#base64加密,方便网络传输
bs = base64.b64encode(en_data).decode()
return bs
def rsa_decrypto(self,ciphertext,path =None):
# 读取密钥
private_key = RSA.import_key(open(path + "rsa_private_key.pem").read(), passphrase=self.password)
cipher_rsa = PKCS1_v1_5.new(private_key)
cipherbyte = base64.b64decode(ciphertext) #base64解码
data = cipher_rsa.decrypt(cipherbyte, None)
return data.decode()
if __name__ == '__main__':
path = os.path.dirname(__file__).split('qts')[0]
cr = CryptoRsa(password='123456')
res = cr.rsa_encrypto(message='wyee',path=path)
print(res)
str = cr.rsa_decrypto(ciphertext=res,path=path)
print(str)
附上rsa库的用法:
import base64
import os
import rsa
class RsaCrypto:
def __init__(self):
self.publicKey = None
self.privateKey = None
def create_key(self):
dir = os.path.dirname(__file__).split('qts')[0]
# 生成公钥、私钥
(self.publicKey, self.privateKey) = rsa.newkeys(1024)
e = self.privateKey.save_pkcs1() # 保存为 .pem 格式 (只能保存为pkcs1格式)
with open(dir + "privateKey.pem", "wb") as x: # 保存私钥
x.write(e)
f = self.publicKey.save_pkcs1() # 保存为 .pem 格式
with open(dir +"publicKey.pem", "wb") as x: # 保存公钥
x.write(f)
return f.decode()
def rsa_encrypt(self,str):
# 明文编码格式
content = str.encode("utf-8")
# 公钥加密
crypto = rsa.encrypt(content, self.publicKey)
return crypto
def rsa_decrypt(self,str):
# 私钥解密
content = rsa.decrypt(str, self.privateKey)
message = content.decode("utf-8")
return message
def verify_sign(self,str): #验签
str = str.encode("utf-8")
sign = rsa.sign(str, self.privateKey, "SHA-256") # 使用私钥进行'sha256'签名
verify = rsa.verify(str, sign, self.publicKey) # 使用公钥验证签名
return verify
def load_key(self,filepath = None,pem = None):
if filepath:
with open(filepath, "rb") as x:
key = x.read()
key = rsa.PublicKey.load_pkcs1(key) # load 公钥,由于之前生成的私钥缺少'RSA'字段,故无法 load
elif pem :
key = rsa.PublicKey.load_pkcs1(pem)
else:
key =None
return key