The Laws of Cryptography:
Unsigned bytes in Java

by Neal R. Wagner

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;

Left shifts work as they ought to, but the result is an int, so it needs to be cast to a byte if that is needed.

```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:
1. All operators return an int, so they must be cast to a byte if a byte is needed. This includes: &, |, ^, >>, >>>, and <<.
2. Hex constants such as 0xff actually define an integer, so this is the same as 0x000000ff. For values bigger than Ox7f a cast to byte is needed.
3. Arithmetic (except for / and %) with Java's signed bytes works just as if the bytes were unsigned, since there is no overflow.

Revision date: 2001-12-28. (Please use ISO 8601, the International Standard.)