SM2 National Secret Algorithm Encryption and Decryption

One point of the interface security design principle is that data cannot be transmitted in plain text. In addition to the necessary request of https, interface data encryption is also an important method. The following describes the use of SM2 national secret algorithm encryption and decryption.

Here I will briefly introduce how to correctly use SM2algorithms to encrypt and decrypt data based on the current separation of front-end and back-end architectures. The introduction is divided into back-end encryption and decryption and front-end encryption and decryption.

1. Backend encryption and decryption

1.1 Import POM dependencies

<!-- hutool -->
<dependency>
  <groupId>cn.hutool</groupId>
  <artifactId>hutool-all</artifactId>
  <version>5.8.5</version>
</dependency>
<!-- 加解密依赖包 -->
<dependency>
  <groupId>org.bouncycastle</groupId>
  <artifactId>bcprov-jdk15to18</artifactId>
  <version>1.71</version>
</dependency>

1.2 Generate public key, private key key pair

/**
 * 生成公钥、私钥,这个保存好,尤其是私钥,切记不可泄漏
 */
public static void generateCommonKey() {
    
    
  SM2 sm2 = SmUtil.sm2();
  // 私钥:这个保存好,切记不要泄漏,真的泄露了就重新生成一下
  byte[] privateKey = BCUtil.encodeECPrivateKey(sm2.getPrivateKey());
  // 公钥:这个是前后端加密用的,不压缩选择带04的,不带04到时候前端会报错
  byte[] publicKey = ((BCECPublicKey) sm2.getPublicKey()).getQ().getEncoded(false);
  Console.log("公钥:\n{}", HexUtil.encodeHexStr(publicKey));
  Console.log("私钥:\n{}", HexUtil.encodeHexStr(privateKey));
}

1.3 Encryption and decryption

/**
 * sm2明文加密
 * PRIVATE_KEY:生成的私钥
 * PUBLIC_KEY:生成的公钥
 * @param data 加密前的明文
 * @return 加密后的密文
 */
public static String encryptData(String data) {
    
    
  SM2 sm2 = SmUtil.sm2(ECKeyUtil.toSm2PrivateParams(PRIVATE_KEY), ECKeyUtil.toSm2PublicParams(PUBLIC_KEY));
  String encryptBcd = sm2.encryptBcd(data, KeyType.PublicKey);
  // 这里的处理前端也可以处理,这个就看怎么约定了,其实都无伤大雅
  if (StrUtil.isNotBlank(encryptBcd)) {
    
    
    // 生成的加密密文会带04,因为前端sm-crypto默认的是1-C1C3C2模式,这里需去除04才能正常解密
    if (encryptBcd.startsWith("04")) {
    
    
      encryptBcd = encryptBcd.substring(2);
    }
    // 前端解密时只能解纯小写形式的16进制数据,这里需要将所有大写字母转化为小写
    encryptBcd = encryptBcd.toLowerCase();
  }
  return encryptBcd;
}

/**
 * sm2密文解密
 * PRIVATE_KEY:生成的私钥
 * PUBLIC_KEY:生成的公钥
 * @param encryptData 加密密文
 * @return 解密后的明文字符串
 */
public static String decryptData(String encryptData) throws Exception {
    
    
  if (StrUtil.isBlank(encryptData)) {
    
    
    throw new RuntimeException("解密串为空,解密失败");
  }
  SM2 sm2 = SmUtil.sm2(ECKeyUtil.toSm2PrivateParams(PRIVATE_KEY), ECKeyUtil.toSm2PublicParams(PUBLIC_KEY));
  // BC库解密时密文开头必须带04,如果没带04则需补齐
  if (!encryptData.startsWith("04")) {
    
    
    encryptData = "04".concat(encryptData);
  }
  byte[] decryptFromBcd = sm2.decryptFromBcd(encryptData, KeyType.PrivateKey);
  if (decryptFromBcd != null && decryptFromBcd.length > 0) {
    
    
    return StrUtil.utf8Str(decryptFromBcd);
  } else {
    
    
    throw new Exception("密文解密失败");
  }
}

2. Front-end encryption and decryption

2.1 Install NPM package dependencies

npm install --save sm-crypto

2.2 Create a new public sm2.js

const sm2 = require('sm-crypto').sm2;
// 加密策略,1 - C1C3C2,0 - C1C2C3,默认为1
const encryptMode = 1;
const publicUiKey = '后端生成的公钥';
const privateKey = '后端生成的私钥';

/**
 * 加密数据
 * @param {Object} data 明文数据
 */
export function encryptData(data) {
    
    
	if (data && (typeof data === 'string') && (data.constructor === String)) {
    
    
		return '04'.concat(sm2.doEncrypt(data, publicUiKey, encryptMode));
	}
	return data;
}


/**
 * 加密对象数据
 * @param {Object} data 对象明文
 */
export function encryptObjectData(data) {
    
    
	if (data) {
    
    
		return '04'.concat(sm2.doEncrypt(JSON.stringify(data), publicUiKey, encryptMode));
	}
	return data;
}

/**
 * 解密数据
 * @param {Object} dataHex 加密的密文数据
 */
export function decryptData(encryptData) {
    
    
	if (encryptData && (typeof encryptData === 'string') && (encryptData.constructor === String)) {
    
    
		const decryptData = sm2.doDecrypt(encryptData, privateKey, encryptMode);
		return decryptData;
	}
}

2.3 use

import {
    
     encryptData, decryptData} from "../../../request/sm2.js";
encryptData('明文');
decryptData('密文');

3. Reference documents

https://www.npmjs.com/package/sm-crypto

Guess you like

Origin blog.csdn.net/active_pig/article/details/126921695