当前位置:   article > 正文

openssl hmac源码分析_openssl c语言hmac算法代码解析

openssl c语言hmac算法代码解析

hmac 原理

HMAC 用于保护消息的完整性,它采用摘要算法对消息、填充以及秘密密钥进行混合
运算。在消息传输时,用户不仅传送消息本身,还传送 HMAC 值。接收方接收数据后也进
行 HMAC 运算,再比对 MAC 值是否一致。由于秘密密钥只有发送方和接收方才有,其他
人不可能伪造假的 HMAC 值,从而能够知道消息是否被篡改。
ssl 协议中用 HMAC 来保护发送消息,并且 ssl 客户端和服务端的 HMAC 密钥是不同的,
即对于双方都有一个读 MAC 保护密钥和写 MAC 保护密钥。

图片来自网络

实现过程

实现在hmac.c中

unsigned char *HMAC(const EVP_MD *evp_md, const void *key, int key_len,
                    const unsigned char *d, size_t n, unsigned char *md,
                    unsigned int *md_len)
{
    HMAC_CTX *c = NULL;
    static unsigned char m[EVP_MAX_MD_SIZE];
    static const unsigned char dummy_key[1] = {'\0'};

    if (md == NULL)
        md = m;
    if ((c = HMAC_CTX_new()) == NULL)
        goto err;

    /* For HMAC_Init_ex, NULL key signals reuse. */
    if (key == NULL && key_len == 0) {
        key = dummy_key;
    }

    if (!HMAC_Init_ex(c, key, key_len, evp_md, NULL))
        goto err;
    if (!HMAC_Update(c, d, n))
        goto err;
    if (!HMAC_Final(c, md, md_len))
        goto err;
    HMAC_CTX_free(c);
    return md;
 err:
    HMAC_CTX_free(c);
    return NULL;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

数据结构

struct hmac_ctx_st {
    const EVP_MD *md;
    EVP_MD_CTX *md_ctx; 
    EVP_MD_CTX *i_ctx;  //输入
    EVP_MD_CTX *o_ctx;  //输出
};


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

初始化

int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int len,
                 const EVP_MD *md, ENGINE *impl)
{
    int rv = 0, reset = 0;
    int i, j;
    unsigned char pad[HMAC_MAX_MD_CBLOCK_SIZE];
    unsigned int keytmp_length;
    unsigned char keytmp[HMAC_MAX_MD_CBLOCK_SIZE];//定义的是144

    /* If we are changing MD then we must have a key */
    if (md != NULL && md != ctx->md && (key == NULL || len < 0))
        return 0;

    if (md != NULL) {
        ctx->md = md;
    } else if (ctx->md) {
        md = ctx->md;
    } else {
        return 0;
    }

    /*
     * The HMAC construction is not allowed  to be used with the
     * extendable-output functions (XOF) shake128 and shake256.
     */
    if ((EVP_MD_meth_get_flags(md) & EVP_MD_FLAG_XOF) != 0)
        return 0;

    if (key != NULL) {
        reset = 1;

        j = EVP_MD_block_size(md);
        if (!ossl_assert(j <= (int)sizeof(keytmp)))//块大小需要小于最大块大小,144 sha3_224的块大小
            return 0;
        if (j < len) {//如果key长度大于最大块大小,需要通过摘要生成一个零时key.
            if (!EVP_DigestInit_ex(ctx->md_ctx, md, impl)
                    || !EVP_DigestUpdate(ctx->md_ctx, key, len)
                    || !EVP_DigestFinal_ex(ctx->md_ctx, keytmp,
                                           &keytmp_length))
                return 0;
        } else {
        //如果key长度小于0或者大于最大块大小,直接返回
            if (len < 0 || len > (int)sizeof(keytmp))
                return 0;
                //如果key小于最大块大小,拷贝key的全部进入临时key空间
            memcpy(keytmp, key, len);
            keytmp_length = len;
        }
        //如果key长度还不够块大小,剩余空间补0
        if (keytmp_length != HMAC_MAX_MD_CBLOCK_SIZE)
            memset(&keytmp[keytmp_length], 0,
                   HMAC_MAX_MD_CBLOCK_SIZE - keytmp_length);
		//对pad进行异或0x36
        for (i = 0; i < HMAC_MAX_MD_CBLOCK_SIZE; i++)
            pad[i] = 0x36 ^ keytmp[i];
            //对pad进行摘要,注意这里是ctx->i_ctx
        if (!EVP_DigestInit_ex(ctx->i_ctx, md, impl)
                || !EVP_DigestUpdate(ctx->i_ctx, pad, EVP_MD_block_size(md)))
            goto err;
		//同上,这次是对ctx->o_ctx进行摘要
        for (i = 0; i < HMAC_MAX_MD_CBLOCK_SIZE; i++)
            pad[i] = 0x5c ^ keytmp[i];
        if (!EVP_DigestInit_ex(ctx->o_ctx, md, impl)
                || !EVP_DigestUpdate(ctx->o_ctx, pad, EVP_MD_block_size(md)))
            goto err;
    }
    //拷贝输入ctx到md_ctx
    if (!EVP_MD_CTX_copy_ex(ctx->md_ctx, ctx->i_ctx))
        goto err;
    rv = 1;
 err:
    if (reset) {
        OPENSSL_cleanse(keytmp, sizeof(keytmp));
        OPENSSL_cleanse(pad, sizeof(pad));
    }
    return rv;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78

update

对数据进行摘要,注意在这之前已经对key进行了处理并进行了摘要


int HMAC_Update(HMAC_CTX *ctx, const unsigned char *data, size_t len)
{
    if (!ctx->md)
        return 0;
    return EVP_DigestUpdate(ctx->md_ctx, data, len);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

final


int HMAC_Final(HMAC_CTX *ctx, unsigned char *md, unsigned int *len)
{
    unsigned int i;
    unsigned char buf[EVP_MAX_MD_SIZE];

    if (!ctx->md)
        goto err;
	//对将缓存区中的数据摘要完成
    if (!EVP_DigestFinal_ex(ctx->md_ctx, buf, &i))
        goto err;
        //将ctx->o_ctx拷贝到ctx_md_ctx
    if (!EVP_MD_CTX_copy_ex(ctx->md_ctx, ctx->o_ctx))
        goto err;
        //对刚才输入的摘要结果再次摘要,注意这个摘要之前已经有ctx->o_ctx的结果
    if (!EVP_DigestUpdate(ctx->md_ctx, buf, i))
        goto err;
        //处理最后的缓冲区
    if (!EVP_DigestFinal_ex(ctx->md_ctx, md, len))
        goto err;
    return 1;
 err:
    return 0;
}



  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

总结

hmac本质就是对数据和key混合进行摘要。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/喵喵爱编程/article/detail/782278
推荐阅读
相关标签
  

闽ICP备14008679号