从种子文件中提取SHA1哈希

25 投票
4 回答
33653 浏览
提问于 2025-04-15 21:12

我查了一下这个问题的答案,但好像只找到了一些可以帮你自动完成的工具。有没有人知道怎么用Python来实现这个呢?

4 个回答

1

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

19

这是我从种子文件中提取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}'

希望这对你有帮助 :)

35

我写了一段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字节的哈希值(每个文件片段一个)。这些哈希值会和磁盘上文件片段的哈希值进行比较。

这段代码唯一复杂的地方是处理多文件的torrent,因为一个torrent的片段可能跨越多个文件(在内部,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()

撰写回答