SM2签名结果的分析(ASN1、142、128)


0.背景

SM2椭圆曲线公钥密码算法

1.格式

在准则中可以看到,签名计算的最后一步是将两个数字转换为字符串。

image-20220208093053523

SM2签名的长度为128位(R+S = 64+64 = 128),有时候我们看到的不止128位,多半是因为做了ASN1格式转换。

2.分析

下方以软加密和加密机签名的结果做分析:

// 软加密签名结果142:
3045022100d596d18be77035b0bb9ef6abf232e9e81f2df3178bedd56d64220dc72c6883a602201b92ddc4c167e22956e5ef32ce19bf4c05f9d6d96aa82c41ace0ba28acba8715

// 加密机签名结果128:
d596d18be77035b0bb9ef6abf232e9e81f2df3178bedd56d64220dc72c6883a61b92ddc4c167e22956e5ef32ce19bf4c05f9d6d96aa82c41ace0ba28acba8715

可以看到,上方代码计算结果长度为142,加密机为128。

咦,连长度都对不上。

这里提前给出结果,下方将描述如何转换:

// 142位的是ASN1的格式
3045022100d596d18be77035b0bb9ef6abf232e9e81f2df3178bedd56d64220dc72c6883a602201b92ddc4c167e22956e5ef32ce19bf4c05f9d6d96aa82c41ace0ba28acba8715
// 128位的是字符串格式
d596d18be77035b0bb9ef6abf232e9e81f2df3178bedd56d64220dc72c6883a61b92ddc4c167e22956e5ef32ce19bf4c05f9d6d96aa82c41ace0ba28acba8715

2.1 ASN1实体类编写

由于SM2的签名结果是由两个数字拼接构成,构建时我们使用ASN1Integer。

import cn.yang37.utils.YangHexUtils;
import org.bouncycastle.asn1.*;
import java.math.BigInteger;

/**
 * @description: SM2签名 ASN1格式
 * @class: SM2SignAsn1
 * @author: yang37
 * @date: 2022/2/8 9:47
 * @version: 1.0
 */
public class SM2SignAsn1 extends ASN1Object {
    private ASN1Integer int1;
    private ASN1Integer int2;

    public ASN1Integer getInt1() {
        return int1;
    }

    public void setInt1(ASN1Integer int1) {
        this.int1 = int1;
    }

    public ASN1Integer getInt2() {
        return int2;
    }

    public void setInt2(ASN1Integer int2) {
        this.int2 = int2;
    }

    public SM2SignAsn1(ASN1Integer int1, ASN1Integer int2) {
        this.int1 = int1;
        this.int2 = int2;
    }

    @Override
    public ASN1Primitive toASN1Primitive() {
        ASN1EncodableVector vector = new ASN1EncodableVector();
        vector.add(int1);
        vector.add(int2);
        return new DERSequence(vector);
    }


    /**
     * 构建ASN1对象
     */
    public static String buildSm2SignAsn1Object(BigInteger int1, BigInteger int2) {
        String res = null;
        try {

            SM2SignAsn1 sm2SignAsn1 = new SM2SignAsn1(
                    new ASN1Integer(int1),
                    new ASN1Integer(int2)
            );
            byte[] encoded = sm2SignAsn1.getEncoded();
            res = YangHexUtils.byteArrToHex(encoded);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return res;
    }

}

2.2 转换为ASN1格式

对于数据

d596d18be77035b0bb9ef6abf232e9e81f2df3178bedd56d64220dc72c6883a61b92ddc4c167e22956e5ef32ce19bf4c05f9d6d96aa82c41ace0ba28acba8715

由128拆分为两个64

d596d18be77035b0bb9ef6abf232e9e81f2df3178bedd56d64220dc72c6883a6
1b92ddc4c167e22956e5ef32ce19bf4c05f9d6d96aa82c41ace0ba28acba8715

上方16进制数转换为大整数,带入buildSm2SignAsn1Object方法即可。

import org.junit.jupiter.api.Test;
import java.math.BigInteger;

class SM2SignAsn1Test {

    /**
     * 构建ASN1
     */
    @Test
    void test1(){
        // hex构建
        BigInteger bigInteger1 = new BigInteger("EC0E1276175276F2F82046DFB26D06125E1B3F23981AF78C14F6DCDE4ADB19C4", 16);
        BigInteger bigInteger2 = new BigInteger("10589A985509C217E9B691F258B9FAB074DBDEE60AACDF4052950D499619E33E", 16);

        String sm2SignAsn1 = SM2SignAsn1.buildSm2SignAsn1Object(bigInteger1, bigInteger2);
        System.out.printf("ASN1格式: %s",sm2SignAsn1);
        System.out.println();
        System.out.printf("长度: %d",sm2SignAsn1.length());
    }

}

输出:

ASN1格式: 3045022100d596d18be77035b0bb9ef6abf232e9e81f2df3178bedd56d64220dc72c6883a602201b92ddc4c167e22956e5ef32ce19bf4c05f9d6d96aa82c41ace0ba28acba8715
长度: 142

2.3 解析ASN1格式数据

上方的ASN1格式数据也可以解析回去,下面是一个demo:

注意40行,这里是因为SM2签名是两个整数组成,即我们开始用的ASN1Integer在构建,所以这里把结果数据做了16进制转换。

不是所有的ASN1都应当这样操作,要结合实体类分析,即2.2节的SM2SignAsn1。

又比如SM2数字信封是4部分组成,看我的这个问题:SM2加密结果转ASN1格式时如何构造DerOctetString?

import org.bouncycastle.asn1.*;
import org.bouncycastle.util.encoders.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigInteger;

/**
 * @description:
 * @class: YangASN1Utils
 * @author: yang37
 * @date: 2022/2/8 9:59
 * @version: 1.0
 */
public class YangASN1Utils {
    private static final Logger log = LoggerFactory.getLogger(YangASN1Utils.class);

    /**
     * 解析SM2的ASN1格式签名数据
     *
     * @param asn1Base64 base64
     * @return 大整数 R+S
     */
    public static String parseSm2SignAsn1Object(String asn1Base64) {
        StringBuilder sb = new StringBuilder();
        byte[] data = Base64.decode(asn1Base64);
        ASN1InputStream ais = new ASN1InputStream(data);
        ASN1Primitive primitive;
        try {
            while ((primitive = ais.readObject()) != null) {
                // 原数据
                log.info("解析到sequence:\n{}", primitive);
                if (primitive instanceof ASN1Sequence) {
                    ASN1Sequence sequence = (ASN1Sequence) primitive;
                    ASN1SequenceParser parser = sequence.parser();
                    ASN1Encodable encodable;
                    while ((encodable = parser.readObject()) != null) {
                        primitive = encodable.toASN1Primitive();
                        String temp = String.valueOf(primitive);
                        //String s = new BigInteger(temp).toString(16);
                        String s = String.format("%064x",new BigInteger(temp))
                        log.info("结果数据: {}", s);
                        sb.append(s);
                    }
                }
            }
            return sb.toString().replace("#", "");
        } catch (Exception e) {
            log.error("解析ASN1格式的SM2签名失败!", e);
            return "";
        }
    }
}

解析数据:

    /**
     * 解析ASN1
     */
    @Test
    void test2() {
        String signBase64 = YangHexUtils.hexToBase64("3045022100ec0e1276175276f2f82046dfb26d06125e1b3f23981af78c14f6dcde4adb19c4022010589a985509c217e9b691f258b9fab074dbdee60aacdf4052950d499619e33e");
        String s = YangASN1Utils.parseSm2SignAsn1Object(signBase64);
        System.out.printf("解析ASN1结果: %s", s);
    }

结果:

2022-02-08 10:13:40.028 -- [main] INFO  cn.yang37.utils.YangASN1Utils.parseSm2SignAsn1Object - 解析到sequence:
[96609110044744864114854453461814827124752609040423567819705864411478992913318, 12471937173666031536193805568391885468913788814372661482682467986500971300629]
2022-02-08 10:13:40.032 -- [main] INFO  cn.yang37.utils.YangASN1Utils.parseSm2SignAsn1Object - 结果数据: d596d18be77035b0bb9ef6abf232e9e81f2df3178bedd56d64220dc72c6883a6
2022-02-08 10:13:40.033 -- [main] INFO  cn.yang37.utils.YangASN1Utils.parseSm2SignAsn1Object - 结果数据: 1b92ddc4c167e22956e5ef32ce19bf4c05f9d6d96aa82c41ace0ba28acba8715
解析ASN1结果: d596d18be77035b0bb9ef6abf232e9e81f2df3178bedd56d64220dc72c6883a61b92ddc4c167e22956e5ef32ce19bf4c05f9d6d96aa82c41ace0ba28acba8715


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM