关于SM2软件加密与硬件加密的问题

SM2国密算法在中国的密码学领域中使用得非常广泛,它是一种基于椭圆曲线公钥密码的算法。日常开发工作中,涉及到SM2算法的加密和解密时,如果一方使用软件实现,而另一方使用硬件实现,可能会遇到一些联调过程中的问题。在SM2的加密和解密过程中,涉及到对ASN.1格式的编码和解码。

当软件加密和硬件加密进行联调时,可能会遇到以下问题:

1.编码/解码不一致:软件和硬件可能采用不同的ASN.1编码规则或者库来处理ASN.1格式的数据。这可能导致加密后的数据在软件端和硬件端之间无法正确解析。

2.数据填充和对齐问题:ASN.1编码的数据可能需要特定的填充或对齐方式。软件和硬件在这方面的处理方式如果不一致,也可能导致问题。

为了解决这些问题,可以采取以下措施:

1.明确接口定义:确保软件和硬件之间的接口定义清晰、一致,并遵循相关的标准和规范。如果可能的话,尽量使软件和硬件使用相同的ASN.1库,以确保编码和解码的一致性。

2.与硬件厂商沟通:如果问题确实出在硬件端,及时与硬件厂商沟通,寻求技术支持和解决方案。

案例:软件加密(主流开源库bouncycastle)和硬件加密接口对接,运行过程中偶现解密失败问题。接口上送的sm2加密值为硬件加密机加密后的asn1字节数组,应用程序需要将asn1转换原始数据进行解密,偶现错误发生在转换过程中。

ASN.1(Abstract Syntax Notation One)是一种接口定义语言,用于描述数据结构,被广泛用于密码学标准中。在SM2加密算法中,asn1的数据格式是这样的:

复制代码
/**
 * 加密数据的ASN.1 数据结构如下:
 * CipherData ::= SEQUENCE {
 * xcoordinate INTEGER,(32)
 * ycoordinate INTEGER,(32)
 * hash OCTET STRING,(32)
 * cigherText OCTET STRING (对应明文字节长度)
 * }
 * <p>
 * C1C3C2格式对应:
 * c1 = xcoordinate + ycoordinate
 * c3 = hash;
 * c2 = cigherText;
 * <p>
 * 格式解析如下:
 * 30 + totalLen  + xTag + xlen + x  + yTag + ylen +y + c3Tag + c3len + c3 + c2Tag + c2len + c2;
 */

将asn1字节写入文件,使用asn1工具打开可以看到完整结构:

asn1字节解析:

0x30:sequence

0x79:总长度totalLen

0x02:x类型标签xTag

0x20:x的长度xlen

0x00~0x92:x的内容

依此类推。。。

x分量: 包含标记+长度+内容,0x02表示整数

y分量:包含标记+长度+内容

摘要:包含标记+长度+内容,0x04表示String

密文:包含标记+长度+内容

应用程序中处理asn1数据转原始数据:

XML 复制代码
        <!--引入开源库 -->        
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk15on</artifactId>
            <version>1.70</version>
        </dependency>
java 复制代码
    //此方法将asn1格式数据转换为原始数据进行解密 
    private static byte[] changeAsn1ToC1C3C2(byte[] asn1) {
        try {
            ASN1InputStream aIn = new ASN1InputStream(asn1);
            ASN1Sequence seq = (ASN1Sequence) aIn.readObject();
            BigInteger x = ASN1Integer.getInstance(seq.getObjectAt(0)).getValue();
            BigInteger y = ASN1Integer.getInstance(seq.getObjectAt(1)).getValue();
            byte[] c3 = ASN1OctetString.getInstance(seq.getObjectAt(2)).getOctets();
            byte[] c2 = ASN1OctetString.getInstance(seq.getObjectAt(3)).getOctets();

            ECPoint c1Point = GMNamedCurves.getByName("sm2p256v1").getCurve().createPoint(x, y);
            byte[] c1 = c1Point.getEncoded(false);
            return ArrayUtil.addAll(c1, c3, c2);
        } catch (Exception ex) {
            return null;
        }
    }

错误发生位置:

ASN1Sequence seq = (ASN1Sequence) aIn.readObject();

debug进入方法,如果出现无法debug情况,将bouncycastle库下载到本地调试。

bouncycastle库最终异常的位置:ASN1Integer#isMalformed

方案一:屏蔽bc关于大整数的校验,设置系统参数org.bouncycastle.asn1.allow_unsafe_integer为true

java 复制代码
    private static byte[] changeAsn1ToC1C3C2(byte[] asn1) {
        try {
            //x,y分量补位问题导致的规范性校验不通过,该配置绕过校验逻辑
            System.setProperty("org.bouncycastle.asn1.allow_unsafe_integer", "true");
            ASN1InputStream aIn = new ASN1InputStream(asn1);
            ASN1Sequence seq = (ASN1Sequence) aIn.readObject();
            BigInteger x = ASN1Integer.getInstance(seq.getObjectAt(0)).getValue();
            BigInteger y = ASN1Integer.getInstance(seq.getObjectAt(1)).getValue();
            byte[] c3 = ASN1OctetString.getInstance(seq.getObjectAt(2)).getOctets();
            byte[] c2 = ASN1OctetString.getInstance(seq.getObjectAt(3)).getOctets();

            ECPoint c1Point = GMNamedCurves.getByName("sm2p256v1").getCurve().createPoint(x, y);
            byte[] c1 = c1Point.getEncoded(false);
            return ArrayUtil.addAll(c1, c3, c2);
        } catch (Exception ex) {
            return null;
        }
    }

方案二:厂商提供asn1转原始数据方法替换bc库(推荐)

方案三:自行解析

复制代码
asn1格式解析如下(16进制表示):x、y、c3、c2为内容
30 + totalLen  + xTag + xlen + x  + yTag + ylen +y + c3Tag + c3len + c3 + c2Tag + c2len + c2;

原始数据格式(c1c3c2模式):

04+x+y+c3+c2

参考:

网联回执报文签名验证和敏感信息解密报错:failed to construct sequence from byte[]: corrupted stream detected [国密SM2]-CSDN博客

https://blog.51cto.com/u_16099268/8806443

关于SM2算法 ASN.1编码 踩过的坑 - 加密_sm2私钥asn.1序列化-CSDN博客

asn.1ber编解码系统与设计asn.1编码规则详解(全面最经典) - 豆丁网

相关推荐
白榆maple5 分钟前
(蓝桥杯C/C++)——基础算法(下)
算法
JSU_曾是此间年少10 分钟前
数据结构——线性表与链表
数据结构·c++·算法
此生只爱蛋1 小时前
【手撕排序2】快速排序
c语言·c++·算法·排序算法
咕咕吖2 小时前
对称二叉树(力扣101)
算法·leetcode·职场和发展
九圣残炎2 小时前
【从零开始的LeetCode-算法】1456. 定长子串中元音的最大数目
java·算法·leetcode
lulu_gh_yu2 小时前
数据结构之排序补充
c语言·开发语言·数据结构·c++·学习·算法·排序算法
丫头,冲鸭!!!3 小时前
B树(B-Tree)和B+树(B+ Tree)
笔记·算法
Re.不晚3 小时前
Java入门15——抽象类
java·开发语言·学习·算法·intellij-idea
为什么这亚子4 小时前
九、Go语言快速入门之map
运维·开发语言·后端·算法·云原生·golang·云计算
4 小时前
开源竞争-数据驱动成长-11/05-大专生的思考
人工智能·笔记·学习·算法·机器学习