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

文章讲述了如何在Apifox中使用SM2和SM4加密算法进行数据加密和解密,涉及前后端交互、加密库的引用、密钥处理及在Python后端的解密与加密过程。作者提供了完整的代码示例和问题解决方案。
摘要由CSDN通过智能技术生成

分配了个新任务,把请求内容通过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解密操作

//引入 gmssl
from 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()
//获得加密过的data
encrypted_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的加解密操作流程都清晰可见了,希望对大伙有所帮助~

  • 20
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现SM2数字签名,加密解密需要使用SM2算法库,可以使用Python的第三方库pycryptodome或gmssl。以下是使用pycryptodome实现SM2数字签名,加密解密的示例代码: 1. SM2数字签名 ```python from Crypto.PublicKey import ECC from Crypto.Signature import DSS from Crypto.Hash import SHA256 from Crypto.Cipher import AES from Crypto.Util.Padding import pad, unpad from binascii import b2a_hex, a2b_hex # 生成SM2密钥对 private_key = ECC.generate(curve='sm2') public_key = private_key.public_key() # 待签名数据 data = b'hello, world' # 计算消息摘要 digest = SHA256.new(data) # 对消息摘要进行数字签名 signer = DSS.new(private_key, 'fips-186-3') signature = signer.sign(digest) # 验证数字签名 verifier = DSS.new(public_key, 'fips-186-3') try: verifier.verify(digest, signature) print("Signature is valid.") except ValueError: print("Signature is invalid.") ``` 2. SM2加密解密 ```python from Crypto.Cipher import SM2Cipher from Crypto.PublicKey import ECC from Crypto.Util.Padding import pad, unpad from binascii import b2a_hex, a2b_hex # 生成SM2密钥对 private_key = ECC.generate(curve='sm2') public_key = private_key.public_key() # 加密数据 plaintext = b'hello, world' cipher = SM2Cipher.new(public_key) ciphertext = cipher.encrypt(plaintext) # 解密数据 cipher = SM2Cipher.new(private_key) decrypttext = cipher.decrypt(ciphertext) print("Plaintext:", plaintext) print("Ciphertext:", b2a_hex(ciphertext)) print("Decrypttext:", decrypttext) ``` 注意,以上代码只是示例,实际使用时需要注意安全性和数据格式转换等问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值