• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            無我

            讓內心永遠燃燒著偉大的光明的精神之火!
            靈活的思考,嚴謹的實現
            豪邁的氣魄、頑強的意志和周全的思考

            eSNACC對OBJECT IDENTIFIER的編碼和解碼

            本文剖析asn-oid.h/c,從源代碼來學習eSNACC對OBJECT IDENTIFIER的編碼和解碼。

            在研究代碼之前,我們先來說明什么是OBJECT IDENTIFIER。

            ————————————以下一段來自于http://www.eccsdk.com/bbs/read.php?tid=1772————————————————

             ASN.1 對象標識符類型 
                  對象標識符(OBJECT IDENTIFIER, OID)類型用層次的形式來表示標準規范.標識符樹通過一個點分的十進制符號來定義,這個符號以組織,子部分然后是標準的類型和各自的子標識符開始. 

                  例如:MD5的OID 是 1.2.840.113549.2.5  表示為"iso(1) member-body (2) US (840) rsadsi(113549) digestAlgorithm (2) md5 (5)", 所以當解碼程序看到這個OID時,就知道是MD5散列. 

                  OID在公鑰算法標準中很流行,它指出證書綁定了哪種散列算法. 同樣,也有公鑰算法,分組算法,和操作模式的OID. 它們是一種高效且可移植的表示數據包中所選算法的形式. 

                  對OID的編碼規則: 
            1、前兩部分如果定義為x.y, 那么它們將合成一個字40*x + y, 其余部分單獨作為一個字節進行編碼. 
            2、每個字首先被分割為最少數量的沒有頭零數字的7位數字.這些數字以big-endian格式進行組織,并且一個接一個地組合成字節. 除了編碼的最后一個字節外,其他所有字節的最高位(位8)都為1.
                 舉例: 30331 = 1 * 128^2 + 108 * 128 + 123  分割成7位數字(0x80)后為{1,108,123}設置最高位后變成{129,236,123}.如果該字只有一個7位數字,那么最高為0.   

                 MD5 OID的編碼: 
                    1. 將1.2.840.113549.2.5轉換成字數組 {42, 840, 113549, 2, 5}. 
                    2. 然后將每個字分割為帶有最高位的7位數字,{{0x2A},{0x86,0x48},{0x86,0xF7,0x0D},{0x02},{0x05}}. 
                    3. 最后完整的編碼為 0x06 08 2A 86 48 86 F7 0D 02 05.

            ————————————————————————————————————————————————————————————

            有了上面的直觀的理解,我們再研究代碼就不會困惑了。

            在eSNACC中,OBJECT IDENTIFIER實現分為oid和RELATIVE OID。oid要求至少必須由兩部分數字組成,因為要編碼的一個值為40*x + y,所以如果不滿足就會報錯。就如同上面例子中的MD5 OID,就有6個部分。而RELATIVE OID就沒有這個要求,對她的編碼沒有做40*x + y的操作,解碼也不需要逆處理。但是RELATIVE OID必須和一個oid根相關聯。因為RELATIVE OID的定義方式和處理函數都與oid類似,僅僅是少了上面所說的第一個編碼規則操作,所以我們只討論oid,而RELATIVE OID就不展開了。

            eSNACC對oid有兩種實現:用字節串存放和用鏈表形式存放,對字節串存放,就是每一個字節存放一個數值;而鏈表,就是每一個節點元素存放一個值。不過文檔說:如果追求更好的性能,應當采用字節串的形式。這兩種方式定義如下:

            字節串形式,定義為AsnOid,直接從AsnOcts定義過來:

            typedef AsnOcts AsnOid;  /* standard oid type  */

            鏈表形式,定義為OID:

            /* linked oid type that may be easier to use in some circumstances */
            #define NULL_OID_ARCNUM    -1
            typedef 
            struct OID
            {
              
            struct OID    *next;
              
            long arcNum;
            #if COMPILER || TTBL
              
            struct Value    *valueRef;
            #endif
            }
             OID;

            頭文件中還定義了若干函數實現這兩者的互相轉換。

            嚴重說明:

            AsnOid存放的是已經對原始的OBJECT IDENTIFIER編碼之后的值!比如上面例子的MD5,字節串是2A 86 48 86 F7 0D 02 05。

            而OID存的是OBJECT IDENTIFIER的原始值鏈。比如上面例子的MD5,鏈表為1->2->840->113549->2->5。

             

             

            /**************************************休息一下********************************************

            上文我們說過:AsnOid存放的是已經對原始的OBJECT IDENTIFIER編碼之后的值。所以我們當我們要對一個AsnOid進行打印輸出時,就需要進行前面所說編碼算法的逆運算,這個我們可以通過打印例程來驗證一下:

            /*
             * Prints the given OID to the given FILE * in ASN.1 Value Notation.
             * Since the internal rep of an OID is 'encoded', this routine
             * decodes each individual arc number to print it.
             
            */

            void
            PrintAsnOid PARAMS ((f,v, indent),
                FILE 
            *f _AND_
                AsnOid 
            *v _AND_
                unsigned 
            int indent)
            {
                unsigned 
            int firstArcNum;
                unsigned 
            int arcNum;
                
            int i;

                fprintf (f,
            "{");

                
            /* un-munge first two arc numbers */
                
            for (arcNum = 0, i=0; (i < (int)(v->octetLen)) && (v->octs[i] & 0x80);i++)
                    arcNum 
            = (arcNum << 7+ (v->octs[i] & 0x7f);

                arcNum 
            = (arcNum << 7+ (v->octs[i] & 0x7f);
                i
            ++;
                firstArcNum 
            = (unsigned short)(arcNum/40);
                
            if (firstArcNum > 2)
                    firstArcNum 
            = 2;

                fprintf (f,
            "%u %u", (unsigned int)firstArcNum, arcNum - (firstArcNum * 40));

                
            for (; i < (int)(v->octetLen); )
                
            {
                    
            for (arcNum = 0; (i < (int)(v->octetLen)) && (v->octs[i] & 0x80);i++)
                        arcNum 
            = (arcNum << 7+ (v->octs[i] & 0x7f);

                    arcNum 
            = (arcNum << 7+ (v->octs[i] & 0x7f);
                    i
            ++;
                    fprintf (f,
            " %u", arcNum);
                }

                fprintf (f,
            "}");
                indent
            =indent; /* referenced to avoid compiler warning. */

            }
             /* PrintAsnOid */

            從代碼可以看到,這個算法就是這樣的:

            首先得到第一個數,因為如果一個編碼后的數用了多個字節表示,那么除了最后一個以外,前面的字節的最高位肯定為1.所以就用一個循環來獲取一個完整的數。后面嵌套的for也是這個原理。然后對取得的第一個數分拆:num=first*40+second。這樣就完成第一步的逆算法并打印出來。

            然后遍歷這個字節串,每獲取一個完整的數就打印出來。由于for循環只是把最高位為1的字節遍歷了,所以都需要加上最后一個字節。其實我們發現用多個字節存的數對應前面的字節的128的n次方和最末尾一個字節值的和。

             

            而OID存的是原始值,就讓我們通過這個OID -> AsnOid的函數來進一步理解兩者的不同:

            /*
             * given an oid list and a pre-allocated ENC_OID
             * (use EncodedOidLen to figure out byte length needed)
             * fills the ENC_OID with a BER encoded version
             * of the oid.
             
            */

            void
            BuildEncodedOid PARAMS ((oid, result),
                OID 
            *oid _AND_
                AsnOid 
            *result)
            {
                unsigned 
            long len;
                unsigned 
            long headArcNum;
                unsigned 
            long tmpArcNum;
                
            char         *buf;
                
            int           i;
                OID          
            *tmpOid;

                buf 
            = result->octs;
                
            /*
                 * oid must have at least 2 elmts
                 
            */

                
            if (oid->next == NULL)
                   
            return;
                
            /*
                 * munge together first two arcNum
                 * note first arcnum must be <= 2
                 * and second must be < 39 if first = 0 or 1
                 * see (X.209) for ref to this stupidity
                 
            */

                
            //head = first * 40 + second
                headArcNum = (oid->arcNum * 40+ oid->next->arcNum;
                tmpArcNum 
            = headArcNum;

                
            /*
                 * 計算存放第一個數需要幾個字節。每7位要一個字節
                 
            */

                
            for (len = 0; (tmpArcNum >>= 7!= 0; len++)
                ;

                
            /*
                 * 從高位到低位,把每7位寫到緩沖區,因為不是最后一個字節,所以都把最高位設為1
                 
            */

                
            for (i=0; i < (int)len; i++)
                    
            *(buf++= (char)(0x80 | (headArcNum >> ((len-i)*7)));

                
            /*
                 * 將寫第一個數的最后7位寫到最后一個字節
                 
            */

                
            *(buf++= (char)(0x7f & headArcNum);


                
            /*
                 * 如果有,就把后面的數寫到緩沖區,原理和第一個數相同,里面不再注釋
                 
            */

                
            for (tmpOid = oid->next->next; tmpOid != NULL; tmpOid = tmpOid->next)
                
            {
                    tmpArcNum 
            = tmpOid->arcNum;
                    
            for (len = 0; (tmpArcNum >>= 7!= 0; len++)
                    ;

                    
            for (i=0; i < (int)len; i++)
                        
            *(buf++= (char)(0x80 | (tmpOid->arcNum >> ((len-i)*7)));

                      
            *(buf++= (char)(0x7f & tmpOid->arcNum);
                }

                result
            ->octetLen = (buf - result->octs);//根據被寫的緩沖區設定字節長度
            }
             /* BuildEncodedOid */

            在上面的函數中,我已經對相應語句做了注釋了,所以這里就不復述了。

             

            文件中其他函數都是這個原理,就很簡單了。本篇就到此吧。

            posted on 2012-04-24 16:30 Tim 閱讀(1797) 評論(0)  編輯 收藏 引用 所屬分類: eSNACC學習

            <2012年4月>
            25262728293031
            1234567
            891011121314
            15161718192021
            22232425262728
            293012345

            導航

            統計

            公告

            本博客原創文章,歡迎轉載和交流。不過請注明以下信息:
            作者:TimWu
            郵箱:timfly@yeah.net
            來源:www.shnenglu.com/Tim
            感謝您對我的支持!

            留言簿(9)

            隨筆分類(173)

            IT

            Life

            搜索

            積分與排名

            最新隨筆

            最新評論

            閱讀排行榜

            国产精品毛片久久久久久久| 久久热这里只有精品在线观看| 久久精品99久久香蕉国产色戒| 热re99久久精品国99热| 精品久久久久久久久午夜福利| 97精品久久天干天天天按摩 | 一本色道久久综合狠狠躁篇 | 久久精品国产亚洲网站| 国产精品久久久久久久久久免费| 亚洲精品成人久久久| 久久国产精品99精品国产987| 久久久黄色大片| 国产精品女同一区二区久久| 午夜久久久久久禁播电影| 国产精品日韩深夜福利久久| 无码人妻精品一区二区三区久久久| 亚洲精品高清国产一久久| 亚洲国产另类久久久精品| 国产精品熟女福利久久AV| AAA级久久久精品无码片| 欧美亚洲国产精品久久久久| 88久久精品无码一区二区毛片 | 亚洲国产精品久久66| 久久久久久久亚洲Av无码| 精品国产乱码久久久久软件| 久久精品国产福利国产琪琪| 久久噜噜电影你懂的| 国产91久久精品一区二区| 人妻久久久一区二区三区| 亚洲日本va中文字幕久久| 久久精品国产一区二区三区| 99久久夜色精品国产网站| 国产精品久久国产精麻豆99网站| 亚洲AV日韩精品久久久久久| 久久久久亚洲AV片无码下载蜜桃| 久久久久精品国产亚洲AV无码| 狠狠色丁香久久婷婷综合_中| 欧美麻豆久久久久久中文| 一本综合久久国产二区| 久久精品国产乱子伦| 久久99国产综合精品女同|