在C#中计算Internet(又名IP,又名RFC791)校验和

时间:2010-02-02 22:03:52

标签: c# checksum ip-protocol

有趣的是,我可以在除C#之外的几乎所有语言中找到Internet Checksum的实现。有没有人有分享的实现?

请记住,internet protocol指定:

“校验和字段是该字符串的16位补码     标头中所有16位字的补码和。出于...的目的     计算校验和时,校验和字段的值为零。“

可以从Dr. Math找到更多解释。

有一些efficiency pointers可用,但这对我来说并不是一个大问题。

请包含您的测试! (编辑:关于测试其他人的代码的有效评论 - 但是我要离开协议并且没有我自己的测试向量,而是宁愿进行单元测试而不是投入生产以查看它是否与当前使用的相匹配! ; - )

编辑:这是我想出的一些单元测试。他们测试一个遍历整个字节集的扩展方法。如果您在测试中发现错误,请发表评论。

[TestMethod()]
public void InternetChecksum_SimplestValidValue_ShouldMatch()
{
    IEnumerable<byte> value = new byte[1]; // should work for any-length array of zeros
    ushort expected = 0xFFFF;

    ushort actual = value.InternetChecksum();

    Assert.AreEqual(expected, actual);
}

[TestMethod()]
public void InternetChecksum_ValidSingleByteExtreme_ShouldMatch()
{
    IEnumerable<byte> value = new byte[]{0xFF};
    ushort expected = 0xFF;

    ushort actual = value.InternetChecksum();

    Assert.AreEqual(expected, actual);
}

[TestMethod()]
public void InternetChecksum_ValidMultiByteExtrema_ShouldMatch()
{
    IEnumerable<byte> value = new byte[] { 0x00, 0xFF };
    ushort expected = 0xFF00;

    ushort actual = value.InternetChecksum();

    Assert.AreEqual(expected, actual);
}

2 个答案:

答案 0 :(得分:4)

我知道我把这个存放在某个地方...... http://cyb3rspy.wordpress.com/2008/03/27/ip-header-checksum-function-in-c/

答案 1 :(得分:1)

好吧,我从旧的代码库中挖出了一个实现,它通过了我在问题中指定的测试,所以这里是(作为扩展方法):

public static ushort InternetChecksum(this IEnumerable<byte> value)
{
    byte[] buffer = value.ToArray();
    int length = buffer.Length;
    int i = 0;
    UInt32 sum = 0;
    UInt32 data = 0;
    while (length > 1)
    {
        data = 0;
        data = (UInt32)(
        ((UInt32)(buffer[i]) << 8)
        |
        ((UInt32)(buffer[i + 1]) & 0xFF)
        );

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

        i += 2;
        length -= 2;
    }

    if (length > 0)
    {
        sum += (UInt32)(buffer[i] << 8);
        //sum += (UInt32)(buffer[i]);
        if ((sum & 0xFFFF0000) > 0)
        {
            sum = sum & 0xFFFF;
            sum += 1;
        }
    }
    sum = ~sum;
    sum = sum & 0xFFFF;
    return (UInt16)sum;
}