密码学之HMAC


MAC(Message Authentication Code,消息认证码算法)是含有密钥散列函数算法,兼容了MD和SHA算法的特性,并在此基础上加上了密钥。因此MAC算法也经常被称作HMAC算法

简述

 密钥相关的哈希运算消息认证码,HMAC运算利用哈希算法,以一个密钥和一个消息为输入,生成一个消息摘要作为输出

HMAC算法首先它是基于信息摘要算法的。目前主要集合了MD和SHA两大系列消息摘要算法。其中MD系列的算法有HmacMD2、HmacMD4、HmacMD5三种算法;SHA系列的算法有HmacSHA1、HmacSHA224、HmacSHA256、HmacSHA384、HmacSHA512五种算法。

HMAC算法除了需要信息摘要算法外,还需要一个密钥。HMAC的密钥可以是任何长度,如果密钥的长度超过了摘要算法信息分组的长度,则首先使用摘要算法计算密钥的摘要作为新的密钥。一般不建议使用太短的密钥,因为密钥的长度与安全强度是相关的。通常选取密钥长度不小于所选用摘要算法输出的信息摘要的长度

HMAC算法表示

算法公式 :
HMAC(K,M)=H(K⊕opad∣H(K⊕ipad∣M))
H 代表所采用的HASH算法(如SHA-256)
K 代表认证密码
Ko 代表HASH算法的密文
M 代表一个消息输入
B 代表H中所处理的块大小,这个大小是处理块大小,而不是输出hash的大小
如,SHA-1和SHA-256 B = 64
SHA-384和SHA-512 B = 128
L 表示hash的大小
Opad 用0x5c重复B次
Ipad 用0x36重复B次
Apad 用0x878FE1F3重复(L/4)次

运算步骤

  1. 在密钥K后面添加0来创建一个字长为B的字符串。(例如,如果K的字长是20字节,B=64字节,则K后会加入44个零字节0x00)
  2. 将上一步生成的B字长的字符串与ipad做异或运算。
  3. 将数据流text填充至第二步的结果字符串中。
  4. 用H作用于第三步生成的数据流。
  5. 将第一步生成的B字长字符串与opad做异或运算。
  6. 再将第四步的结果填充进第五步的结果中。
  7. 用H作用于第六步生成的数据流,输出最终结果
    由上述描述过程,我们知道HMAC算法的计算过程实际是对原文做了两次类似于加盐处理的哈希过程。

应用

hmac主要应用在身份验证中,它的使用方法是这样的:
(1) 客户端发出登录请求(假设是浏览器的GET请求)
(2) 服务器返回一个随机值,并在会话中记录这个随机值
(3) 客户端将该随机值作为密钥,用户密码进行hmac运算,然后提交给服务器
(4) 服务器读取用户数据库中的用户密码和步骤2中发送的随机值做与客户端一样的hmac运算,然后与用户发送的结果比较,如果结果一致则验证用户合法
在这个过程中,可能遭到安全攻击的是服务器发送的随机值和用户发送的hmac结果,而对于截获了这两个值的黑客而言这两个值是没有意义的,绝无获取用户密码的可能性,随机值的引入使hmac只在当前会话中有效,大大增强了安全性和实用性。大多数的语言都实现了hmac算法,比如php的mhash、python的hmac.py、java的MessageDigest类,在web验证中使用hmac也是可行的,用js进行md5运算的速度也是比较快的

安全性浅析

由上面的介绍,我们可以看出,HMAC算法更象是一种加密算法,它引入了密钥,其安全性已经不完全依赖于所使用的HASH算法,安全性主要有以下几点保证:
(1) 使用的密钥是双方事先约定的,第三方不可能知道。由3.2介绍的应用流程可以看出,作为非法截获信息的第三方,能够得到的信息只有作为“挑战”的随机数和作为“响应”的HMAC结果,无法根据这两个数据推算出密钥。由于不知道密钥,所以无法仿造出一致的响应

缺点

在实际应用中,密钥一般在注册的时候服务端提供, 以后不再提供,大大增强了安全性,密钥发出后,客户端和服务端各在本地保存一份.但这样有一个缺点:即如果客户端换手机登录,密钥就不存在了
下面说说解决思路:
服务端:密钥,加密之后的密码
客户端登录思路:

  1. 用户输入账号,密码
  2. 本地查找密钥,如果没有密钥,向服务器获取
  3. 如果应用添加了设备锁,需要解锁(类似qq登录),旧手机同意登录验证后才给新手机发送密码进行登录
  4. 手机银行等登录(密码+密钥+时间(年月日时分)),服务端获取当前时间和前一分钟进行加密,和客户端发来的进行比对

在objective中应用的代码示例

 NSString* key = @"secret";
 NSString* data = @"Message";

 const char *cKey = [key cStringUsingEncoding:NSASCIIStringEncoding];
 const char *cData = [data cStringUsingEncoding:NSASCIIStringEncoding];
 unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];
 CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
 NSData *hash = [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)];

 NSLog(@"%@", hash);

猜你喜欢

转载自blog.csdn.net/qq_30357519/article/details/85044905
今日推荐