从种子文件中提取SHA1哈希值

25

我已经查看了相关的答案,但似乎只有能够自动完成此任务的软件。请问是否有人知道如何在Python中实现此功能?


7
Torrent文件存储共享文件每个分片的SHA1哈希值以及种子元数据(元信息哈希)的SHA1哈希值。您需要哪个哈希值? - Alex Jasmin
这将是每个文件块的哈希值。该文件是否还包含用于检查错误的已完成文件的哈希值? - user271528
3
一些.torrent文件包括每个文件的MD5哈希值,但这是文件格式的可选扩展。当然,可以使用片段哈希来检查文件的有效性。您只需检查所有片段是否存在,并且它们是否都具有正确的哈希值即可。 - Alex Jasmin
4个回答

34

我写了一段Python代码,用于验证已下载的文件的哈希值与.torrent文件中的哈希值是否匹配。如果你想检查下载文件是否损坏,你可能会发现这个代码很有用。

你需要使用bencode包来使用此代码。Bencode是.torrent文件中使用的序列化格式。它可以像JSON一样编组列表、字典、字符串和数字。

该代码获取了info['pieces']字符串中包含的哈希值:

torrent_file = open(sys.argv[1], "rb")
metainfo = bencode.bdecode(torrent_file.read())
info = metainfo['info']
pieces = StringIO.StringIO(info['pieces'])

这个字符串包含了一系列20字节的哈希值(每个块一个)。然后,这些哈希值会与磁盘文件中每个块的哈希值进行比较。

这段代码中唯一复杂的部分是处理多文件种子,因为单个种子“块”可以跨越多个文件 (内部 BitTorrent 将多文件下载视为单个连续文件)。我使用生成器函数 pieces_generator() 来抽象出这一点。

你可能想阅读BitTorrent规范以更深入地理解这个过程。

完整代码如下:

import sys, os, hashlib, StringIO, bencode

def pieces_generator(info):
    """Yield pieces from download file(s)."""
    piece_length = info['piece length']
    if 'files' in info: # yield pieces from a multi-file torrent
        piece = ""
        for file_info in info['files']:
            path = os.sep.join([info['name']] + file_info['path'])
            print path
            sfile = open(path.decode('UTF-8'), "rb")
            while True:
                piece += sfile.read(piece_length-len(piece))
                if len(piece) != piece_length:
                    sfile.close()
                    break
                yield piece
                piece = ""
        if piece != "":
            yield piece
    else: # yield pieces from a single file torrent
        path = info['name']
        print path
        sfile = open(path.decode('UTF-8'), "rb")
        while True:
            piece = sfile.read(piece_length)
            if not piece:
                sfile.close()
                return
            yield piece

def corruption_failure():
    """Display error message and exit"""
    print("download corrupted")
    exit(1)

def main():
    # Open torrent file
    torrent_file = open(sys.argv[1], "rb")
    metainfo = bencode.bdecode(torrent_file.read())
    info = metainfo['info']
    pieces = StringIO.StringIO(info['pieces'])
    # Iterate through pieces
    for piece in pieces_generator(info):
        # Compare piece hash with expected hash
        piece_hash = hashlib.sha1(piece).digest()
        if (piece_hash != pieces.read(20)):
            corruption_failure()
    # ensure we've read all pieces 
    if pieces.read():
        corruption_failure()

if __name__ == "__main__":
    main()

不知道这是否解决了原帖的问题,但它确实解决了我的问题(一旦我解决了bencode包的问题:http://stackoverflow.com/questions/2693963/importing-bittorrent-bencode-module)。谢谢! - Nicholas Knight
我一直想要这样的工具,本来打算深入研究旧的官方Python客户端以找出如何编写一个。谢谢! - netvope
非常感谢。这个功能在大多数带有GUI的BitTorrent客户端中都可用,使用“Force Re-Check”选项或类似选项即可。我原以为你可以在下载它们之前提取或计算种子内所有文件的哈希值(md5、sha1或其他),但显然除非“.torrent”文件包含此类元数据,否则不可能实现,而这并非强制要求。 - Smeterlink
请注意,此脚本适用于python2,因此您需要安装python-pip而不是默认的python3-pip才能使其正常工作,还需运行pip2 install bencode。要启动脚本,请运行python2 yourscript.py file.torrent。如果没有问题,则只会输出被测试文件的名称,否则将输出错误信息。 - Smeterlink

18

我是如何从种子文件中提取HASH值的:

#!/usr/bin/python

import sys, os, hashlib, StringIO
import bencode



def main():
    # Open torrent file
    torrent_file = open(sys.argv[1], "rb")
    metainfo = bencode.bdecode(torrent_file.read())
    info = metainfo['info']
    print hashlib.sha1(bencode.bencode(info)).hexdigest()    

if __name__ == "__main__":
    main()

这与运行命令相同:

transmissioncli -i test.torrent 2>/dev/null | grep "^hash:" | awk '{print $2}'

希望它能有所帮助 :)


2
这将为您提供种子的信息哈希值 - Alex Jasmin
3
+1,因为这正是我访问有关“从种子文件中提取SHA1哈希”的问题时想要做的。 - sjy
不错的小代码片段,bencode 不在 Debian/Ubuntu 发行版中,所以你需要使用 pip install 安装它,或者我觉得更容易使用 python-bzrlib 中的 bzrlib.bencode 模块。 - marcz

1
如果有人想知道如何从兼容BitTorrent v2的种子中提取文件哈希值,可以使用这个命令行工具

-3
根据this,你应该能够通过搜索看起来像这样的数据部分来找到文件的md5sums: (SHA不是规范的一部分)

2
只需在您链接的页面上搜索SHA,您就会看到它被广泛使用。另外引用:“md5sum:(可选)32个字符的十六进制[...] BitTorrent根本不使用此功能,但某些程序包括了它。” - Alex Jasmin
啊,我明白了,就像 d[...]9:info_hash[length]:[SHA hash]e 这样的东西。 - Brendan Long
2
很抱歉,正如我在问题评论中提到的那样,文件本身没有SHA1哈希值,但每个小文件块都有。块哈希值非常有用,因为它们可以在下载过程的早期进行验证。一旦您拥有一个有效的块,就可以与其他对等方共享它... 话虽如此,您的md5解决方案具有简单易行的优点。只是不能保证在所有.torrent文件中都可用。 - Alex Jasmin

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