从 'crypto' 迁移到 crypto-js 库:二进制编码
Migrating from 'crypto' to crypto-js library: Binary encoding
我正在尝试在不支持标准节点 crypto
库的设备上生成 SHA256 和 HmacSHA512 哈希值。所以我正在调整代码以改用 CryptoJS。但是,CryptoJS 无法将哈希编码为二进制(只有 Hex、Base64 和 Latin1 是可用的编码器)。
下面是我要迁移的函数。之前的(不可用的)代码被注释掉了。
const getMessageSignature = (path, request, secret, nonce) => {
// Expected outcome:
// API-Sign = Message signature using HMAC-SHA512 of (URI path + SHA256(nonce + POST data)) and base64 decoded secret API key
const message = JSON.stringify(request);
const secret_buffer = btoa(secret);
const hash = CryptoJS.algo.SHA256.create();
const hmac = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, secret_buffer);
const hash_digest = hash.update(nonce + message).finalize().toString(CryptoJS.enc.Base64);
const hmac_digest = hmac.update(path + hash_digest).finalize().toString(CryptoJS.enc.Base64);
// CANNOT USE BELOW (Buffer and crypto not supported)
// const secret_buffer = new Buffer(secret, 'base64');
// const hash = new crypto.createHash('sha256');
// const hmac = new crypto.createHmac('sha512', secret_buffer);
// const hash_digest = hash.update(nonce + message).digest('binary');
// const hmac_digest = hmac.update(path + hash_digest, 'binary').digest('base64');
return hmac_digest;
};
我找到了答案。首先:btoa()
不是必需的,因为 CryptoJS 具有将 Base64 转换为自己的格式(WordLists)的功能:CryptoJS.enc.Base64.parse
。接下来是 path
和 hash_digest
无法正确合并,因为存在类型不匹配(字符串和二进制),因此 JS 使用字符串表示。解决方案是首先使用 CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA512, secret)
创建一个 SHA512 HMAC,然后使用 hmac.update(value, secret)
为每个值逐步更新它。最后,您还必须使用 CryptoJS 的内置 Base64 解码器来最终生成签名字符串。
const getMessageSignature = (path, request, secret, nonce) => {
// API-Sign = Message signature using HMAC-SHA512 of (URI path + SHA256(nonce + POST data)) and base64 decoded secret API key
const message = JSON.stringify(request);
const hash = CryptoJS.SHA256(nonce + message);
const secret_buffer = CryptoJS.enc.Base64.parse(secret);
const hmac = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA512, secret_buffer);
hmac.update(path, secret_buffer);
hmac.update(hash, secret_buffer);
return hmac.finalize().toString(CryptoJS.enc.Base64);
};
我正在尝试在不支持标准节点 crypto
库的设备上生成 SHA256 和 HmacSHA512 哈希值。所以我正在调整代码以改用 CryptoJS。但是,CryptoJS 无法将哈希编码为二进制(只有 Hex、Base64 和 Latin1 是可用的编码器)。
下面是我要迁移的函数。之前的(不可用的)代码被注释掉了。
const getMessageSignature = (path, request, secret, nonce) => {
// Expected outcome:
// API-Sign = Message signature using HMAC-SHA512 of (URI path + SHA256(nonce + POST data)) and base64 decoded secret API key
const message = JSON.stringify(request);
const secret_buffer = btoa(secret);
const hash = CryptoJS.algo.SHA256.create();
const hmac = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, secret_buffer);
const hash_digest = hash.update(nonce + message).finalize().toString(CryptoJS.enc.Base64);
const hmac_digest = hmac.update(path + hash_digest).finalize().toString(CryptoJS.enc.Base64);
// CANNOT USE BELOW (Buffer and crypto not supported)
// const secret_buffer = new Buffer(secret, 'base64');
// const hash = new crypto.createHash('sha256');
// const hmac = new crypto.createHmac('sha512', secret_buffer);
// const hash_digest = hash.update(nonce + message).digest('binary');
// const hmac_digest = hmac.update(path + hash_digest, 'binary').digest('base64');
return hmac_digest;
};
我找到了答案。首先:btoa()
不是必需的,因为 CryptoJS 具有将 Base64 转换为自己的格式(WordLists)的功能:CryptoJS.enc.Base64.parse
。接下来是 path
和 hash_digest
无法正确合并,因为存在类型不匹配(字符串和二进制),因此 JS 使用字符串表示。解决方案是首先使用 CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA512, secret)
创建一个 SHA512 HMAC,然后使用 hmac.update(value, secret)
为每个值逐步更新它。最后,您还必须使用 CryptoJS 的内置 Base64 解码器来最终生成签名字符串。
const getMessageSignature = (path, request, secret, nonce) => {
// API-Sign = Message signature using HMAC-SHA512 of (URI path + SHA256(nonce + POST data)) and base64 decoded secret API key
const message = JSON.stringify(request);
const hash = CryptoJS.SHA256(nonce + message);
const secret_buffer = CryptoJS.enc.Base64.parse(secret);
const hmac = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA512, secret_buffer);
hmac.update(path, secret_buffer);
hmac.update(hash, secret_buffer);
return hmac.finalize().toString(CryptoJS.enc.Base64);
};