消息摘要算法HMAC

一、概述

通过哈希算法,我们可以验证一段数据是否有效,方法就是对比该数据的哈希值,例如,判断用户口令是否正确,我们用保存在数据库中的password_md5对比计算md5(password)的结果,如果一致,用户输入的口令就是正确的。

为了防止黑客通过彩虹表根据哈希值反推原始口令,在计算哈希的时候,不能仅针对原始输入计算,需要增加一个salt来使得相同的输入也能得到不同的哈希,这样,大大增加了黑客破解的难度。

如果salt是我们自己随机生成的,通常我们计算MD5时采用md5(message + salt)。但实际上,把salt看做一个“口令”,加salt的哈希就是:计算一段message的哈希时,根据不同口令计算出不同的哈希。要验证哈希值,必须同时提供正确的口令。

这实际上就是Hmac算法:Keyed-Hashing for Message Authentication code。它通过一个标准算法,在计算哈希的过程中,把key混入计算过程中。

和我们自定义的加salt算法不同,Hmac算法针对所有哈希算法都通用,无论是MD5还是SHA-1。采用Hmac替代我们自己的salt算法,可以使程序算法更标准化,也更安全。

关于hmac算法的详情可以参看RFC 2104(http://www.ietf.org/rfc/rfc2104.txt)。

这里需要说明的是经过mac算法得到的摘要值也可以使用十六进制编码表示,其摘要值得长度与实现算法的摘要值长度相同。例如 HmacSHA算法得到的摘要长度就是SHA1算法得到的摘要长度,都是160位二进制数,换算成十六进制的编码为40位。

HMAC用于保护消息的完整性,他采用摘要算法对消息、填充以及秘密密钥进行混合运算。在消息传输时,用户不仅传送消息本身,还传送HMAC值。接收方数据后也进行HMAC运算,再比对MAC值是否一致。由于秘密密钥只有发送方和接收才有,其他人不可能伪造假的HMAC值,从而能够知道消息是否被串改。

Python内置的hmac模块实现了标准的Hmac算法,它利用一个key对message计算“杂凑”后的hash,使用hmac算法比标准hash算法更安全,因为针对相同的message,不同的key会产生不同的hash。

二、python应用

>>> import hmac
>>> message = b'Hello, world!'
>>> key = b'secret'
>>> h = hmac.new(key, message, digestmod='MD5')
>>> # 如果消息很长,可以多次调用h.update(msg)
>>> h.hexdigest()
'fa4ee7d173f2d97ee79022d1a7355bcf'

可见使用hmac和普通hash算法非常类似。hmac输出的长度和原始哈希算法的长度一致。需要注意传入的key和message都是bytes类型,str类型需要首先编码为bytes

三、openssl应用

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)
evp_md 指明HMAC使用的摘要算法
key为秘密密钥指针地址
key_len为秘密密钥的长度
d为需要做HMAC运算的数据指针地址
n为d的长度
md用于存放HMAC值
md_len为HMAC值的长度

aliyun mqtt上传信息时hmac应用:

    //username和 Password 签名模式下的设置方法,参考文档 https://help.aliyun.com/document_detail/48271.html?spm=a2c4g.11186623.6.553.217831c3BSFry7
    HMAC(EVP_sha1(), secretKey, strlen(secretKey), clientIdUrl, strlen(clientIdUrl), tempData, &len);
    char resultData[100];
    int passWordLen = EVP_EncodeBlock((unsigned char *) resultData, tempData, len);
    resultData[passWordLen] = '\0';
    printf("passWord is %s", resultData);
    char userNameData[128];
    sprintf(userNameData,"Signature|%s|%s", accessKey, instanceId);
    userName = userNameData;
    passWord = resultData;

 

参考:

1. hmac  廖雪峰Python教程

2. openssl编程——摘要与HMAC

posted @ 2015-12-14 22:22  yuxi_o  阅读(321)  评论(0编辑  收藏  举报