基于apifox、python:利用SM2和SM4实现前端参数加密与后端数据解密加密

five_otto 2024-06-22 11:33:01 阅读 97

分配了个新任务,把请求内容通过sm2和sm4方法加密后发往后端解密再将返回数据进行加密返回到前端解密


apifox前置操作

外部库引用的问题

需要使用的sm2和sm4加密方法apifox内置的cryptoJs库并没有,只能引入新的库

参考文档:https://apifox.com/help/pre-post-processors-and-scripts/scripts/api-references/javascript-library

写法:

//内置类var cryptoJs = require("crypto-js");//外部引用类fox.liveRequire("sm-crypto", (smCrypto) => { try { //... } catch (error) { console.error("An error occurred during liveRequire callback", error); throw error; }});

但是这样写有可能有问题,主要看apifox的版本(至少我是这样)

我将加密方法写在fox.liveRequire里,但是我运行发送请求却走不到fox.liveRequire,而同事却可以,所以我直接更新到最新版(当前版本 2.5.13 原先版本:2.3.17)再发送就可以正确获得报错信息了

sm2加密读取空值属性‘multiply’

请添加图片描述

在吧里找了找,发现了解决方法,我直接在公钥前面拼接了‘04’就好了:

// 对随机密钥进行公钥加密const encryptedKey = smCrypto.sm2.doEncrypt(randomKey, "04" + publicKey);

参考文章:https://blog.csdn.net/ciwei0605/article/details/125844154

sm4加密无效密钥:

请添加图片描述

我一开始使用的Math.random().toString(36).substring(2, 18)来获取随机的密钥,但由于 Math.random() 生成的浮点数是伪随机的,在进行转换为字符串后可能会出现一些小数精度上的问题,所以我得到的并不一定是16位的随机数,密钥就无效了(smCrypto.sm4.encrypt函数需要接受一个16字节长度的Buffer类型密钥)

解决方法:

//方法一 自己写一个随机字符串的方法function RandomString(length) { var result = ''; var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; var charactersLength = characters.length; for (var i = 0; i < length; i++) { result += characters.charAt(Math.floor(Math.random() * charactersLength)); } return result;}//方法二 使用 crypto 模块中的 randomBytes 方法(引入方法参考上面的:外部库引用的问题)const randomKey = Buffer.from(crypto.randomBytes(16).toString('hex').substring(0, 16));

这就顺利加密成功了

完整加密代码

const { v4: uuidv4 } = require('uuid');function RandomString(length) { var result = ''; var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; var charactersLength = characters.length; for (var i = 0; i < length; i++) { result += characters.charAt(Math.floor(Math.random() * charactersLength)); } return result;}fox.liveRequire("sm-crypto", (smCrypto) => { try { // 生成随机密钥 const randomNum = RandomString(16); const randomKey = Buffer.from(randomNum, 'utf-8').toString('hex'); pm.environment.set('randomKey', randomKey); // 获取请求数据 const requestData = pm.request.body.raw; console.log(requestData) // 公钥 const publicKey = 'sm2生成的密钥对的公钥 放这里'; // 对随机密钥进行公钥加密 const encryptedKey = smCrypto.sm2.doEncrypt(randomNum, publicKey); // 对请求数据进行加密 const encryptedData = smCrypto.sm4.encrypt(requestData, randomKey); // 构建加密后的数据包 const dataPackage = { data: encryptedData, encrypt: encryptedKey, seq: uuidv4(), timestamp: Date.now() }; // 更新请求体中的数据 pm.request.body.update(JSON.stringify(dataPackage)); } catch (error) { console.error("An error occurred during liveRequire callback", error); throw error; }});


python后端解密

确认sm2的密钥对是否正确匹配

解密跟开锁一样,最重要的是你的锁得和你的钥匙配对,你拿错误的钥匙死怼门锁也是开不了的,所以密钥对必须得先确保是一对配套的。我主要测试随便网上生成了一对sm2的密钥对,我也不知道是不是压缩过的,我看未压缩的公钥前面都自带04,我生成的就没有,我就直接加上了04进行了加密,但是我后端用私钥却无法正确解开,折腾了好久,又去网上生成了一对新的密钥对,这次公钥自带04我没做任何修改,解码的时候就顺利解开了。

sm2解密操作

//引入 gmsslfrom gmssl import sm4, sm2//创建sm2算法实例sm2_crypt = sm2.CryptSM2(public_key=config.SM2_PUBLIC_KEY, private_key=config.SM2_PRIVATE_KEY)//获得请求中的数据decrypted_data = json_decode(self.request.body)//获取加密过的密钥encrypted_key = decrypted_data.get("encrypt")//使用sm2私钥对密钥进行解密,获得解密后的密钥并转码decode_encrypted_key = sm2_crypt.decrypt(bytes.fromhex(encrypted_key))v_key = decode_encrypted_key.decode("utf-8")//创建sm4算法实例sm4_crypt = sm4.CryptSM4()//获得加密过的dataencrypted_data = decrypted_data.get("data")//使用解密后的密钥设置sm4的解密密钥sm4_crypt.set_key(v_key.encode("utf-8"), sm4.SM4_DECRYPT)//使用sm4算法对加密数据进行解密decrypted_data_str = sm4_crypt.crypt_ecb(bytes.fromhex(encrypted_data))//存放密钥 用于加密返回数据self.sm4Key = v_key...后续可对解密后的数据进行操作获得返回数据,并使用解密后的密钥再对其加密返回


python后端加密

对返回数据进行加密

from gmssl import sm4//创建sm4算法实例sm4_crypt = sm4.CryptSM4()//获取密钥v_key = self.sm4Key//设置sm4的加密密钥sm4_crypt.set_key(v_key.encode("utf-8"), sm4.SM4_ENCRYPT)//进行加密操作encrypted_data = sm4_crypt.crypt_ecb(json.dumps(data).encode("utf-8")).hex()...data是我需要返回的数据,根据实际数据替换。如果是json对象需要转为json字符串再加密,我的就是json对象,所以我转为了json字符串后进行加密


apifox后置操作

对返回数据进行解密

const encryptedData = pm.response.json().data;// 获取随机密钥const randomKey = pm.environment.get('randomKey');fox.liveRequire("sm-crypto", (smCrypto) => { try { // sm4解密 获取解密后的data 并转为json对象 const decryptedData = smCrypto.sm4.decrypt(encryptedData, randomKey); const decryptedObject = JSON.parse(decryptedData); // 替换原始响应数据 const json = pm.response.json(); json.data = decryptedObject; pm.response.setBody(json) } catch (error) { console.error("An error occurred during liveRequire callback", error); throw error; }});


至此对于使用apifox、python对sm2、sm4的加解密操作流程都清晰可见了,希望对大伙有所帮助~



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。