HMAC(Hash-BasedMessageAuthenticationCode)由,和于1996年提出的一种基于Hash函数和密钥进行消息认证的方法,并于1997年作为RFC2104被公布,并在IPSec和其他网络协议(如SSL)中得以广泛应用,现在已经成为事实上的Internet安全标准。它可以与任何迭代散列函数捆绑使用。
HMAC算法除了需要消息摘要算法外,还需要一个密钥。HMAC的密钥可以是任何长度,如果密钥的长度超过了摘要算法信息分组的长度,则首先使用摘要算法计算密钥的摘要作为新的密钥。一般不建议使用太短的密钥,因为密钥的长度与安全强度是相关的。通常选取密钥长度不小于所选用摘要算法输出的信息摘要的长度。
HMAC认证,主要是为了能让人对对方身份正确性和消息有效性进行验证,与消息摘要的最大不同,就是有签名密钥。而摘要算法,只是能够证明消息的有效性。HMAC被广泛地运用于网络协议的认证阶段,例如邮件协议使用到了它,SSL也有它的身影。
二、举例理解HMAC的核心思想是身份认证和消息有效性认证。
1、前提条件在消息认证码生成的一方和校验的一方,必须有一个共同的秘钥。
双方约定好使用同样的哈希函数对数据进行运算。
2、流程发送者:
发送原始法消息
将原始消息生成消息认证码:哈希函数(原始消息+秘钥)=散列值(消息认证码)
将消息认证码发送给对方
接收者:
接收原始数据
接收消息认证码
校验:哈希函数(接收的消息+秘钥)*哈希函数=散列值,将本地计算的散列值和接收的散列值进行比较。
算法公式:
HMAC(K,Text)=H((K⊕opad)|H((K⊕ipad)|Text))
H代表所采用的HASH算法(如MD5、SHA1、SHA-256等)。
K代表认证密码。
Text代表一个消息输入。
⊕代表异或。
|表示两个消息合并。
Opad用0x5c重复填充大小为B的数组。
Ipad用0x36重复填充大小为B的数组。
Apad用0x878FE1F3重复(L/4)次。
B代表H中所处理的块大小,这个大小是处理块大小,而不是输出hash的大小。
如MD5、SHA-1和SHA-256对应B=64,SHA-384和SHA-512对应B=128。
L表示hash结果的大小,L=16forMD5,L=20forSHA-1。
C演示代码表示:
voidhmac_md5(text,text_len,key,key_len,digest)unsignedchar*text;/*pointertodatastream*/inttext_len;/*lengthofdatastream*/unsignedchar*key;/*pointertoauthenticationkey*/intkey_len;/*lengthofauthenticationkey*/unsignedchar*digest;/*output:digest*/{unsignedchartk[16];unsignedchark_ipad[64];/*innerpadding-*keyXORwithipad*/unsignedchark_opad[64];/*outerpadding-*keyXORwithopad*/MD5_CTXcontext;/*ifkeyislongerthan64bytesresetittokey=MD5(key)*/if(key_len64){MD5_CTXtctx;MD5Init(tctx);MD5Update(tctx,key,key_len);MD5Final(tk,tctx);key=tk;key_len=16;}/*startoutbystoringkeyinpads*/memset(k_ipad,0,sizeof(k_ipad));memset(k_opad,0,sizeof(k_opad));memcpy(k_ipad,key,key_len);memcpy(k_opad,key,key_len);/*XORkeywithipadandopadvalues*/for(inti=0;i64;i++){k_ipad[i]^=0x36;k_opad[i]^=0x5c;}/*performinnerMD5*/MD5Init(context);/*initcontextfor1stpass*/MD5Update(context,k_ipad,64)/*startwithinnerpad*/MD5Update(context,text,text_len);/*thentextofdatagram*/MD5Final(digest,context);/*finishup1stpass*//*performouterMD5*/MD5Init(context);/*initcontextfor2ndpass*/MD5Update(context,k_opad,64);/*startwithouterpad*/MD5Update(context,digest,16);/*thenresultsof1sthash*/MD5Final(digest,context);/*finishup2ndpass*/}四、运算步骤如果密钥K的长度大于B的字长,对密钥K计算hash(K),结果当作输入密钥;
在密钥K后面添加0来创建一个字长为B的字符串(例如,如果K的字长是20字节,B=64字节,则K后会加入44个零字节0x00);
将第(2)步生成的B字长的字符串与ipad做异或运算;
将数据流text补充至第(3)步的结果字符串的尾部;
用H作用于第(4)步生成的数据流;
将第(2)步生成的B字长字符串与opad做异或运算;
再将第(6)步的结果补充至第五步的结果的尾部;
用H作用于第(7)步生成的数据流,输出最终结果。
由上述描述过程,我们知道HMAC算法的计算过程实际是对原文做了两次类似于加盐处理的哈希过程。
HMAC的密钥长度可以是任意大小,如果小于n(hash输出值的长度),那么将会削弱算法安全的强度。建议使用长度大于n的密钥,但是采用长度大的密钥并不意味着增强了函数的安全性。密钥应该是随机选取的,可以采用一种强伪随机发生器,并且密钥需要周期性更新,这样可以减少弱密钥的危险性以及已经暴露密钥所带来的破坏。
五、计算结果演示消息:ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789
密钥:iloveyou
#
HMAC函数
计算结果
字节长度
1
Hmac-md2
62b22a645d7f331422b4d087e0558675
16
2
Hmac-md4
fbff23b3c9903291fdc5a00d410b77a8
16
3
Hmac-md5
79e44af262dc67cf7feefc2a08a2fda6
16
4
Hmac-sha1
ea1a4b8e9185f607ba02b9773cb7dadd736de12b
20
5
Hmac-sha256
8635a9cfa8c0f8569cb08b4268446df0c5a9088a407b25a09dd5f050bd0d5cf7
32
6
Hmac-sha512
4e9efe08ad0229636975e9f756c6802cce93e75adbfaacf94cad9bdf9dba35a9e3bdd42619bce98b6d4c118b8a7431bb9b15ea88ba26d8de365252c7308be39b
64
7
Hmac-sha224
5235a3edbc52ed72fb1cc3bb9d32745b56eaee4e91a056019ee75116
28
8
Hmac-sha384
15ae925c4dc725c155a5155c7877e0fd29b7dc6f2e811f2b0252112a7aa2fee3cf2ee40f8642805850862e0ffb601053
48
9
Hmac-sha3-224
9d53a512f6cc446734627cdea59057c254db3bbc7f490a35e680fd08
28
10
Hmac-sha3-256
df7cd9e4c124a764ae151694b2acae7cec0490a0ddeece8e9e76023afdbf5dbc
32
11
Hmac-sha3-384
4bb7e1eda41dd5b803b1bfbdf93070d757b18c6e18e759155bfd2fed5000ef4d4630b2d55ad2f0a6d18631b2c338c997
48
12
Hmac-sha3-512
bf8c6284396c6c3fab7bab7558109715ed40c9b8012391fd51c23f5c57143aa1aba7dd5e0a2106fbda3e0c4d547015aa2911ce9049201409bd618cd71b87b3e8
64
六、支持的散列函数目前用来对消息进行认证的主要方式有2种:消息加密和消息认证码。
消息加密:它利用分组密码对整个消息加密,将密文作为认证符;
消息认证码:秘钥+散列函数。
消息认证码的方式比消息加密的方式计算速度更快,这对于高速网络业务处理来说,分秒必争。
消息认证码的关键是散列函数的选择,这就要在安全强度和速度两方面综合考虑。
HMAC算法首先它是基于消息摘要算法的,目前主要集合了MD和SHA两大系列消息摘要算法,其中MD系列的算法有HMAC-MD2、HMAC-MD4、HMAC-MD5三种算法;SHA系列的算法有HMAC-SHA1、HMAC-SHA224、HMAC-SHA256、HMAC-SHA384、HMAC-SHA512五种算法。
HMAC算法还支持大量的消息摘要算法:md5、sha1、sha256、sha512、adler32、crc32、crc32b、fnv132、fnv164、fnv1a32、fnv1a64、gost、gost-crypto、haval128,3、haval128,4、haval128,5、haval160,3、haval160,4、haval160,5、haval192,3、haval192,4、haval192,5、haval224,3、haval224,4、haval224,5、haval256,3、haval256,4、haval256,5、joaat、md2、md4、ripemd128、ripemd160、ripemd256、ripemd320、sha224、sha3-224、sha3-256、sha3-384、sha3-512、sha384、sha512/224、sha512/256、snefru、snefru256、tiger128,3、tiger128,4、tiger160,3、tiger160,4、tiger192,3、tiger192,4、whirlpool。
七、HMAC独特优势与数字签名比较,HMAC并不完美,存在一个弊端和两个无法解决的问题。
弊端:秘钥分发困难。
无法解决的问题:不能进行第三方证明和不能防止否认。
理想往往败给现实,数字签名需要分发公钥与私钥,且签名验证速度慢,证书颁发还要到专门的机构申请和缴费。HMAC对密码的使用很处理比较简单,对于要求快速处理的业务来说,其好处的吸引力非常诱人。
而与分组密码认证相比,HMAC有几大优势:
一般的散列函数的软件执行速度比分组密码更快;
如果找到或需要更快或更安全的散列函数,能够很容易地代替原来嵌入的散列函数。
八、典型应用1、IPSec和SSL协议中的应用HMAC算法广泛应用在在互联网的安全认证和安全传输中。
在浏览网页时,https开头的网址都是用到了SSL协议,用于保证网页内容的安全,这是由HMAC算法实现的。
2、API接口签名验证我们在网上购物、买票、银行转账、炒股等都用到了HMAC算法。各大银行和BAT大厂的后台与前端都用到了API接口签名验证。
用户需要先在网站上申请key、secret,然后校验流程如下:
方法一参数方式请求接口:;home=worldwork=java
客户端:
1生成当前时间戳timestamp=now和唯一随机字符串nonce=random;
2按照请求参数名的字母升序排列非空请求参数(包含accessKey)
stringA="home=worldname=hellowork=javaaccessKey=keytimestamp=nownonce=random";
3计算签名signature=HMAC-SHA256(secret,stringA);
4最终请求
;home=worldwork=javaaccessKey=keytimestamp=nownonce=noncesign=signature.
服务器:
1按照请求参数名的字母升序排列非空请求参数(包含accessKey)
stringB="home=worldname=hellowork=javaaccessKey=keytimestamp=nownonce=random";
2通过key在数据库获取secret;
3计算签名signature=HMAC-SHA256(secret,stringB);
4将signature与接收的签名串比较。
方法二请求体Body方式客户端:
1将请求参数封装成json字符串,也就是请求体body;
2使用HMAC-SHA256算法加secret对Msg(请求url+timestamp+nonce+body)加密生成摘要signature;
3将key,signature放入header中一并传给服务器。
服务器:
1获取请求中的请求体body字符串;
2使用HMAC-SHA256算法加secret(通过header中的key在数据库获取)对Msg(请求url+timestamp+nonce+body)加密生成摘要signature;
3服务端生成的摘要串与客户端通过header传递过来的摘要串进行比较。
timestamp+nonce方案(防止重放攻击)nonce指唯一的随机字符串,用来标识每个被签名的请求。通过为每个请求提供一个唯一的标识符,服务器能够防止请求被多次使用(记录所有用过的nonce以阻止它们被二次使用)。
假设允许客户端和服务端最多能存在15分钟的时间差,同时追踪记录在服务端的nonce集合。当有新的请求进入时,首先检查携带的timestamp是否在15分钟内,如超出时间范围,则拒绝,然后查询携带的nonce,如存在已有集合,则拒绝。否则,记录该nonce,并删除集合内时间戳大于15分钟的nonce(可以使用redis的expire,新增nonce的同时设置它的超时失效时间为15分钟)。
注意使用HMAC-SHA256更加安全,而且我们可以直接将请求参数封装成json字符串放入请求体中(也就是通过io流)进行传递。
方法三Token+AppKeyToken身份验证1用户登录向服务器提供认证信息(如账号和密码),服务器验证成功后返回Token给客户端;
2客户端将Token保存在本地,后续发起请求时,携带此Token;
3服务器检查Token的有效性,有效则放行,无效(Token错误或过期)则拒绝。
为客户端分配AppKey(密钥,用于接口加密,不参与传输)将所有请求参数组合成串,根据HMAC+AppKey签名算法生成签名值,发送请求时将签名值一起发送给服务器验证。这样,即使Token被劫持,对方不知道AppKey,就无法伪造请求和篡改参数。再结合重发攻击解决方案,即使请求参数被劫持也无法伪造二次重复请求。
3、客户端与服务器身份认证(1)先由客户端向服务器发出一个验证请求;
(2)服务器接到此请求后生成一个随机数并通过网络传输给客户端(此为挑战);
(3)客户端将收到的随机数提供给ePass,由ePass使用该随机数与存储在ePass中的密钥进行HMAC-MD5运算并得到一个结果作为认证证据传给服务器(此为响应);
(4)与此同时,服务器也使用该随机数与存储在服务器数据库中的该客户密钥进行HMAC-MD5运算,如果服务器的运算结果与客户端传回的响应结果相同,则认为客户端是一个合法用户。