SM2 국가 기밀 알고리즘 암호화 및 복호화

인터페이스 보안 설계 원칙 중 하나는 데이터를 일반 텍스트로 전송할 수 없다는 것입니다.https의 필수 요청 외에도 인터페이스 데이터 암호화도 중요한 방법입니다.다음은 SM2 국가 비밀 알고리즘 암호화 및 복호화 사용에 대해 설명합니다.

SM2여기서는 현재 프론트엔드와 백엔드 아키텍처의 분리를 기반으로 알고리즘을 올바르게 사용하여 데이터를 암호화하고 복호화하는 방법에 대해 간략히 소개하겠습니다 .

1. 백엔드 암호화 및 복호화

1.1 POM 의존성 가져오기

<!-- 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 공개 키, 개인 키 키 쌍 생성

/**
 * 生成公钥、私钥,这个保存好,尤其是私钥,切记不可泄漏
 */
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 암호화 및 복호화

/**
 * 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. 프런트엔드 암호화 및 복호화

2.1 NPM 패키지 종속성 설치

npm install --save sm-crypto

2.2 새 공개 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 사용

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

3. 참고 문헌

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

추천

출처blog.csdn.net/active_pig/article/details/126921695