如何在特定位置将文件的CRC32包含到其中?

时间:2018-12-22 12:41:01

标签: file checksum crc32

我正在使用一个数据生成器,以将二进制文件生成到一个封闭的系统中,对于该系统,我们假设没有外部攻击的风险,也没有任何恶意的意图。

这个想法是找到一种方法来使这些二进制文件包含一种快速且相对可靠的方法,以确保它们不会在工具链中意外损坏,因此该二进制文件的最终接收者可以检查文件完整性而无需任何其他资源(例如作为包含校验和的file.sha1)。

由于它可能会影响解决方案,因此我必须告诉您,二进制文件的大小可能为1 kB,最多可能为300 MB。在文件中有一个特定的位置,我可以在其中放置所有文件的任何固定长度的校验和。位置已经定义,我不能更改,但是可以更改长度。

因此,如果解决方案是在此位置包括128个字节的数据以适合任何可能的情况,则所有二进制文件在此位置都将包含此字节长度。

由于在检查之前不需要将其加密就不可能在其中包含文件的加密哈希,因此我读到CRC32是实现此目标的好方法。我还了解了诸如“欺骗”或“ CRC操纵器”之类的实用程序,但是它们似乎并不能满足我的情况。

这是我需要的一个简单例子。让我们考虑一个二进制文件:

               This position will never change
               v
1011101100010010000000010110011100100110
               ^^^^^^^^
               This is the fixed-length part dedicated to file integrity check

我想找到一种方法来插入正确的校验和,以便包含校验和的完整文件具有相同的校验和。也许已经有一个已知程序了?

感谢您的支持

2 个答案:

答案 0 :(得分:0)

您仍然可以使用加密哈希,只需复制哈希,然后在检查哈希之前将哈希块清零即可。同样,在对文件进行哈希处理之前,您需要确保哈希块全为零。

您可以在外壳程序脚本中使用dd将数据复制到文件中的特定字节位置。或者,您可以使用任何良好的编程语言来使用标准的随机访问文件I / O。

但是,我会问这种复杂性是否真的必要。更标准的解决方案是将散列单独放置(在单独的文件中,或者在文件的开头或结尾),这可以完全避免此问题。根据文件格式,将哈希放在文件末尾可能会使读取文件更加不便,但是将哈希放在文件开头应该不会有问题。

答案 1 :(得分:0)

您需要计算CRC向前和向后插入点的位置,然后将这两个位置的异或值放在此处。那么整个事物的CRC将是一个常数。 (假设没有损坏。)

这是示例代码:

// Example of the generation of a "middle" CRC, which is inserted somewhere in
// the middle of a sequence, where the CRC is generated such that the CRC of
// the complete sequence will be zero. This particular CRC has no pre or post
// processing.
//
// Placed into the public domain by Mark Adler, 11 May 2016.

#include <stddef.h>         // for size_t
#include <stdint.h>         // for uint32_t and uint64_t

#define POLY 0xedb88320     // CRC polynomial

// Byte-wise CRC tables for forward and reverse calculations.
uint32_t crc_forward_table[256];
uint32_t crc_reverse_table[256];

// Fill in CRC tables using bit-wise calculations.
void crc32_make_tables(void) {
    for (uint32_t n = 0; n < 256; n++) {
        uint32_t crc = n;
        for (int k = 0; k < 8; k++)
            crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
        crc_forward_table[n] = crc;
        crc_reverse_table[crc >> 24] = (crc << 8) ^ n;
    }
}

// Return the forward CRC of buf[0..len-1], starting with crc at the front.
uint32_t crc32(uint32_t crc, unsigned char *buf, size_t len) {
    for (size_t n = 0; n < len; n++)
        crc = (crc >> 8) ^ crc_forward_table[(crc ^ buf[n]) & 0xff];
    return crc;
}

// Return the reverse CRC of buf[0..len-1], starting with crc at the end.
uint32_t crc32_reverse(uint32_t crc, unsigned char *buf, size_t len) {
    while (len)
        crc = (crc << 8) ^ crc_reverse_table[crc >> 24] ^ buf[--len];
    return crc;
}

// Put a 32-bit value into a byte buffer in little-endian order.
void put4(uint32_t word, unsigned char *pos) {
    pos[0] = word;
    pos[1] = word >> 8;
    pos[2] = word >> 16;
    pos[3] = word >> 24;
}

#include <stdlib.h>         // for random() and srandomdev()

// Fill dat[0..len-1] with uniformly random byte values. All of the bits from
// each random() call are used, except for possibly a few leftover at the end.
void ranfill(unsigned char *dat, size_t len) {
    uint64_t ran = 1;
    while (len) {
        if (ran < 0x100)
            ran = (ran << 31) + random();
        *dat++ = ran;
        ran >>= 8;
        len--;
    }
}

#include <stdio.h>          // for printf()

#define LEN 1024            // length of the message without the CRC

// Demonstrate the generation of a middle-CRC, using the forward and reverse
// CRC computations. Verify that the CRC of the resulting sequence is zero.
int main(void) {
    crc32_make_tables();
    srandomdev();
    unsigned char dat[LEN+4];
    ranfill(dat, LEN/2);
    put4(0, dat + LEN/2);       // put zeros where the CRC will go
    ranfill(dat + LEN/2 + 4, (LEN+1)/2);
    put4(crc32(0, dat, LEN/2) ^ crc32_reverse(0, dat + LEN/2, (LEN+1)/2 + 4),
         dat + LEN/2);          // replace the zeros with the CRC
    printf("%08x\n", crc32(0, dat, LEN+4));
    return 0;
}