日志格式规范 —— SM2密钥销毁日志长什么样

我记得刚接手审计系统时,第一个感觉就是:日志格式怎么这么乱?有的系统用 JSON,有的用 XML,时间戳有的带时区有的不带,字段名也不统一。后来我发现,真正成熟的密钥销毁日志,必须有一套严格的标准。否则审计人员拿到日志,根本没法解析,更别说验证签名了。

说白了,SM2密钥销毁日志的格式规范,就是给审计链打地基。地基不稳,后面全是坑。这一节我把核心要素拆开讲:标准字段、时间戳、签名方式、以及两种常见序列化结构。

标准字段都有哪些

一个合格的销毁日志,至少要包含以下字段。我用一张表列出来,你对照着看会清楚很多。

字段名 英文标识 说明 示例值
日志ID log_id 全局唯一,防重放 a1b2c3d4-e5f6-7890-abcd-ef1234567890
销毁时间 destruction_time UTC时间,精确到毫秒 2026-03-15T08:32:17.456Z
密钥标识 key_id 被销毁密钥的SM2公钥哈希 sm2-20260315-001
操作者 operator 执行销毁的用户或设备ID admin@security
销毁原因 reason 枚举值或描述 密钥到期 / 合规轮换
签名值 signature SM2签名(十六进制) 3045022100...
签名公钥 signer_public_key 签名者SM2公钥(PEM或Hex) 04b7... (65字节)
我个人的经验:千万别漏掉 log_id。我在项目中遇到过因为日志ID不唯一,导致审计系统里出现两条一模一样的销毁记录,结果合规审查时被质疑日志造假。后来强制用UUID v4,再也没出过这种问题。

时间戳格式 —— 别让时区坑了你

时间戳看着简单,但坑最多。你想想看,系统A在上海,系统B在伦敦,如果日志里只写 2026-03-15 16:32:17,请问这是北京时间还是格林威治时间?审计人员根本没法判断。

我建议统一用 UTC ISO 8601,带毫秒和时区标识。例如:

2026-03-15T08:32:17.456Z

这里的 Z 表示 UTC。如果你偏要用偏移量,也可以:

2026-03-15T16:32:17.456+08:00

但无论如何,必须明确时区。我曾经在处理跨国密钥销毁日志时,因为时间戳没带时区,导致两次销毁事件的时间顺序错乱,差点被当成安全事件上报。后来我在代码里加了强制校验:非UTC或非明确偏移量的日志直接拒绝入库。

注意:不要用本地时间戳。审计日志最怕的就是“我以为”。你的本地时间可能是UTC+8,别人的可能是UTC-5。统一用UTC,全系统都省心。

签名方式 —— 用SM2自证清白

日志一旦生成,怎么证明它是原始记录,没被篡改过?答案是:对日志内容进行SM2签名。

常见的做法是:先将日志的固定字段(除去签名本身)拼成一个待签名原文,然后用签名者的SM2私钥签出 (r, s) 值。接收方拿到日志后,用同样的方式拼出原文,再用公钥验签。

我习惯的拼装顺序是:

  1. log_id(UUID字符串)
  2. destruction_time(ISO 8601字符串)
  3. key_id
  4. operator
  5. reason

把这些字段用 || 分隔拼接成字符串(或者用TLV编码,但字符串拼接更简单)。然后做SM2签名,签名结果按ASN.1 DER编码,再转成十六进制字符串存入日志。

避坑指南:
我曾经在验签时发现总失败,排查了半天,原来是拼接时多了一个空格。后来我明确规定:字段值之间不加任何分隔符,直接按固定顺序拼接。比如:a1b2c3d4-e5f6-7890-abcd-ef12345678902026-03-15T08:32:17.456Zsm2-20260315-001admin@securitykey_expired。这样两边完全一致,签名自然就通了。

JSON / XML 结构 —— 两种马甲,一个内核

序列化格式方面,业界主要用 JSON 和 XML。JSON 轻量,XML 带命名空间和Schema校验,各有优势。我两个都给出例子,你根据自己系统的生态选一个就好。

先看 JSON 版本:

{
  "log_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "destruction_time": "2026-03-15T08:32:17.456Z",
  "key_id": "sm2-20260315-001",
  "operator": "admin@security",
  "reason": "key_expired",
  "signer_public_key": "04b742...省略...",
  "signature": "3045022100d89f...省略..."
}

XML 版本(带命名空间):

<?xml version="1.0" encoding="UTF-8"?>
<Sm2KeyDestructionLog
  xmlns="urn:ietf:params:sm2:audit:1.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <logId>a1b2c3d4-e5f6-7890-abcd-ef1234567890</logId>
  <destructionTime>2026-03-15T08:32:17.456Z</destructionTime>
  <keyId>sm2-20260315-001</keyId>
  <operator>admin@security</operator>
  <reason>key_expired</reason>
  <signerPublicKey>04b742...省略...</signerPublicKey>
  <signature>3045022100d89f...省略...</signature>
</Sm2KeyDestructionLog>
我建议:如果你要对接多个异构系统,优先用 JSON。JSON 解析器几乎每个语言都有,而且字段顺序清晰,签名拼接时也可以按 key 字母序排序,减少歧义。XML 虽然可读性强,但 tag 名称、命名空间、大小写都容易引入签名不一致的坑。

核心流程回顾

我把日志从生成到审计的流程画成一张图,方便你理解整体脉络。

SM2密钥销毁日志生成与审计流程 密钥销毁事件 组装日志字段 添加UTC时间戳 SM2签名 序列化JSON/XML 存储/传输 审计系统解析+验签 验证签名时注意 字段拼接顺序一致

整个流程并不复杂,但每个环节都有小的细节。比如时间戳格式、签名原文的拼装规则、序列化时字段的排序等等。只要你把这些规范定死,并在代码里用单元测试覆盖住,后面的审计链路跑起来就会很顺畅。