1. 程式人生 > >數字簽名和驗簽過程實現分析

數字簽名和驗簽過程實現分析

本文件的Copyleft歸rosetta所有,使用GPL釋出,可以自由拷貝、轉載,轉載時請保持文件的完整性。

         數字簽名在網路安全領域用的比較多,可實現使用者身份的真實可靠性;實現資訊的完整性,確保資料在儲存、傳輸和處理的過程中免遭任何非授權的或非預期的修改、插入、刪除、重發等破壞,從而實現資料的真實性、有效性和一致性;實現抗抵賴性,通過數字簽名確保資訊的傳送方不能抵賴曾經發送的資訊,不能否認自己的操作行為。
        下面結合著名的VPN開源專案openswan-2.4.7來理解數字簽名和解簽名的具體過程。
一、數字簽名和解籤(驗籤)過程:使用hash函式對報文資料生成摘要,使用自己的私鑰對摘要進行簽名(其實就是加密過程),生成簽名資料,把原始資料報文和簽名資料傳送給對方。接收方收到原始資料報文和簽名資料後,首先使用相同的hash函式對原始資料生成一個摘要,其次,用對方的公鑰對簽名資料進行解簽名(解密過程),這個解簽名的結果也是個摘要,最後比較這兩個摘要是否相同,如果相同那麼接收方就能確認該數字簽名是傳送方的。
        用以下hash1、hash2和hash3表明不同時期的摘要:
              傳送方:  簽名值=f(hash1(msg),私鑰); (msg表示原始報文資料)
              接收方:hash2(msg) = f^(-1)(簽名值,公鑰);(我覺得就是f的反函式,所以寫了f^(-1)表示)
                             hash3(msg);
     正常情況下hash2通過公鑰對“傳送方發過來的簽名值”解籤後應該等於hash1。hash1和hash3都是對原始報文資料進行摘要,所以只要最後比較hash2和hash3是否相同,就能確定訊息的完整性和證明資料是由對方傳送的(抗抵賴)。

二、openswan協商總體流程,只關注第5、6個包即可。
                Initiator                          Responder
               -----------                        -----------
                HDR, SA                     -->
 第1個包      main_outI1(傳送初始化資料1)
                                            <--    HDR, SA
 第2個包                                            main_inI1_outR1(接收到初始化資料1, 傳送響應資料1)
                HDR, KE, Ni                 -->
第3個包        main_inR1_outI2(接收到響應資料1,傳送初始化資料2)
                                            <--    HDR, KE, Nr
第4個包                                             main_inI2_outR2(接收到初始化資料2, 傳送響應資料2)
                HDR*, IDii, [ CERT, ] SIG_I -->
第5個包        main_inR2_outI3(接收到響應資料2,傳送初始化資料3)
                                            <--    HDR*, IDir, [ CERT, ] SIG_R
第6個包                                             main_inI3_outR3(接收到初始化資料3, 傳送響應資料3)
        main_inR3(接收到響應資料3, 完成主模式協商, 建立ISAKMP SA)
        
        由rfc2409 5.1 使用簽名方法進行IKE第一階段認證,可知簽名載荷SIG_I在第5個包中傳送給對方,對方在第6個包中對簽名進行驗籤,併發送另外一個簽名給發起方,最後發起方對收到的簽名進行驗籤。
                5.1 使用簽名方法進行IKE第一階段認證
        
           使用簽名方法時,在第二個傳輸往返中交換的輔助資訊是當前時間(nonce);
           交換的認證是通過對一個相互可得到的hash值進行簽名。使用簽名認證的主模
           式描述如下:   
                發起者                             響應者
               -----------                        -----------
                HDR, SA                     -->
                                            <--    HDR, SA
                HDR, KE, Ni                 -->
                                            <--    HDR, KE, Nr
                HDR*, IDii, [ CERT, ] SIG_I -->
                                            <--    HDR*, IDir, [ CERT, ] SIG_R
三、簽名過程
        1,函式呼叫過程:        
        main_inR2_outI3()
          ->main_mode_hash()
          ->RSA_sign_hash()
                ->sign_hash()
        2,具體分析(只是摘取關鍵程式碼片段):
        main_inR2_outI3()
        {
            /* HASH_I or SIG_I out */
            {
            u_char hash_val[MAX_DIGEST_LEN];
            size_t hash_len = main_mode_hash(st, hash_val, TRUE, &id_pbs);//對資料st和id_pbs做摘要(即原始資料msg),摘要值放在hash_val中(即hash1),摘要長度為返回值hash_len。
        
            if (auth_payload == ISAKMP_NEXT_HASH)
            {
                /* HASH_I out */
                if (!out_generic_raw(ISAKMP_NEXT_NONE
                         , &isakmp_hash_desc
                         , &md->rbody
                         , hash_val, hash_len, "HASH_I"))
                return STF_INTERNAL_ERROR;
            }
            else
            {
                /* SIG_I out */
                u_char sig_val[RSA_MAX_OCTETS];
                size_t sig_len = RSA_sign_hash(st->st_connection
                , sig_val, hash_val, hash_len);//對摘要值hash_val(hash1)做簽名,簽名使用的證書私鑰放在st->st_connection中,最終的簽名值為sig_val,長度為返回值sig_len.
        
                if (sig_len == 0)
                {
                loglog(RC_LOG_SERIOUS, "unable to locate my private key for RSA Signature");
                return STF_FAIL + AUTHENTICATION_FAILED;
                }
        
                if (!out_generic_raw(ISAKMP_NEXT_NONE
                         , &isakmp_signature_desc
                         , &md->rbody
                         , sig_val
                         , "SIG_I"))
                return STF_INTERNAL_ERROR;
            }
            }
        }

        //hash函式
        static size_t   /* length of hash */
        main_mode_hash(struct state *st
        , u_char *hash_val  /* resulting bytes */
        , bool hashi    /* Initiator? */
        , const pb_stream *idpl)    /* ID payload, as PBS; cur must be at end */
        {
            struct hmac_ctx ctx;
        
            hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid);
            main_mode_hash_body(st, hashi, idpl, &ctx.hash_ctx, ctx.h->hash_update);
            hmac_final(hash_val, &ctx);
            return ctx.hmac_digest_len;
        }

        //簽名函式
        static size_t
        RSA_sign_hash(struct connection *c
        , u_char sig_val[RSA_MAX_OCTETS]
        , const u_char *hash_val, size_t hash_len)
        {
            size_t sz = 0;
            smartcard_t *sc = c->spd.this.sc;
        
            if (sc == NULL)     /* no smartcard */
            {
            const struct RSA_private_key *k = get_RSA_private_key(c);
        
            if (k == NULL)
                return 0;   /* failure: no key to use */
        
            sz = k->pub.k;
            passert(RSA_MIN_OCTETS <= sz && 4 + hash_len < sz && sz <= RSA_MAX_OCTETS);
            sign_hash(k, hash_val, hash_len, sig_val, sz);
            }
                ……
                ……
        }
                
四、驗簽過程
        1,函式呼叫關係:
                main_inI3_outR3()
                 ->main_inI3_outR3_tail()
                        ->main_id_and_auth()
                               ->oakley_id_and_auth()
                                  ->decode_peer_id()//使用ca校驗對方證書的合法性,先不關注。
                                        ->decode_cert()
                                                ->verify_x509cert()
                               ->RSA_check_signature()//驗籤
                                      ->take_a_crack()
                                         ->try_RSA_signature()//最終的比較過程
        2,具體分析(摘取關鍵程式碼片段):
        static stf_status
        oakley_id_and_auth(struct msg_digest *md
                 , bool initiator   /* are we the Initiator? */
                 , bool aggrmode                /* aggressive mode? */
                 , cont_fn_t cont_fn    /* continuation function */
                 , const struct key_continuation *kc    /* current state, can be NULL */
        )
        {
            struct state *st = md->st;
            u_char hash_val[MAX_DIGEST_LEN];
            size_t hash_len;
            stf_status r = STF_OK;
        
            /* ID Payload in.
             * Note: this may switch the connection being used!
             */
            if (!decode_peer_id(md, initiator, aggrmode))//使用ca校驗對方證書的合法性,先不關注。
            return STF_FAIL + INVALID_ID_INFORMATION;
        
            /* Hash the ID Payload.
             * main_mode_hash requires idpl->cur to be at end of payload
             * so we temporarily set if so.
             */
            {
            pb_stream *idpl = &md->chain[ISAKMP_NEXT_ID]->pbs;
            u_int8_t *old_cur = idpl->cur;
        
            idpl->cur = idpl->roof;
            hash_len = main_mode_hash(st, hash_val, !initiator, idpl);//對資料st和id_pbs做摘要(即傳送方的原始資料msg),摘要值放在hash_val中(即hash3),摘要長度為返回值hash_len。
            idpl->cur = old_cur;
            }
            switch (st->st_oakley.auth)
            {
            case OAKLEY_PRESHARED_KEY:
            {
                pb_stream *const hash_pbs = &md->chain[ISAKMP_NEXT_HASH]->pbs;
        
                if (pbs_left(hash_pbs) != hash_len
                || memcmp(hash_pbs->cur, hash_val, hash_len) != 0)
                {
                DBG_cond_dump(DBG_CRYPT, "received HASH:"
                    , hash_pbs->cur, pbs_left(hash_pbs));
                loglog(RC_LOG_SERIOUS, "received Hash Payload does not match computed value");
                /* XXX Could send notification back */
                r = STF_FAIL + INVALID_HASH_INFORMATION;
                }
            }
            break;
        
            case OAKLEY_RSA_SIG:
            r = RSA_check_signature(st, hash_val, hash_len//hash_val是剛上面計算出來的hash3,這裡的st沒什麼意義,公鑰會在函式裡取到。
                , &md->chain[ISAKMP_NEXT_SIG]->pbs//pbs中存放傳送方發過來的簽名值
                );
        ……
        ……
        }

          RSA_check_signature(struct state *st
        , const u_char hash_val[MAX_DIGEST_LEN]
        , size_t hash_len
        , const pb_stream *sig_pbs
        #ifdef USE_KEYRR
        , const struct pubkey_list *keys_from_dns
        #endif /* USE_KEYRR */
        , const struct gw_info *gateways_from_dns
        )
        {
            const struct connection *c = st->st_connection;
            struct tac_state s;
            err_t dns_ugh = NULL;
        
            s.st = st;
            s.hash_val = hash_val;//hash3賦給s
            s.hash_len = hash_len;
            s.sig_pbs = sig_pbs;//簽名值賦給s
        
            s.best_ugh = NULL;
            s.tried_cnt = 0;
            s.tn = s.tried;
        
            /* try all gateway records hung off c */
            if ((c->policy & POLICY_OPPO))
            {
            struct gw_info *gw;
        
            for (gw = c->gw_info; gw != NULL; gw = gw->next)
            {
                /* only consider entries that have a key and are for our peer */
                if (gw->gw_key_present
                && same_id(&gw->gw_id, &c->spd.that.id)
                && take_a_crack(&s, gw->key, "key saved from DNS TXT"))
                return STF_OK;
            }
            }
        
            /* try all appropriate Public keys */
            {
            struct pubkey_list *p, **pp;
            int pathlen;
        
            pp = &pubkeys;
            pathlen = pathlen;      /* make sure it used even with !X509 */
        
            {
              char buf[IDTOA_BUF];
        
              DBG(DBG_CONTROL,
                  dntoa_or_null(buf, IDTOA_BUF, c->spd.that.ca, "%any");
                  DBG_log("required CA is '%s'", buf));
            }
        
            for (p = pubkeys; p != NULL; p = *pp)//獲取需要使用的公鑰,如何獲取不再深入。
            {
                struct pubkey *key = p->key;
        
                if (key->alg == PUBKEY_ALG_RSA && same_id(&c->spd.that.id, &key->id)
                && trusted_ca(key->issuer, c->spd.that.ca, &pathlen))//最終匹配到的對方公鑰由指標key指向。
                {
                time_t now;
        
                {
                  char buf[IDTOA_BUF];
        
                  DBG(DBG_CONTROL,
                      dntoa_or_null(buf, IDTOA_BUF, key->issuer, "%any");
                      DBG_log("key issuer CA is '%s'", buf));
                }
        
                /* check if found public key has expired */
                time(&now);
                if (key->until_time != UNDEFINED_TIME && key->until_time < now)
                {
                    loglog(RC_LOG_SERIOUS,
                    "cached RSA public key has expired and has been deleted");
                    *pp = free_public_keyentry(p);
                    continue; /* continue with next public key */
                }
        
                if (take_a_crack(&s, key, "preloaded key"))//傳入s(包含簽名值和hash3)和公鑰。
                return STF_OK;
                }
                pp = &p->next;
            }
           }
        ……
        ……
        }

        take_a_crack(struct tac_state *s
        , struct pubkey *kr
        , const char *story USED_BY_DEBUG)
        {
            err_t ugh = try_RSA_signature(s->hash_val, s->hash_len, s->sig_pbs
            , kr, s->st);//s->hash_val為hash3, s->sig_pbs為簽名值,kr為公鑰。
            const struct RSA_public_key *k = &kr->u.rsa;
        ……
        ……
        }

        static err_t
        try_RSA_signature(const u_char hash_val[MAX_DIGEST_LEN], size_t hash_len
        , const pb_stream *sig_pbs, struct pubkey *kr
        , struct state *st)
        {
                ……
                ……
           /* We have the decoded hash: see if it matches. */
            if (memcmp(hash_val, hash_in_s, hash_len) != 0)//hash_val還是傳進來的hash3,沒有變化;hash_in_s是由公鑰對簽名值進行了解籤的結果(即hash2),如中解簽名不再分析。所以這裡比較hash3 == hash2 ? 如果相同,那麼驗籤通過,否則失敗。
            {
            DBG_cond_dump(DBG_CRYPT, "decrypted SIG", s, sig_len);
            DBG_cond_dump(DBG_CRYPT, "computed HASH", hash_val, hash_len);
            /* XXX notification: INVALID_HASH_INFORMATION */
            return "9" "authentication failure: received SIG does not match computed HASH, but message is we
            }
        
            unreference_key(&st->st_peer_pubkey);
            st->st_peer_pubkey = reference_key(kr);
        
            return NULL;    /* happy happy */
        }


相關推薦

數字簽名過程實現分析

本文件的Copyleft歸rosetta所有,使用GPL釋出,可以自由拷貝、轉載,轉載時請保持文件的完整性。          數字簽名在網路安全領域用的比較多,可實現使用者身份的真實可靠性;實現資訊的完整性,確保資料在儲存、傳輸和處理的過程中免遭任何非授權的或非預期的修改

圖片理解數字簽名過程

數字簽名是什麼? 1. 鮑勃(伺服器)有兩把鑰匙,一把是公鑰,另一把是私鑰。 2. 鮑勃把公鑰送給他的朋友們----帕蒂(客戶端1)、道格(客戶端2)、蘇珊(客戶端3)----每人一把。 3. 蘇珊(客戶端3)給鮑勃(伺服器)寫信,寫完後用鮑勃的公

數字簽名的詳細過程

簽名 post 對比 摘要算法 -- 數字信封 div body blog 將原文進行哈希計算 1)A-----------------------------------------------------------------------

Java RSA (SHA1withRSA)簽名

enc exce x509 get ont pat ram sign ase static { try { SIGNATURE = Signature.getInstance("SHA1withRSA", "BC"); } catch (N

深入淺出數字簽名

數字簽名是什麼?1.鮑勃(伺服器)有兩把鑰匙,一把是公鑰,另一把是私鑰。2.鮑勃把公鑰送給他的朋友們----帕蒂(客戶端1)、道格(客戶端2)、蘇珊(客戶端3)----每人一把。3.蘇珊(客戶端3)給鮑勃(伺服器)寫信,寫完後用鮑勃的公鑰加密,達到保密的效果。4.鮑勃收信後,

RSA加密/解密簽名/過程理解

轉自:https://www.jianshu.com/p/8dc4a5f64e06 這裡將A理解為客戶端,B理解為服務端,可以比較好理解. 加解密過程簡述 A和B進行通訊加密,B要先生成一對RSA金鑰,B自己持有私鑰,給A公鑰 --->A使用B的公鑰加密要傳送的內容,然後

非對稱加密的簽名籤、加密解密的Java語言實現

本文采用java.security包的簽名和驗籤。採用A的私鑰簽名傳送至B,B採用A的公鑰進行驗籤。 加解密可以私鑰加密、公鑰解密(或者公鑰加密、私鑰解密)。 一般用於銀行報文傳輸、支付寶、微信、銀行以及各大銀行的資料交換。 package com.example.demo; impo

小王的尷尬日常(四)--openssl 實現國密演算法(簽名籤)

昨天呢,更新了加密和解密的實現,今天我們接著來簽名和驗籤。 還是按照王氏慣例先說一下這個理論知識: 下列符號適用於本部分。 A,B:使用公鑰密碼系統的兩個使用者。 a,b: Fq中的元素,它們定義Fq上的一條橢圓曲線E。 2dA:使用

python實現aes加密解密,RSA簽名籤,RSA加密解密,並呼叫介面

用python實現呼叫介面的示例程式碼,過程涉及到很多的加密演算法,值得分享一下。首先公鑰和私鑰如何生成,並且能相容java平臺,嘗試了很多方法。最終決定用openssl命令前提,需要安裝openssl,Crypto庫生成公鑰私鑰對過程:生成私鑰: openssl ge

用Python實現MD5&RSA簽名

用pem檔案 pub_key.pem -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQChNn3wKRtPmxaKq2dKsfMn6sO6AKxvtxZgNdh7 HBWq

Exchange企業實戰技巧:郵件中使用數字簽名郵件加密功能

clip 節點 模式 chan 打開 ont 發送 菜單欄 電子郵件 SMTP最初是為了在封閉的網絡中傳送相對來說不太重要的簡短郵件,因此SMTP傳輸郵件時,安全性不高。自從安全、多用途INTERNET郵件擴展(S/MIME)成為增強SMTP電子郵件安全功能的標準,使得實現

加密、數字簽名數字證書

對稱加密 非對稱加密 數字簽名 數字證書加密、數字簽名和數字證書 1 對稱加密對稱加密算法中,加密和解密使用的是同一個秘鑰,所以秘鑰的保護是非常重要的,對稱加密和解密過程如下圖:對稱算法加密過程對稱算法解密過程盡管對稱秘鑰能夠滿足對內容的加密了,但是對稱算法還是存在以下兩個問題的。1、秘鑰泄密風險

RSA加密、解密、簽名的原理及方法

發送消息 私鑰 簽名 兩個 篡改 方法 保留 即使 指令 二、RSA加密、簽名區別   加密和簽名都是為了安全性考慮,但略有不同。常有人問加密和簽名是用私鑰還是公鑰?其實都是對加密和簽名的作用有所混淆。簡單的說,加密是為了防止信息被泄露,而簽名是為了防止信息被篡改。這裏舉2

Linux fsyncfdatasync系統呼叫實現分析(Ext4檔案系統)

參考:https://blog.csdn.net/luckyapple1028/article/details/61413724 在Linux系統中,對檔案系統上檔案的讀寫一般是通過頁快取(page cache)進行的(DirectIO除外),這樣設計的可以延時磁碟IO的操作,從而可以減少磁碟讀

什麼是數字簽名證書?

什麼是數字簽名和證書?  趁風捲 關注 2016.09.18 15:50* 字數 1861 閱讀 10630評論 3喜歡 27 公鑰密碼系統是本文的理解基礎。 本文不對公鑰密碼系統做過多描述。若對公鑰密碼不熟悉,可以參考閱讀維基百科-公開金鑰加密

php api介面數字簽名

<?php //說明:第三方請求引數中,需要在平臺申請帳號,生成一個appid,每個appid對應一個appserect,請求如下: $param = array(   'appid'=>'137876891',   'name'=>'張三',   'mobile'=>'1389*

使用RSA算法對接口參數簽名

address nic orz byte create exce tst class size 在不同的服務器或系統之間通過API接口進行交互時,兩個系統之間必須進行身份的驗證,以滿足安全上的防抵賴和防篡改。 通常情況下為了達到以上所描述的目的,我們首先會想到使用非對稱加密

Python與Java之間的簽名籤問題

// 最新碰到一個需求, 需要同java下的簽名做驗籤, 感覺有必要總結下: // 整個過程碰到以下幾個問題: /* 1、如何生成指定的公私鑰? # 使用linux指令openssl, openssl這個東西是真的強, (證書問題, 加解密問題, 公私鑰問題等)都

公鑰密碼學_數字簽名訊息認證的區別

在公鑰密碼學不足的問題在於怎麼讓接收方確定訊息的傳送者是誰,以及傳送的訊息是否被攻擊者篡改過,解決這兩個問題就可以讓公鑰加密變得完善   訊息認證 訊息認證就是確定接收者接收到的訊息是否真實,例如有沒有被改動過啊,訊息認證又叫完整性校驗,在我們通訊OSI安全模型中稱

CSP應用開發-簽名

下面程式碼實現了呼叫CSP實現資料的簽名和驗籤,函式中有些細節沒有處理好,但總體流程上應該是沒有問題的,測試通過: //本程式通過呼叫CSP實現簽名及驗籤功能 #include "stdafx.h" #include <windows.h> #include