赞
踩
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; }
struct hmac_ctx_st {
const EVP_MD *md;
EVP_MD_CTX *md_ctx;
EVP_MD_CTX *i_ctx; //输入
EVP_MD_CTX *o_ctx; //输出
};
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; }
对数据进行摘要,注意在这之前已经对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);
}
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; }
hmac本质就是对数据和key混合进行摘要。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。