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