如何找到相同校验和的校验和? (求职面试问题)

时间:2010-03-31 15:17:10

标签: algorithm

设计一个简单的算法,创建一个只包含其自身校验和的文件。

假设它是CRC-32,所以这个文件必须是4个字节长。

5 个答案:

答案 0 :(得分:33)

如果您知道算法的工作原理,可能会有一些聪明的数学方法可以找到它(或证明不存在)。

但是因为我很懒,CRC32只有2 ^ 32个值,所以我会蛮力。在等待算法遍历所有2 ^ 32值时,我会使用Google和Stack Overflow来查找某人是否有解决方案。

对于SHA-1,MD5和其他或多或少的加密安全算法,我会受到设计这些算法并放弃的数学家的威胁。

编辑1:暴力逼迫......到目前为止,我找到了一个; CC4FBB6A采用big-endian编码。可能还有更多。我正在检查4种不同的编码:ASCII大写和小写,以及二进制大端和小端。

编辑2:蛮力完成。结果如下:

CC4FBB6A(big-endian)
FFFFFFFF(big-endian& little-endian)
32F3B737(大写ASCII)

代码为here。在我的超频C2Q6600上运行大约需要1.5小时。现在该程序是单线程的,但是很容易使它成为多线程的,这将提供良好的线性可伸缩性。

答案 1 :(得分:10)

除了Jerry Coffin和Esko Luontola对一个不寻常问题的良好答案外,我想补充一下:

在数学上,我们正在寻找X,使得F(X)= X,其中F是校验和函数,X是数据本身。 由于校验和的输出是固定大小的,并且我们要查找的输入具有相同的大小,无法保证这样的X甚至存在!很可能每个输入值都是固定大小与该大小的不同值相关。

编辑:你的问题没有指明校验和应该在文件中格式化的确切方式,所以我假设你的意思是校验和的字节表示。当字符串和编码以及格式化字符串出现时,事情变得更加复杂。

答案 2 :(得分:1)

缺乏相反的任何具体指导,我将不存在的数据的校验和定义为不存在的校验和,因此创建一个空文件将满足要求。

另一种典型的方法是负校验和 - 即在数据写入之后,您写入一个值,使整个文件的校验和(包括校验和)变为零。在这种情况下,你写一个0的校验和,这一切都可以解决。

答案 3 :(得分:1)

蛮力。这是Adler32,我之前没有实现过,也没有打扰测试,所以我很可能搞砸了。但是,我不希望修正后的版本运行得慢得多,除非我做了一些非常错误的事情。

这假设32位校验和值写入文件little-endian(我没有找到带有big-endian的固定点):

#include <iostream>
#include <stdint.h>
#include <iomanip>

const int modulus = 65521;

void checkAllAdlers(uint32_t sofar, int depth, uint32_t a, uint32_t b) {
    if (depth == 4) {
        if ((b << 16) + a == sofar) {
            std::cout << "Got a fixed point: 0x" << 
                std::hex << std::setw(8) << std::setfill('0') << 
                sofar << "\n";
        }
        return;
    }
    for (uint32_t i = 0; i < 256; ++i) {
        uint32_t newa = a + i;
        if (newa >= modulus) newa -= modulus;
        uint32_t newb = b + a;
        if (newb >= modulus) newb -= modulus;

        checkAllAdlers(sofar + (i << (depth*8)), depth + 1, newa, newb);
    }
    return;
}

int main() {
    checkAllAdlers(0, 0, 1, 0);
}

输出:

$ g++     adler32fp.cpp   -o adler32fp -O3 && time ./adler32fp
Got a fixed point: 0x03fb01fe

real    0m31.215s
user    0m30.326s
sys     0m0.015s

[编辑:已经修复了几个错误,我对这段代码的正确性无任何信心;-)无论如何,你得到了一个想法:32位校验和只使用输入的每个字节一次对于暴力非常便宜。校验和通常设计为快速计算,而散列通常要慢得多,即使它们具有表面上类似的效果。如果您的校验和是“2轮Adler32”(意味着目标校验和是计算校验和然后计算校验和的校验和的结果)那么我的递归方法将无助于这么多,并且会有相对较少的具有公共前缀的输入之间通用。 MD5有4轮,SHA-512有80轮。]

答案 4 :(得分:0)

蛮力。 CRC-32为您提供一个长度为8的字符串,其中包含A-F的数字和字母(换句话说,它是十六进制数字)。尝试每种组合,给你16 8 =多种可能性。然后散列每种可能性并查看它是否为您提供原始字符串。

您可以尝试通过假设解决方案将使用每个字符不超过两次或三次来尝试优化它,这可能会使它更快完成。

如果您可以访问CRC32实现,您也可以尝试破解算法并更快地找到解决方案,但我不知道您是如何做到的。