Calculating a checksum in C#

12,098

There are notes in line as I go along. Some more notes on the calculation at the end.

uint sum = 0;
uint zeroOffset = 0x30; // ASCII '0'

byte[] inputData = Encoding.ASCII.GetBytes(recordCheckSum);

for (int i = 0; i < inputData.Length; i++)
{
    int product = inputData[i] & 0x7F; // Take the low 7 bits from the record.
    product *= i + 1; // Multiply by the 1 based position.
    sum += (uint)product; // Add the product to the running sum.
}

byte[] result = new byte[8];
for (int i = 0; i < 8; i++) // if the checksum is reversed, make this:
                            // for (int i = 7; i >=0; i--) 
{
    uint current = (uint)(sum & 0x0f); // take the lowest 4 bits.
    current += zeroOffset; // Add '0'
    result[i] = (byte)current;
    sum = sum >> 4; // Right shift the bottom 4 bits off.
}

string checksum = Encoding.ASCII.GetString(result);

One note, I use the & and >> operators, which you may or may not be familiar with. The & operator is the bitwise and operator. The >> operator is logical shift right.

Share:
12,098
Mark
Author by

Mark

Updated on June 04, 2022

Comments

  • Mark
    Mark almost 2 years

    I am writing a checksum for a manifest file for a courrier based system written in C# in the .NET environment. I need to have an 8 digit field representing the checksum which is calculated as per the following:

    Record Check Sum Algorithm Form the 32-bit arithmetic sum of the products of

    • the 7 low order bits of each ASCII character in the record

    • the position of each character in the record numbered from 1 for the first character. for the length of the record up to but excluding the check sum field itself :

    Sum = Σi ASCII( ith character in the record ).( i ) where i runs over the length of the record excluding the check sum field.

    After performing this calculation, convert the resultant sum to binary and split the 32 low order bits of the Sum into eight blocks of 4 bits (octets). Note that each of the octets has a decimal number value ranging from 0 to 15.

    Add an offset of ASCII 0 ( zero ) to each octet to form an ASCII code number.

    Convert the ASCII code number to its equivalent ASCII character thus forming printable characters in the range 0123456789:;<=>?.

    Concatenate each of these characters to form a single string of eight (8) characters in overall length.

    I am not the greatest at mathematics so I am struggling to write the code correctly as per the documentation. I have written the following so far:

    byte[] sumOfAscii = null;
    
    for(int i = 1; i< recordCheckSum.Length; i++)
    {
        string indexChar = recordCheckSum.ElementAt(i).ToString();
        byte[] asciiChar = Encoding.ASCII.GetBytes(indexChar);
    
         for(int x = 0; x<asciiChar[6]; x++)
         {
            sumOfAscii += asciiChar[x];
         }
    }
    
         //Turn into octets
        byte firstOctet = 0;
    for(int i = 0;i< sumOfAscii[6]; i++)
    {
        firstOctet += recordCheckSum;
    }
    

    Where recordCheckSum is a string made up of deliveryAddresses, product names etc and excludes the 8-digit checksum.

    Any help with calculating this would be greatly appreciated as I am struggling.

  • Mark
    Mark almost 8 years
    Amazing answer! Thank you so so much!