QSL 卡片的数字签名
- 前言
近年来,越来越多的电台不再发送纸质 QSL 卡片,转而使用电子版 QSL 卡片或使用在线日志服务。我们意识到在线日志服务过于依赖某些中心化网站,且不足以展示电台个性,因而无法完全取代纸质 QSL 卡片.
同时,不含有签名电子版 QSL 卡片极易被伪造,不能独自有效证明通联的真实性。本文提出了一种可行的数字签名方案,在不影响电子 QSL 卡片功能、个性化 QSL 卡片的前提下,对 QSL 卡片上的信息进行数字签名.
- 范围
本文定义了一种对数字 QSL 卡片进行数字签名的方法。但本文不对公钥的分发、信任和吊销流程做出要求.
- 要求
本文提出的数字签名满足以下要求:
i. 数字签名可以被方便的识别、验证且不依赖中心化第三方服务.
ii. 数字签名不对 QSL 卡片设计、美观性产生显著影响
iii. 接收方对收到的 QSL 卡片进行格式转换等操作不影响签名有效性
iv. 接收方可以打印含有数字签名的 QSL 卡片,打印后的卡片可以被独立验证.
- 规范性引用文件
GB/T 1.1-2020 标准化工作导则 第 1 部分:标准化文件的结构和起草规则.
本文中粗体 “(不)应”、“(不)宜”、“可、不必”、“(不)能”、“(不)可能” 的使用符合 《GB/T 1.1-2020 标准化工作导则 第 1 部分:标准化文件的结构和起草规则》中附录 C 的定义.
- 定义
5.1 基本定义
- 字节 由 8 位二进制组成的符号
- 签名有效载荷 实际被签名的数据中,有意义的部分
- 被签名数据 数字签名算法的输入
- 签名 由文件头、签名算法描述和数字签名等部分组成的文件
5.2 SSH 消息
本文多次描述 SSH 消息结构体,在本文的语义下,用到的类型有:
ssh-string
四个字节、大端序表示的字符串长度和由前述长度指定的字节串,串中可以有 Unicode NUL 字符,串位不含有多余的 Unicode NUL 字符.uint32
四个字节、大端序表示的 32 位无符号整数.byte[N]
N 个字节,无其它信息varint
变长数字,其最高位表示是否为该数最后一位(1 为非,0 为是),如 150 表示为10010110 00000001
,16 进制转写为96 01
. 注:此类型非 SSH 消息定义.具体实现
6.1. 数字签名算法选择
在本设计中,我们将使用 SSH 密钥对 QSL 卡片上的信息进行数字签名,这是因为 SSH 的签名消息相比于 PGP 签名后的消息更小,更易于在 QSL 卡片上展示.
对于具体的算法选择,我们使用 Ed25519 椭圆曲线密码,这是因为 Ed25519 的公钥大小和签名大小都足够小,可以更方便地嵌入在 QSL 卡片中.
签名内容不包含被签名的信息.
6.2 数字签名有效载荷 ADIF
数字签名的有效载荷为一 ADIF 文件,其可以从 QSL 卡片上所展示的信息唯一构造.
6.2.1 构造 ADIF
被数字签名的信息使用 ADIF 格式,它人类可读的特性使得它可以被简单地构造,同时由于数字签名不包含被签名的信息,被签名信息的长度对签名的长度没有影响.
以下信息会依次包含在 ADIF 数据当中:
- QSO_DATE
- TIME_ON
- BAND
- CALL
- MODE
- STATION_CALLSIGN
- OPERATOR
其中,QSO_DATE
为 8 位数字(年、月、日)表示的协调时(UTC)日期,TIME_ON
为 6 位数字(时、分、秒)表示的协调时(UTC)时间,无论 QSL 卡片上是否印刷出了通联的秒数,时间都应截断至整分钟(即将秒数简单置 0).
上述各项均应用大写字母。如果 QSL 卡片上没有指明操作员,则 OPERATOR
为不含任何修饰的 STATION_CALLSIGN
.
如,以下的 QSL 卡片:
TO BB0BBB DE B4/BG6TOE
Date Time (BJT) / Freq / Mode / RST
2023-01-01 02:00:59 14.245 MHz USB 59 59
[x]PSE [ ]TNX QSL
VY TU! 73
其 ADIF 转写为:
<QSO_DATE:8>20221231<TIME_ON:6>180000<BAND:3>20M<CALL:6>BB0BBB<MODE:3>USB<STATION_CALLSIGN:9>B4/BG6TOE<OPERATOR:6>BG6TOE<EOR>
该文件的 xxd
转储为:
00000000: 3c51 534f 5f44 4154 453a 383e 3230 3232 <QSO_DATE:8>2022
00000010: 3132 3331 3c54 494d 455f 4f4e 3a36 3e31 1231<TIME_ON:6>1
00000020: 3830 3030 303c 4241 4e44 3a33 3e32 304d 80000<BAND:3>20M
00000030: 3c43 414c 4c3a 363e 4242 3042 4242 3c4d <CALL:6>BB0BBB<M
00000040: 4f44 453a 333e 5553 423c 5354 4154 494f ODE:3>USB<STATIO
00000050: 4e5f 4341 4c4c 5349 474e 3a39 3e42 342f N_CALLSIGN:9>B4/
00000060: 4247 3654 4f45 3c4f 5045 5241 544f 523a BG6TOE<OPERATOR:
00000070: 363e 4247 3654 4f45 3c45 4f52 3e 6>BG6TOE<EOR>
需要注意:文末不应有任何多余字符(含换行、空格、制表符等), 即 <EOR>
后不含有任何字符.
6.2.2 构造含有多个 QSO 的 ADIF 信息
若一张 QSL 卡片上含有多个 QSO, 则对应的 ADIF 文件应按照通联的时间顺序,直接拼接各个 QSO 的 ADIF 数据,文末不应有任何多余字符(含换行、空格、制表符等), 即,以最后一个 QSO 的 <EOR>
后不含有任何字符.
6.3 签名数据
6.3.1 展示方式
签名数据可以在经由 Base64 编码后直接显示在 QSL 卡片上。以文本形式表示的签名数据宜使用等宽字体排版。使用的字体应足以分辨 i
、l
、1
, O
、o
、0
, 5
、S
等 Base64 使用的编码字符.
签名数据可以在经由 Base32 编码后直接显示在 QSL 卡片上。以文本形式表示的签名数据宜使用等宽字体排版.
签名数据宜在经由 Base45 编码后包含于 QR Code 中。此时签名数据应为独立的二维码。该二维码可使用除黑、白之外的颜色,但应用浅色区域作为二维码背景、深色作为二维码前景色.
为保证生成二维码识别成功率,使用 QR Code 为载体的签名数据不宜使用 Base45 以外的编码.
6.3.2 二进制签名数据格式
二进制签名为 SSH 签名结构体,其格式为:
byte[6] MAGIC_PREAMBLE
uint32 SIG_VERSION
ssh-string publickey
ssh-string namespace
ssh-string reserved
ssh-string hash_algorithm
ssh-string signature
其中:MAGIC_PREAMBLE
为 SSHSIG
, SIG_VERSION
为 1.
publickey
为序列化后的签名密钥的公钥.
namespace
应为 adif-qslv1
.
reserved
应为空.
hash_algorithm
应为 sha512
(即,总是使用 SHA512 对数据进行签名).
signature
为 SSH 正文的签名,使用 ssh-ed25519
算法.
6.3.3 签名的精简
为了使得签名内容更容易被展示,可以对签名内容进行精简。精简之后的签名仅包含头部及 ED25519 签名数据。其中,头部固定为 DQSLV1
,后紧跟 64 字节的 ED25519 签名 X||Y
。当接收方获得开头为 DQSLV1
的签名数据时,应将其展开为标准签名格式进行校验。
6.3.4 被签名内容
实际被签名的内容为:
byte[6] MAGIC_PREAMBLE
ssh-string namespace
ssh-string reserved
ssh-string hash_algorithm
ssh-string H(message)
其中:MAGIC_PREAMBLE
为 SSHSIG
, SIG_VERSION
为 1.
publickey
应为序列化后的签名密钥的公钥.namespace
应为 adif-qslv1
.
reserved
应为空.
hash_algorithm
应为 sha512
(即,总是使用 SHA512 对数据进行签名).
message
4.2 节所描述的 ADIF 文件,H(message)
为其 SHA-512 算法下的指纹.
将此内容经由 SSH Message 格式编码后,使用 Ed25519 私钥和 ssh-ed25519
进行签名,即得到 4.3.1 节中的 signature
字段.
- 附加原始 QSO 数据
签名前可附加原始 QSO 数据,以方便机器直接识别、校验。原始 QSO 数据为精简表示的极小 QSO 元数据,包含以下字段:通联时间、通联波段、通联模式、收方呼号、发方呼号、OP。
其格式为:
byte[6] MAGIC_PREAMBLE
varint call
varint station_callsign
varint operator
ssh-string data
其中,call、station_callsign、operator 为呼号的 37 进制数表示(见下表):
+---------++----+----++----+----+
|Char|Num ||Char|Num ||Char|Num |
+---------++----+----++----+----+
| 0 | 0 || C | 12 || O | 24 |
| 1 | 1 || D | 13 || P | 25 |
| 2 | 2 || E | 14 || Q | 26 |
| 3 | 3 || F | 15 || R | 27 |
| 4 | 4 || G | 16 || S | 28 |
| 5 | 5 || H | 17 || T | 29 |
| 6 | 6 || I | 18 || U | 30 |
| 7 | 7 || J | 19 || V | 31 |
| 8 | 8 || K | 20 || W | 32 |
| 9 | 9 || L | 21 || X | 33 |
| A | 10 || M | 22 || Y | 34 |
| B | 11 || N | 23 || Z | 35 |
| / | 36 |+----+----++----+----+
+----+----+
如 B1CRA
表示为 11 * 37^4 + 1 * 37^3 + 12 * 37^2 + 27 * 37 + 10 = 20683861
其中,data 为多个最小 QSO 拼接而成的字符串,其格式为
varint QSO Timestamp
varint Band
byte[8] Mode
其中 QSO Timestamp 为协调时 1970 年元旦以来的秒数(但精确到分钟)。Band 为波段对应频率的低端(千赫兹)数,如 20 米波段表示为 14000。Mode 为表示模式的字符串,不足 8 字节用 \0
补全。
- 示例
假设 ST4TION
使用电台 C3SHI
与 TE5T
在北京时 2023 年 1 月 1 日 10:05:30,在 20 米段上使用 MFSK 调制方式完成了一次通联完成了一次通联。现 ST4TION
欲以其自己名义签名如下 QSL 卡片:
TO TE5T DE C3SHI OP ST4TION
Date Time (BJT) / Freq / Mode / RST
2023-01-01 10:00 14.074 MHz MFSK 59 59
[x]PSE [ ]TNX QSL
VY TU! 73
ST4TION
的私钥为:
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACADTnJZ6blw4CsqVoxzv9iWVVl0ycM8Neqb9QvTyvKqCAAAAJiuWf0orln9
KAAAAAtzc2gtZWQyNTUxOQAAACADTnJZ6blw4CsqVoxzv9iWVVl0ycM8Neqb9QvTyvKqCA
AAAEDgyhqzLTK6rmVqjfvHpvHPYJzdeVuDhRo93XO98jDl1QNOclnpuXDgKypWjHO/2JZV
WXTJwzw16pv1C9PK8qoIAAAAFW1hdHN1QEJHNlRPRS1Ob3RlYm9vaw==
-----END OPENSSH PRIVATE KEY-----
其公钥为:
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIANOclnpuXDgKypWjHO/2JZVWXTJwzw16pv1C9PK8qoI
则其构造如下的 ADIF 数据 (签名有效载荷):
<QSO_DATE:8>20230101<TIME_ON:6>020500<BAND:3>20M<CALL:4>TE5T<MODE:4>MFSK<STATION_CALLSIGN:5>C3SHI<OPERATOR:7>ST4TION<EOR>
需要注意:
- 卡面上的北京时间应转换为协调世界时
- 生成的 ADIF 文件中的秒被无条件截断至 0
- 波段从 14.074 得出,为 20M
- RST 不包含在 ADIF 当中
该 ADIF 的 SHA512
指纹为:
5d10 5c01 843a 14ad 9852 5f40 f9e9 36d5
0e00 56b0 d98b a04f 6d1d d337 efb8 11bb
f397 52d3 6233 6b64 ab8f 430f cf6b e95d
bfb4 39b9 26c8 fb39 9cbf 414a b386 a1b4
构造如下被签名数据:
00000000: 5353 4853 4947 0000 000a 6164 6966 2d71 SSHSIG....adif-q
00000010: 736c 7631 0000 0000 0000 0006 7368 6135 slv1........sha5
00000020: 3132 0000 0040 5d10 5c01 843a 14ad 9852 12...@].\..:...R
00000030: 5f40 f9e9 36d5 0e00 56b0 d98b a04f 6d1d _@..6...V....Om.
00000040: d337 efb8 11bb f397 52d3 6233 6b64 ab8f .7......R.b3kd..
00000050: 430f cf6b e95d bfb4 39b9 26c8 fb39 9cbf C..k.]..9.&..9..
00000060: 414a b386 a1b4 AJ....
应用前述私钥及 ssh-ed25519
签名方式进行签名:
00000000: 0000 0053 0000 000b 7373 682d 6564 3235 ...S....ssh-ed25
00000010: 3531 3900 0000 4082 84f9 edcb 8ef8 6cdf 519...@.......l.
00000020: 5bee c347 6762 84ea ce4b 4644 6429 6900 [..Ggb...KFDd)i.
00000030: 4139 6e79 9bbd f74c 2b94 0e53 541e 4dfa A9ny...L+..ST.M.
00000040: 94db 704a 9b77 aad1 4dcd 2e5d 6b3f 30c6 ..pJ.w..M..]k?0.
00000050: 44c6 7e84 ca4d 07 D.~..M.
构造签名:
00000000: 5353 4853 4947 0000 0001 0000 0033 0000 SSHSIG.......3..
00000010: 000b 7373 682d 6564 3235 3531 3900 0000 ..ssh-ed25519...
00000020: 2003 4e72 59e9 b970 e02b 2a56 8c73 bfd8 .NrY..p.+*V.s..
00000030: 9655 5974 c9c3 3c35 ea9b f50b d3ca f2aa .UYt..<5........
00000040: 0800 0000 0a61 6469 662d 7173 6c76 3100 .....adif-qslv1.
00000050: 0000 0000 0000 0673 6861 3531 3200 0000 .......sha512...
00000060: 5300 0000 0b73 7368 2d65 6432 3535 3139 S....ssh-ed25519
00000070: 0000 0040 8284 f9ed cb8e f86c df5b eec3 ...@.......l.[..
00000080: 4767 6284 eace 4b46 4464 2969 0041 396e Ggb...KFDd)i.A9n
00000090: 799b bdf7 4c2b 940e 5354 1e4d fa94 db70 y...L+..ST.M...p
000000a0: 4a9b 77aa d14d cd2e 5d6b 3f30 c644 c67e J.w..M..]k?0.D.~
000000b0: 84ca 4d07 ..M.
精简签名:
00000000: 4451 534c 5631 8284 f9ed cb8e f86c df5b DQSLV1.......l.[
00000010: eec3 4767 6284 eace 4b46 4464 2969 0041 ..Ggb...KFDd)i.A
00000020: 396e 799b bdf7 4c2b 940e 5354 1e4d fa94 9ny...L+..ST.M..
00000030: db70 4a9b 77aa d14d cd2e 5d6b 3f30 c644 .pJ.w..M..]k?0.D
00000040: c67e 84ca 4d07 .~..M.
签名的 Base64 编码:
U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgA05yWem5cOArKlaMc7/YllVZdMnDPDXq
m/UL08ryqggAAAAKYWRpZi1xc2x2MQAAAAAAAAAGc2hhNTEyAAAAUwAAAAtzc2gtZWQyNTUxOQAA
AECChPnty474bN9b7sNHZ2KE6s5LRkRkKWkAQTlueZu990wrlA5TVB5N+pTbcEqbd6rRTc0uXWs/
MMZExn6Eyk0H
精简签名的 Base64 编码:
RFFTTFYxgoT57cuO+GzfW+7DR2dihOrOS0ZEZClpAEE5bnmbvfdMK5QOU1QeTfqU23BKm3eq0U3N
Ll1rPzDGRMZ+hMpNBw==
签名的 Base45 编码:
1OAK69*B9000100000610000B00ZQET7D CSF6RW6C97000524C-9MGB.JNCFS%F50YHHBOA0J+DB MPNR7TTT1:U%YQMUUN010002E1AVCC-CIFE1WDY86000000000V 0 8DRW6KE60008MA0006K1OQEBX50UCVW61A6000J10MMG QV0XPBIVTASD8U919KKCZUTAN93T8QA5K10WB7 GFV0OES9CWI2OAH$3NUVGXRJJ9Y5FVKQB.PK BL:7-2P94PJZG9X9
精简签名的 Base45 编码:
TS8*NAF+AMMG QV0XPBIVTASD8U919KKCZUTAN93T8QA5K10WB7 GFV0OES9CWI2OAH$3NUVGXRJJ9Y5FVKQB.PK BL:7-2P94PJZG9X9
- 信息性引用文件
RFC4634 US Secure Hash Algorithms (SHA and HMAC-SHA)
RFC4648 The Base16, Base32, and Base64 Data Encodings
RFC8709 Ed25519 and Ed448 Public Key Algorithms for the Secure Shell (SSH) Protocol
RFC9285 The Base45 Data Encoding)
ADIF Amateur Data Interchange Format (ADIF) Specification