Bouncy Castle 的 ASN1 使用方法


本文介绍BC中的ASN1组装和解析,ASN1是什么就不解释了。其实直接使用BC解析ASN1的场景是比较少见的, 因为大多数操作已经对应封装好了。比如说X509解析本身就已经封装好,不需要一步一步的用这些函数解析。但有些场景需要用到自定义的ASN1结构时,自己组装和解析就不可避免了。下面的例子中使用的bcprov-ext-jdk15on-1.51.jar包请自行下载,我所使用的是1.51,其他旧版本基本上一致,应该可以使用。

1.1首先是简单组装

创建一个简单的ASN1格式数据,里面包含Integer和Boolean值。
try{
	ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
	//创建ByteArrayOutputStream,用于放置输出的byte流
	DEROutputStream derOutputStream = new DEROutputStream(outputStream);
	//创建DEROutputStream
	derOutputStream.writeObject(new DERInteger(10));
	//写入DERInteger数据,10对应的hex为0a。
	derOutputStream.writeObject(new DERBoolean(false));
	//写入DERBoolean数据,false对应asn1中的hex为00
	derOutputStream.flush();
	System.out.println(StringUtils.Hex(outputStream.toByteArray()));
	//将输出的bytearray转换为直观显示的Hex格式输出
} catch (Exception e) {
	e.printStackTrace();
}
输出:02 01 0a 01 01 00
对应解析:
02 : Interger
<span style="white-space:pre">	</span>01 : Len
<span style="white-space:pre">	</span>0a : value(10)
01 : Boolean
<span style="white-space:pre">	</span>01 : len
<span style="white-space:pre">	</span>00 : value(false)


说明:首先是需要创建ASN1OutputStream,然后就能往里面填充输出的数据了。这个例子非常简单,输出中的02 01 0a,02是TAG = Integer,01是后续长度,0a就是Integer的值了。另一个也同理。

1.2序列的组装

在1.1的基础上,加入一个Sequence。

try{
	ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
	//创建ByteArrayOutputStream,用于放置输出的byte流
	DEROutputStream derOutputStream = new DEROutputStream(outputStream);
	//创建DEROutputStream
	derOutputStream.writeObject(new DERInteger(10));
	//写入DERInteger数据,10对应的hex为0a。
	derOutputStream.writeObject(new DERBoolean(false));
	//写入DERBoolean数据,false对应asn1中的hex为00
	
	ASN1EncodableVector encodableVector = new ASN1EncodableVector();
	//创建ASN1EncodableVector,用于放Sequence的数据
	encodableVector.add(new DERPrintableString("PP"));
	//encodableVector中写入各种对象
	encodableVector.add(new DERUTCTime(new Date()));
	encodableVector.add(new DERNull());
	DERSequence derSequence = new DERSequence(encodableVector);
	//ASN1EncodableVector封装为DERSequence
	
	derOutputStream.writeObject(derSequence);
	//写入DERSequence数据。
	
	derOutputStream.flush();
	System.out.println(StringUtils.Hex(outputStream.toByteArray()));
	//将输出的bytearray转换为直观显示的Hex格式输出
} catch (Exception e) {
	e.printStackTrace();
}
输出:02 01 0a 01 01 00 30 15 13 02 50 50 17 0d 31 35 30 35 31 36 30 32 33 39 31 32 5a 05 00
对应解析
02 : Interger
<span style="white-space:pre">	</span>01 : Len
<span style="white-space:pre">	</span>0a : value(10)
01 : Boolean
<span style="white-space:pre">	</span>01 : len
<span style="white-space:pre">	</span>00 : value(false)
30 : Sequence
<span style="white-space:pre">	</span>15 : len
<span style="white-space:pre">	</span>13 : PrintableString
<span style="white-space:pre">		</span>02 : len
<span style="white-space:pre">		</span>50 50 : value(PP)
<span style="white-space:pre">	</span>17 : UTCTime
<span style="white-space:pre">		</span>0d : len
<span style="white-space:pre">		</span>31 35 30 35 31 36 30 32 33 39 31 32 5a : value(150516023912GMT+00:00)
<span style="white-space:pre">	</span>05 : NULL
<span style="white-space:pre">		</span>00 : len


说明:需要创建序列的时候,先要创建ASN1EncodableVector,填充后序列内容后,再添加到DEROutputStream中即可。输出中30 15即为DERSequence的TAG和长度。

2.解析

解析1.2中生成的DER
try{
	ASN1InputStream asn1InputStream = new ASN1InputStream(StringUtils.Hex("02010a010100301513025050170d3135303531363032333931325a0500"));
	//将hex转换为byte输出
	ASN1Primitive asn1Primitive = null;
	while ((asn1Primitive = asn1InputStream.readObject()) != null) {
	//循环读取,分类解析。这样的解析方式可能不适合有两个同类的ASN1对象解析,如果遇到同类,那就需要按照顺序来调用readObject,就可以实现解析了。
		if ( asn1Primitive instanceof ASN1Integer) {
			ASN1Integer asn1Integer = (ASN1Integer) asn1Primitive;
			System.out.println("Integer:" + asn1Integer.getValue());
		}else if (asn1Primitive instanceof ASN1Boolean) {
			ASN1Boolean asn1Boolean = (ASN1Boolean) asn1Primitive;
			System.out.println("Boolean:"+asn1Boolean.isTrue());
		}else if (asn1Primitive instanceof ASN1Sequence) {
			ASN1Sequence asn1Sequence = (ASN1Sequence) asn1Primitive;
			ASN1SequenceParser asn1SequenceParser = asn1Sequence.parser();
			ASN1Encodable asn1Encodable = null;
			while ((asn1Encodable = asn1SequenceParser.readObject()) != null) {
				asn1Primitive = asn1Encodable.toASN1Primitive();
				if (asn1Primitive instanceof ASN1String) {
					ASN1String string = (ASN1String) asn1Primitive;
					System.out.println("PrintableString:"+string.getString());
				}else if (asn1Primitive instanceof ASN1UTCTime) {
					ASN1UTCTime asn1utcTime = (ASN1UTCTime) asn1Primitive;
					System.out.println("UTCTime:"+asn1utcTime.getTime());
				}else if (asn1Primitive instanceof ASN1Null) {
					System.out.println("NULL");
				}
			}
		}
	}
} catch (Exception e) {
	e.printStackTrace();
}
输出:
Integer:10
Boolean:false
PrintableString:PP
UTCTime:150516023912GMT+00:00
NULL

说明:无

  • 6
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值