by Neal R. Wagner
Copyright © 2001 by Neal R. Wagner. All rights reserved.
NOTE: This site is obsolete. See book draft (in PDF):
The Advanced Encryption Standard (AES) makes extensive use of the unsigned byte type. This creates awkward code in Java, because Java supports only the signed byte type. In addition, some of the Java operators do not work as in the documentation, creating further problems. For example:
public class TestRightShift0 {
public static void main(String[] args) {
byte b = (byte)0x80;
int c = b >>> 4;
System.out.println("b: " + b + ", c: " + c);
c = 0x0ffffff8;
System.out.println("c: " + c);
}
}
/* Output:
b: -128, c: 268435448
c: 268435448
*/
The output shows that b has the value 0x80 or 1000 0000 in binary, as one would expect. According to The Java Programming Language, Third Edition, page 164, the >>> operator should fill new high-order bits with zeros. In fact, though, Java is converting b to int type with sign-extended value 0xffffff80, right shifting this and putting just four zeros at the right, to give 0x0ffffff8. To get the desired value, one can use either of the following:
public class TestRightShift1 {
public static void main(String[] args) {
byte b = (byte)0x80;
int c = (b & 0xf0) >> 4;
System.out.println("b: " + b + ", c: " + c);
c = (b >> 4) & 0xf;
System.out.println("b: " + b + ", c: " + c);
}
}
/* Output:
b: -128, c: 8
b: -128, c: 8
*/
Similarly, a right shift of 3 could use either of the lines:
public class TestRightShift2 {
public static void main(String[] args) {
byte b = (byte)0x80;
int c = (b & 0xf1) >> 3;
System.out.println("b: " + b + ", c: " + c);
c = (b >> 3) & 0x1f;
System.out.println("b: " + b + ", c: " + c);
}
}
/* Output:
b: -128, c: 16
b: -128, c: 16
*/
This seems to require different constants for different shifts, but actually, the first method works with a fixed constant:
public class TestRightShift3 {
public static void main(String[] args) {
byte b = (byte)0x80;
for (int i = 0; i < 9; i++) {
int c = (b & 0xff) >> i;
System.out.println("b: " + b + ", shift by: " + i + ", c: " + c);
}
}
}
/* Output:
b: -128, shift by: 0, c: 128
b: -128, shift by: 1, c: 64
b: -128, shift by: 2, c: 32
b: -128, shift by: 3, c: 16
b: -128, shift by: 4, c: 8
b: -128, shift by: 5, c: 4
b: -128, shift by: 6, c: 2
b: -128, shift by: 7, c: 1
b: -128, shift by: 8, c: 0
*/
Law JB1: In the Java language, to right shift an integer
amount shiftAmount, use the code
int shiftedValue = (byteValue & 0xff) >> shiftAmount;
where byteValue is of type
byte and
shiftAmount is an
int in the range from
0 to
8. A
0 for
shiftAmount is the same
as not doing the shift, but just to store an
unsigned byte into an
int type requires
int shiftedValue = byteValue & 0xff;
public class TestLeftShift {
public static void main(String[] args) {
byte b = (byte)0x01;
for (int i = 0; i < 9; i++) {
int c = (b << i);
System.out.println("b: " + b + ", shift by: " + i + ", c: " + c);
byte bb = (byte)(b << i);
System.out.println("b: " + b + ", shift by: " + i + ", bb: " + bb);
}
}
}
/* Output:
b: 1, shift by: 0, c: 1
b: 1, shift by: 0, bb: 1
b: 1, shift by: 1, c: 2
b: 1, shift by: 1, bb: 2
b: 1, shift by: 2, c: 4
b: 1, shift by: 2, bb: 4
b: 1, shift by: 3, c: 8
b: 1, shift by: 3, bb: 8
b: 1, shift by: 4, c: 16
b: 1, shift by: 4, bb: 16
b: 1, shift by: 5, c: 32
b: 1, shift by: 5, bb: 32
b: 1, shift by: 6, c: 64
b: 1, shift by: 6, bb: 64
b: 1, shift by: 7, c: 128
b: 1, shift by: 7, bb: -128
b: 1, shift by: 8, c: 256
b: 1, shift by: 8, bb: 0
*/
Law JB2: In the Java language, logical and shifting operators
work as follows: