本文首先介绍公钥格式相关的若干概念/技术,随后以示例的方式剖析DER格式的ECC公钥,最后介绍如何使用Java生成、解析和使用ECC公钥。
ASN.1
Abstract Syntax Notation One (ASN.1)是一种接口描述语言,提供了一种平台无关的描述数据结构的方式。ASN.1是ITU-T、ISO、以及IEC的标准,广泛应用于电信和计算机网络领域,尤其是密码学领域。
ASN.1与大家熟悉的Protocol Buffers和Apache Thrift非常相似,都可以通过schema来定义数据结构,提供跨平台的数据序列化和反序列化能力。不同的是,ASN.1早在1984年就被定为标准,比这两者要早很多年,并得到了广泛的应用,被用来定义了很多世界范围内广泛使用的数据结构,有大量的RFC文档使用ASN.1定义协议、数据格式等。比如https所使用的X.509证书结构,就是使用ASN.1定义的。
ASN.1定义了若干基础的数据类型和结构类型:
Topic | Description |
---|---|
Basic Types | BIT STRING BOOLEAN INTEGER NULL OBJECT IDENTIFIER OCTET STRING |
String Types | BMPString IA5String PrintableString TeletexString UTF8String |
Constructed Types | SEQUENCE SET CHOICE |
上述的基础类型可以在这里找到详尽的解释。我们可以使用这些来描述我们自己的数据结构:
FooQuestion ::= SEQUENCE {
trackingNumber INTEGER,
question IA5String
}
如上定义了一个名为FooQuestion的数据结构。它是一个SEQUENCE结构,包含了一个INTEGER一个IA5String
一个具体的FooQuestion可以描述为:
myQuestion FooQuestion ::= {
trackingNumber 5,
question "Anybody there?"
}
用ASN.1定义的数据结构实例,可以序列化为二进制的BER、文本类型的JSON、XML等。
Object Identifier
Object Identifier (OID)是一项由ITU和ISO/IEC制定的标准,用来唯一标识对象、概念,或者其它任何具有全球唯一特性的东西。
一个OID表现为用.分隔的一串数字,比如椭圆曲线secp256r1的OID是这样:
1.2.840.10045.3.1.7
其每个数字的含义如下:
iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3) prime(1) 7
OID是全局统一分配的,全部的OID可以看做一棵多叉树,每一个有效的OID表现为树上的一个节点。当前所有的OID可以在这里找到。
OID是ASN.1的基本类型。
BER & DER
Basic Encoding Rules (BER)是一种自描述的ASN.1数据结构的二进制编码格式。每一个编码后的BER数据依次由数据类型标识(Type identifier),长度描述(Length description), 实际数据(actual Value)排列而成,即BER是一种二进制TLV编码。TLV编码的一个好处,是数据的解析者不需要读取完整的数据,仅从一个不完整的数据流就可以开始解析。
Distinguished Encoding Rules (DER)是BER的子集,主要是消除了BER的一些不确定性的编码规则,比如在BER中Boolean类型true的value字节,可以为任何小于255大于0的整数,而在DER中,value字节只能为255。DER的这种确定性,保证了一个ASN.1数据结构,在编码为为DER后,只会有一种正确的结果。这使得DER更适合用在数字签名领域,比如X.509中广泛使用了DER。
关于各种ASN.1数据类型是如何被编码为DER,可以在这里找到详尽的解释。
如果有DER数据需要解析查看内容,这里有一个很方便的在线工具。
用DER来编码ASN.1小节中自定义的myQuestion如下: