zoukankan      html  css  js  c++  java
  • HMAC算法及其应用

    MAC

    在现代的网络中,身份认证是一个经常会用到的功能,在身份认证过程中,有很多种方式可以保证用户信息的安全,而MAC(message authentication code)就是一种常用的方法。

    消息认证码是对消息进行认证并确认其完整性的技术。通过使用发送者和接收者之间共享的密钥,就可以识别出是否存在伪装和篡改行为。

    MAC是通过MAC算法+密钥+要加密的信息一起计算得出的。

    同hash算法(消息摘要)相比,消息摘要只能保证消息的完整性,即该消息摘要B是这个消息A生成的。而MAC算法能够保证消息的正确性,即判断确实发的是消息A而不是消息C。

    同公私钥体系相比,因为MAC的密钥在发送方和接收方是一样的,所以发送方和接收方都可以来生成MAC,而公私钥体系因为将公钥和私钥分开,所以增加了不可抵赖性。

    MAC有很多实现方式,比较通用的是基于hash算法的MAC,比如今天我们要讲的HMAC。还有一种是基于分组密码的实现,比如(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:块字节的长度,块是hash操作的基本单位。这里B=64。
    L:hash算法计算出来的字节长度。(L=16 for MD5, L=20 for SHA-1)。
    K:共享密钥,K的长度可以是任意的,但是为了安全考虑,还是推荐K的长度>B。当K长度大于B时候,会先在K上面执行hash算法,将得到的L长度结果作为新的共享密钥。 如果K的长度<B, 那么会在K后面填充0x00一直到等于长度B。
    text: 要加密的内容
    opad:外部填充常量,是 0x5C 重复B次。
    ipad: 内部填充常量,是0x36 重复B次。
    XOR: 异或运算。

    计算步骤如下:

    1. 将0x00填充到K的后面,直到其长度等于B。
    2. 将步骤1的结果跟 ipad做异或。
    3. 将要加密的信息附在步骤2的结果后面。
    4. 调用H方法。
    5. 将步骤1的结果跟opad做异或。
    6. 将步骤4的结果附在步骤5的结果后面。
    7. 调用H方法。

    HMAC的应用

    hmac主要应用在身份验证中,如下是它的使用过程:

    1. 客户端发出登录请求(假设是浏览器的GET请求)
    2. 服务器返回一个随机值,并在会话中记录这个随机值
    3. 客户端将该随机值作为密钥,用户密码进行hmac运算,然后提交给服务器
    4. 服务器读取用户数据库中的用户密码和步骤2中发送的随机值做与客户端一样的hmac运算,然后与用户发送的结果比较,如果结果一致则验证用户合法。

    在这个过程中,可能遭到安全攻击的是服务器发送的随机值和用户发送的hmac结果,而对于截获了这两个值的黑客而言这两个值是没有意义的,绝无获取用户密码的可能性,随机值的引入使hmac只在当前会话中有效,大大增强了安全性和实用性。

    HMAC实现举例

    /*
    ** 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 */
    }
    

    更多教程请参考flydean的博客

  • 相关阅读:
    C. Shaass and Lights 解析(思維、組合)
    D. Binary String To Subsequences(队列)(贪心)
    CodeForces 1384B2. Koa and the Beach (Hard Version)(贪心)
    CodeForces 1384B1. Koa and the Beach (Easy Version)(搜索)
    CodeForces 1384C. String Transformation 1(贪心)(并查集)
    CodeForces 1384A. Common Prefixes
    POJ-2516 Minimum Cost(最小费用最大流)
    POJ3261-Milk Patterns(后缀数组)
    HDU-1300 Pearls(斜率DP)
    HDU-4528 小明系列故事-捉迷藏(BFS)
  • 原文地址:https://www.cnblogs.com/flydean/p/12680408.html
Copyright © 2011-2022 走看看