Hmac概念与实现(js和go实现)

目录

一.什么是Hmac

二.HMAC各方法的优劣

Hmacsha1

Hmacsha256和Hmacsha512

三.HMAC签名的实现

js实现HMAC签名

go实现HMAC签名

备注

参考


一.什么是Hmac

维基百科对Hmac的释义是:

In cryptography, an HMAC (sometimes expanded as either keyed-hash message authentication code or hash-based message authentication code) is a specific type of message authentication code (MAC) involving a cryptographic hash function and a secret cryptographic key. As with any MAC, it may be used to simultaneously verify both the data integrity and the authenticity of a message.

大致意思就是 : 

密钥散列消息认证码(英语:Keyed-hash message authentication code),又称散列消息认证码(Hash-based message authentication code,缩写为HMAC),是一种通过特别计算方式之后产生的消息认证码(MAC),使用密码散列函数,同时结合一个加密密钥。它可以用来保证资料的完整性,同时可以用来作某个消息的身份验证。

维基上还有更详细的释义,如果想研究可以直接去维基那里查看:https://en.wikipedia.org/wiki/HMAC,当然,如果比较迷茫的话,下面还有个巧妙的比喻帮你理解hmac(原文地址:

ionous: HMAC vs. raw SHA-1

okay- maybe this shouldn't have taken me quite so long to understand, but I've been a little bit confused about the differences between SHA-1 and HMAC.

HMAC employs a cryptographic hashing function (ex. SHA-1) but it wasn't clear to me why the cryptographic hashing function itself wasn't "good enough" -- why couldn't HMAC just be SHA-1.

SHA-1 generates a fixed size output of 20-bytes for an arbitrarily long message; but so does an HMAC when it uses SHA-1. So what's the difference?

Turns out the answer is actually relatively straightforward.


For sake of explanation, assume that you want to declare your undying love to someone you've been dating. You'd love to come up with a beautiful sonnet, but in the end you decide that simply saying "i love you" is enough.

You want the message to arrive intact and unaltered, but you don't care if the contents of message itself are known to the world. Knowing a little about cryptographic hashes: you generate a digest from your message using SHA-1.

That message results in: 'bb7b1901d99e8b26bb91d2debdb7d7f24b3158cf'.

On receipt of the message, your would-be-love recomputes the SHA-1 from the message, compares the computed digest to the sent digest. They match and all seems well.

A sinister rival however has other plans. They intercept your message, and replace the message with another "don't call me anymore", they then generate a brand new digest: 'e267e18f05cb6ea3b10b761bbac21a0f92bb8d0d' and replace your original digest. On receipt your love reads the message in disbelief; quickly calculating the hash to make sure the message hasn't been altered. But the hash itself has been changed so the altered hash matches altered message and chaos ensues.

Things look grim, but you explain to your would-be-love what's happened, and they decide to give you another chance. So that this doesn't happen again you decide to tell your lover from now on, whenever they get a message from you, before computing the hash prepend the text "our secret key.", and you will do the same.

This time that same message generates the digest '8a2c1bfa977478f73dbfab8508bc09360b20b569'

Simply replacing the digest doesn't work anymore. If naive attacker still attempts to use the 'e267e18f...' digest your lover would see that the key + the message doesn't compute. You don't send the key in the message itself, and no one knows your secret key so no one can generate a fake message.

There is however a problem still, and the problem is the reason for the difference between SHA-1 and HMAC.

SHA-1 uses an iterative algorithm. It generates digests by first splitting a message into blocks of 64 bytes and, one after the other, combining those blocks together to generate the 20 byte digest. But, since your message can be of any length, and since SHA by its iterative nature works by computing block after block of 64 bytes there is a problem.

Your rival trying once again to subvert your message could just tack additional data onto your message, and this time use the digest in your message as the seed to generate their own new digest of your message. They don't need your secret key because the key was already embedded the blocks that you built. They can't alter what you've written, but they can add more. Your lack of punctuation has in fact made this even easier.

By simply adding "but please don't call me anymore" and updating the digest to '725fbcbd1e94d03c2e54b01da3944c6385d17e4d' your love will think the entire message is from you even though only the first part was -- and doubly so because of the secret key.

Good bye romance.

An HMAC fixes this.

The algorithm adds one more layer: essentially it takes the hash of your key + message, prepends the key to that hash, and then re-hashes the result. I say essentially because it actually does one other thing to make things more cryptographically sound. HMAC masks your key during the first -- inner -- hash with a fixed constant. Then on the second -- outer -- hash it masks your key again with a different fixed constant. The masking operations result in a different inner and outer key value, and the entire process effectively seals your message, hides your key, and makes it impossible to tack new data on the end.

According to wikipedia no known message extension attacks have ever been found.

Good luck romance.

emmmmm太长了,直接机翻一下:

好吧-也许我不应该花这么长时间来理解,但是我对SHA-1和HMAC之间的区别有点困惑。

HMAC使用了一个加密哈希函数(例如SHA-1),但我不清楚为什么加密哈希函数本身“不够好”——为什么HMAC不能仅仅是SHA-1。

SHA-1为任意长的消息生成20字节的固定大小输出;但是当HMAC使用SHA-1时也是如此。那么有什么区别呢?

其实答案是相对简单的。

为了方便解释,假设你想向你的约会对象表达你永恒的爱。你想写出一首优美的十四行诗,但最后你决定简单地说一句“我爱你”就够了。

您希望消息完整无损地到达,但不关心消息本身的内容是否为世界所知。对加密哈希略知一二:使用SHA-1从消息生成摘要。

该消息的结果是:'bb7b1901d99e8b26bb91d2debdb7d7f24b3158cf'。

在收到消息后,你的意中人会从消息中重新计算SHA-1,将计算出的摘要与发送的摘要进行比较。他们很相配,一切似乎都很好。

然而,一个邪恶的对手却另有计划。他们截获你的信息,然后用另一个“不要再给我打电话了”替换这条信息,然后生成一个全新的摘要:“e267e18f05cb6ea3b10b761bbac21a0f92bb8d0d”并替换你原来的摘要。一收到你的爱就难以置信地读着这条信息;快速计算哈希值以确保消息没有被更改。但是哈希本身被改变了,所以改变的哈希匹配了改变的消息,混乱随之而来。

事情看起来很严峻,但你向你的爱人解释发生了什么,他们决定再给你一次机会。为了防止这种情况再次发生,你决定从现在开始告诉你的爱人,无论何时他们收到你的信息,在计算哈希之前把“我们的秘密密钥。”这一文本,你也会做同样的事情。

这一次,相同的消息生成摘要'8a2c1bfa977478f73dbfab8508bc09360b20b569'

简单地替换摘要已经不起作用了。如果天真的攻击者仍然试图使用'e267e18f…“消化你的爱人会发现,钥匙+信息是不能计算的。你没有在消息中发送密钥,没有人知道你的密钥,所以没有人可以生成假消息。

但是仍然存在一个问题,这个问题是SHA-1和HMAC差异的原因。

SHA-1使用迭代算法。它生成摘要的方法是,首先将消息分割为64字节的块,然后一个接一个地将这些块组合在一起生成20字节的摘要。但是,由于您的消息可以是任意长度,而且由于SHA的迭代特性,它可以计算一个接一个64字节的块,因此存在一个问题。

如果您的竞争对手再次试图破坏您的消息,那么可以将额外的数据添加到您的消息中,这一次使用您的消息中的摘要作为种子,生成他们自己的消息的新摘要。他们不需要你的密钥,因为密钥已经嵌入到你构建的块中。他们不能修改你写的东西,但他们可以添加更多。事实上,你没有标点符号反而让这更容易。

只要简单地加上“但是请不要再给我打电话了”,并把摘要更新为“725fbcbd1e94d03c2e54b01da3944c6385d17e4d”,你的爱就会认为整条信息都是你写的,尽管只有第一部分是你写的——而且因为密钥的缘故更是如此。

再见了,爱情。

一个HMAC解决了这个问题。

该算法添加了另一层:本质上,它获取键+消息的散列,将键添加到该散列中,然后重新散列结果。我说本质上是因为它实际上做了另一件事让东西听起来更密码学。HMAC在第一个—内部—散列中使用一个固定的常量掩码。然后在第二个——外部——哈希中,它再次使用不同的固定常量掩盖键值。屏蔽操作会产生不同的内键和外键值,整个过程会有效地密封消息,隐藏键,并且不可能在末尾添加新数据。

根据维基百科,没有已知的消息扩展攻击已经被发现。

祝你好运,爱情。

二.HMAC各方法的优劣

HMAC支持很多散列方法,比如 md4 md5 sha1 sha224 sha256 sha384 sha512,各方法的性能上的差距不是很大,如下图:(资料来源:https://xilinx.github.io/Vitis_Libraries/security/2020.1/guide_L1/internals/hmac.html

 这里我们着重对比下最常用的Hmacsha1、Hmac256和Hmac512三种方法。

Hmacsha1

同另外两种加密方式相比,Hmacsha1有着毫无争议的速度优势,国外有一个关于Hmacsha1速度上的答复:

How much HMAC-SHA256 is slower than HMAC-SHA1?

Those sorts of crypto performance questions are quite platform specific, and so it's hard to answer definitively. In my experience, I've seen SHA-1 (and hence HMAC-SHA-1) be about 30% faster than SHA-256; Your Mileage May Vary, of course.

Of course, the obvious comeback is "how much is this performance delta important to you?". That rather depends on how fast you're adding/checking integrity tags.

嗯,一般来说快个30%,不过由于这些签名方法本身就很快,所以除非系统的签名体非常大或者对性能有着极高的要求,否则Hmacsha1在性能上的领先并不多。

但是Hmacsha1在安全上就有些捉襟见肘了,作为加密基本的sha1算法目前已日渐乏力(There is a known weakness to SHA1 that allows someone to compute a collision in less time than expected:SHA1有一个已知的弱点,可以让人们在比预期更短的时间内计算出碰撞。摘自 hash - HMAC-SHA1 vs HMAC-SHA256 - Cryptography Stack Exchange),尽管Hmacsha1目前仍然是安全的,但是谁也说不准将来Hmacsha1会一直保持在现如今的抗暴力破解水平。

Hmacsha256和Hmacsha512

速度上来说:在 64 位机器上,SHA-512 比 SHA-256 更快(因为它们在内部使用 64 位算法);
在 8、16 和 32 位机器上,SHA-256 比 SHA-512 更快。

从安全性上来说,sha512要比sha256相对而言安全度要更高,但是即使是 SHA-256 也有相当大的安全余量。

三.HMAC签名的实现

这里以Hmac512为例,其他散列方法类似,只是换个参数名而已。

js实现HMAC签名

    // 声明签名秘钥和签名体
    let key = "dGhpcyBpcyBhIGtleQ=="
    let data = "this is a demo"


    // 使用HmacSha512签名 js
    var crypto = require("crypto");
    var hmac = crypto.createHmac("sha512", key);
    var signed = hmac.update(Buffer.from(data, 'utf-8')).digest("base64")
    console.log(signed)

没错,就只有两行代码就能实现签名,前提是得引入crypto包。

我这里的js是node环境所以直接require("crypto"),如果是浏览器环境,也可以尝试其他引入方式。

go实现HMAC签名

import (
	"crypto/hmac"
	"crypto/sha512"
	"encoding/base64"
)


/**
 * HmacSha512签名
 * message:签名内容
 * secret 签名秘钥
 * import "crypto/hmac"	"crypto/sha512"
 */
func ComputeHmacSha512(message string, secret string) string {
	key := []byte(secret)
	h := hmac.New(sha512.New, key)
	h.Write([]byte(message))
	return base64.StdEncoding.EncodeToString([]byte(h.Sum(nil)))
}

这里封了一个方法,调用的话就直接

ret := ComputeHmacSha512("this is a demo", "dGhpcyBpcyBhIGtleQ==")

两个端签名的结果都是一样的

 因为工具包都是现成的,所以签名意外的简单。

备注

国内资料较少,本文中列出的资料网站一般是国外网站,大多需要翻墙才能访问。

参考

https://en.wikipedia.org/wiki/HMAC  维基百科Hmac,虽然也有中文站,但是英文站的资料要全面的多

hash - HMAC-SHA1 vs HMAC-SHA256 - Cryptography Stack Exchange 讨论Hmacsha1和Hmacsha256 孰优孰劣的帖

c# - Difference between HMACSHA256 and HMACSHA512 - Stack Overflow  讨论HMACSHA256 和 HMACSHA512 的区别的帖

ionous: HMAC vs. raw SHA-1 通俗的讲解Hmac

https://xilinx.github.io/Vitis_Libraries/security/2020.1/guide_L1/internals/hmac.html

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值