【问题标题】:Is this the right way to find a checksum?这是找到校验和的正确方法吗?
【发布时间】:2015-12-25 06:19:08
【问题描述】:

我正在尝试计算某些数据的校​​验和。这是代码:

#include <stdio.h>
#include <string.h>

int main()
{
    char MyArray[] = "my secret data";
    char checksum = 0;
    int SizeOfArray = strlen(MyArray);

    for(int x = 0; x < SizeOfArray; x++)
    {
          checksum += MyArray[x];
    }
    printf("Sum of the bytes for MyArray is: %d\n", checksum);

    printf("The checksum: \n");
    checksum = (checksum ^ 0xFF);
    printf("%d\n",checksum);
}

输出:

Sum of the bytes for MyArray is: 70
The checksum:
-71

代码中的修改:

#include <stdio.h>
#include <string.h>

int main()
{
    char MyArray[] = "my secret data";
    char checksum = 0; // could be an int if preferred
    int SizeOfArray = strlen(MyArray);

    for(int x = 0; x < SizeOfArray; x++)
    {
          checksum += MyArray[x];
    }
    printf("Sum of the bytes for MyArray is: %d\n", checksum);

    //Perform bitwise inversion
    checksum=~checksum;
    //Increment
    checksum++;
    printf("Checksum for MyArray is: %d\n", checksum);
    }

输出:

Sum of the bytes for MyArray is: 70
Checksum for MyArray is: -70

为什么要修改校验和值?不同的算法会提供不同的校验和吗?

最终价值有什么用处?好吧,实际上我不清楚校验和及其在数据验证中的用途。我在网上搜索了很多文章,但仍然不清楚。希望我今天能在这里了解校验和。

【问题讨论】:

  • 这是一个很差的校验和。两个随机文件将具有相同的校验和,概率为 1/256。这对于实际应用来说是相当无用的。
  • @n.m.感谢您的评论。你能添加一个答案并解释一下校验和吗?
  • 考虑一种情况,发件人发送例如一个文件,带有校验和给任何人。发送时会出错,因此更改了一位。接收方会得到损坏的文件,所以他会用与发送方相同的算法计算校验和,并与接收方的校验和进行比较。它会有所不同,因此他会知道此消息已损坏,因此接收者可以要求发送者重新发送文件。
  • 这里有一个更好的校验和算法:en.wikipedia.org/wiki/Adler-32 还有很多其他不同的速度、复杂性和质量。
  • 看下面的答案,不错的

标签: c checksum


【解决方案1】:

在考虑如何生成校验和之前,您需要了解什么是校验和。假设通过不可靠的通信通道(例如网络连接)发送数据的问题。您需要确保没有影响您的消息的干扰。

执行此操作的一种方法是发送消息两次,并检查差异(实际上,在两个消息的传输过程中发生完全相同的错误的可能性很小)。但是,这需要使用相当多的带宽(发送两次消息)。

一种更有效的方法是根据消息计算一个值并将其附加到消息中。然后接收者应用相同的函数并检查值是否相同。

举个更直观的例子,一本书的校验和可能是页数。你从图书馆买了一本书并数了数它的页数。如果页数不是你预期的,那就有问题了。

您实现了一个特定的校验和函数(总和的 LSB),这很好。所有校验和函数都有一些您应该注意的属性,但关键是没有正确的方法来计算校验和。有许多函数可以用于此目的。

【讨论】:

  • 在问题中检查我的新代码,为什么输出不一样!?
  • 因为通过执行按位补码并将 1 加到一个整数上,您计算它是负数。这就是计算机的工作方式,在这种情况下,校验和基本上是字节总和的负数。
  • 但这在校验和中将如何工作?所以接收者也使用相同的程序并输入秘密数据并检查值?如果它与发件人发送时相同,那么是否没有丢失或损坏?就是这个?使用 2 的补码和使用 0XFF 进行异或有什么区别??
  • 没有“秘密”数据。只是数据。基本上接收方重新计算校验和并检查是否与发送方计算的相同。
【解决方案2】:

这是校验和算法的:生成校验和的方式以及检查它的方式在某种程度上是对称

  1. 关于校验和

校验和通常用于验证数据的完整性,尤其是在嘈杂/不可靠的通信通道上。因此,它主要用于错误检测。也就是说,知道收到的数据是否正确

这与 纠错 完全不同。因为它的用途不仅仅是检查是否有错误,还可以纠正错误。

错误检测和错误纠正都有开销(或增广)数据。即,不属于原始数据的一部分,但添加到原始数据中的数据是为了检查原始数据是否被更改(例如在案例或错误检测中)或纠正它(例如在大小写或错误更正)。

与错误检测算法不同,纠错算法的开销数据大小往往与原始数据按比例增长(因为您拥有的数据越多,恢复它所需的开销就越大)。

我们通常不希望开销数据很大,因为大数据意味着我们需要处理更多资源(即处理时间、传输时间等)。因此,从这个意义上说,良好校验和算法通常是使用最少数量的开销数据来检测错误但具有很好的稳健性(极少产生错误结果)。

有了这样的理解,问题就出在了,因为校验和的稳健性实际上不仅取决于算法,还取决于通道特性。某些通道可能容易出现某些错误,而其他通道可能会出现不同的错误。

然而,一般来说,有一些校验和比其他校验和更受欢迎和更健壮。后者,部分是因为它具有确保它在大多数(如果不是全部)通道中都具有鲁棒性的固有属性(我最喜欢的错误检测算法之一是 CRC - 循环冗余校验,因为它具有该固有属性)。 但是对于每个场景都没有完美的校验和,这真的取决于使用和场景。

但是,您仍然可以测量 robustness 的校验和算法。并且有一种数学方法可以做到这一点,我认为这超出了本次讨论的范围。因此,在这些意义上,某些校验和可以说比其他校验和弱。您在问题中显示的校验和也是弱校验和,因为它们可能比强校验和(例如 CRC)更容易产生错误结果。

  1. 关于代码

8 位 0xFF 的 XOR 完全等同于对值进行二进制反转,而且不难看出。

与 0xFF 异或

1110 0010
1111 1111
--------- XOR
0001 1101 //notice that this is exactly the same as binary inverting!

因此,当您对 0xFF 和 ~checksum 进行异或运算时,您会得到相同的结果 -71(并且由于您的数据类型是 char,因此它具有负数)。然后将其增加 1,从而得到 -70。

  1. 关于 2' 补码

二进制补码是对二进制数的数学运算,以及基于此运算的二进制有符号数表示。它在计算中的广泛使用使其成为基数补码的最重要示例。 (wikipedia)

换句话说,2' 补码是找到一个值的负表示(在计算机二进制中),它的方法是,正如你所做的那样,通过反转它的所有位,然后加一。这就是为什么你得到 -70 by 2' 补充 70。但这确实意味着 2' 补码和 0xFF 异或是相同,并且正如您通过示例所看到的,它确实不一样。

0xFF 对 8 位数据执行的 XOR 操作只是 相当于反转其所有位。它不会添加一个

  1. 关于读取add/read checksum的方式

由于校验和用于了解数据的完整性(无论是否更改),人们试图找到最佳实践来做到这一点。您所做的实际上是通过 2' 补码或与 0xFF 进行异或来获得校验和。

他们就是这样做的:

  • 用于 2' 补码校验和。 假设您的消息长度为 N。由于您通过 N 个数字的总和得到的结果是,比如说,70。然后通过添加 2' 补码校验和(即 -70),在接收方,您只需要将所有 N+1 条消息(包括校验和)相加,如果消息未更改,您应该得到 0。这是正确使用 2' 补码校验和的方法。
  • 对于 0xFF 的异或 同样,使用与前面相同的示例,如果将所有 N+1 条消息(包括校验和)相加,则应该得到 -1。由于 -1 的十六进制表示是 8 位有符号的 0xFF,因此 通过将结果 (-1) 与 0xFF 进行异或运算,如果消息不包含错误,您应该得到 0xFF ^ 0xFF = 0

因此在这两种情况下,您只需要通过检查最终结果是否为 0(无错误)来检查消息是否包含错误! 这通常适用于校验和算法!

这是校验和算法的:生成校验和的方式以及检查方式是否以某种方式对称

【讨论】:

【解决方案3】:

校验和通常用于检测数据的变化。通信、加密/签名等...校验和无处不在。

校验和如何有用?

  • 它检测到例如 1 位的变化
  • 它甚至可以在超过 1 位更改时检测到更改

这可能看起来自相矛盾,但是当只有 1 位更改时,您的校验和就会起作用。但是,采取

(A) checksum += 0x11 instead of 0x10

以后

(B) checksum += 0x30 instead of 0x31

在 (A) 中,校验和将为 -1...,在 (B) 中,校验和为 +1。加减 1 == 0。这两个错误不会被您的校验和检测到。

基本上,校验和的质量取决于

  • 关于校验和的长度(校验和越大,它将包含更大的数据,没有“循环”(一个字节只有 256 个可能的校验和,2 个字节有 65536 ;请注意,在上面的情况下)使用不会改变结果的算法)

  • 校验和计算的质量,以尽可能防止两个差异相互抵消。

有许多可用的算法。 This answer on SO 是一个好的开始。

【讨论】:

  • 在问题中检查我的新代码,为什么输出不一样!?
  • 在第二个中,1 被添加到校验和中......更改校验和 计算后没有任何好处。请参阅我建议的链接和其他算法来构建强大的校验和。
猜你喜欢
  • 2013-04-25
  • 1970-01-01
  • 1970-01-01
  • 2013-09-25
  • 1970-01-01
  • 1970-01-01
  • 2015-06-30
  • 1970-01-01
  • 2023-02-15
相关资源
最近更新 更多