我正在尝试为 HOTP 计算手动 HMAC SHA-1 截断,但它不会返回与我使用源代码计数相同的结果。例如,我有代码将HMAC SHA-1生成为:
$hash = hash_hmac('sha1','375317186160478973','test'(;
它会给我 HMAC = c359e469b8ef0939f83e79a300b20a6ef4b53a05
并将其划分为 [19] 个数组,这样它就是:
C3 59 E4 69 B8 EF 09 39 F8 3E 79 A3 00 B2 0A 6E F4 B5 3A 05
从最后一个数组中,我有 05(二进制为 101(,之后是 101 和 0xf = 5
所以我从第 5 个数组 ef (11101111( 09 (1001( 39 (111001( f8 (11111000( 开始计数
之后做((11101111(和0x7f(<<24(|(((1001( & 0xff( <<16( |(((111001( & 0xff( <<8( |((11111000( & 0xff(( % POW (10,6(
它给我的结果是:56024
但是如果我使用此代码:
$offset = ($hash[19]) & 0xf;
$otp = (((($hash[$offset + 0]) & 0x7f) << 24) |
((($hash[$offset + 1]) & 0xff) << 16) |
((($hash[$offset + 2]) & 0xff) << 8) |
(($hash[$offset + 3]) & 0xff)) % pow(10, 6);
它给我的结果是:599808
如果我将二进制或十进制值写入数组中的值,将显示相同的不同结果。有人可以帮我解释我的错在哪里,这样我就可以计算手册和源代码,并给我的结果与 HOTP 值相同。谢谢
Apa kabar :)首先,SHA-1 的大小为 160 位(20 字节(,而不是 19。你正在使用PHP对吗?问题是,像这样访问数组是行不通的,因为你总是只读取字符:
$hash[5] // (4)
$hash[6] // (6)
$hash[7] // (9)
$hash[8] // (b)
以下应该有效:
((intval(substr($hash, ($offset + 0) * 2, 2), 16) & 0x7f) << 24) |
((intval(substr($hash, ($offset + 1) * 2, 2), 16) & 0xff) << 16) |
((intval(substr($hash, ($offset + 2) * 2, 2), 16) & 0xff) << 8) |
(intval(substr($hash, ($offset + 3) * 2, 2), 16) & 0xff);
重要的是,由于$hash
似乎是 php 一个字符串,因此您不能简单地将其作为数组访问,因为这将返回错误的值。但是您可以借助 substr
方法获取字符串的组件。您始终必须读取 2 个字节并将其转换为整数。Sicne 字符串包含十六进制值,您必须在 intval
中使用基数 16 。
PS:我假设哈希字符串正好是 20 字节长。
总结:例如,$hash[5] 不会给你预期的数组值0xEF,但它会给你第 5 个字符串字符 '4'(子字符串 E4 的一部分(。