[英]HOTP issue: Node.js crypto.createHmac works only when count is 0
我正在尝试创建一个基于 HMAC 的一次性密码。 我遵循 rfc4226 ( https://www.rfc-editor.org/rfc/rfc4226 ) 规范,但是当计数值不同于 0 时,我无法使算法工作。我做错了什么?
我相信这与我转换计数值的方式有关: countBuffer.writeUInt32BE(count, 4);
.
// The following text is copied from https://www.rfc-editor.org/rfc/rfc4226
// PAGE 32
// The following test data uses the ASCII string
// "12345678901234567890" for the secret:
// my note: Why above the secret is different than the one specified here?
// Secret = 0x3132333435363738393031323334353637383930
// Table 1 details for each count, the intermediate HMAC value.
// Count Hexadecimal HMAC-SHA-1(secret, count)
// 0 cc93cf18508d94934c64b65d8ba7667fb7cde4b0
// 1 75a48a19d4cbe100644e8ac1397eea747a2d33ab
// 2 0bacb7fa082fef30782211938bc1c5e70416ff44
// 3 66c28227d03a2d5529262ff016a1e6ef76557ece
// 4 a904c900a64b35909874b33e61c5938a8e15ed1c
// 5 a37e783d7b7233c083d4f62926c7a25f238d0316
// 6 bc9cd28561042c83f219324d3c607256c03272ae
// 7 a4fb960c0bc06e1eabb804e5b397cdc4b45596fa
// 8 1b3c89f65e6c9e883012052823443f048b4332db
// 9 1637409809a679dc698207310c8c7fc07290d9e5
// Table 2 details for each count the truncated values (both in
// hexadecimal and decimal) and then the HOTP value.
// Truncated
// Count Hexadecimal Decimal HOTP
// 0 4c93cf18 1284755224 755224
// 1 41397eea 1094287082 287082
// 2 82fef30 137359152 359152
// 3 66ef7655 1726969429 969429
// 4 61c5938a 1640338314 338314
// 5 33c083d4 868254676 254676
// 6 7256c032 1918287922 287922
// 7 4e5b397 82162583 162583
// 8 2823443f 673399871 399871
// 9 2679dc69 645520489 520489
const crypto = require("crypto");
const secret = "12345678901234567890"
// When I try to change count to any other number the
// results won't match the table above
// When using 0 the result matches the table above
const count = 0;
let countBuffer = Buffer.alloc(8, 0);
countBuffer.writeUInt32BE(count, 4);
const hmac_result = crypto.createHmac("sha1", secret)
.update(countBuffer)
.digest();
const offset = hmac_result[hmac_result - 1] & 0xf ;
const bin_code = (hmac_result[offset] & 0x7f) << 24
| (hmac_result[offset+1] & 0xff) << 16
| (hmac_result[offset+2] & 0xff) << 8
| (hmac_result[offset+3] & 0xff) ;
let hotp = bin_code % (10 ** 6);
console.log(count, bin_code, hotp);
在玩了一会儿并将我的代码与这个https://github.com/adalberht/hotp-totp-generator/blob/master/index.js进行比较后,我设法使它工作。
const crypto = require("crypto");
function generateHOTP(algorithm, secret, count, digits) {
// Convert the string to binary data in the form of a sequence of bytes
secret = Buffer.from(secret);
// Writes value to buf at the specified offset with the specified endianness
let countBuffer = Buffer.alloc(8, 0);
countBuffer.writeUInt32BE(count, 4);
// Creates and returns an Hmac object that uses the given algorithm and key
const hmac_result = crypto.createHmac(algorithm, secret)
.update(countBuffer)
.digest("hex");
// Chose the last byte of the hmac to do the dynamic truncation
const offset = parseInt(hmac_result.charAt(hmac_result.length - 1), 16);
// Dynamic truncation
let hotp = parseInt(hmac_result.substr(offset * 2, 2 * 4), 16);
hotp = hotp & 0x7fffffff;
hotp = hotp.toString().padStart(digits, "0");
return hotp;
}
for (let i = 0; i <= 9; i++) {
console.log(i, generateHOTP("sha1", "12345678901234567890", i, 6));
}
output 匹配问题表中的十进制截断值:
0 '1284755224'
1 '1094287082'
2 '137359152'
3 '1726969429'
4 '1640338314'
5 '868254676'
6 '1918287922'
7 '82162583'
8 '673399871'
9 '645520489'
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.