【问题标题】:Why is hashing the info dict turning out wrong?为什么散列信息字典结果错误?
【发布时间】:2017-07-11 19:42:04
【问题描述】:

多年来,我一直在尝试让 BitTorrent 在 Java 中工作的这种哈希方法,但它总是出错。

我已将其缩小到几行代码,我 99% 确定问题出在:

Bencode bencode = new Bencode(Charset.forName("UTF-8"));
byte[] fileBytes = new byte[33237];
Map<String, Object> dict = bencode.decode(fileBytes, Type.DICTIONARY);
Map infoMap = (Map) object.get("info");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
BencodeOutputStream bos = new BencodeOutputStream(baos);
bos.writeDictionary(infoMap);
byte[] hash = DigestUtils.sha1(baos.toByteArray());

我已经硬编码了数组的大小,以确保问题不是由一堆零引起的。

UTF-8US-ASCII 我都试过了。

我已经尝试使用两个不同的库进行编码,所以它可能不存在问题所在。

编辑: 从规范看来,info dict 应该被 urlencoded 为 info_hash。所以我尝试将字典写成ByteArrayOutputStream,然后对ByteArrayOutPutStream 持有的byte[] 进行sha1 哈希处理。

DigestUtils.sha1方法会提供 URL 编码器吗?找不到任何相关信息。

【问题讨论】:

  • 如有疑问,请调试
  • 我不知道你在做什么,但我查了the spec。是您要计算的info_hash 吗?它说应该是info 的值,而不是pieces
  • @thatotherguy 阅读时似乎是这样,是的。我尝试的时候没有用。在您看来,您是否会假设信息图已经进行了 sha1 编码?读起来好像是这样,但同时又很模糊。
  • 信息映射被编码:“来自 Metainfo 文件的信息键值的 urlencoded 20 字节 SHA1 哈希。请注意,该值将是一个编码字典”。我如何运行您的示例?您不提供任何输入或输出数据
  • 谢谢。看来我的代码现在正在解码大字典,获取解码的信息字典,对其进行编码,然后进行 sha1 散列。这似乎不是让它工作的合理流程吗?

标签: java bittorrent bencoding


【解决方案1】:

正如 Encombe 所指出的,问题在于编码。在 Bencode 规范中,它谈到了 byte strings,这似乎表明它只是一个没有任何编码的数据流。

我查看的两个库都将所有字节字符串转换为某种编码,因此我编写了一个 Bencode 库,该库仅在特别要求时才进行转换。

上面的代码基本上是正确的,但这里是我现在使用的客户端代码:

public void readManifest() throws IOException, Exception {
    byte[] fileBytes = FileUtils.readFileToByteArray(file);
    ByteArrayInputStream bis = new ByteArrayInputStream(fileBytes);
    BDecoder decoder = new BDecoder(bis, "UTF-8");
    BDict dict = decoder.decodeDict();
    Map<String, Object> valueMap = dict.getValue();
    infoMap = (Map<String, Object>) valueMap.get("info");
}

public String hash() throws Exception {
    if (hash == null) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        BEncoder encoder = new BEncoder(baos, "UTF-8");
        encoder.encodeDict(infoMap);
        hash = DigestUtils.sha1Hex(baos.toByteArray());
    }
    return hash;
}

【讨论】:

  • 好。您可以通过将 d4:infod4:name5:b.txt6:lengthi1e12:piece lengthi32768e6:pieces20:1234567890abcdefghijee 保存为 unsort_dict.torrent 来验证它是否可以处理 special case of a unsorted info-dict 它应该具有 info_hash:34FCC6C1ACC8C8A56DE3C2EF20924043CC51685E
  • @Encombe 我收到了那个哈希,是的。我使用的是 LinkedHashMap,因此所有内容的排序方式与读取时相同。
  • 小提示:虽然 100% 正确的是,经过编码的“字符串”实际上是任意字节序列(BEP52 对此进行了澄清),但可以使用 ISO 8859-1 作为解决方法将它们视为字符串,因为它是 1: 1 将原始字节映射到 unicode 代码点(即 java 中的 char 值)。但这是一个 hack,因为如果这些 String 实例实际上应该是 UTF8,它将包含乱码数据。但是,如果必须通过需要字符串的 API 传递字节数据,这仍然是一个有用的技巧。
猜你喜欢
  • 1970-01-01
  • 2014-01-03
  • 1970-01-01
  • 2021-08-06
  • 2020-02-18
  • 2011-08-18
  • 1970-01-01
  • 1970-01-01
  • 2012-02-28
相关资源
最近更新 更多