首页 > 其他分享 >SM2 签名与验签前后端对接指南(基于 Hutool 和 sm-crypto)

SM2 签名与验签前后端对接指南(基于 Hutool 和 sm-crypto)

时间:2025-01-02 18:12:11浏览次数:1  
标签:与验 示例 SM2 Hutool 签名 sm data crypto

SM2 签名与验签前后端对接指南

本文档旨在指导如何使用 Hutool(Java)和 sm-crypto(TypeScript)库,实现基于 SM2 算法的签名与验签功能。确保前后端在签名与验证过程中,参数传递和密钥格式一致,避免因格式不匹配导致的验证失败。

目录

前提条件

  • 后端:Java 环境,推荐使用 Hutool 库。本文版本5.8.35
  • 前端:TypeScript 或者 JavaScript环境,使用 sm-crypto 库。本文版本·^0.3.13
  • 熟悉 SM2 算法的基本原理。

密钥格式说明

私钥[要是位数不对,检查下什么语言生成的,java的没有无符号,所以可能要加前导0]

  • 格式:16 进制字符串,长度为 64 字符
  • 示例
    4BD9A450D7E68A5D7E08EB7A0BFA468FD3EB32B71126246E66249A73A9E4D44A
    

公钥[可根据自己项目来,但是你要不理解密钥封装格式,就按这个来]

  • 格式
    • 非压缩格式:以 04 开头,后跟 X 和 Y 坐标,每个坐标 64 字符(总长度 130 字符)。
    • 压缩格式(可选):以 0203 开头,后跟 X 坐标(64 字符),新版规范的明确了0203
  • 示例(非压缩)
    04970AB36C3B870FBC04041087DB1BC36FB4C6E125B5EA406DB0EC3E2F80F0A55D8AFF28357A0BB215ADC2928BE76F1AFF869BF4C0A3852A78F3B827812C650AD3
    

后端实现(Java + Hutool)

依赖引入

确保在项目中引入 Hutool 库。如果使用 Maven,可以在 pom.xml 中添加:

<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-crypto</artifactId>
    <version>5.8.35</version> <!-- 请根据实际情况选择版本 -->
</dependency>

SM2 签名与验签代码示例

以下是使用 Hutool 实现 SM2 签名与验签的完整代码示例:

package org.dromara.hutool.crypto.asymmetric;
import org.dromara.hutool.core.codec.binary.HexUtil;


public class SM2Example {
    public void sm2Verify1Test(){
        // 私钥(16 进制,64 字符)
        final String privateKey = "4BD9A450D7E68A5D7E08EB7A0BFA468FD3EB32B71126246E66249A73A9E4D44A";
        // 公钥(非压缩格式,130 字符,以04开头)
        final String publicKey = "04970AB36C3B870FBC04041087DB1BC36FB4C6E125B5EA406DB0EC3E2F80F0A55D8AFF28357A0BB215ADC2928BE76F1AFF869BF4C0A3852A78F3B827812C650AD3";
        // 待签名数据
        final String data = "旧信";
        // 初始化 SM2 实例
        final SM2 sm2 = new SM2(privateKey, publicKey);
        // 签名(可选)
        // final String signHex = sm2.signHex(data.getBytes(), "1234567812345678".getBytes());
        // System.out.println("Hutool签名的hex:" + signHex);
        // 示例签名(TypeScript 生成的签名)
        final String tsSignHex = "3046022100970a8f60bdb6e3c6248e4da9f99acbddf32451b658be846fad5680e1f2fecccb02210081725f32b56afd60aac928c7462df5a0b384b756df1bb6ae8994b9b6f201cd38";
        // 验签
        final boolean verify1 = sm2.verify(data.getBytes(), HexUtil.decode(tsSignHex));
        System.out.println("验签结果: " + verify1);
    	}
	public static void main(String[] args) {
		SM2Example example = new SM2Example();
		example.sm2Verify1Test();
	}
}

说明

  • 私钥与公钥:需确保私钥为 64 字符的 16 进制字符串,公钥为以 04 开头的 130 字符非压缩格式。
  • 签名:可以使用 Hutool 生成签名,也可以接受前端生成的签名(如示例中的 tsSignHex)。
  • 验签:通过 sm2.verify 方法,传入原始数据和签名,返回验签结果。

前端实现(TypeScript + sm-crypto)

安装 sm-crypto

使用 npm 或 yarn 安装 sm-crypto

npm install sm-crypto

yarn add sm-crypto

SM2 签名与验签代码示例

以下是使用 sm-crypto 实现 SM2 签名与验签的完整代码示例:

import { sm2 } from 'sm-crypto';

/**
 * 使用 SM2 算法进行签名和验签
 * @param data - 待签名的数据
 * @param privateKey - 用于签名的私钥(16 进制字符串,64 字符)
 * @param publicKey - 用于验证签名的公钥(非压缩格式,130 字符)
 * @returns {string} 返回签名结果以及验签结果
 */
const sm2Test = (data: string, privateKey: string, publicKey: string): string => {
    // 使用私钥对数据进行签名
    const sign: string = sm2.doSignature(data, privateKey, {
        der: true,
        hash: true,
        userId: '1234567812345678'
    });

    // 使用公钥验证签名
    const isValid: boolean = sm2.doVerifySignature(data, sign, publicKey, {
        der: true,
        hash: true,
        userId: '1234567812345678'
    });
    // 返回签名及验证结果
    return `TS生成的签名: ${sign}\n签名验证结果: ${isValid}`;
};
// 测试数据
const privateKey = "4BD9A450D7E68A5D7E08EB7A0BFA468FD3EB32B71126246E66249A73A9E4D44A";
const publicKey = "04970AB36C3B870FBC04041087DB1BC36FB4C6E125B5EA406DB0EC3E2F80F0A55D8AFF28357A0BB215ADC2928BE76F1AFF869BF4C0A3852A78F3B827812C650AD3";
const data = '旧信';

// 执行测试
console.log(sm2Test(data, privateKey, publicKey));

说明

  • 私钥与公钥:确保私钥为 64 字符的 16 进制字符串,公钥为以 04 开头的 130 字符非压缩格式。
  • 签名
    • der: true:生成的签名使用 DER 编码。
    • hash: true:对数据进行哈希处理(默认使用 SM3)。
    • userId:用户标识,需与后端保持一致。
  • 验签:使用 sm2.doVerifySignature 方法,传入原始数据、签名和公钥,返回验签结果。

完整示例与测试

1. 前端生成签名并发送至后端

假设前端使用上述 TypeScript 代码生成签名,并通过 API 将数据和签名发送至后端:

// 生成签名和验证结果
const result = sm2Test(data, privateKey, publicKey);
console.log(result);

// 示例输出
// TS生成的签名: 3046022100970a8f60bdb6e3c6248e4da9f99acbddf32451b658be846fad5680e1f2fecccb02210081725f32b56afd60aac928c7462df5a0b384b756df1bb6ae8994b9b6f201cd38
// 签名验证结果: true
// 将 data 和 sign 发送至后端

2. 后端接收数据并进行验签

后端接收 datasign 后,使用 Hutool 进行验签:

public void sm2VerifyFromFrontEnd(String data, String signHex){
    final String privateKey = "4BD9A450D7E68A5D7E08EB7A0BFA468FD3EB32B71126246E66249A73A9E4D44A";
    final String publicKey = "04970AB36C3B870FBC04041087DB1BC36FB4C6E125B5EA406DB0EC3E2F80F0A55D8AFF28357A0BB215ADC2928BE76F1AFF869BF4C0A3852A78F3B827812C650AD3";
    final SM2 sm2 = new SM2(privateKey, publicKey);
    final boolean isValid = sm2.verify(data.getBytes(), HexUtil.decodeHex(signHex));
    System.out.println("前端签名验证结果: " + isValid);
}

调用示例

public static void main(String[] args) {
    SM2Example example = new SM2Example();
    String data = "lin";
    String signHex = "d2f1bbdfcc77e6051caa1729dfd13ed35617ecf92f2d8eca82c2c9fe3c3bd59a1643de0e7ff201acae1f6067f4cbe9fb1467003ebf948994f63d7748c9ec5127";
    example.sm2VerifyFromFrontEnd(data, signHex);
}

预期输出

前端签名验证结果: true

注意事项

  1. 密钥格式一致性:确保前后端使用的私钥、公钥格式一致,避免因格式不匹配导致验签失败。[格式真的很多,但是私钥就是一个整数,不同格式就是对它的编码而已]
  2. 用户标识(User ID):SM2 签名过程中,用户标识需要保持前后端一致。本示例中使用 1234567812345678[hutool默认是这个,sm-crypto默认应该也是,我记得规范写了这个值],但是GmSSL库中默认ID字符串为16个字节的ASCII字符串anonym@gmssl.org,不包含末尾的0。
  3. 签名编码
    • 前端生成的签名需与后端解析方式一致。本示例中,前端使用 der: false 生成 r||s 格式的签名,后端需使用相应方式进行验签。
  4. 字符编码:确保前后端对待签名数据(如 data)的字符编码一致,推荐使用 UTF-8
  5. 安全性:妥善保管私钥,避免泄露。传输过程中建议使用 HTTPS 等安全协议。

通过以上步骤,您可以实现前后端基于 SM2 算法的签名与验签功能,确保数据传输的完整性和真实性。如在实际应用中遇到问题,建议参考相关文档或社区资源寻求帮助。

标签:与验,示例,SM2,Hutool,签名,sm,data,crypto
From: https://www.cnblogs.com/lylhqy/p/18648417

相关文章

  • 【thinkphp】国密sm2
    一、下载  lpilp/guomi依赖composerrequirelpilp/guomi二、使用lpilp/guomi<?phpnamespaceapp\controller;useRtgm\sm\RtSm2;useRtgm\sm\RtSm3;classSm{protected$privateKey=null;protected$publicKey=null;publicfunction__cons......
  • hutool的一个奇怪现象,main ERROR Log4j2 could not find a logging implementation. P
    hutool有一个强大的功能,一行代码实现增删改查。在src/main/resources目录增加一个db.settings配置文件:url=jdbc:mysql://localhost:3306/ujcms?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=trueuser=rootpass=root##......
  • 从思路到方法,一文讲清药物靶点的筛选与验证
    一、什么是药物靶点研究?在人类与疾病的漫长斗争中,新药的研发无疑是最为关键的环节之一。在下方的图片中展示了新药研发从一个想法的诞生,到实验室中的初步研究,再到最终的药物上市的全过程,这里的每一步都充满了机遇与挑战。我们今天所讲的药物靶点研究是指实验室阶段的研究,即......
  • Java 项目实战:基于 Spring Boot、MyBatis、PageHelper、Spring Security、FastJSON、S
    一、系统概述1.1系统目标本系统的主要目标是提供一个集成化的商品管理平台,实现以下功能:高效的商品信息管理,包括商品的基本信息、类型、供应商、客户等的录入、查询、修改和删除。精确的采购流程管理,涵盖采购订单的创建、修改、查询、入库操作以及与供应商的信息关联。完善......
  • SM2 - 数字签名算法
    符号A,B:使用公钥密码系统的两个用户。\(a,b\):\(F_q\)中的元素,他们定义\(F_q\)上的一条椭圆曲线\(E\)。\(d_A\):用户A的私钥。\(E⁡(F_q)\):\(F_q\)上椭圆曲线\(E\)的所有有理点(包括无穷远点\(O\))组成的集合。\(e\):密码杂凑函数作用于消息\(M\)的输出值。\(e'\):密码杂凑函数作......
  • BurpSuite工具-暴力破解模块与验证码识别
    一、暴力破解-Intruder1.1.攻击目标(Target)1.2.有效负载位置(Positions)1.2.1.狙击手(Sniper)1.2.2.破城槌(Batteringram)1.2.3.音叉(Pitchfork)1.2.4.集束炸弹(Clusterbomb)1.3.有效载荷(Payloads)1.4.资源池(ResourcePool)1.5.选项(Options)二、验证码识别2......
  • sm2
    packagemainimport("crypto/ecdsa""crypto/rand""crypto/x509/pkix""fmt""github.com/tjfoc/gmsm/sm2""github.com/tjfoc/gmsm/x509""math/big""ti......
  • 使用 Hutool 在 Java 中生成验证码
    文章目录详细步骤1.安装JDK和IDE2.创建Maven项目3.添加Hutool依赖4.编写验证码生成代码5.运行代码6.查看结果详细步骤1.安装JDK和IDE安装JDK访问OracleJDK或OpenJDK网站下载适合你操作系统的JDK版本。按照安装向导完成安装,并配置环境......
  • x509.MarshalSm2PrivateKey
    根据搜索结果,x509.MarshalSm2PrivateKey函数需要两个参数:一个*sm2.PrivateKey和一个[]byte类型的密码。以下是使用x509.MarshalSm2PrivateKey将SM2私钥编码为PEM格式的示例代码:gopackagemainimport( "crypto/rand" "encoding/pem" "fmt" "github.com/tjfoc......
  • burp(6)暴力破解与验证码识别绕过
    声明!学习视频来自B站up主**泷羽sec**有兴趣的师傅可以关注一下,如涉及侵权马上删除文章,笔记只是方便各位师傅的学习和探讨,文章所提到的网站以及内容,只做学习交流,其他均与本人以及泷羽sec团队无关,切勿触碰法律底线,否则后果自负!!!!有兴趣的小伙伴可以点击下面连接进入b站主页[B站......