HMAC算法及其應(yīng)用

MAC

在現(xiàn)代的網(wǎng)絡(luò)中,身份認(rèn)證是一個(gè)經(jīng)常會(huì)用到的功能,在身份認(rèn)證過程中,有很多種方式可以保證用戶信息的安全,而MAC(message authentication code)就是一種常用的方法。

消息認(rèn)證碼是對(duì)消息進(jìn)行認(rèn)證并確認(rèn)其完整性的技術(shù)。通過使用發(fā)送者和接收者之間共享的密鑰,就可以識(shí)別出是否存在偽裝和篡改行為。

MAC是通過MAC算法+密鑰+要加密的信息一起計(jì)算得出的。

同hash算法(消息摘要)相比,消息摘要只能保證消息的完整性,即該消息摘要B是這個(gè)消息A生成的。而MAC算法能夠保證消息的正確性,即判斷確實(shí)發(fā)的是消息A而不是消息C。

同公私鑰體系相比,因?yàn)镸AC的密鑰在發(fā)送方和接收方是一樣的,所以發(fā)送方和接收方都可以來生成MAC,而公私鑰體系因?yàn)閷⒐€和私鑰分開,所以增加了不可抵賴性。

MAC有很多實(shí)現(xiàn)方式,比較通用的是基于hash算法的MAC,比如今天我們要講的HMAC。還有一種是基于分組密碼的實(shí)現(xiàn),比如(OMAC, CBC-MAC and PMAC)。

HMAC

HMAC 是Keyed-Hashing for Message Authentication的縮寫。HMAC的MAC算法是hash算法,它可以是MD5, SHA-1或者 SHA-256,他們分別被稱為HMAC-MD5,HMAC-SHA1, HMAC-SHA256。

HMAC用公式表示:

H(K XOR opad, H(K XOR ipad, text))

其中
H:hash算法,比如(MD5,SHA-1,SHA-256)
B:塊字節(jié)的長(zhǎng)度,塊是hash操作的基本單位。這里B=64。
L:hash算法計(jì)算出來的字節(jié)長(zhǎng)度。(L=16 for MD5, L=20 for SHA-1)。
K:共享密鑰,K的長(zhǎng)度可以是任意的,但是為了安全考慮,還是推薦K的長(zhǎng)度>B。當(dāng)K長(zhǎng)度大于B時(shí)候,會(huì)先在K上面執(zhí)行hash算法,將得到的L長(zhǎng)度結(jié)果作為新的共享密鑰。 如果K的長(zhǎng)度<B, 那么會(huì)在K后面填充0x00一直到等于長(zhǎng)度B。
text: 要加密的內(nèi)容
opad:外部填充常量,是 0x5C 重復(fù)B次。
ipad: 內(nèi)部填充常量,是0x36 重復(fù)B次。
XOR: 異或運(yùn)算。

計(jì)算步驟如下:

  1. 將0x00填充到K的后面,直到其長(zhǎng)度等于B。
  2. 將步驟1的結(jié)果跟 ipad做異或。
  3. 將要加密的信息附在步驟2的結(jié)果后面。
  4. 調(diào)用H方法。
  5. 將步驟1的結(jié)果跟opad做異或。
  6. 將步驟4的結(jié)果附在步驟5的結(jié)果后面。
  7. 調(diào)用H方法。

HMAC的應(yīng)用

hmac主要應(yīng)用在身份驗(yàn)證中,如下是它的使用過程:

  1. 客戶端發(fā)出登錄請(qǐng)求(假設(shè)是瀏覽器的GET請(qǐng)求)
  2. 服務(wù)器返回一個(gè)隨機(jī)值,并在會(huì)話中記錄這個(gè)隨機(jī)值
  3. 客戶端將該隨機(jī)值作為密鑰,用戶密碼進(jìn)行hmac運(yùn)算,然后提交給服務(wù)器
  4. 服務(wù)器讀取用戶數(shù)據(jù)庫中的用戶密碼和步驟2中發(fā)送的隨機(jī)值做與客戶端一樣的hmac運(yùn)算,然后與用戶發(fā)送的結(jié)果比較,如果結(jié)果一致則驗(yàn)證用戶合法。

在這個(gè)過程中,可能遭到安全攻擊的是服務(wù)器發(fā)送的隨機(jī)值和用戶發(fā)送的hmac結(jié)果,而對(duì)于截獲了這兩個(gè)值的黑客而言這兩個(gè)值是沒有意義的,絕無獲取用戶密碼的可能性,隨機(jī)值的引入使hmac只在當(dāng)前會(huì)話中有效,大大增強(qiáng)了安全性和實(shí)用性。

HMAC實(shí)現(xiàn)舉例

/*
** Function: hmac_md5
*/

void
hmac_md5(text, text_len, key, key_len, digest)
unsigned char*  text;                /* pointer to data stream */
int             text_len;            /* length of data stream */
unsigned char*  key;                 /* pointer to authentication key */
int             key_len;             /* length of authentication key */
caddr_t         digest;              /* caller digest to be filled in */

{
        MD5_CTX context;
        unsigned char k_ipad[65];    /* inner padding -
                                      * key XORd with ipad
                                      */
        unsigned char k_opad[65];    /* outer padding -
                                      * key XORd with opad
                                      */
        unsigned char tk[16];
        int i;
        /* if key is longer than 64 bytes reset it to key=MD5(key) */
        if (key_len > 64) {

                MD5_CTX      tctx;

                MD5Init(&tctx);
                MD5Update(&tctx, key, key_len);
                MD5Final(tk, &tctx);

                key = tk;
                key_len = 16;
        }

        /*
         * the HMAC_MD5 transform looks like:
         *
         * MD5(K XOR opad, MD5(K XOR ipad, text))
         *
         * where K is an n byte key
         * ipad is the byte 0x36 repeated 64 times
       * opad is the byte 0x5c repeated 64 times
         * and text is the data being protected
         */

        /* start out by storing key in pads */
        bzero( k_ipad, sizeof k_ipad);
        bzero( k_opad, sizeof k_opad);
        bcopy( key, k_ipad, key_len);
        bcopy( key, k_opad, key_len);

        /* XOR key with ipad and opad values */
        for (i=0; i<64; i++) {
                k_ipad[i] ^= 0x36;
                k_opad[i] ^= 0x5c;
        }
        /*
         * perform inner MD5
         */
        MD5Init(&context);                   /* init context for 1st
                                              * pass */
        MD5Update(&context, k_ipad, 64)      /* start with inner pad */
        MD5Update(&context, text, text_len); /* then text of datagram */
        MD5Final(digest, &context);          /* finish up 1st pass */
        /*
         * perform outer MD5
         */
        MD5Init(&context);                   /* init context for 2nd
                                              * pass */
        MD5Update(&context, k_opad, 64);     /* start with outer pad */
        MD5Update(&context, digest, 16);     /* then results of 1st
                                              * hash */
        MD5Final(digest, &context);          /* finish up 2nd pass */
}

更多教程請(qǐng)參考flydean的博客

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 這篇文章主要講述在Mobile BI(移動(dòng)商務(wù)智能)開發(fā)過程中,在網(wǎng)絡(luò)通信、數(shù)據(jù)存儲(chǔ)、登錄驗(yàn)證這幾個(gè)方面涉及的加密...
    雨_樹閱讀 3,055評(píng)論 0 6
  • 在介紹加密算法之前, 先介紹一下 base64: 0. base64 Base64要求把每三個(gè)8Bit的字節(jié)轉(zhuǎn)換為...
    reboot_q閱讀 13,768評(píng)論 3 8
  • 1 基礎(chǔ) 1.1 對(duì)稱算法 描述:對(duì)稱加密是指加密過程和解密過程使用相同的密碼。主要分:分組加密、序列加密。 原理...
    御淺永夜閱讀 2,727評(píng)論 1 4
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,694評(píng)論 1 32
  • 寫文章然后能夠發(fā)表出去,這件事對(duì)我們七零八零后在上學(xué)時(shí)候如果有人能做到這件事情,相信大家都會(huì)對(duì)他從內(nèi)心由衷的佩服。...
    高密久愛閱讀 273評(píng)論 1 1

友情鏈接更多精彩內(nèi)容