计算种子文件的信息哈希值

6
我正在使用C++解析种子文件的信息散列值,与这个网站相比,我很难得到一个“正确”的散列值:http://i-tools.org/torrent
为了确保我掌握了基础知识,我构建了一个非常简单的示例。
我在Sublime中打开了一个.torrent文件,并剥离了除了信息字典以外的所有内容,所以我有一个看起来像这样的文件:
d6:lengthi729067520e4:name31:ubuntu-12.04.1-desktop-i386.iso12:piece lengthi524288e6:pieces27820:¡´E¶ˆØËš3í   ..............(more unreadable stuff.....)..........

我使用以下代码读取并解析此文件:

我使用以下代码读取并解析此文件:

#include <string>
#include <sstream>
#include <iomanip>
#include <fstream>
#include <iostream>

#include <openssl/sha.h>


void printHexRep(const unsigned char * test_sha) {

    std::cout << "CALLED HEX REP...PREPPING TO PRINT!\n";
    std::ostringstream os;
    os.fill('0');
    os << std::hex;
    for (const unsigned char * ptr = test_sha; ptr < test_sha + 20; ptr++) {

        os << std::setw(2) << (unsigned int) *ptr;
    }
    std::cout << os.str() << std::endl << std::endl;
}


int main() {

    using namespace std;

    ifstream myFile ("INFO_HASH__ubuntu-12.04.1-desktop-i386.torrent", ifstream::binary);

    //Get file length
    myFile.seekg(0, myFile.end);
    int fileLength = myFile.tellg();
    myFile.seekg(0, myFile.beg);

    char buffer[fileLength];

    myFile.read(buffer, fileLength);
    cout << "File length == " << fileLength << endl;
    cout << buffer << endl << endl;

    unsigned char datSha[20];
    SHA1((unsigned char *) buffer, fileLength, datSha);
    printHexRep(datSha);

    myFile.close();

    return 0;
}

按以下方式编译它:

g++ -o hashes info_hasher.cpp -lssl -lcrypto

我得到了以下输出:

4d0ca7e1599fbb658d886bddf3436e6543f58a8b

当我期望这个输出时:
14FFE5DD23188FD5CB53A1D47F1289DB70ABF31E

有没有人知道我在这里可能做错了什么?问题是否出在文件结尾无法读取上?我需要先解析为十六进制还是其他什么吗?

2个回答

11
请确保文件末尾没有换行符,并且最好以“e”结尾。
Torrent(种子)文件的info-hash是.torrent文件中信息部分(以bencoded形式)的SHA-1哈希值。实质上,您需要对文件进行解码(它是以bencoded形式编码的),并记住与“info”键相关联的值的内容开始和结束的字节偏移量。这就是您需要哈希的字节范围。
例如,如果这个是torrent文件:
d4:infod6:pieces20:....................4:name4:test12:piece lengthi1024ee8:announce27:http://tracker.com/announcee

您想要仅对此部分进行哈希处理:
d6:pieces20:....................4:name4:test12:piece lengthi1024ee

如需了解有关bencoding的更多信息,请参见BEP3


我非常确定问题出在换行符!谢谢! 上面的示例是一个玩具示例,我删除了种子文件中除信息字典之外的所有内容。 - Ethan
3
请注意,Arvid提供的示例种子文件中,根字典和信息字典都是未排序的。根据bencode规范,字典必须排序。然而,当某些原因导致信息字典未排序时,约定俗成的做法是将信息字典原始内容(未排序)进行哈希处理,正如Arvid所解释的那样。 - Encombe
3
是的,很好的观点。这也可以作为一个例证,即使bencoded 字典未正确排序,info-hash 仍然是原文形式的哈希值。一些客户端(过去)在哈希之前解码和重新编码,这会导致在这种情况下出现不正确的info-hash。 - Arvid
这是实现的方法吗?如果我错了,请纠正我。(1) x =字符串中“4:info”的位置 (2) y =字符串中“8:announce”的位置 (3) 如果x > y或y为假(未找到“8:announce”),则y =字符串中最后一个“e”的位置 (4) infohash =从x +6开始以y-1结束的子字符串的sha-1散列。 - Sharanya Dutta
bencoded消息形成一棵树。您可以将字典嵌套为另一个字典的值。仅查找字符串是不够的,您必须将信息字典的开头(紧随“4:info”后面的“d”)与其终止的“e”匹配起来。在其中可能会有其他d和e。 - Arvid

1
SHA1计算与您所写的一样简单,或多或少。如果从库函数中得到错误的答案,则可能是您提供给它的数据有问题。
我无法评论您做的种子文件准备工作,但我看到了一些问题。如果您重新访问SHA1文档,请注意SHA1函数从未要求其自身的摘要长度作为参数。接下来,您需要非常确定您正在使用的读取文件内容的技术是否忠实地吸收了确切的字节,没有进行转换。
一个不太重要的风格建议:利用SHA1的第三个参数。一般规则是,最好避免在库中使用静态存储。始终首选提供自己的缓冲区。此外,在您的打印函数中硬编码20的地方,正是您一直在试图使用的摘要长度常量的好地方。

哎呀,我完全误读了,以为传递给SHA1的长度是接收数组的长度!我已经修复了这个问题,显然我得到了不同的哈希值,但它仍然不正确....我认为问题出在种子文件上,可能是我做或没做的事情。我裁剪掉前面的种子文件与我输入到网页中获取不同结果的相同文件,因此它基本上没有损坏或其他问题。我更改了发布的代码以反映这些更改。 - Ethan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接