asn.1
编解码asn.1
语法ruby
语言实现简单的编解码我这几天没有找到满足要求的 java
库, 所以先用 Ruby
asn.1
标准的 der
文件require ‘openssl‘
int = OpenSSL::ASN1::Integer.new(1)
str = OpenSSL::ASN1::PrintableString.new(‘abc‘)
sequence = OpenSSL::ASN1::Sequence.new([int, str])
der = sequence.to_der
open ‘rubytest.der‘, ‘w‘ do |io|
io.write der
end
我感觉这个没啥好说的,调用 ruby openssl库
生成了一个 asn.1
标准的数据结构,再将其写入 der
文件。
der
文件require ‘openssl‘
der = File.binread(‘rubytest.der‘)
OpenSSL::ASN1.traverse der do |depth, offset, header_len, length, constructed, tag_class, tag|
puts "Depth: #{depth} Offset: #{offset} Length: #{length}"
puts "Header length: #{header_len} Tag: #{tag} Tag class: #{tag_class} Constructed: #{constructed}"
end
输出结果是这样的
Depth: 0 Offset: 0 Length: 8
Header length: 2 Tag: 16 Tag class: UNIVERSAL Constructed: true
Depth: 1 Offset: 2 Length: 1
Header length: 2 Tag: 2 Tag class: UNIVERSAL Constructed: false
Depth: 1 Offset: 5 Length: 3
Header length: 2 Tag: 19 Tag class: UNIVERSAL Constructed: false
先看 Constructed
,true
代表其为结构节点,包含子节点; false
代表其为数据节点。
我们来看一看 Tag
和 Tag class
。asn.1
标准文件中,每一个节点都有 Tag
和 Tag class
,在不特别指定的情况下,Tag class
默认值为 Universal
,Tag
默认值由这个节点的数据类型来定,对应关系如下表:
Type | Tag |
---|---|
INTEGER | 2 |
BIT STRING | 3 |
OCTET STRING | 4 |
NULL | 5 |
OBJECT IDENTIFIER | 6 |
SEQUENCE and SEQUENCE OF | 16 |
SET and SET OF | 17 |
PrintableString | 19 |
T61String | 20 |
IA5String | 22 |
UTCTime | 23 |
offset
表示节点在整个文件中的偏移长度,Length
表示节点数据字节长度
Header Length
是节点头部长度,个人认为这个长度把 头字节
和 LEN(存储节点数据长度的字段)
都算了进去
第一个节点(Sequence
)的 Length = 8
,可以由其两个子节点的 Length + Header Length
求得
require ‘openssl‘
der = File.binread(‘rubytest.der‘)
asn1 = OpenSSL::ASN1.decode der
pp asn1
结果如下
#<OpenSSL::ASN1::Sequence:0x0000555723211270
@indefinite_length=false,
@tag=16,
@tag_class=:UNIVERSAL,
@tagging=nil,
@value=
[#<OpenSSL::ASN1::Integer:0x0000555723211310
@indefinite_length=false,
@tag=2,
@tag_class=:UNIVERSAL,
@tagging=nil,
@value=#<OpenSSL::BN 1>>,
#<OpenSSL::ASN1::PrintableString:0x0000555723211298
@indefinite_length=false,
@tag=19,
@tag_class=:UNIVERSAL,
@tagging=nil,
@value="abc">]>
@indefinite_length=false
表示编码长度是有限的(我不确定)@value
可以看到节点的值tag
require ‘openssl‘
int = OpenSSL::ASN1::Integer.new(1, 0, :EXPLICIT)
der = int.to_der
pp OpenSSL::ASN1.decode der
以 Integer
为例,Integer.new()
第一个参数是这个节点的 value
,第二个参数是自定义的 tag
值,第三个参数指定采用 implicit
还是 explicit
模式。
输出如下
#<OpenSSL::ASN1::ASN1Data:0x0000564fe9f2db60
@indefinite_length=false,
@tag=0,
@tag_class=:CONTEXT_SPECIFIC,
@value=
[#<OpenSSL::ASN1::Integer:0x0000564fe9f2dbb0
@indefinite_length=false,
@tag=2,
@tag_class=:UNIVERSAL,
@tagging=nil,
@value=#<OpenSSL::BN 1>>]>
我们可以发现 explicit
模式,是直接在原节点外包裹了一个新节点,新节点的 tag class
默认为 CONTEXT_SPECIFIC
再试试 implicit
模式
require ‘openssl‘
int = OpenSSL::ASN1::Integer.new(1, 0, :IMPLICIT)
der = int.to_der
pp OpenSSL::ASN1.decode der
输出为
#<OpenSSL::ASN1::ASN1Data:0x000055a6f86762a0
@indefinite_length=false,
@tag=0,
@tag_class=:CONTEXT_SPECIFIC,
@value="\x01">
我们发现,implicit
模式是直接改变了原节点
Ruby
的 openssl
库对新手非常友好,适合实践解决疑惑。文档也相当齐全,用起来很爽。但我还是得找 java
或者 Rust
的 openssl
方案,因为不会用 Ruby
写项目……
原文:https://www.cnblogs.com/mtzf/p/12769923.html