英文:
Translate createHmac from crypto to crypto-js with Buffers
问题
我正在尝试将给定的代码使用crypto翻译成使用crypto-js的版本,但迄今为止没有成功。
我甚至无法获得相同的哈希值。
最终目标是生成TOTP令牌,我需要在web浏览器中使用crypto-js来生成它们。
关键部分是"步骤1: 生成HMAC-SHA-1值",我无法获得与crypto-js中的const hmacResult = hmac.digest();相同的结果...
const crypto = require('crypto');
const cryptojs = require('crypto-js');
const base32 = require('hi-base32');
function generateHOTP(secret, counter) {
const decodedSecret = base32.decode.asBytes(secret);
const buffer = Buffer.alloc(8);
for (let i = 0; i < 8; i++) {
buffer[7 - i] = counter & 0xff;
counter = counter >> 8;
}
// 步骤1: 生成HMAC-SHA-1值
let hmacjs = cryptojs.algo.HMAC.create(cryptojs.algo.SHA1, cryptojs.enc.Utf8.stringify(decodedSecret) );
hmacjs.update(buffer);
console.log(hmacjs.finalize().toString());
const hmac = crypto.createHmac('sha1', Buffer.from(decodedSecret));
hmac.update(buffer);
const hmacResult = hmac.digest();
console.log(hmacResult.toString('hex'));
// 步骤2: 生成4字节字符串 (动态截断)
const code = dynamicTruncationFn(hmacResult);
// 步骤3: 计算HOTP值
return code % 10 ** 6;
}
function dynamicTruncationFn(hmacValue) {
const offset = hmacValue[hmacValue.length - 1] & 0xf;
return (
((hmacValue[offset] & 0x7f) << 24) |
((hmacValue[offset + 1] & 0xff) << 16) |
((hmacValue[offset + 2] & 0xff) << 8) |
(hmacValue[offset + 3] & 0xff)
);
}
function generateTOTP(secret, window = 0) {
const counter = Math.floor(Date.now() / 30000);
return generateHOTP(secret, counter + window);
}
console.log(generateTOTP('GEZDGNBVGY3TQOJQGEZDG', 0));
我尝试了各种变化并查阅了文档,但无法找到解决方案。
英文:
I am trying to translate a given Code using crypto to a version using crypto-js without luck so far.
I am not even able to get the same hash values.
The final goal is to generate TOTP tokens and I need to do it with crypto-js, because I want to generate them in a webbrowser.
The critical part is "Step 1: Generate an HMAC-SHA-1 value", I am not able to get a identical result as in const hmacResult = hmac.digest(); in crypto-js...
const crypto = require('crypto');
const cryptojs = require('crypto-js');
const base32 = require('hi-base32');
function generateHOTP(secret, counter) {
const decodedSecret = base32.decode.asBytes(secret);
const buffer = Buffer.alloc(8);
for (let i = 0; i < 8; i++) {
buffer[7 - i] = counter & 0xff;
counter = counter >> 8;
}
// Step 1: Generate an HMAC-SHA-1 value
let hmacjs = cryptojs.algo.HMAC.create(cryptojs.algo.SHA1, cryptojs.enc.Utf8.stringify(decodedSecret) );
hmacjs.update(buffer);
console.log(hmacjs.finalize().toString());
const hmac = crypto.createHmac('sha1', Buffer.from(decodedSecret));
hmac.update(buffer);
const hmacResult = hmac.digest();
console.log(hmacResult.toString('hex'));
// Step 2: Generate a 4-byte string (Dynamic Truncation)
const code = dynamicTruncationFn(hmacResult);
// Step 3: Compute an HOTP value
return code % 10 ** 6;
}
function dynamicTruncationFn(hmacValue) {
const offset = hmacValue[hmacValue.length - 1] & 0xf;
return (
((hmacValue[offset] & 0x7f) << 24) |
((hmacValue[offset + 1] & 0xff) << 16) |
((hmacValue[offset + 2] & 0xff) << 8) |
(hmacValue[offset + 3] & 0xff)
);
}
function generateTOTP(secret, window = 0) {
const counter = Math.floor(Date.now() / 30000);
return generateHOTP(secret, counter + window);
}
console.log(generateTOTP('GEZDGNBVGY3TQOJQGEZDG', 0));
I tried diverse variation and consulted the documentations, but couldn't figure out a solution.
答案1
得分: 0
CryptoJS内部使用WordArray数据类型,即您需要将decodedSecret(JavaScript数组)和buffer(NodeJS缓冲区)转换为WordArray,并将生成的HMAC作为WordArray转换为NodeJS缓冲区。
有几种方法可以实现这一点。一种可能的方法是通过Latin1进行转换:
// 步骤1:生成HMAC-SHA-1值
let decodedSecretWA = cryptojs.enc.Latin1.parse(Buffer.from(decodedSecret).toString('latin1')); // JS数组 -> WordArray
let bufferWA = cryptojs.enc.Latin1.parse(buffer.toString('latin1')); // NodeJS缓冲区 -> WordArray
let hmacjsWA = cryptojs.algo.HMAC.create(cryptojs.algo.SHA1, decodedSecretWA);
hmacjsWA.update(bufferWA);
let hmacResultjsWA = hmacjsWA.finalize();
const hmacResultjs = Buffer.from(hmacResultjsWA.toString(cryptojs.enc.Latin1), 'latin1'); // WordArray -> NodeJS缓冲区
console.log(hmacResultjs);
另一种方法是直接使用cryptojs.lib.WordArray.create()将其转换为WordArray,该方法可以处理JavaScript数组(通过类型化数组)和NodeJS缓冲区。没有CryptoJS支持的反向方向,但可以使用这里的CryptJsWordArrayToUint8Array()进行转换:
// 步骤1:生成HMAC-SHA-1值
let decodedSecretWA = cryptojs.lib.WordArray.create(new Uint8Array(decodedSecret)); // JS数组 -> WordArray
let bufferWA = cryptojs.lib.WordArray.create(buffer); // NodeJS缓冲区 -> WordArray
let hmacjsWA = cryptojs.algo.HMAC.create(cryptojs.algo.SHA1, decodedSecretWA);
hmacjsWA.update(bufferWA);
let hmacResultjsWA = hmacjsWA.finalize();
const hmacResultjs = Buffer.from(CryptJsWordArrayToUint8Array(hmacResultjsWA)); // WordArray -> NodeJS缓冲区
console.log(hmacResultjs);
英文:
CryptoJS uses the WordArray data type internally, i.e. you have to convert decodedSecret (JavaScript array) and buffer (NodeJS buffer) into a WordArray and the resulting HMAC as WordArray into a NodeJS buffer.
There are several approaches to this. One possibility is the conversion via latin1:
// Step 1: Generate an HMAC-SHA-1 value
let decodedSecretWA = cryptojs.enc.Latin1.parse(Buffer.from(decodedSecret).toString('latin1')); // JS array -> WordArray
let bufferWA = cryptojs.enc.Latin1.parse(buffer.toString('latin1')); // NodeJS Buffer -> WordArray
let hmacjsWA = cryptojs.algo.HMAC.create(cryptojs.algo.SHA1, decodedSecretWA);
hmacjsWA.update(bufferWA);
let hmacResultjsWA = hmacjsWA.finalize();
const hmacResultjs = Buffer.from(hmacResultjsWA.toString(cryptojs.enc.Latin1), 'latin1'); // WordArray -> NodeJS Buffer
console.log(hmacResultjs);
Another approach is to convert directly to a WordArray with cryptojs.lib.WordArray.create(), which can handle JavaScript arrays (via typed arrays) and NodeJS buffers. There is no CryptoJS support for the reverse direction, but e.g. CryptJsWordArrayToUint8Array() from here can be applied:
// Step 1: Generate an HMAC-SHA-1 value
let decodedSecretWA = cryptojs.lib.WordArray.create(new Uint8Array(decodedSecret)); // JS array -> WordArray
let bufferWA = cryptojs.lib.WordArray.create(buffer); // NodeJS Buffer -> WordArray
let hmacjsWA = cryptojs.algo.HMAC.create(cryptojs.algo.SHA1, decodedSecretWA);
hmacjsWA.update(bufferWA);
let hmacResultjsWA = hmacjsWA.finalize();
const hmacResultjs = Buffer.from(CryptJsWordArrayToUint8Array(hmacResultjsWA)); // WordArray -> NodeJS Buffer
console.log(hmacResultjs);
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论