SM2 国家機密アルゴリズムの暗号化と復号化

インターフェイスのセキュリティ設計原則の 1 つは、データを平文で送信できないことです。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