Go ASN.1编码

106 阅读5分钟

ASN.1基本信息

ASN.1(Abstract Syntax Notation One)是一种国际标准(由ITU-T X.680系列建议定义),用于描述数据的结构。它主要用于定义和编码传输协议中的数据,以确保不同系统间的数据交换。

ASN.1语法可用来描述各种类型的数据,包括文本、图形、视频与音频等。通常用于定义应用数据的抽象语法和PDU的结构。比如SNMP中使用ASN.1进行管理信息结构SMI的定义和管理数据库MIB的定义。ASN.1编码可用来规范数据传输过程,解决异构网络对数据理解的二义性。

ASN.1最初是ITU针对电信协议设计而制定,后来被ISO接受成为国际标准。

ASN.1的主要应用:

  • 网络协议:ASN.1被广泛用于各种网络协议,如SNMP(Simple Network Management Protocol)、LDAP(Lightweight Directory Access Protocol)和X.500目录服务。它帮助定义和编码数据,使不同的系统可以互相通信。

  • 电信系统:在电信行业,ASN.1用于信令协议,如SS7(Signaling System No. 7)和GSM(Global System for Mobile Communications)。它确保不同电信设备之间的互操作性。

  • 安全协议:ASN.1被用于许多安全协议,如X.509数字证书和SSL/TLS。它帮助定义和编码证书、密钥和其他安全相关的数据结构。

  • 金融系统:在金融行业,ASN.1用于标准化各种交易和信息交换协议,如ISO 20022标准。这有助于不同金融机构之间的信息交换和处理。

  • 多媒体通信:ASN.1还用于多媒体通信协议,如H.323和H.264,用于视频会议、VoIP和其他实时通信应用。

  • 智能卡:在智能卡应用中,ASN.1用于定义和传输数据,如在电子护照和支付卡中。

  • 数据交换格式:ASN.1可用于定义通用数据交换格式,使不同系统能够理解和处理相同的数据结构。

ASN.1编码规则

ASN.1的广泛应用得益于其灵活性和扩展性,以及它支持多种编码规则,如BER(Basic Encoding Rules)、DER(Distinguished Encoding Rules)和PER(Packed Encoding Rules),以满足不同应用的需求。ASN.1 提供了多种编码规范,以适应不同应用的需求。主要的编码规范包括:

  • BER(Basic Encoding Rules):

    • 基本编码规则,是ASN.1的最基本编码规则,灵活且容易实现。
    • 使用标签类型(Type)、长度(length)和内容(value)三部分来表示数据。
    • BER的灵活性也意味着它可能会生成冗长的编码,不适合对效率要求高的场合。
  • DER(Distinguished Encoding Rules):

    • 区别编码规则,是BER的子集,消除了BER中的不确定性,确保了唯一的编码方式。
    • 用于需要唯一编码的场合,如数字证书(X.509)和加密协议。
  • CER(Canonical Encoding Rules):

    • 规范编码规则,与DER类似,但用于无限长字符串的情况下。
    • 通过规范化处理,确保编码的唯一性,适用于一些需要数据一致性的应用。
  • PER(Packed Encoding Rules):

    • 紧凑编码规则,通过优化编码来减少数据的长度,适合对带宽敏感的场合。
    • 有两种变体:对齐(Aligned PER)和非对齐(Unaligned PER),对齐的编码会以八位字节为单位,而非对齐则不会。
  • XER(XML Encoding Rules):

    • XML编码规则,将ASN.1描述的数据结构编码为XML格式,便于与基于XML的系统进行互操作。
    • 易于阅读和调试,但比其他编码规则更加冗长。
  • OER(Octet Encoding Rules):

    • 八位字节编码规则,旨在提供一种高效且容易解析的编码规则。
    • 适用于需要紧凑和快速解析的应用场合。
  • JER(JSON Encoding Rules):

    • JSON编码规则,将ASN.1描述的数据结构编码为JSON格式。
    • 适用于与基于JSON的系统和应用进行互操作。

ASN.1的关键字

基本类型如:

INTEGER:

  • 输出类型:整数
  • 解释:表示整数值。
  • 十六进制值:0x02

OCTET STRING:

  • 输出类型:字节串
  • 解释:表示任意长度的字节序列。
  • 十六进制值:0x04

NULL:

  • 输出类型:空值
  • 解释:表示一个空值。
  • 十六进制值:0x05

PrintableString:

  • 输出类型:可打印字节串
  • 解释:表示任意长度的打印字符串。
  • 十六进制值:0x13

结构化类型如:

SEQUENCE:

  • 输出类型:序列
  • 解释:表示一组有序的数据项。
  • 十六进制值:0x30

实现

  • main.go
package main

import (
	"encoding/asn1"
	"encoding/hex"
	"fmt"
	"log"
)

type Person struct {
	Name string
	Age  int
}

func main() {
	person := Person{Name: "Alice", Age: 30}

	// 编码
	data, err := asn1.Marshal(person)
	if err != nil {
		log.Fatalf("Marshaling failed: %v", err)
	}
	fmt.Printf("Encoded data: %x\n", data)
	fmt.Printf("Hex data: %v\n", hex.Dump(data))

	// 解码
	var decodedPerson Person
	_, err = asn1.Unmarshal(data, &decodedPerson)
	if err != nil {
		log.Fatalf("Unmarshaling failed: %v", err)
	}
	fmt.Printf("Decoded person: %+v\n", decodedPerson)
}
  • 运行
[xiaofeng@localhost asn]$ go run main.go 
Encoded data: 300a1305416c69636502011e
Hex data: 00000000  30 0a 13 05 41 6c 69 63  65 02 01 1e              |0...Alice...|

Decoded person: {Name:Alice Age:30}
  • 分析
    • 类型|长度|值
    • 30 表示序列结构类型
    • 0a 长度为10
    • 13 表示可打印字符串
    • 05 长度为5
    • 41 6c 69 63 65 表示值Alice
    • 02 表示整数类型
    • 01 表示长度为1
    • 1e 表示值30

参考