谷仓密钥使用说明

1. 什么是谷仓密钥.

每一个开通了开发者账号的客户,至少都会拥有一个默认应用。开发者可以配置属于应用的密钥对,包括公钥和私钥。 开发者使用应用接口传递业务数据时,都需要使用谷仓密钥进行数据加密。数据使用公钥进行加密,使用私钥解密。
建议开发者对于接口返回的数据进行解密核验校对,确认返回的数据是否正确,防止被第三方拦截攻击。
谷仓密钥使用SM2国密算法,前端后端代码均可以通过算法进行加解密校验。

2. 数据加解密示例.

Java加解密

使用antherd进行加解密示例
import com.antherd.smcrypto.sm2.Keypair;
import com.antherd.smcrypto.sm2.Sm2;
import io.netty.util.internal.StringUtil;
public class SM2Encryptor {
    /**
     * 加密,使用公钥
     *
     * @param publicKey
     * @param originalText
     * @return
     */
    public static String encryptText(String publicKey, String originalText) throws Exception {
        if (StringUtil.isNullOrEmpty(publicKey)) {
            throw new Exception("密钥不能为空...");
        }
        if (StringUtil.isNullOrEmpty(originalText)) {
            throw new Exception("明文不能为空...");
        }
        try {
            return Sm2.doEncrypt(originalText, publicKey);//HexUtil.encodeHexStr(cipherText); // 加密结果
        } catch (Exception e) {
            throw new Exception("加密错误:密钥不正确...");
        }
    }
    /**
     * 解密,使用私钥
     *
     * @param privateKey
     * @param cipherText
     * @return
     */
    public static String decryptText(String privateKey, String cipherText) throws Exception {
        if (StringUtil.isNullOrEmpty(privateKey)) {
            throw new Exception("密钥不能为空...");
        }
        if (StringUtil.isNullOrEmpty(cipherText)) {
            throw new Exception("明文不能为空...");
        }
        try {
            return Sm2.doDecrypt(cipherText, privateKey); // new String(sm2.decrypt(sourceData,prvKey)); // 解密结果
        } catch (Exception e) {
            throw new Exception("解密错误:密钥不正确...");
        }
    }
    /**
     * 获取sm2密钥对,
     *
     * @return 返回String[];第0个为公钥,第1个为私钥
     * @throws Exception
     */
    public static String[] generateKeyPair() throws Exception {
        try {
            Keypair keypair = Sm2.generateKeyPairHex();
            String[] result = new String[2];
            if (keypair != null) {
                result[0] = keypair.getPublicKey(); //公钥
                result[1] = keypair.getPrivateKey(); // 私钥
            }
            return result;
        } catch (Exception e) {
            throw new Exception("生成密钥对失败...");
        }
    }
    public static void main(String[] args) throws Exception {
        //生成一对 公钥与私钥
        String[] keys = generateKeyPair();
        //公钥
        String publicKey = keys[0];
        System.out.println("公钥" + publicKey);
        //私钥
        String privateKey = keys[1];
        System.out.println("私钥" + privateKey);
        String str = "测试使用SM2加密、解密";
        //加密字符串
        String encryptText = SM2Encryptor.encryptText(publicKey, str);
        System.out.println(encryptText);
        //解密字符串
        String decryptText = SM2Encryptor.decryptText(privateKey, encryptText);
        System.out.println(decryptText);
    }
}
					
使用Hutool的SM2工具类进行加解密示例
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.SM2;
import cn.hutool.core.util.StrUtil;
/**使用指定的密钥对进行加解密测试*/
public void testDiySm2() {
	String text = "伯牙善鼓琴,锺。子期善听。"
		+ "伯牙鼓琴,志在登高山,锺子期曰:“善哉,峨峨兮若泰山!”志在流水,锺子期曰:“善哉,洋洋兮若江河!”伯牙所念,锺子期必得之。"
		+ "伯牙游于泰山之阴,卒(cù)逢暴雨,正于岩下,心悲,乃援琴而鼓之。"
		+ "初为霖雨之操,更造崩山之音。"
		+ "曲每奏,锺子期辄穷其趣,伯牙乃舍琴而叹曰:“善哉,善哉,子之听夫!志想象犹吾心也,吾于何逃声哉?”";
		// 公钥加密,私钥解密
	String privateKey = "308193020100301306072a8648ce3d020106082a811ccf5501822d047930770201010420f97cade46ccc9c24fa8e7cc6"
		+ "d5f937d4f68e51e41ea5ed1b45f90d24ff109fb4a00a06082a811ccf5501822da14403420004dee120256e01bee93dc812d063c411"
		+ "cfdef08abbc393157e3f341f5b95e65a6fe670208043c8d43f05f8ced762a74d9e6df757732f62feb1b17e04792074e233";
	String publicKey = "3059301306072a8648ce3d020106082a811ccf5501822d03420004dee120256e01bee93dc812d063c411cfdef08abbc39"
		+ "3157e3f341f5b95e65a6fe670208043c8d43f05f8ced762a74d9e6df757732f62feb1b17e04792074e233";
	SM2 sm2 = SmUtil.sm2(privateKey, publicKey);
	String encryptStr = sm2.encryptBcd(text, KeyType.PublicKey);
	System.out.println("加密后:" + encryptStr);
	String decryptStr = StrUtil.utf8Str(sm2.decryptFromBcd(encryptStr, KeyType.PrivateKey));
	System.out.println("解密后:" + decryptStr);
}
					

VUE等Node.js项目加解密示例


在项目下执行脚本以安装依赖:
npm install --save sm-crypto

因为前端vue基本上使用统一的request.js,在项目的interceptor内处理相关参数的加解密比较简单,这里不再赘述。以下是核心代码示例:

const sm2 = require('sm-crypto').sm2 // 获取sm2对象
const cipherMode = 0 // 选择加密策略,1 - C1C3C2,0 - C1C2C3,默认为1
const sysPublicKey = '你对应的后台的公钥' // 系统后台公钥
const uiPrivateKey = '你自己前端的私钥' // 前端UI私钥

/**
 * SM2加密string数据
 * @param {string} data 原始数据
 * @returns {string} 加密后数据
 */
export function getSm2DataHexByString(data) {
  if (data && (typeof data === 'string') && data.constructor === String) {
    return '04' + sm2.doEncrypt(data, sysPublicKey, cipherMode)
  }
  return null
}

/**
 * SM2加密object数据
 * @param {Object} data 原始数据
 * @returns {string} 加密后数据
 */
export function getSm2DataHexByObject(data) {
  if (data) {
    return '04' + sm2.doEncrypt(JSON.stringify(data), sysPublicKey, cipherMode)
  }
  return null
}

/**
 * SM2解密数据
 * @param {string} dataHex 原始加密数据
 * @returns {string} 解密后数据
 */
export function getSm2DataByString(dataHex) {
  if (dataHex && (typeof dataHex === 'string') && dataHex.constructor === String) {
    dataHex = dataHex.substring(2).toLocaleLowerCase()
    return sm2.doDecrypt(dataHex, uiPrivateKey, cipherMode)
  }
}