为什么 & 0xff 应用于字节变量

Why is & 0xff applied to a byte variable

为什么在基于时间的 OTP(TOTP,RFC 6238)的参考实现中将 & 0xff 应用于字节变量?在我看来,这不会改变值,因为字节数据类型的长度为 8 位。

byte[] hash = hmac_sha(crypto, k, msg);
int offset = hash[hash.length - 1] & 0xf;

int binary =
  ((hash[offset] & 0x7f) << 24) |
  ((hash[offset + 1] & 0xff) << 16) |
  ((hash[offset + 2] & 0xff) << 8) |
  (hash[offset + 3] & 0xff);

int otp = binary % DIGITS_POWER[codeDigits];

此外,将XAND 运算符应用于第一个带有0x7f 的元素的原因是什么?它仍然可以得到一个 10 位数字,比 DIGITS_POWER 中最大的条目 100 000 000.

(https://www.rfc-editor.org/rfc/rfc6238, 第 13 页)

根据 JLS,文字 0xff 的类型为 int
同样根据 JLS,当在 byteint 之间执行操作时,byte 安全地 加宽 int 结果是 int.

这意味着表达式:

hash[offset + 1] & 0xff

大致相同:

(int)(hash[offset + 1]) & 0xff

事实上,需要一个 int 作为结果类型才能使以下移位操作有意义。

(hash[offset + 1] & 0xff) << 16

如果位移是在 byte 上完成的,这些位将旋转回原来的位置(16 是 8 的整数倍)。

整个代码正在从 byte[].

构造 int

用在高字节上的奇数掩码 0x7f 代替 0xff 来掩码最左边(或最高有效位)的位,即 符号bit,保证最后的结果不为负。

byte b = -5;
System.out.println(b);
System.out.println(b & 0xFF);

这会产生以下输出:

-5
251

当执行&时,两个操作数首先被提升为32位。 -5 表示为 11111111111111111111111111111011,而 0xFF 只是“末尾有 24 个零和 8 个一”,因此 (-5) & 0xFF 给出 11111011(省略前导零) .

操作确实改变了值。 byte & 0xff 将带符号的字节转换为表示对应于字节位模式的无符号值的 int。