2

我正在编写一个使用 HMAC 进行消息身份验证的 Web 服务。我在准备摘要的“数据”时遇到了一些问题,并且在 Python 与 NodeJS 中为相同的“数据”获得了不同的摘要。

我相当确定这个问题是由于编码造成的,但我不确定如何最好地解决这个问题。

Python代码:

import hmac
from hashlib import sha1

f = open('../test.txt')
raw = f.read()

raw = raw.strip()

hm = hmac.new('12345', raw, sha1)
res = hm.hexdigest()
print res

>> 5bff447a0fb82f3e7572d9fde362494f1ee2c25b

NodeJS(咖啡)代码:

fs = require 'fs'
http = require 'http'
{argv} = require 'optimist'
crypto = require 'crypto'

# Load the file
file = fs.readFileSync argv.file, 'utf-8'
file = file.trim()

# Create the signature
hash = crypto.createHmac('sha1', '12345').update(file).digest('hex')
console.log(hash)

>> a698f82ea8ff3c4e9ffe0670be2707c104d933aa

编辑:另外,raw 的长度比文件长 2 个字符,但我不知道这两个字符来自哪里。

4

2 回答 2

4

这是您从文件系统读取的数据的编码问题,与您使用的算法无关。

当你在 Python 和 JavaScript 中处理字符串数据时,你应该对存储数据的编码非常小心。尝试使用字符串(特别是具有编码这样的属性)来处理数据,或者用“原始数据”。在读取和签署数据时,您可能不应该关心编码,并尝试在您的语言中尽可能多地使用“原始”数据。

需要注意的几点:

  • 文件系统存储“原始”字节,对文件的内容和编码一无所知。此外,对于某些文件(例如 jpeg),“编码”概念毫无价值
  • 这同样适用于加密算法。他们使用原始字节,对它的“字符表示”一无所知。这就是为什么数字签名适用于各种二进制文档等的原因。
  • trim()在 javascript 或strip()python 中使用字符串,它们的行为可能因底层编码而异(u's '.encode('utf-16').strip().decode('utf-16')例如,在 python 中尝试)。如果可能的话,我宁愿避免使用修剪,而不是混合使用数据的方式。
  • Python 2.x(我想还有 Javascript)有一套用于字符串和原始数据之间隐式转换的规则。

在您的代码中,您在 Python 中处理二进制数据,但在定义要读取的文件的编码时,在 JavaScript 中转换为字符串。显然,在加密模块中有一种从 utf-8 到原始字符串的隐式转换,但我不知道它做了什么。

如此处所述,在 node.js 中处理原始字符串的最合理的方式是使用缓冲区。您可以从文件系统读取缓冲区,但不幸的是,nodejs 加密库还不支持它们。如此处所述:

Crypto 模块被添加到 Node 之前,还有统一的 Stream API 的概念,以及用于处理二进制数据的 Buffer 对象。

因此,流类没有其他 Node 类中的典型方法,并且许多方法默认接受和返回二进制编码的字符串,而不是缓冲区。

也就是说,为了使示例工作,当前的方法是通过将“二进制”作为调用的第二个参数传递来读取数据:

file = fs.readFileSync argv.file, "binary"

另外,正如我所说,我宁愿避免剥离我刚刚从文件中读取的数据。

于 2012-10-23T19:02:58.667 回答
1

一些尝试的想法:

  • 检查raw具有相同的长度file
  • f以二进制形式打开
  • import codecscodecs.open与编码一起使用
  • strip将删除 Python 中字符串开头和结尾的所有空格 - 我认为trim只会从结尾删除。因此,您可能希望rstrip()设置显式字符来获得相同的行为
于 2012-10-23T18:26:18.450 回答