1 使用hash算法,能够保证消息没有内容的完整性,但是不能防止伪装者
例如:Alice给bob发送一个数据:希望bob想自己的合同中打款100万,hash值是100,但是中间窃听者窃听到了alic和bob的通信,得到了该hash值100,虽然窃听者虽然不能修改内容,因为修改了内容对应的hash值会发送变化。
但是窃听者存在伪造出一模一样的内容和hash值,例如窃听者可以伪造出一个数据内容 叫bob给窃听者的某个账号打款1000万,该内容的hash也是100,
窃听者将该数据发送给bob,bob收到数据之后计算hash值一计算hash值是正确的,就向窃听者的账号打款1000万人民币。
使用hmac消息认证能够避免上面的问题:
就是在Alice和bob之间首先共享一个key,使用key来计算出hash值,美元key是无法计算出hash值的,因为key只有在alic和bob之间拥有,而窃听者无法得到该key,就能够保证消息内容的本意没有被修改,就是发送者的本意,消息必须来自正确的发送者。
窃听者是因为没有知道alice和bob之间的共享密钥的,所以无法就算出hash值,并且哪怕消息中的任何一点内容发送了变化,hash值也会发送变化。
所以使用hmac算法。保证了消息来自正确的发送者,消息的内容的本意没有被修改,窃听者无法伪造出叫bob银行给自己打卡1000万的内容,因为窃听者没有共享的key。
但是hmac算法存在一个问题,无法防止重放攻击,虽然窃听者没有key修改内容一次性叫bob打款1000万人民币,但是可以采用下面的方式获得1000万:
alice和bob拥有贡献的key,窃听者窃听alice和bob的通信
第一步:窃听者是一个用户,到alice银行填写一个转账申请,要求bob银行转账到100万到窃听者的账户。
第二步:窃听者将窃取到的消息保存起来。
第三步: BOB收到消息之后使用共享的key进行验证发现内容没有发生变化,向窃听者打款100万。
第四步:窃听者可以继续将窃听到的内容发送给bob,bob收到内容之后使用key验证消息的内容,内容正确,又给窃听者打款100万,窃听者这样就会使用这种方法能够不断的收到钱
无法抵制重放攻击
所以hmac算法无法证明消息的内容一定来自alice,该消息有可能来自窃听者。
即使没有窃听者,也不能一定说明该消息是alice发出的,alice可以说:bob收到的消息可能是bob自己伪造的,因为共享的key除了alice知道,bob也知道bob可以利用key自己给自己发数据,无法保证消息一定来自alice,要解决这个情况,可以使用数字签名,使用了数字签名就一定能够证明消息来自alice。
hmac在java中的代码如下:
1、代码类型
It is mostly Java code but there are some slight differences. Adapted from Dev Takeout - Groovy HMAC/SHA256 representation.
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
def hmac_sha256(String secretKey, String data) {
try {
Mac mac = Mac.getInstance("HmacSHA256")
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(), "HmacSHA256")
mac.init(secretKeySpec)
byte[] digest = mac.doFinal(data.getBytes())
return digest
} catch (InvalidKeyException e) {
throw new RuntimeException("Invalid key exception while converting to HMac SHA256")
}
}
def hash = hmac_sha256("secret", "Message")
encodedData = hash.encodeBase64().toString()
log.info(encodedData)
上面的secretKey就是客户端和发送端都知道的。下面这种是自己产生一个sercreKey
3、hmac和普通散列函数sha1、md5的区别
“HMAC是密钥相关的哈希运算消息认证码(Hash-based Message Authentication Code),HMAC运算利用哈希算法,以一个密钥和一个消息为输入,生成一个消息摘要作为输出。”
可以看出,HMAC是需要一个密钥的。所以,HMAC_SHA1也是需要一个密钥的,而SHA1不需要。
以下是两种算法在Java中的实现:
如下方法是使用sha1计算一个文件的摘要,不需要密钥,有点类似于md5,注意这句:
下面是对一个文件进行sha1摘要的计算 public static String sha1Digest(String filename) {
InputStream fis = null;
byte[] buffer = new byte[Constants.BUFFER_SIZE];
int numRead = 0;
MessageDigest sha1;
try {
fis = new FileInputStream(filename);
sha1 = MessageDigest.getInstance("SHA-1");
while ((numRead = fis.read(buffer)) > 0) {
sha1.update(buffer, 0, numRead);
}
return toHexString(sha1.digest());
} catch (Exception e) {
System.out.println("error");
return null;
} finally {
try {
if (fis != null) {
fis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
4、使用场景
摘要算法的使用场景:常用于下载文件完整性的认证
Hmac算法的场景:常用于客户端和服务器身份的认证
HMAC的一个典型应用是用在“挑战/响应”(Challenge/Response)身份认证中,认证流程如下:
(1) 先由客户端向服务器发出一个验证请求。
(2) 服务器接到此请求后生成一个随机数并通过网络传输给客户端(此为挑战)。
(3) 客户端将收到的随机数提供给ePass,由ePass使用该随机数与存储在ePass中的密钥进行HMAC-MD5运算并得到一个结果作为认证证据传给服务器(此为响应)。
(4) 与此同时,服务器也使用该随机数与存储在服务器数据库中的该客户密钥进行HMAC-MD5运算,如果服务器的运算结果与客户端传回的响应结果相同,则认为客户端是一个合法用户 。