0

I'm attempting to calculate the TCP checksum value (which apparently is the same as the IP4 checksum) but getting the wrong results. I think the issue is arrising from either the padding at the end or the TCP header field but I can't find any details (from the RFC) on how they should be calculated.

For building the pseudoheader (wiki) I'm using the following code to bring together the data (field('xyz').bin() returns a binary string of the field xyz.):

public String genChecksum()
{
    String pseudoHeader = "";

    // From IPv4 - Pseudo Header
    pseudoHeader += peekField("source").bin();
    pseudoHeader += peekField("destination").bin();
    pseudoHeader += "00000000"; // reserved block
    pseudoHeader += peekField("protocol").bin();

    /* TCP Length field: 
     * headerSize() = (TCP.dataOffset * 32) to get TCP header length
     * dataSize() = (IP4.totalLength * 8) - ((IP4.internetHeaderLength * 32) + (TCP.dataOffset * 32)) 
     */

    pseudoHeader += Types.hexToBin(Types.numToHex((int) Math.ceil((headerSize() + dataSize()) / 8)));

    // From TCP Header
    pseudoHeader += field("srcPort").bin();
    pseudoHeader += field("dstPort").bin();
    pseudoHeader += field("seqNum").bin();
    pseudoHeader += field("ackNum").bin();
    pseudoHeader += field("dataOffset").bin();
    pseudoHeader += field("reserved").bin();
    pseudoHeader += field("flagNS").bin();
    pseudoHeader += field("flagCWR").bin();
    pseudoHeader += field("flagECE").bin();
    pseudoHeader += field("flagURG").bin();
    pseudoHeader += field("flagACK").bin();
    pseudoHeader += field("flagPSH").bin();
    pseudoHeader += field("flagRST").bin();
    pseudoHeader += field("flagSYN").bin();
    pseudoHeader += field("flagFIN").bin();
    pseudoHeader += field("windowSize").bin();
    pseudoHeader += "0000000000000000"; // checksum zeroed out
    pseudoHeader += field("urgPointer").bin();
    pseudoHeader += field("optional").bin();
    pseudoHeader += field("data").bin();

    // Pad to 16 bit boundary as stated in RFC
    for (int i = 0; i < (pseudoHeader.length() % 16); i++)
    {
        pseudoHeader += "0";
    }

    System.out.println("pseudoHeader: " + Types.binToHex(pseudoHeader));

    return Types.binToHex(pseudoHeader);
}

I'm fairly sure the values in pulling together (field() and peekField() are correct, I've verified them with wireshark & the checksum of IP4 is correct. The actual checksum method is included below but i've got a test to check that's correct too:

public static String CRC16(String hex) 
{
    byte[] buf = Types.hexToBytes(hex);
    int length = buf.length;
    int i = 0;

    long sum = 0;
    long data;

    while (length > 1) 
    {
        data = (((buf[i] << 8) & 0xFF00) | ((buf[i + 1]) & 0xFF));
        sum += data;

        if ((sum & 0xFFFF0000) > 0) 
        {
            sum = sum & 0xFFFF;
            sum += 1;
        }

        i += 2;
        length -= 2;
    }

    if (length > 0) 
    {
        sum += (buf[i] << 8 & 0xFF00);

        if ((sum & 0xFFFF0000) > 0) 
        {
            sum = sum & 0xFFFF;
            sum += 1;
        }
    }

    sum = ~sum;
    sum = sum & 0xFFFF;

    System.out.println("CRCV: " + String.format("%X", sum));
    return String.format("%X", sum);
}

public static void assertTestChecksum()
{
    byte[] buf = {(byte) 0xe3, 0x4f, 0x23, (byte) 0x96, 0x44, 0x27, (byte) 0x99, (byte) 0xf3};

    if (!CRC16(Types.bytesToHex(buf)).equals("1AFF"))
    {
        Utils.exit("Checksum.java", "assertTestChecksum() failed.");
    }       
}

Am I doing anything overtly wrong?

Crizly
  • 971
  • 1
  • 12
  • 33
  • Using`Types.binToHex(pseudoHeader)` is strange: Why content of pseudoHeader it converted to hex, when is seems to be already a hex string. – SKi May 29 '19 at 08:49
  • @SKi field("xyz").bin() returns a binary string of the value, after i've put it all together i convert it to hex - I would do it natively in hex but there's an issue with single bit values not being converted properly so i need to do it this way for now till i fix :P – Crizly May 29 '19 at 08:57
  • Hmm. For me this looks like appending hex dump to string: `pseudoHeader += "00000000"` – SKi May 29 '19 at 09:31
  • @SKi That's the 8-bit reserved block at offset 64 – Crizly May 29 '19 at 09:33
  • Ok, now I got it. – SKi May 29 '19 at 09:35

0 Answers0