为啥散列信息字典结果错误?

Posted

技术标签:

【中文标题】为啥散列信息字典结果错误?【英文标题】: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 散列。这似乎不是让它工作的合理流程吗? 【参考方案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 传递字节数据,这仍然是一个有用的技巧。

以上是关于为啥散列信息字典结果错误?的主要内容,如果未能解决你的问题,请参考以下文章

为啥字典查找会导致“不可散列类型”错误,但使用直接值不会?

信息安全作业5 散列函数的应用及其安全性发展

为啥我应该使用 JWT 而不是简单的散列令牌

为啥intellij idea不能显示错误信息

Python中字典数据类型,字典.values()可以进行遍历,为啥不能通过角标进行获取元素?

为啥标准不提供通过内容检查散列 c 字符串的专业化