我想创建一个带有密钥abcdeg
的 I love cupcakes
的哈希值。
如何使用 Node.js Crypto 创建该哈希值?
我想创建一个带有密钥abcdeg
的 I love cupcakes
的哈希值。
如何使用 Node.js Crypto 创建该哈希值?
加密相关文档:http://nodejs.org/api/crypto.html
const crypto = require('crypto')
const text = 'I love cupcakes'
const key = 'abcdeg'
crypto.createHmac('sha1', key)
.update(text)
.digest('hex')
update()
和digest()
这两种方法是过时的,因此新的流API方法被引入。但现在文档表明这两种方法都可以使用。例如:var crypto = require('crypto');
var text = 'I love cupcakes';
var secret = 'abcdeg'; //make this your secret!!
var algorithm = 'sha1'; //consider using sha256
var hash, hmac;
// Method 1 - Writing to a stream
hmac = crypto.createHmac(algorithm, secret);
hmac.write(text); // write in to the stream
hmac.end(); // can't read from the stream until you call end()
hash = hmac.read().toString('hex'); // read out hmac digest
console.log("Method 1: ", hash);
// Method 2 - Using update and digest:
hmac = crypto.createHmac(algorithm, secret);
hmac.update(text);
hash = hmac.digest('hex');
console.log("Method 2: ", hash);
测试过node v6.2.2和v7.7.2。
请参阅https://nodejs.org/api/crypto.html#crypto_class_hmac。提供了更多使用流式方法的示例。
update
而不是 write
。我很困惑,现在哪种做法是最佳实践?我找不到像您所提到的那样清晰明了的资源。 - SCBuergelGwerder的解决方案行不通,因为hash = hmac.read();
在流被最终化之前发生。这就是AngraX的问题所在。此外,在这个例子中,hmac.write
语句是不必要的。
改为这样做:
var crypto = require('crypto');
var hmac;
var algorithm = 'sha1';
var key = 'abcdeg';
var text = 'I love cupcakes';
var hash;
hmac = crypto.createHmac(algorithm, key);
// readout format:
hmac.setEncoding('hex');
//or also commonly: hmac.setEncoding('base64');
// callback is attached as listener to stream's finish event:
hmac.end(text, function () {
hash = hmac.read();
//...do something with the hash...
});
更正式地说,如果您愿意,该行
hmac.end(text, function () {
可以被书写
hmac.end(text, 'utf8', function () {
因为在这个示例中,文本是一个UTF字符串
read()
,而没有关于完成事件的任何内容。 - stronciumfinish
事件,而是依赖于可读的readable
和end
事件。 - stroncium尽管有关于签名和验证哈希算法的所有示例代码,但我仍然需要进行实验和调整才能使其正常工作。这是我的工作示例,我相信它已经涵盖了所有边缘情况。
它是URL安全的(即不需要编码),它需要一个过期时间,并且不会意外地抛出异常。它依赖于Day.js,但您可以将其替换为另一个日期库或自己编写日期比较。
使用TypeScript编写:
// signature.ts
import * as crypto from 'crypto';
import * as dayjs from 'dayjs';
const key = 'some-random-key-1234567890';
const replaceAll = (
str: string,
searchValue: string,
replaceValue: string,
) => str.split(searchValue).join(replaceValue);
const swap = (str: string, input: string, output: string) => {
for (let i = 0; i < input.length; i++)
str = replaceAll(str, input[i], output[i]);
return str;
};
const createBase64Hmac = (message: string, expiresAt: Date) =>
swap(
crypto
.createHmac('sha1', key)
.update(`${expiresAt.getTime()}${message}`)
.digest('hex'),
'+=/', // Used to avoid characters that aren't safe in URLs
'-_,',
);
export const sign = (message: string, expiresAt: Date) =>
`${expiresAt.getTime()}-${createBase64Hmac(message, expiresAt)}`;
export const verify = (message: string, hash: string) => {
const matches = hash.match(/(.+?)-(.+)/);
if (!matches) return false;
const expires = matches[1];
const hmac = matches[2];
if (!/^\d+$/.test(expires)) return false;
const expiresAt = dayjs(parseInt(expires, 10));
if (expiresAt.isBefore(dayjs())) return false;
const expectedHmac = createBase64Hmac(message, expiresAt.toDate());
// Byte lengths must equal, otherwise crypto.timingSafeEqual will throw an exception
if (hmac.length !== expectedHmac.length) return false;
return crypto.timingSafeEqual(
Buffer.from(hmac),
Buffer.from(expectedHmac),
);
};
你可以像这样使用它:
import { sign, verify } from './signature';
const message = 'foo-bar';
const expiresAt = dayjs().add(1, 'day').toDate();
const hash = sign(message, expiresAt);
const result = verify(message, hash);
expect(result).toBe(true);
crypto.timingSafeEqual(Buffer.from(a), Buffer.from(b))
:https://dev59.com/K10Z5IYBdhLWcg3wwyne#PrejEYcBWogLw_1bn4tn - baptx