Translation of Go-Code to Java but there are problems with ranges of DataTypes

Hello World !,

i tried to translate a piece of code to java but I have problems about the ranges of the datatypes and the bit operations is someone able to help.

Both Code pieces are ready to compile and work but get different results :frowning:

If someone could help I would be really thankful !!!
The Go-Code :

package main

import (
	"encoding/binary"
	"fmt"
	"strconv"
)

func crc32v(idx int) int {
	POLY := 0x04c11db7
	c := idx << 24 & 0xFFFFFFFF
	for i := 0; i < 8; i++ {
		k:= c&0x80000000
		if k > 0 {
			c = c<<1 ^ POLY
		} else {
			c = c << 1 & 0xFFFFFFFF
		}
	}
	return c
}

func adler32(bs []byte) int {
	s1 := 4
	s2 := 0
	for _, x := range bs {
		s1 = (s1 + int(x)) % 65521
		s2 = (s2 + s1) % 65521
	}
	res := (s2 << 16) | s1
	return res
}

func prepareSubs(key []int) [][]int {
	table1 := make([]int, 256)
	for i := range table1 {
		table1[i] = i
	}
	s := 0
	for i := range table1 {
		s += table1[i]
		s += key[i%len(key)]
		s &= 0xFF
		table1[i] = table1[s]
	}

	table2 := make([]int, 256)
	for i, v := range table1 {
		table2[i] = v
	}
	s = 0
	for i := range table2 {
		if i > 0 {
			s = (table2[i] + s) & 0xFF
			table2[i] = table2[s]
		}
	}
	out := [][]int{table1, table2}
	return out
}

func Reverse(s string) (result string) {
	for _, v := range s {
		result = string(v) + result
	}
	return
}

func rbit(x int, width int) int {
	x2 := strconv.FormatInt(int64(x), 2)
	orig := len(x2)
	for i := 0; i < width-orig; i++ {
		x2 = fmt.Sprintf("0%s", x2)
	}
	x3, _ := strconv.ParseInt(Reverse(x2), 2, 32)
	return int(x3)
}


func hashFunction(srcData []byte, timestamp int) string {

	ldsBytes := []byte{0x0D, 0xC0, 0xA0, 0xE1, 0xF0, 0x00, 0x2D, 0xE9, 0xE9, 0x00, 0x40, 0xE2, 0x00, 0x70, 0xA0, 0xE1, 0x01, 0x00, 0xA0, 0xE1, 0x02, 0x10, 0xA0, 0xE1, 0x03, 0x20, 0xA0, 0xE1, 0x78, 0x00, 0x9C, 0xE8}
	stackCrc := crc32v(0x63)
	inpbs := make([]byte, 0)
	for i := 0; i < 4; i++ {
		next := srcData[i*16 : i*16+4]
		for _, b := range next {
			inpbs = append(inpbs, b)
		}
	}


	// Append timestamp bytes to inpbs
	tsBytes := make([]byte, 4)
	binary.BigEndian.PutUint32(tsBytes, uint32(timestamp))

	for _, b := range tsBytes {
		inpbs = append(inpbs, b)
	}
	ldsChecksum := adler32(ldsBytes)
	crcbs := 0
	for i := 0; i < 4; i++ {
		crcbs = (crcbs << 4) + (ldsChecksum & 0xff)
		ldsChecksum >>= 8
	}
	crcbs = (crc32v(crcbs&0xFF) ^ crc32v((crcbs>>8)&0xFF))
	key := []int{
		crcbs & 0xFF,
		0,
		(crcbs >> 8) & 0xFF,
		(stackCrc >> 8) & 0xFF,
		(crcbs >> 16) & 0xFF,
		(crcbs >> 24) & 0xFF,
		0,
		stackCrc & 0xFF,
	}

	// Returns multi-dimensional int array
	sbox := prepareSubs(key)
	result := make([]int, len(inpbs)) // It prepends like 6 bytes before the return

	for r, i := range inpbs {
		result[r] = int(i)
	}

	for i := range result {
		result[i] ^= sbox[0][(sbox[1][i+1]<<1)&0xFF]
	}

	for i := range result {
		x := ((result[i] << 4) & 0xF0) | ((result[i] >> 4) & 0xF)
		x ^= result[(i+1)%len(result)]
		x = rbit(x, 8)
		x ^= 0xFF
		x ^= 0x14
		result[i] = x
	}

	pre := make([]int, len(result)+6)
	pre[0] = 0x03
	pre[1] = 0x6F
	pre[2] = key[7]
	pre[3] = key[3]
	pre[4] = 0
	pre[5] = 0

	for r, v := range result {
		pre[r+6] = v
	}

	str := ""
	for _, p := range pre {
		str = fmt.Sprintf("%s%02x", str, p)
	}

	fmt.Println("As []int: \t", pre)
	fmt.Printf("As hex:\t\t%02x\n", pre)
	fmt.Printf("As hex string:\t%v\n", str)
	return str
}

func main() {

	var favicon = []byte{
		0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00,
		0x10, 0x00, 0x00, 0x00, 0x0f, 0x04, 0x03, 0x00, 0x00, 0x00, 0x1f, 0x5d, 0x52, 0x1c, 0x00, 0x00, 0x00, 0x0f, 0x50,
		0x4c, 0x54, 0x45, 0x7a, 0xdf, 0xfd, 0xfd, 0xff, 0xfc, 0x39, 0x4d, 0x52, 0x19, 0x16, 0x15, 0xc3, 0x8d, 0x76, 0xc7,
		0x36, 0x2c, 0xf5, 0x00, 0x00, 0x00, 0x40, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x95, 0xc9, 0xd1, 0x0d, 0xc0, 0x20,
		0x0c, 0x03, 0xd1, 0x23, 0x5d, 0xa0, 0x49, 0x17, 0x20, 0x4c, 0xc0, 0x10, 0xec, 0x3f, 0x53, 0x8d, 0xc2, 0x02, 0x9c,
		0xfc, 0xf1, 0x24, 0xe3, 0x31, 0x54, 0x3a, 0xd1, 0x51, 0x96, 0x74, 0x1c, 0xcd, 0x18, 0xed, 0x9b, 0x9a, 0x11, 0x85,
		0x24, 0xea, 0xda, 0xe0, 0x99, 0x14, 0xd6, 0x3a, 0x68, 0x6f, 0x41, 0xdd, 0xe2, 0x07, 0xdb, 0xb5, 0x05, 0xca, 0xdb,
		0xb2, 0x9a, 0xdd, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,
	}
	hashFunction(favicon,1)
}

The Java Code :

import java.nio.ByteBuffer;
import java.util.Arrays;

public class Lev {

    public static long crc32v(long idx) {
        int POLY = 0x04c11db7;
        long c = (idx << 24) & 0xFFFFFFFF;
        long k;
        for (int i = 0; i < 8; i++) {
            k = c&0x80000000;
            if (k > 0) {
                c = (c << 1) ^ POLY;
            } else {
                c = (c << 1) & 0xFFFFFFFF;
            }
        }
        return c;
    }

    public static long adler32(int[] bs) {
        long s1 = 4;
        long s2 = 0;
        for (int i = 0; i < bs.length; i++) {
            s1 = (s1 + (int) bs[i]) % 65521;
            s2 = (s2 + s1) % 65521;
        }
        long res = (s2 << 16) | s1;
        return res;
    }

    public static long[][] prepareSubs(long[] key) {
        long[] table1 = new long[256];
        for (int i = 0; i < table1.length; i++) {
            table1[i] = i;
        }
        int s = 0;
        for (int i = 0; i < table1.length; i++) {
            s += table1[i];
            s += key[i % key.length];
            s &= 0xFF;
            table1[i] = table1[s];
        }

        long[] table2 = new long[256];

        for (int i = 0; i < table1.length; i++) {
            table2[i] = table1[i];
        }
        s = 0;
        for (int i = 0; i < table2.length; i++) {
            if (i > 0) {
                s = (int) ((table2[i] + s) & 0xFF);
                table2[i] = table2[s];
            }
        }
        long[][] out = new long[][]{
                table1, table2
        };
        return out;
    }

    // Reverse a string
    static String Reverse(String s) {
        StringBuilder sb = new StringBuilder(s);
        return sb.reverse().toString();
    }

    public static int rbit(int x, int width) {
        String x2 = Long.toString((long) x, 2);
        int orig = x2.length();
        for (int i = 0; i < width - orig; i++) {
            x2 = String.format("0%s", x2);
        }
        int x3 = Integer.parseInt(Reverse(x2), 2);
        return x3;
    }

    public static String hashFunction(int[] srcData, int timestamp) {

        int[] ldsBytes = new int[]{
                0x0D, 0xC0, 0xA0, 0xE1, 0xF0, 0x00, 0x2D, 0xE9, 0xE9, 0x00, 0x40, 0xE2, 0x00, 0x70, 0xA0, 0xE1, 0x01, 0x00, 0xA0, 0xE1, 0x02, 0x10, 0xA0, 0xE1, 0x03, 0x20, 0xA0, 0xE1, 0x78, 0x00, 0x9C, 0xE8
        };
        long stackCrc = crc32v(0x63);
        byte[] inpbs = new byte[0];
        for (int i = 0; i < 4; i++) {
            int[] next = Arrays.copyOfRange(srcData, i * 16, i * 16 + 4);

            for (int f = 0; f < next.length; f++) {
                inpbs = append(inpbs, next[f]);
            }
        }


        // Append timestamp bytes to inpbs
        byte[] tsBytes = new byte[4];
        tsBytes = ByteBuffer.allocate(4).putInt(timestamp).array();



        //binary.BigEndian.PutUint32(tsBytes, uint32(timestamp))

        for (int i = 0; i < tsBytes.length; i++) {
            inpbs = append(inpbs, tsBytes[i]);
        }

        long ldsChecksum = adler32(ldsBytes);
        long crcbs = 0;
        for (int i = 0; i < 4; i++) {
            crcbs = (crcbs << 4) + (ldsChecksum & 0xff);
            ldsChecksum >>= 8;
        }
        crcbs = (crc32v(crcbs & 0xFF) ^ crc32v((crcbs >> 8) & 0xFF));
        long[] key = new long[]{
                crcbs & 0xFF,
                0,
                (crcbs >> 8) & 0xFF,
                (stackCrc >> 8) & 0xFF,
                (crcbs >> 16) & 0xFF,
                (crcbs >> 24) & 0xFF,
                0,
                stackCrc & 0xFF,
        };

        // Returns multi-dimensional int array
        long[][] sbox = prepareSubs(key);
        int[] result = new int[inpbs.length]; // It prepends like 6 bytes before the return

        for (int i = 0; i < inpbs.length; i++) {
            result[i] = inpbs[i];
        }

        for(int i = 0; i < result.length;i++){
            result[i] ^= sbox[0][(int) ((sbox[1][i + 1] << 1) & 0xFF)];
        }

        for(int i = 0; i < result.length;i++){
            int x =((result[i] << 4) & 0xF0) | ((result[i] >> 4) & 0xF);
            x ^= result[(i + 1) % result.length];
            x = rbit(x, 8);
            x ^= 0xFF;
            x ^= 0x14;
            result[i] = x;
        }

        long[] pre =new long[result.length + 6];
        pre[0] = 0x03;
        pre[1] = 0x6F;
        pre[2] = key[7];
        pre[3] = key[3];
        pre[4] = 0;
        pre[5] = 0;

        for (int i = 0; i < result.length; i++) {
            pre[i + 6] = result[i];
        }

        String str="";
        for(int i = 0; i < pre.length; i++){
            str = str.format("%s%02x", str, pre[i]);
        }


        System.out.println(str);
        return str;
    }

     public static void main(String[] args) {
        int[] favicon = new int[]{
                0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00,
                0x10, 0x00, 0x00, 0x00, 0x0f, 0x04, 0x03, 0x00, 0x00, 0x00, 0x1f, 0x5d, 0x52, 0x1c, 0x00, 0x00, 0x00, 0x0f, 0x50,
                0x4c, 0x54, 0x45, 0x7a, 0xdf, 0xfd, 0xfd, 0xff, 0xfc, 0x39, 0x4d, 0x52, 0x19, 0x16, 0x15, 0xc3, 0x8d, 0x76, 0xc7,
                0x36, 0x2c, 0xf5, 0x00, 0x00, 0x00, 0x40, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x95, 0xc9, 0xd1, 0x0d, 0xc0, 0x20,
                0x0c, 0x03, 0xd1, 0x23, 0x5d, 0xa0, 0x49, 0x17, 0x20, 0x4c, 0xc0, 0x10, 0xec, 0x3f, 0x53, 0x8d, 0xc2, 0x02, 0x9c,
                0xfc, 0xf1, 0x24, 0xe3, 0x31, 0x54, 0x3a, 0xd1, 0x51, 0x96, 0x74, 0x1c, 0xcd, 0x18, 0xed, 0x9b, 0x9a, 0x11, 0x85,
                0x24, 0xea, 0xda, 0xe0, 0x99, 0x14, 0xd6, 0x3a, 0x68, 0x6f, 0x41, 0xdd, 0xe2, 0x07, 0xdb, 0xb5, 0x05, 0xca, 0xdb,
                0xb2, 0x9a, 0xdd, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,
        };
        hashFunction(favicon, 1);

    }

    public static byte[] append(byte[] arr, byte b){
        byte[] re = new byte[arr.length+1];
        for(int i = 0; i < arr.length; i ++){
            re[i] = arr[i];
        }
        re[arr.length] = b;
        return re;
    }
    public static byte[] append(byte[] arr, int b){
        byte[] re = new byte[arr.length+1];
        for(int i = 0; i < arr.length; i ++){
            re[i] = arr[i];
        }
        re[arr.length] = (byte) b;
        return re;
    }
    public static int[] append(int[] arr, byte b){
        int[] re = new int[arr.length+1];
        for(int i = 0; i < arr.length; i ++){
            re[i] = arr[i];
        }
        re[arr.length] = b;
        return re;
    }
}

As you mentioned ranges, then just looking at adler32 you have byte in the Go version (range 0 to 255) and int in the Java version (32-bit integer) for the input array.

You might also want to specify the size of your int datatypes, e.g. int64, int32 to correspond directly to Java’s long and int.

https://golang.org/pkg/builtin/#byte
https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html

My Problem is I am not able to change the go code just the java code to prevent changes in result. Could you tell me what i have to change in java ?

Best regards
Joost

The problem was not the ranges, but that Java needs you to specify if a number is long. The discrepancies arise in crc32v, and the only changes needed are to add an L to 0x80000000 and 0xFFFFFFFF.

    public static long crc32v(long idx) {
        int POLY = 0x04c11db7;
        long c = (idx << 24) & 0xFFFFFFFFL;
        long k;
        for (int i = 0; i < 8; i++) {
            k = c&0x80000000L;
            if (k > 0) {
                c = (c << 1) ^ POLY;
            } else {
                c = (c << 1) & 0xFFFFFFFFL;
            }
        }
        return c;
    }

without the L, Java treats the number as a 32-bit int, and sign extends it to 64-bits.

1 Like

Thank you so much !!!