SNMP中BER编码解析
字符占用字节数解析
1. 英文字符
- ASCII 编码:1字节 (8比特)
- 示例:
'A'
→ 二进制01000001
- 示例:
- UTF-8 编码:1字节 (8比特)
- 兼容 ASCII 的英文字符仍占1字节
2. 中文字符
编码类型 | 字节数 | 比特数 | 示例 |
---|---|---|---|
GBK/GB2312 | 2字节 | 16比特 | '中' → 0xD6 0xD0 |
UTF-8 | 3字节 | 24比特 | '中' → 0xE4 0xB8 0xAD |
UTF-16 | 2字节 | 16比特 | '中' → 0x4E 0x2D |
特殊说明:少数生僻汉字在 UTF-8 中占4字节(如
𠀀
→0xF0 0xA0 0x80 0x80
)
BER 编码解析
原始数据:
[0x06, 0x08, 0x2B, 0x06, 0x01, 0x02, 0x01, 0x01, 0x01, 0x00]
对应 OID 1.3.6.1.2.1.1.1.0
BER 解码步骤
1. 分解 TLV 结构
部分 | 字节 | 含义 |
---|---|---|
Tag | 0x06 | 对象类型:OBJECT IDENTIFIER |
Length | 0x08 | 值域长度:8字节 |
Value | 0x2B 0x06 0x01 0x02 0x01 0x01 0x01 0x00 | OID 编码值 |
2. OID 值域解码
# OID 编码规则:
# 第一段 = (X * 40) + Y
# 后续段:Base128 变长编码(最高位1表示继续)value = [0x2B, 0x06, 0x01, 0x02, 0x01, 0x01, 0x01, 0x00]# 步骤1:解码前两个数字
first_byte = 0x2B # 43
x = first_byte // 40 # 43 ÷ 40 = 1
y = first_byte % 40 # 43 % 40 = 3
→ 得到 1.3# 步骤2:直接解码单字节数字
0x06 → 6
0x01 → 1
0x02 → 2
0x01 → 1
0x01 → 1
0x01 → 1
0x00 → 0# 最终OID:1.3.6.1.2.1.1.1.0
3. 完整解码过程
字节 | 二进制 | 解码规则 | 结果数字 |
---|---|---|---|
0x2B | 00101011 | (X*40)+Y | X=1, Y=3 → 1.3 |
0x06 | 00000110 | 直接取值 | 6 |
0x01 | 00000001 | 直接取值 | 1 |
0x02 | 00000010 | 直接取值 | 2 |
0x01 | 00000001 | 直接取值 | 1 |
0x01 | 00000001 | 直接取值 | 1 |
0x01 | 00000001 | 直接取值 | 1 |
0x00 | 00000000 | 直接取值 | 0 |
最终 OID:
1.3.6.1.2.1.1.1.0
为什么这样设计?
1. 编码优化目标
- 最小化空间:使用变长编码压缩大数字
- 快速解码:单字节直接取值无需计算
- 兼容性:支持无限长的 OID
2. 特殊规则说明
-
前两段合并:因 OID 前两段范围有限(
0≤X≤2
,0≤Y≤39
),可用1字节表示:取值范围 = 0 到 (2*40 + 39) = 119 实际最大值:X=2时,Y无上限(但标准定义Y<40)
-
大数字处理(本例未涉及):
# 示例:数字 30000 的编码 30000 的二进制: 1 1101010 0110000 分组(7位一组): [1, 1101010, 0110000] 添加最高位: 0b11101010 → 0xEA (最高位1,表示继续)0b00110000 → 0x30 (最高位0,结束) 最终编码: [0xEA, 0x30]
编码验证工具
使用 Python 验证编码:
from pyasn1.type import univ
from pyasn1.codec.ber import encoder# 定义 OID 对象
oid = univ.ObjectIdentifier('1.3.6.1.2.1.1.1.0')# BER 编码
ber_encoded = encoder.encode(oid)
print(list(ber_encoded))
# 输出: [6, 8, 43, 6, 1, 2, 1, 1, 1, 0] (即十六进制 06 08 2B 06 01 02 01 01 01 00)
总结
-
字符占用:
- 英文:1字节(ASCII/UTF-8)
- 中文:2字节(GBK)或 3字节(UTF-8)
-
OID BER 编码:
- TLV 结构:Type(1B) + Length(1B) + Value(NB)
- 值域规则:
- 前两段合并为
40*X + Y
- 后续段直接单字节取值(值<128时)
- 大数字使用 Base128 变长编码(最高位为延续标志)
- 前两段合并为
-
示例解码:
[0x06, 0x08, 0x2B, 0x06, 0x01, 0x02, 0x01, 0x01, 0x01, 0x00] → Tag=OID, Length=8, Value=1.3.6.1.2.1.1.1.0