【商密测评】ASN.1编码在国密算法中的应用、实现与安全性评估

admin 2025-12-28 01:54:05 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文阐述ASN.1编码规则及其在国密算法中的应用,重点解析SM2签名的DER编码细节与实现难点。通过OFD签章实例演示了从解码到验证的完整流程,并基于商密测评提出安全性评估策略,强调需严格验证编码的合规性与唯一性,以防范解析漏洞保障系统安全。 综合评分: 96 文章分类: 数据安全,应用安全,技术标准,解决方案,安全建设


cover_image

【商密测评】ASN.1编码在国密算法中的应用、实现与安全性评估

利刃信安

利刃信安

2025年12月27日 00:41 北京

ASN.1编码在国密算法中的应用、实现与安全性评估

一、ASN.1 基础记法与商用密码数据类型定义

ASN.1(Abstract Syntax Notation One,抽象语法记法一)是一种独立于具体编码实现、用于描述数据结构的形式化语言。在信息技术领域,特别是在需要跨平台、跨系统进行数据交换的场景中,ASN.1扮演着定义“数据模板”或“数据契约”的关键角色。根据国家标准《GB/T 16262.1-2025 信息技术 抽象语法记法一(ASN.1) 第1部分:基本记法规范》,ASN.1提供了一套标准记法,用于精确定义数据类型、值及约束,其本身不规定具体的编码规则,而是为其他定义编码规则(如BER、DER、PER)的标准提供基础。

在商用密码领域,密码算法、密钥、证书、签名等复杂数据结构需要在不同的实体(如加密芯片、服务器、客户端)之间进行传递和解析。ASN.1的形式化、无歧义描述能力使其成为定义这些密码相关数据结构的理想工具。例如,公钥证书(X.509)、证书签名请求(CSR)、以及国密算法(如SM2)的签名值等,其抽象结构通常都采用ASN.1进行定义。理解ASN.1的基础数据类型是解析和构建这些密码数据的第一步。

以下是商用密码协议中最为常见的几种ASN.1基础数据类型及其规范:

🔢 INTEGER(整数类型)

INTEGER是ASN.1中的基本简单类型,用于表示整数值。

  • 取值与范围

    :其值域理论上包含所有整数(正、负、零)。在实际应用中,常通过子类型约束来限定其有效范围,例如使用值范围约束 INTEGER (0..255) 或枚举值约束 INTEGER {sha256(0), sm3(1)}

  • 标记

    :其通用类别(UNIVERSAL)标签号为 2

  • 编码独立性

    :ASN.1规范本身不规定INTEGER的具体编码方式(如占用的字节数),这由后续选定的编码规则(如DER)决定。编码规则可能对可编码的整数范围有限制,但这不影响ASN.1抽象值的定义。

  • 在密码学中的应用

    :INTEGER类型广泛用于表示版本号、枚举值(如算法标识)、大整数(如RSA的模数n、SM2签名中的rs值)等。

🧩 SEQUENCE(序列类型)

SEQUENCE用于定义有序的、固定结构的复合类型,是构建复杂数据结构的核心。

  • 语法结构

    :使用 SEQUENCE { ... } 定义,花括号内按顺序列出各个组件(ComponentTypeLists)。每个组件有唯一的标识符和类型。

  • 可选性与默认值

    :组件可以声明为 OPTIONAL(可选),表示该组件在具体值中可以不存在。也可以使用 DEFAULT 指定默认值,当实际值等于默认值时,在编码中可以省略。

  • 可扩展性

    :通过在组件列表末尾添加 ...(扩展标记),可以定义可扩展的SEQUENCE类型,允许未来版本在不破坏向前兼容性的前提下添加新组件。新增组件通常放在 [[ ]] 版本括号内。

  • 标记

    :SEQUENCE类型的通用类别标签号为 16

  • 在密码学中的应用

    SEQUENCE是定义密码数据结构最常用的类型。例如,一个X.509证书的主体信息、一个PKCS#7的签名数据块、或一个SM2签名值(通常包含rs两个INTEGER组件),都可以定义为一个SEQUENCE。

🏷️ OBJECT IDENTIFIER (OID,对象标识符)

OBJECT IDENTIFIER用于在全球范围内唯一地、无歧义地标识一个对象,如算法、协议、信息客体等。

  • 树状结构与值

    :OID值是一个从国际对象标识符树根节点到某个节点的路径,表示为一系列非负整数(主整数值)构成的序列。每个节点(弧)由一个注册机构分配。

  • 命名形式

    :除了数字序列,每个弧还可以关联一个可读的辅标识符(如 isoitu-tjoint-iso-itu-t)。在ASN.1记法中,可以混合使用数字和标识符(如 { iso(1) member-body(2) 156 } 表示中国),但编码时只使用整数序列。

  • 注册与唯一性

    :OID的分配遵循国际标准(如ITU-T X.660/ISO IEC 9834),确保全局唯一性。在密码学中,各种加密算法、哈希算法、签名方案等都有其唯一的OID。例如,SM2、SM3、SM4等国密算法都在相应的OID弧下进行了注册。

  • 标记

    :OBJECT IDENTIFIER的通用类别标签号为 6

  • 在密码学中的应用

    :OID是算法标识的核心。在证书、签名等结构中,会使用OID来明确指出所使用的签名算法(如sm2sign-with-sm3)、哈希算法或加密算法。

综上所述,INTEGER、SEQUENCE和OBJECT IDENTIFIER构成了描述商用密码数据结构的基石。INTEGER用于承载数值,SEQUENCE用于组织结构,而OBJECT IDENTIFIER则用于明确标识算法与协议。这些基础类型的规范定义于《GB/T 16262.1-2025》等基础标准中,而它们在具体密码协议(如GM/T 0009-2012 SM2密码算法使用规范)中的应用,则是在此基础上进行的精确定义和约束。理解这些基础类型的语法和语义,是后续深入分析国密算法中具体ASN.1结构、编码规则及安全实践的必要前提。

二、DER 编码规则在国密算法中的具体实现

在国密算法(如SM2、SM3、SM4)的工程实现中,ASN.1抽象语法所定义的数据结构(如公钥、签名、算法标识)最终需要转换为确切的字节流以供存储、传输或计算。DER(非典型编码规则) 正是完成这一转换的核心规则集。它并非创造新的数据结构,而是在BER(基本编码规则)的基础上,施加一系列严格的约束,旨在为任何一个给定的ASN.1值生成唯一且确定的八位位组序列。这种唯一性对于数字签名、证书等安全应用至关重要。

🔒 DER 的核心约束与在密码学中的价值

根据GB/T 16263.1-2025,DER相较于BER和CER,施加了最为严格的限制,以确保编码的唯一性(确定性)紧凑性。其核心约束可归纳为:

  1. 长度形式必须确定且最小化

    :必须使用确定长度形式,且长度值必须用尽可能少的八位位组进行编码(即优先使用短形式,必要时使用最简长形式)。禁止使用不定长度形式

  2. 串编码禁止结构化

    :对于位串(BIT STRING)、八位位组串(OCTET STRING)等类型,禁止使用结构化编码(即不能分块),必须使用原始编码。

  3. 集合组件必须排序

    :SET类型的组件必须按照其标签值的升序进行编码。

  4. 类型特定约束

  • INTEGER

    :必须使用最小数量的八位位组进行编码,即内容字节的首个字节的所有位不能全为0或全为1(与第二个字节的最高位共同判断),以消除前导零或冗余符号位。

  • 布尔值TRUE

    :必须编码为 0xFF(所有位为1)。

  • 位串

    :未使用的尾部位必须置零,并在编码前被移除。

在国密算法应用中,选择DER而非BER或CER的主要依据正是其唯一性。例如,在SM2数字签名过程中,待签名的数据(通常是消息摘要的ASN.1结构)必须被唯一地编码为字节串,然后输入签名算法。如果使用BER,同一抽象值可能存在多种合法编码(如长度字段可选短/长形式,INTEGER可有前导零),这将导致对“同一数据”生成不同的签名,或在验证时因编码差异而失败,甚至可能引入安全风险。DER消除了这种歧义,确保了“所见即所签”。

⚙️ 对国密算法中关键ASN.1类型的编码实现

国密算法实现中频繁使用的ASN.1类型,其DER编码需遵循以下具体规则:

  • OBJECT IDENTIFIER (OID)

    :用于标识算法(如 sm2sign-with-sm3)。DER编码要求使用压缩的字节表示,将OID的各个弧(arc)进行可变长度编码(Base 128)并拼接。

  • INTEGER

    :用于表示大整数,如SM2签名值中的 r 和 s、ECC公钥坐标 x 和 y。编码必须满足:

  1. 将整数值转换为二进制补码形式。
  2. 使用最小数量的八位位组。例如,正数 0x0038(有前导零)必须编码为 0x38(一个字节);负数 -128 的补码为 0x80,编码为一个字节 0x80,而不是两个字节 0xFF80
  3. 编码格式为:标签(0x02)| 长度(内容字节数)| 内容(补码字节)
  • SEQUENCE / SEQUENCE OF

    :用于组织复合结构,如SM2签名值 SM2Signature ::= SEQUENCE { r INTEGER, s INTEGER }。DER编码要求:

  1. 使用结构化编码(标签 0x30)。
  2. 使用确定长度形式,且长度值编码最小化。
  3. 组件严格按照ASN.1定义中的顺序进行编码。
  • OCTET STRING

    :常用于封装哈希值(如SM3输出)、对称密钥等。DER编码要求使用原始编码(标签 0x04),禁止使用结构化编码。

📏 长度字段的强制要求与实现要点

长度字段的编码是DER实现的关键细节,必须严格遵守:

  1. 强制确定长度

    :国密算法的所有DER编码必须使用确定长度。例如,一个包含两个INTEGER的SEQUENCE,其总长度必须在编码前计算确定。

  2. 长度编码最小化

  • 当内容长度 L ≤ 127 时,必须使用短形式:单个长度字节,最高位为0,低7位存储长度值。例如,长度 38 编码为 0x26
  • 当 L ≥ 128 时,必须使用长形式,且使用最少的后续字节数。例如,长度 200 应编码为 0x81 0xC8(一个后续字节),而不是 0x82 0x00 0xC8(两个后续字节)。

🛡️ 在国密算法实现中的关键注意事项

基于DER规则,在实现国密算法的ASN.1编解码时,应重点关注:

  1. 编码唯一性验证

    :在生成用于签名的数据(如SignedData)或证书时,编码器必须严格遵循DER所有约束。解码器在验证签名时,也应能识别并拒绝非DER编码(如包含不定长度或非最小整数编码),或至少将其规范化为DER编码后再进行验证比较。

  2. 整数编码的边界处理

    :正确处理大正数和大负数的补码转换,并确保移除所有前导冗余字节。这是实现互通性的常见难点。

  3. OID的预编码与比对

    :将常用国密算法OID(如SM2、SM3、SM4)的DER编码形式预先计算并存储为常量,以提高编解码效率,并在比对时进行字节级比较。

  4. 依赖可靠的基础库

    :应使用经过严格测试、支持DER规范编解码的密码学库(如支持国密的OpenSSL分支或专用商用密码库),避免自行实现底层DER编码可能引入的细微错误。

总之,DER编码规则为国密算法的数据交换提供了可靠、无歧义的二进制表示基础。其实现的核心在于将ASN.1抽象定义,通过一系列严格的字节级规则,转换为唯一确定的序列,从而保障了密码学操作(尤其是数字签名)的安全性与互操作性。

三、SM2 签名值的 ASN.1 结构与 DER 编码细节

SM2 数字签名算法产生的核心输出是一对 256 位(32 字节)的大整数 r 和 s。为了在数字证书、电子签章等应用中进行交换和存储,这对值需要按照 ASN.1 语法进行结构化定义,并遵循 DER 编码规则转换为唯一的字节序列。

1. ASN.1 结构定义

根据相关规范,SM2 签名值的抽象数据结构被定义为一个 SEQUENCE,该序列包含两个 INTEGER 类型的组件,分别对应签名值 r 和 s。其 ASN.1 记法可表述为:

SM2Signature ::= SEQUENCE {
    r   INTEGER,
    s   INTEGER
}

这个定义明确了签名值是一个有序的复合结构,其中 r 和 s 的排列顺序是固定的。

2. DER 编码的 TLV 结构

根据 DER 规则,上述 ASN.1 结构将被编码为一个 TLV(Tag-Length-Value) 三元组序列。

  • 外层 SEQUENCE 的 TLV

  • Tag (T)

    0x30(SEQUENCE 的通用标签)。

  • Length (L)

    :一个或多个字节,表示整个 Value 字段的总长度。该长度是内部两个 INTEGER 的 TLV 编码的字节数之和。

  • Value (V)

    :包含 r 和 s 的 INTEGER 的完整 DER 编码流。

  • 内层 INTEGER (r 和 s) 的 TLV

  • Tag (T)

    0x02(INTEGER 的通用标签)。

  • Length (L)

    :一个或多个字节,表示该 INTEGER 值(r 或 s)的字节长度。

  • Value (V)

    r 或 s 的整数值本身,以二进制补码形式表示的大端序字节串。

3. 核心编码规则与长度变化

编码过程的核心在于对 r 和 s 这两个 INTEGER 值的处理。根据 DER 规范(如 GB/T 16263.1-2025),整数编码必须满足 “最短补码表示” 原则,这直接导致了签名编码长度的动态变化。

🔵 规则一:前导零填充(补零)

当 r 或 s 值的第一个字节(最高有效字节)的最高位(bit 8)为 1 时,该值在 DER 编码中会被视为一个负数(因为最高位是符号位)。为了避免将正数 r/s 错误解释为负数,必须在值前补充一个 0x00 字节

  • 效果

    :使该 INTEGER 的 Value 字段长度从 32 字节变为 33 字节,其长度字段相应变为 0x21(十进制33)。

  • 长度影响

  • 若 r 和 s 均无需补零,则每个 INTEGER 编码长度为 1(Tag) + 1(Length) + 32(Value) = 34 字节。外层 SEQUENCE 的 Value 长度为 34 + 34 = 68 字节,长度字段为 0x44。总编码长度为 1 + 1 + 68 = 70 字节。

  • 若 r 和 s 中只有一个需要补零,则一个 INTEGER 为 34 字节,另一个为 35 字节。SEQUENCE 的 Value 长度为 69 字节,长度字段为 0x45。总编码长度为 71 字节。

  • 若 r 和 s 均需要补零,则每个 INTEGER 为 35 字节。SEQUENCE 的 Value 长度为 70 字节,长度字段为 0x46。总编码长度为 72 字节。

🔵 规则二:前导零删除(删零)

当 r 或 s 值的开头存在一个或多个 0x00 字节时,为了满足“最短”表示的要求,可以(且通常应该)删除这些前导零

  • 条件

    :删除前导零后,剩余部分的第一个字节的最高位必须不为 1。如果删除后第一个字节的最高位为 1,则必须保留前导零(即应用规则一)。

  • 效果

    :使该 INTEGER 的 Value 字段长度从 32 字节减少为 31 字节(如果只删一个零),其长度字段相应变为 0x1F(十进制31)。

  • 长度影响

    :这会导致总编码长度出现 69字节 等非常规情况。例如,当 r 或 s 之一删除了一个前导零(变为31字节),而另一个为标准的32字节(且无需补零)时,SEQUENCE 的 Value 长度为 (1+1+31) + (1+1+32) = 67 字节,长度字段为 0x43,总编码长度为 69 字节。

🔵 长度变化总结表

| 情况 | r 值状态 | s 值状态 | INTEGER(r) 长度字段 | INTEGER(s) 长度字段 | SEQUENCE 长度字段 | 总编码长度 | | — | — | — | — | — | — | — | | 常规 | 最高位非1,无前导0 | 最高位非1,无前导0 | 0x20 (32) | 0x20 (32) | 0x44 (68) | 70字节 | | 补零 | 最高位为1,需补0 | 最高位非1,无前导0 | 0x21 (33) | 0x20 (32) | 0x45 (69) | 71字节 | | 补零 | 最高位非1,无前导0 | 最高位为1,需补0 | 0x20 (32) | 0x21 (33) | 0x45 (69) | 71字节 | | 双补零 | 最高位为1,需补0 | 最高位为1,需补0 | 0x21 (33) | 0x21 (33) | 0x46 (70) | 72字节 | | 删零 | 有前导0,删除后最高位非1 | 最高位非1,无前导0 | 0x1F (31) | 0x20 (32) | 0x43 (67) | 69字节 | | 删零 | 最高位非1,无前导0 | 有前导0,删除后最高位非1 | 0x20 (32) | 0x1F (31) | 0x43 (67) | 69字节 |

4. 编码示例与流程

从一个实际的 OFD 电子签章文件中,可以解析出如下 SM2 签名值的 DER 编码(Hex):

3046022100d623bb6a495b3964f7c10069257083b54d2300ea889322513c15e33813f25c2e022100c9a886a7cc21c7946781a9a6633613ca0f30a52f7dea54ab7d6b9ed58c63d0ad

解码分析:

  1. 30 46

    :外层 SEQUENCE,标签 0x30,长度 0x46(十进制70字节)。

  2. 02 21 00d623bb...c2e

    :第一个 INTEGER (r)。

  • 02

    :INTEGER 标签。

  • 21

    :长度33字节。

  • 00d6...

    :值字段,以 0x00 开头,说明原始 r 值的最高位为1,进行了补零。

  1. 02 21 00c9a886...0ad

    :第二个 INTEGER (s)。

  • 同样,s 也进行了补零,编码为33字节。

完整的编码流程可总结为:

  1. 获取原始值

    :获得 SM2 签名算法输出的 32 字节 r 和 s

  2. 预处理整数

    :对每个 32 字节整数,判断其第一个字节的最高位。

  • 若为 1,则在值前添加一个 0x00 字节,使其变为 33 字节。
  • 若为 0,检查其是否为前导零。若是,且删除该零后新首字节最高位不为 1,则删除它,使其变为 31 字节;否则保持 32 字节。
  1. 编码 INTEGER

    :为每个处理后的值构造 TLV:0x02 + 长度 + 值。

  2. 计算总长

    :将两个 INTEGER 的编码长度相加。

  3. 编码 SEQUENCE

    :构造最外层的 TLV:0x30 + 总长度 + (INTEGER(r)编码 + INTEGER(s)编码)。

  4. 输出

    :得到最终的 DER 编码字节流。

正是这些基于严格规则的、对边界情况的细致处理,确保了 SM2 签名值在任何兼容系统中都能被唯一且正确地解析,为后续的签名验证流程奠定了可靠的数据基础。

四、从 ASN.1 解码到签名验证的完整技术流程

在电子签章验签场景中,完整的流程始于对携带签名信息的结构化数据(通常以 ASN.1 DER 编码)进行解码,终于调用密码算法完成验证。本流程以 GB/T 38540-2020《信息安全技术 安全电子签章密码技术规范》在 OFD 文件中的应用为典型实例。

🔍 第一步:定位并提取待解码的原始字节流

验签流程的输入并非凭空产生,而是从已签名的文档容器中提取。在 OFD 文件中:

  1. 文件定位

    :解压 OFD 文件包,定位到签名数据所在的目录(如 Doc_0/Signs/Sign_0/)。

  2. 关键文件

    :该目录下通常包含 Signature.xml(描述签名属性)和 SignedValue.dat(核心的签名值及关联数据的 DER 编码二进制文件)。

  3. 目标数据

    SignedValue.dat 文件是整个解码流程的起点,其内容是一个复杂的 ASN.1 结构,封装了版本、签名者信息、公钥、签名数据摘要以及最终的签名值。

🛠️ 第二步:ASN.1 DER 解码的核心步骤

解码过程是编码的逆过程,需严格按照 DER 规则逐层解析 SignedValue.dat 的字节流。以下结合一个实际解码案例进行说明(数值为十六进制,括号内为 (偏移量,长度) 的解析记录):

解码目标:从嵌套结构中提取出 SM2 公钥签名数据的哈希值(e) 以及 SM2 签名值(r, s)

  1. 解析外层结构
  • 起始字节 0x30 表示一个 SEQUENCE
  • 后续长度字段为 0x04 0x93(或类似),表示该 SEQUENCE 总长度为 1171 字节(0x0493)。
  • 解析该 SEQUENCE 内的组件。
  1. 识别算法并定位签名数据
  • 公钥

    :在 CONTEXT_SPECIFIC [3] 标签后的 BIT STRING 中提取。例如,解码得到公钥字节串:0487ebf8accd69d5d83f623eafb47494eceb8abee0649ab464a247fb2820857e0bf08a8b857a53308264e68d2971212bb9be48eefcf04d0125b55eeced49884c36

  • 签名数据(SignedData)的哈希

    :在 OBJECT IDENTIFIER 为 Message Digest (1.2.840.113549.1.9.4) 的属性对应的 OCTET STRING 中提取。例如,得到 32 字节的 SM3 哈希值:ff19036408d85e5cf425899b9b58185ce70556d4ec4352cf8e74dab67a5a607a。此即待验签的消息摘要 e

  • 在偏移量 (0:4, L:10) 处,解析到一个 OBJECT IDENTIFIER,其值为 1.2.156.10197.6.1.4.2.2,标识此为“签名数据类型”。

  • 随后在 [0] 上下文特定标签下,找到包含签名信息的嵌套 SEQUENCE

  • 在此结构中,需要定位两个关键部分:

  1. 解码核心签名值
  • 第一个子项:Tag=0x02 (INTEGER), Length=0x21(33字节),值(含一个前导零)为 00d623bb6a495b3964f7c10069257083b54d2300ea889322513c15e33813f25c2e。去除前导零,得到 32字节的签名分量 r

  • 第二个子项:Tag=0x02 (INTEGER), Length=0x21(33字节),值为 00c9a886a7cc21c7946781a9a6633613ca0f30a52f7dea54ab7d6b9ed58c63d0ad。去除前导零,得到 32字节的签名分量 s

  • 解码流程最终定位到一个 OCTET STRING(在 SM2-1数字签名算法 OID 之后),其内部包含的就是 SM2Signature 的 DER 编码。

  • 解析此 OCTET STRING(例如在偏移 (0:1101, L:72)),其内容以 0x30 (SEQUENCE) 开头,长度 0x46(70字节)。

  • 解析该 SEQUENCE

解码过程中的边界与安全验证

  • 长度字段验证

    :必须检查每个 TLV 结构中的长度字段 L 是否与后续实际数据字节数严格一致,防止缓冲区溢出或解析错误。

  • 标签匹配

    :在每一层解析时,读取到的标签必须与预期结构定义的标签(如 SEQUENCE 的 0x30INTEGER 的 0x02)相符,否则表示数据损坏或遭受篡改。

  • 顺序与唯一性

    :对于 SEQUENCE,需验证子项顺序是否符合定义;利用 DER 的唯一编码特性,任何对编码数据的非法修改都会导致解码失败。

✅ 第三步:签名验证的执行

解码步骤完成后,验证算法所需的所有输入参数均已就绪:

  1. 输入参数

  • 公钥

    :从 BIT STRING 中解码得到的椭圆曲线点。

  • 消息哈希 e

    :从 Message Digest 属性中提取的 32 字节 OCTET STRING。

  • 签名 (r, s)

    :从最内层 SM2Signature 的 SEQUENCE 中解析出的两个大整数。

  1. 调用验签算法

    :将上述三个参数传递给 SM2 数字签名验证算法

  2. 验证结果

    :算法执行完毕,输出验证结果(如 0 表示成功,1 表示失败)。此结果最终决定了电子签章的有效性。

⚠️ 第四步:错误处理机制

在整个解码与验证流程中,任何一步的异常都应导致验签失败:

  • 解码错误

    :包括但不限于长度字段溢出、未知标签、违反 DER 规范(如不定长编码、组件顺序错误)、或 ASN.1 结构不匹配。遇到此类错误,应立即终止流程,返回“签名格式无效”。

  • 密码运算错误

    :如公钥坐标点不在曲线上、r 或 s 值不在 SM2 算法规定的有效范围内(1 ≤ r, s ≤ n-1),或 SM2 验签算法本身计算不通过。此时应返回“签名验证失败”。

📊 流程总结

从 ASN.1 解码到签名验证是一个严密的链式过程,其完整性与安全性依赖于每一步对 DER 编码规则的严格遵守和对数据完整性的校验。

最终,只有解码和密码验证双双通过,才能确认该 ASN.1 编码数据块所承载的数字签名是有效且可信的。

五、ASN.1 在 SM2、SM3、SM4 等国密算法中的应用场景

ASN.1 作为描述结构化数据的抽象语法,在商用密码体系中扮演着“数据蓝图”的角色。它本身不执行密码运算,但为密码算法所需的输入、输出及中间数据提供了标准化、无歧义的定义框架,是实现系统间互操作性的基石。在国密算法生态中,ASN.1 的应用深度与广度因算法功能而异。

🔑 SM2:非对称密码的完整数据封装

SM2 作为椭圆曲线密码算法,其应用涉及密钥管理、数字签名和公钥加密,这些环节均重度依赖 ASN.1 进行数据结构化。

1. X.509 数字证书中的核心载体SM2 公钥最普遍的呈现形式是嵌入在 X.509 数字证书中。证书的 ASN.1 结构 Certificate 序列中的 tbsCertificate.subjectPublicKeyInfo 字段,是 SM2 公钥的标准“包装盒”。

  • algorithm

    字段:通过 OBJECT IDENTIFIER 明确标识所使用的公钥算法为 SM2(例如,1.2.156.10197.1.301 用于 sm2sign-with-sm3)。

  • subjectPublicKey

    字段:是一个 BIT STRING,其内容即为遵循 GM/T 0009-2023 定义的 SM2PublicKey 值,通常是 04 ‖ X ‖ Y(非压缩格式)的字节串。

2. 公私钥的多样表示SM2 的公私钥在存储和交换时,存在多种 ASN.1 封装格式,以适应不同协议和场景:

  • 公钥

  • SubjectPublicKeyInfo

    :通用格式,包含算法标识和公钥值,如前所述。

  • SM2PublicKey

    :简化的裸公钥格式,直接定义为 BIT STRING

  • 私钥

  • ECPrivateKey

    (遵循 GM/T 0010-2023/SEC 1):常见格式,是一个 SEQUENCE,包含版本、私钥值(OCTET STRING 类型)、可选的曲线参数和可选的公钥。

  • PrivateKeyInfo

    (PKCS#8):更通用的封装,是一个 SEQUENCE,内层可包裹 ECPrivateKey 结构。

3. 签名与加密数据的结构化输出SM2 运算产生的签名和密文,均通过 ASN.1 结构进行组织,确保接收方能正确解析。

  • 签名数据 (SM2Signature)

    :定义为 SEQUENCE { r INTEGER, s INTEGER }。两个大整数 r 和 s 严格按照此顺序进行 DER 编码。编码细节至关重要:每个 INTEGER 的编码需去除冗余前导零,但若值的最高位为1(即该字节 >= 0x80),则必须补一个 0x00 字节以表明其为正数。这导致最终 DER 编码的字节长度可能在 69 至 72 字节之间浮动。

  • 加密数据 (SM2Cipher)

    :定义为 SEQUENCE { XCoordinate INTEGER, YCoordinate INTEGER, HASH OCTET STRING SIZE(32), CipherText OCTET STRING }。该结构完整封装了 SM2 加密算法的输出:曲线点 C1 的坐标 (XCoordinateYCoordinate)、256位消息认证码 C3 (HASH)、以及与明文等长的异或密文 C2 (CipherText)。

🔍 SM3:哈希值的间接应用

根据现有资料,文档未明确描述 SM3 哈希值本身有独立的、标准的 ASN.1 编码格式。SM3 的输出通常是固定长度(256位/32字节)的原始字节串 (OCTET STRING)。

然而,SM3 在 ASN.1 结构中的应用无处不在,它作为核心组件被引用:

  • 在 X.509 证书 的 signatureAlgorithm 或 tbsCertificate.signature 字段中,OID 1.2.156.10197.1.401 标识了 SM3 哈希算法。
  • 在 SM2 签名算法标识 中,OID 1.2.156.10197.1.501 代表了 sm2sign-with-sm3,即使用 SM3 进行消息摘要的 SM2 签名方案。
  • 在 安全电子签章 的 TBS_Sign.dataHash 字段中,存储的即是使用 SM3 对原文计算得到的哈希值,类型为 OCTET STRING。 因此,SM3 的“应用场景”更多是作为其他 ASN.1 数据结构中的一个构成元素(杂凑值)或算法标识的一部分。

🔒 SM4:对称密钥的上下文封装

根据现有资料,文档未提及 SM4 算法的密钥、IV(初始化向量)或密文存在专用的、标准化的 ASN.1 数据结构定义

在实际协议中,SM4 密钥可能以 OCTET STRING 类型出现在更上层的密钥交换或密钥封装结构中。密文通常也作为 OCTET STRING 处理。其应用场景高度依赖于具体的传输协议或数据格式规范,而非由 SM4 算法本身定义一套 ASN.1 结构。

🧩 综合应用实例:安全电子签章 (SES)

安全电子签章格式 (GB/T 38540-2020) 是 ASN.1 在国密应用中一个复杂的综合范例,它集成了证书(含SM2公钥)、签名(SM2withSM3)和哈希(SM3)。

  1. 电子印章 (SESeal)

    :一个 SEQUENCE,包含印章信息、制章者证书、签名算法OID和签名值。其中 signedValue 是对前几个字段的 DER 编码序列进行 SM2 签名的结果。

  2. 电子签章 (SES_Signature)

    :一个 SEQUENCE,包含待签数据块(内含电子印章、原文SM3哈希等)、签章者证书、签名算法OID和签名值。这里的 signature 是对相应字段的 DER 编码序列进行的 SM2 签名。

在这个场景中,ASN.1 层层嵌套,定义了从原始哈希值到最终签章数据的完整信任链结构,是 SM2、SM3 以及 X.509 证书协同工作的典型体现。

六、ASN.1 编码安全性评估与攻击防护策略

前文系统阐述了 ASN.1 及其 DER 编码规则在国密算法与应用中的核心作用,构建了从语法定义、唯一编码到具体实现的“正确性”基石。然而,在商用密码应用安全性评估(密评)与实战部署中,对 ASN.1 编码数据本身的正确处理与验证,本身就是一项关键的安全要求。本章将基于密评实践,分析由 ASN.1 编码处理不当可能引发的风险,并阐述相应的防护性验证策略。

本章的安全性评估将紧密围绕文档所强调的合规性验证正确性验证展开,这些是防范因编码误解或实现错误导致安全失效的第一道防线。

🔍 安全性评估的核心:基于密评实践的验证要点

在密评过程中,对 ASN.1 编码数据的分析并非为了寻找编码规则本身的漏洞,而是为了验证应用系统是否正确、安全地处理了这些预定义的结构化数据。评估聚焦于以下几个层面:

  1. 结构合规性验证
  • 评估点

    :所有接收或生成的 ASN.1 数据(如证书、签名、密钥)是否严格遵循相关标准(如 GM/T、X.509、PKCS#)中定义的抽象语法。

  • 风险

    :私自定义或篡改数据结构会导致互通性失败,更严重的是,可能绕过某些验证逻辑。例如,一个非标准的“SM2签名”结构可能导致验签函数解析错误,从而引发拒绝服务或未预期的行为。

  • 防护策略

    :在密评中,使用 Asn1View 等解码工具对数据流进行可视化解析,逐层核对标签(Tag)、长度(Length)和值(Value),确保其与标准定义的 SEQUENCEINTEGERBIT STRING 等结构完全一致。

  1. 编码唯一性(DER)验证
  • 强制要求并验证签名操作中,待签名的 tbsCertificate(证书)或 TBS_Sign(签章)等数据必须采用 DER 编码。

  • 特别关注 INTEGER 类型的编码,确保其表示为最短字节数且正确处理符号位(前导 0x00 字节的增删)。文档特别指出,SM2 签名值 (r, s) 的 DER 编码长度可能在 69 至 72 字节间浮动,实现时必须能正确解析所有合规情况

  • 评估点

    :对于要求使用 DER 编码的场景(如所有数字签名涉及的数据),检查编码是否满足“唯一性”约束。

  • 风险

    :使用 BER 或非规范 DER 编码可能导致“同一逻辑数据对应多个字节流”。在签名场景中,如果对待签名数据的编码不唯一,攻击者可能在不改变语义的前提下,构造出另一个不同的字节流,而原签名对此依然验证通过,这违背了签名的唯一绑定原则。

  • 防护策略

  1. 内容正确性与逻辑一致性验证
  • 证书

    :验证有效期(validity)、签名算法标识(内层 signature 与外层 signatureAlgorithm 必须一致)、密钥用法扩展(extensions)是否与当前使用场景匹配。

  • 公私钥

    :验证算法标识 OID 是否正确(如 SM2 应为 1.2.156.10197.1.301 或 1.2.840.10045.2.1 结合 SM2 曲线参数);检查私钥是否以明文 INTEGER 或 OCTET STRING 存储而未加密;使用密码工具验证公钥与私钥是否匹配

  • 签名数据

    :不仅解析出 r 和 s(对于 SM2),更重要的是将其与对应的公钥、原始消息摘要(e)一起,送入密码算法进行验签运算,这是最终的安全闸门。

  • 安全电子签章

    :需要逐层验证,从 SES_Signature 中提取签章者证书和签名值,验证其对 toSign 数据的签名;进而从 toSign 中的 eseal 字段解析 SESeal,验证制章者对印章信息的签名。

  • 评估点

    :检查 ASN.1 结构内部字段值的正确性与逻辑关联。

  • 风险与防护策略

🛡️ 主要防护策略总结

基于上述评估要点,形成以下系统性的防护策略:

  1. 严格遵循标准与唯一编码
  • 在设计与实现中,对所有用于签名、验证和密钥交换的 ASN.1 数据结构,强制规定并使用 DER 编码规则,从源头消除编码歧义。
  • 在解析端,实现应能严格校验 DER 合规性,对非 DER 编码的数据应视为格式错误而拒绝。
  1. 实施深度解析与关联验证
  • 开发或采用健壮的 ASN.1 解析库,但不止步于语法解析。必须实现语义层验证,包括字段值范围检查、内部逻辑关系校验(如证书内外签名算法一致)。
  • 建立关联验证链条,例如,从签名数据中解析出公钥 OID 和值,必须与本地信任链或提供的证书中的公钥信息进行比对。
  1. 工具辅助的自动化检查
  • 在密评和系统自检中,集成 Asn1View、OpenSSL ASN.1 解析模块等工具,对关键密码数据(如收到的证书、签章文件)进行自动化或半自动化的格式与编码合规性扫描。
  • 对于 OFD 签章等复合文档,建立标准的解包、定位(如找到 SignedValue.dat)、解析和验证流程。
  1. 关注边界与异常情况
  • 特别注意边界编码

    :如 SM2 签名中 INTEGER 值恰好位于字节边界时(最高位为1),必须添加前导 0x00;反之,当最高位为0且次高位为0时,应去除前导零。解析器必须正确处理这两种情况。

  • 警惕“非标准”简化

    :文档提示,实际应用中可能存在为“提高效率”而直接拼接数据部分(如去掉 TLV 结构)的情况。安全策略应明确拒绝此类简化,因为它们会破坏标准的、可验证的解析逻辑,引入兼容性和安全性风险。

综上所述,在国密体系下,ASN.1 编码的安全性并非主要源于其自身密码学强度,而是依赖于全体参与者对同一套抽象语法和唯一编码规则的共同遵守,以及在此基础上建立的、对编码数据深度、关联的逻辑验证体系。将 ASN.1 数据的合规性、正确性验证作为密码运算前不可或缺的预处理步骤,是构建健壮商用密码应用的关键防护策略。


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:利刃信安 利刃信安《【商密测评】ASN.1编码在国密算法中的应用、实现与安全性评估》

评论:0   参与:  2