1. 程式人生 > >ASN1編解碼實現方法

ASN1編解碼實現方法

目 錄

版本記錄 1

目 錄 1

第1章 概述 3

1.1 背景 3

1.2 ASN.1概念 3

1.3 TAG 4

第2章 開發工具 4

2.1 開發庫 4

2.2 輔助工具 5

第3章 JavaAsn1Compiler 6

3.1 定義ASN.1描述檔案 6

3.2 生成java程式碼 6

3.2.1 程式碼生成 6

3.2.2 程式碼案例 6

3.2.3 編解碼 7

3.3 總結 8

第4章 bouncycastle 8

4.1 編碼 8

4.1.1 確定編碼的檔案格式 8

4.1.2 構造ASN1對映類 9

4.2 解碼 11

4.2.1 定義實體結構 11

4.2.2 定義實體解析類 11

4.2.3 外部呼叫介面 12



第1章 概述

1.1 背景
系統與充值平臺的介面是檔案的方式,充值平臺將檔案內容以ASN.1方式進行編碼,系統需要根據ASN.1協議進行解碼。

關於ASN.1開發的資料,網上資料非常少,特別是涉及到具體的語言,如java,資料、案例及第三方庫更是少之又少。從無到有是很困難的,為了防止後期其他系統還需要做類似介面,將其記錄為文章以便後查,文章會以充值介面作為案例進行介紹。

1.2 ASN.1概念
在電信和計算機網路領域,ASN.1(Abstract Syntax Notation one) 是一套標準,是描述資料的表示、編碼、傳輸、解碼的靈活的記法。它提供了一套正式、無歧義和精確的規則以描述獨立於特定計算機硬體的物件結構。 


ASN.1 包括幾個標準化編碼規則,如基本編碼規則(BER) -X.209 、規範編碼規則(CER)、識別名編碼規則(DER)、壓縮編碼規則(PER)和 XML編碼規則(XER)。這些編碼規則描述瞭如何對 ASN.1 中定義的數值進行編碼,以便用於傳輸,而不管計算機、程式語言或它在應用程式中如何表示等因素。ASN.1 的編碼方法比許多與之相競爭的標記系統更先進,它支援可擴充套件資訊快速可靠的傳輸 — 在無線寬頻中,這是一種優勢。1984年,ASN.1 就已經成為了一種國際標準,它的編碼規則已經成熟並在可靠性和相容性方面擁有更豐富的歷程。  

簡潔的二進位制編碼規則(BER、CER、DER、PER,但不包括 XER)可當作更現代 XML 的替代。然而,ASN.1 支援對資料的語義進行描述,所以它是比 XML 更為高階的語言。  


ASN.1 的描述可以容易地被對映成 C 或 C++ 或 Java 的資料結構,並可以被應用程式程式碼使用,並得到執行時程式庫的支援,進而能夠對編碼和解碼 XML 或 TLV 格式的,或一種非常緊湊的壓縮編碼格式的描述。同時,ASN.1也是一種用於描述結構化實體的結構和內容的語言。 

如:使用ASN.1語法可以這樣定義一個類:

Report ::= SEQUENCE {

author OCTET STRING,  

title OCTET STRING,   

body OCTET STRING,  

biblio INTEGER  





詳見《ASN.1編碼規則詳解》:http://wenku.baidu.com/view/33ba22d276eeaeaad1f3304c.html 

注:在進行ASN1開發前,需要先閱讀上述文章,瞭解其中的一些基本概念。

1.3 TAG
由於TAG在ASN1中非常之重要,而且在對檔案進行解析時就是因為TAG的問題導致浪費了很多時間,因此這裡對其單獨介紹,不過只是提出概念,詳細描述還需參見相關規範。

TAG是對ASN1協議中每個資料域的標識,通過2.2的截圖可以看到,每個結點名稱後面都有一個數字,這個就TAG值。TAG有可分為四大類:UNIVERSAL、Context、Private、Application。詳見:http://wenku.baidu.com/view/33ba22d276eeaeaad1f3304c.html 

第2章 開發工具
通常情況下,如果使用該協議進行互動,雙方應該規定出一個以ASN.1語法描述的協議檔案,類似webservice開發中的wsdl,然後各自系統使用相關工具進行編解碼。 

2.1 開發庫
目前網上能查到的第三方免費工具,主要有JavaAsn1Comiler和bouncycastle子庫:

l JavaAsn1Comiler(JAC.jar):

n 該工具可根據ASN.1協議描述檔案,生成對應的java類,同時提供的API介面非常友好,命名概念同理論基本一致,使用非常方便,但是前提是必須要有完整的ASN.1描述檔案,而且非常重要的一點使用限制是,該庫目前支援TAG值在0-127之間,即:如果協議中的資料使用了超過127的TAG值,則該庫無法支援,不可使用(否則會出現編碼錯誤,無法解析)。

n 該庫提供了相當豐富的使用案例,可參考其工程下的test目錄。

l bouncycastle(bcprov-jdk16-1.46.jar)

n 該工具沒有提供自動生成java程式碼的能力,如果要進行編解碼,則需要手動對協議中的類進行定義,並且自己呼叫相應的API實現編解碼。使用起來較JAC複雜,但是該庫對TAG值沒有限制,適合用在TAG值大於127的場景。

n 在使用該類進行解析時,由於沒有提供方便的API進行自動解析,因此需要手工編寫解析程式碼,比較鬱悶的是其幫助文件也沒有比較詳細的案例,最後的解碼操作還是通過閱讀其ASN1Dump類的實現方才完成。

2.2 輔助工具
由於經ASN.1編碼後的檔案是二進位制格式,無法直接閱讀,因此在開發過程中,為了能夠比較直觀的閱讀到其編碼後的記錄,需要藉助第三方工具來檢視編碼後的檔案內容。

網上有幾個檢視工具,但是最方便、最直觀的工具則是ASN1VE 2.1(未註冊版有功能限制,只能檢視編碼後的檔案),通過該軟體可以很輕鬆的檢視到檔案內容,截圖如下:

l 二進位制檢視:



l XML檢視





第3章 JavaAsn1Compiler
3.1 定義ASN.1描述檔案
通過通訊雙方約定的資料格式,使用ASN.1語法對其進行定義(參見1.2百度文庫),形成.asn檔案,如vc.asn。

3.2 生成java程式碼
3.2.1 程式碼生成
將編寫好的.asn檔案放到JAC.jar目錄,執行:

java -jar JAC.jar -d c:/jac_test -p vc vc.asn

引數描述:

-d:生成java程式碼檔案的儲存目錄;

-p:生成java程式碼的package;

3.2.2 程式碼案例
以下程式碼可從JavaAsn1Compiler工程的test目錄下獲取,ASN1檔案內容:

MiddleSeq ::= SEQUENCE

{

status [22] INTEGER,

location [APPLICATION 11] INTEGER

}

生成的java程式碼如下:

import com.turkcelltech.jac.*;

import com.chaosinmotion.asn1.Tag;



public class MiddleSeq extends Sequence

{

public ASN1Integer status = new ASN1Integer("status");

public ASN1Integer location = new ASN1Integer("location");



public

MiddleSeq()

{

super();

setUpElements();

}

public

MiddleSeq(String name)

{

super(name);

setUpElements();

}



protected void

setUpElements()

{

super.addElement(status);

status.setTagClass(Tag.CONTEXT);

status.setTagNumber(22);

super.addElement(location);

location.setTagClass(Tag.APPLICATION);

location.setTagNumber(11);

/* end of element setup */

}

}

3.2.3 編解碼
// 編碼

ByteArrayOutputStream outStream = new ByteArrayOutputStream();

BerOutputStream out = new BerOutputStream(outStream);

MiddleSeq ms = new MiddleSeq();

ms.status.setValue(2);

ms.location.setValue(314);

ms.encode(out);



// 解碼

ByteArrayInputStream inputStream;

BerInputStream in;

inputStream = new ByteArrayInputStream(outStream.toByteArray());

in = new BerInputStream(inputStream);

MiddleSeq decode_ms = new MiddleSeq("decode_ms");

decode_ms.decode(in);



System.out.println("ms.status=" + decode_ms.status.getValue());

可見編解碼非常簡單,如果是巢狀結構,只要對最外層物件執行encode/decode操作即可。

3.3 總結
使用該庫在有ASN1協議描述檔案時,開發ASN1編解碼非常容易,缺點就是不支援超過127的TAG值。

第4章 bouncycastle
bouncycastle(簡稱bc)包含了一系列的java編解碼工具,ASN1只是其中的一類。在沒有ASN1協議描述檔案的情況下,結合ASN1VE工具,可以進行相關的編解碼開發,雲南服務質量管理系統與VC充值平臺正是使用這種方式開發的。

4.1 編碼
在雲南服務質量管理系統中,實際上並沒用用到ASN1編碼的知識,但是在從零開始的背景下,為了更好的學習和理解ASN1的編碼格式,這裡便開發了一個編碼模型。

4.1.1 確定編碼的檔案格式
由於沒有ASN1檔案,只有編碼後的檔案,因此需要通過ASN1VE來檢視編碼後是什麼格式,如圖所示:



通過上圖可以看出整個檔案的組織結構、每個資料域對應的TAG值以及TAG的型別(Application)。但是ASN1的編碼有多種方式,如:BER/DER/PER等,bc庫提供的API就包含了BER和DER兩種型別,為了確定具體的編碼格式,利用b