将`crypto`中的`createHmac`函数转换为使用`crypto-js`和缓冲区(Buffers)的形式。

huangapple go评论72阅读模式
英文:

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(&#39;crypto&#39;);
const cryptojs = require(&#39;crypto-js&#39;);
const base32 = require(&#39;hi-base32&#39;);
function generateHOTP(secret, counter) {
const decodedSecret = base32.decode.asBytes(secret);
const buffer = Buffer.alloc(8);
for (let i = 0; i &lt; 8; i++) {
buffer[7 - i] = counter &amp; 0xff;
counter = counter &gt;&gt; 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(&#39;sha1&#39;, Buffer.from(decodedSecret)); 
hmac.update(buffer);
const hmacResult = hmac.digest();
console.log(hmacResult.toString(&#39;hex&#39;));
// 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] &amp; 0xf;
return (
((hmacValue[offset] &amp; 0x7f) &lt;&lt; 24) |
((hmacValue[offset + 1] &amp; 0xff) &lt;&lt; 16) |
((hmacValue[offset + 2] &amp; 0xff) &lt;&lt; 8) |
(hmacValue[offset + 3] &amp; 0xff)
);
}
function generateTOTP(secret, window = 0) {
const counter = Math.floor(Date.now() / 30000);
return generateHOTP(secret, counter + window);
}
console.log(generateTOTP(&#39;GEZDGNBVGY3TQOJQGEZDG&#39;, 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(&#39;latin1&#39;)); // JS array -&gt; WordArray 
let bufferWA = cryptojs.enc.Latin1.parse(buffer.toString(&#39;latin1&#39;));                            // NodeJS Buffer -&gt; 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), &#39;latin1&#39;); // WordArray -&gt; 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 -&gt; WordArray 
let bufferWA = cryptojs.lib.WordArray.create(buffer);                               // NodeJS Buffer -&gt; 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 -&gt; NodeJS Buffer
console.log(hmacResultjs);

huangapple
  • 本文由 发表于 2023年7月3日 15:13:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/76602578.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定