【问题标题】:Calculating the info-hash of a torrent file计算种子文件的信息哈希
【发布时间】:2013-11-13 23:19:01
【问题描述】:

我正在使用 C++ 解析 torrent 文件的信息哈希,与此站点相比,我无法获得“正确”的哈希值:

http://i-tools.org/torrent

我构建了一个非常简单的玩具示例,只是为了确保我掌握了正确的基础知识。

我在 sublime 中打开了一个 .torrent 文件并剥离了除 info 字典之外的所有内容,所以我有一个如下所示的文件:

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

有人知道我在这里做错了什么吗?问题可能出在文件末尾的不可读性上吗?我需要先将其解析为十六进制吗?

【问题讨论】:

    标签: c++ hash sha1 bittorrent info-hash


    【解决方案1】:

    确保文件末尾没有换行符,您可能还想确保它以“e”结尾。

    torrent 文件的 info-hash 是 .torrent 文件中 info-section(以编码形式)的 SHA-1 哈希。本质上,您需要解码文件(它已被编码)并记住与“info”键关联的值的内容开始和结束的字节偏移量。这就是您需要散列的字节范围。

    例如,如果这是 torrent 文件:

    d4:infod6:pieces20:....................4:name4:test12:piece lengthi1024ee8:announce27:http://tracker.com/announcee
    

    你只想散列这个部分:

    d6:pieces20:....................4:name4:test12:piece lengthi1024ee
    

    有关编码的更多信息,请参阅BEP3

    【讨论】:

    • 我很确定问题出在换行符上!谢谢!上面的示例是一个玩具示例,我删除了 torrent 文件中的所有内容,但 info-dictionary 除外。
    • 请注意 Arvid 给出的示例 torrent 文件,根字典和信息字典都未排序。根据 bencode 规范,必须对字典进行排序。但是,当信息字典由于某种原因未排序时,约定的约定是将信息字典原样(未排序)散列,如上面 Arvid 所述。
    • 是的,好点。它也可以作为一个说明,即使当 bencoded 字典被错误地排序时,info-hash 仍然是逐字形式的散列。一些客户端(过去)在散列之前解码和重新编码,在这种情况下会导致不正确的信息散列。
    • 这是实现这个的方法吗?如果我错了,请纠正我。 (1) x = 4:info 在字符串中的位置 (2) y = 8:announce 在字符串中的位置 (3) 如果 x > y 或 y 为假(未找到8:announce),则 y = 的位置字符串中的最后一个e (4) infohash = sha-1 子字符串的哈希值,从 x+6 开始,到 y-1 结束。
    • 经过编码的消息形成一棵树。您可以将字典作为值嵌套在另一个字典中。仅仅查找字符串是不够的,您必须将信息字典的开头(紧跟在“4:info”之后的“d”)与其终止的“e”相匹配。中间可能还有其他的 d 和 e
    【解决方案2】:

    SHA1 计算和你写的一样简单,或多或少。如果您从库函数中得到错误答案,则错误可能出在您输入的数据中。

    我无法谈论您所做的 torrent 文件准备工作,但我确实看到了一些问题。如果您要重新访问SHA1 docs,请注意 SHA1 函数从不需要自己的摘要长度作为参数。接下来,您需要非常确定您用于读取文件内容的技术是忠实地吸收确切的字节,而不是翻译。

    一个不太重要的风格建议:利用 SHA1 的第三个参数。一般规则,最好避免在库中进行静态存储。总是喜欢提供自己的缓冲区。此外,如果您在打印函数中有一个硬编码的 20,那对于您一直在调情的摘要长度常数来说,这是一个了不起的地方。

    【讨论】:

    • 哎呀完全误读了,并认为传递给 SHA1 的长度是用于接收数组的!我解决了这个问题,显然我得到了一个不同的哈希值,但它仍然不是正确的哈希值....我认为问题出在我正在或未在做的 torrent 文件上。我修剪前面的种子文件与我输入该网页以获得不同结果的种子文件相同,因此它基本上没有损坏或任何东西。我更改了发布的代码以反映更改。
    猜你喜欢
    • 1970-01-01
    • 2012-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-23
    • 2015-12-18
    • 1970-01-01
    相关资源
    最近更新 更多