如何在NodeJS中验证Hmac?

5

我可以使用以下代码通过NodeJS成功创建Hmac:

(来自https://nodejs.org/api/crypto.html#cryptocreatehmacalgorithm-key-options的略微修改的示例)
Crypto.createHmac('sha256', Crypto.randomBytes(16))
   .update('I love cupcakes')
   .digest('hex');

这将导致生成以下值(基于十六进制的字符串Hmac签名): fb2937ca821264812d511d68ae06a643915931375633173ba64af9425f2ffd53 我如何使用该签名验证数据未被篡改?(当然使用NodeJS)
我的假设是,您可以调用一种方法,向其提供数据和签名,然后获取一个布尔值,告诉您数据是否被篡改或类似的东西。
哦,等等,当我写这个问题时,我开始思考...
我需要存储我生成的原始随机字节(Crypto.randomBytes(16)),并将它们传递给接收者,以便他们只需再次生成HMac并验证结果是否相同(fb2937ca821264812d511d68ae06a643915931375633173ba64af9425f2ffd53)吗?
如果是这样的话,那很奇怪,因为Crypto.randomBytes(16)的参数被命名为secret(在官方示例中)。看起来像是需要保密??
请告诉我是否有一种方法在接收端验证签名以及如何执行该操作。
官方文档:有点令人困惑
下面是官方文档中定义的函数: crypto.createHmac(algorithm, key[, options]) 在函数定义中,可以看到第二个参数被命名为key。
但是,在示例中,他们将其称为secret。
const secret = 'abcdefg';
const hash = crypto.createHmac('sha256', secret)
               .update('I love cupcakes')
               .digest('hex');
console.log(hash);

3
为了进行验证,您需要再次使用相同的密钥构建数据的HMAC。即签名和验证双方都需要数据和密钥。 - Topaco
啊,这就是我想知道的——当我在思考它时偶然发现了它。 那Official NodeJS文档示例将该项命名为“_secret_”真的很奇怪。 它应该像在函数的定义中那样将变量命名为“_key_”。谢谢你的帮助。如果您将其写成答案,我会标记它为答案,也许它会帮助其他人。 - raddevus
1
它是“秘密”,但不一定是“私人的”。你可以分享秘密,但不能与任何人分享。虽然密钥应该是“随机的”,但它并不需要是随机的。例如,您可以使用密钥封装(使用另一个密钥进行加密)、密钥协商和/或密钥派生来在双方执行“密钥建立”。如果您认为这样的对称加密存在问题,那么是的,这就是为什么我们还有非对称加密,如RSA和(EC)DH。 - Maarten Bodewes
我投票关闭此问题,因为这个问题与不理解密码学有关。尽管发布者无疑学到了一些有价值的经验教训,但这些经验教训在任何关于密码学的文本中都可以找到,它们与编程无关。 - Maarten Bodewes
1个回答

10

我只是发布答案,以便将来的任何人都能得到最终答案。

正如评论者(Topaco)所指出的那样,简单的答案是:

想要验证Hmac的接收方只需要使用相同的key值和data并将其应用于方法并检索哈希值即可。

const secret = 'abcdefg';
const hash = crypto.createHmac('sha256', secret)
               .update('I love cupcakes')
               .digest('hex');
console.log(hash);

原始的HMAC创建方必须为验证方提供三件事:
  1. data : (可以是来自AES256的加密数据,例如)
  2. key : 传递到createHmac() 方法中的原始密钥 -- 注意:此项在NodeJS(上述代码)的示例代码中称为secret
  3. hash :原始创建者调用createHmac()方法生成的(明文)哈希值。
有了这三个内容,验证方现在可以调用createHmac()方法,并确定他们获得的哈希值是否与原始HMAC创建方生成的哈希值匹配。
这样做可以验证已发送的数据是否被损坏或更改。
关于密钥(secret)的附加说明
我稍微思考了一下HMAC后又回来了。
虽然需要双方都知道密钥(也就是secret),但这并不意味着应该将其暴露给其他人。
这必须保密(正如代码所示),因为如果一个恶意的人知道该值并能够更改它,那么他们也可以更改数据并生成新的密钥(secret),然后将其传递,就好像原始创建者发送了它(MITM - 中间人攻击)。
因此,这里的重点是,是的,双方都必须知道密钥(secret)值,但不应在可能被恶意人员发现的地方共享。
相反,必须达成共识或基于秘密密码等。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接