Python版SM2加密

一、场景

  • 在使用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:
            # get请求时,CustomSm2实例化不需要传参,生成密钥对,之后自己存入session中,将公钥给前端加密
            self.init_key_pair()
        else:
            # post请求时,从session中拿到密钥对,传给CustomSm2实例化
            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):
        # 后端使用py_sm2.js生成密钥对
        # 前端也需要使用sm2.js,配合后端返回的公钥对数据加密
        key_pair_js_path = os.path.join(os.path.dirname(__file__), 'js', 'py_sm2.js')
        # 注意,这里为自己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

你可能感兴趣的:(python)