Why is & 0xff applied to a byte variable in the reference implementation of the time-based OTP (TOTP, RFC 6238)? In my opinion, this does not change the value since the byte data type has a length of 8 bits.
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];
Besides, what is the reason to apply the XAND operator to the first element with 0x7f? It can still result in a number with 10 digits, which is larger than the largest entry in DIGITS_POWER, which is 100 000 000.
(https://www.rfc-editor.org/rfc/rfc6238, page 13)
byte b = -5;
System.out.println(b);
System.out.println(b & 0xFF);
This produces the following output:
-5
251
When & is executed, both operands first get promoted to 32 bits. -5 is represented as 11111111111111111111111111111011, while 0xFF is just '24 zeroes and 8 ones on the end', so (-5) & 0xFF gives 11111011 (leading zeroes omitted).
The literal 0xff is, as per the JLS, of type int.
Also as per the JLS, when an operation is performed between a byte and and int, the byte is safely widened to an int and the result is an int.
What this means is that the expression:
hash[offset + 1] & 0xff
Is more or less the same as:
(int)(hash[offset + 1]) & 0xff
In fact, an int is needed as the result type for the following bit-shift operation to make sense.
(hash[offset + 1] & 0xff) << 16
If the bit-shift was done on a byte, the bits would just rotate back to their original position (16 being an exact multiple of 8).
The whole code is constructing an int from a byte[].
The odd mask 0x7f used on the high byte is used instead of 0xff to mask off the left-most (or most significant) bit, which is the sign bit, to ensure the final result is not negative.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With