一、场景
- 在使用Python进行后端开发过程中,需要对用户登录信息进行加密,并有一定的安全性要求,于是采用了“国密sm2”进行加密。
二、策略
- 在每次加密过程中都会首先生成新的公私钥,并存入session
- 后端生成密钥对和前端加密都使用同样的js代码
- 公钥返回给前端,用于加密
- 前端加密上传数据后,后端从session中取出密钥对,使用sm2对数据解密,并进行信息认证
三、后端代码
import os
from threading import Lock
import execjs
from gmssl import sm2
class CustomSm2(object):
_instance = None
lock = Lock()
public_key = 'B9C9A6E04E9C91F7BA880429273747D7EF5DDEB0BB2FF6317EB00BEF331A83081A6994B8993F3F5D6EADDDB81872266C87C018FB4162F5AF347B483E24620207'
private_key = '00B9AB0B828FF68872F21A837FC303668428DEA11DCD1B24429D0C99E24EED83D5'
def __init__(self,public_key=None,private_key=None):
if not public_key or not private_key:
self.init_key_pair()
else:
self.public_key = public_key
self.private_key = private_key
self.sm2_cry = sm2.CryptSM2(public_key=self.public_key, private_key=self.private_key)
def __new__(cls, *args, **kwargs):
with cls.lock:
if not cls._instance:
cls._instance = object.__new__(cls)
return cls._instance
def init_key_pair(self):
key_pair_js_path = os.path.join(os.path.dirname(__file__), 'js', 'py_sm2.js')
with open(key_pair_js_path, 'rt', encoding='utf-8') as f:
docjs = execjs.compile(f.read())
res = docjs.call('get_key_pair')
self.public_key, self.private_key = res.split(';')
def get_enc_data(self, ciphertext):
"""
加密
:param ciphertext: 元数据
:return:
"""
if not ciphertext:
return ''
enc_data = self.sm2_cry.encrypt(ciphertext.encode('utf-8'))
return enc_data
def get_dec_data(self, enc_data):
"""
解密
:param enc_data: sm2加密后的数据
:return:
"""
if not enc_data:
return ''
dec_data = self.sm2_cry.decrypt(bytes.fromhex(enc_data)).decode('utf-8')
return dec_data
四、需要使用的js版加密文件
sm2.js及py_sm2.js下载 提取码: 479q