如何从json获取相同的哈希值

问题描述 投票:5回答:1

我需要签署一个JSON,但我注意到解编/编组可能会改变JSON的顺序,这可能会使签名无效。

无论如何,尽管它的顺序是从JSON字符串生成相同的哈希?

我已经看过JOSE但是找不到真正散列JSON的函数。

json go hash cryptography
1个回答
0
投票

JOSE JWS绝对会以管理签名和验证密钥为代价完成您的工作。

但是我们假设您并不真正需要JOSE中的整个密钥管理和一般加密功能,并且您并不是SUPER关注性能(因此在此过程中稍微纠结一点就可以了)。

你可以愚蠢地解组你的JSON并重新编组,然后哈希:

package main

import (
    "crypto/sha256"
    "encoding/hex"
    "fmt"
    json "encoding/json"
)

// NB These docs are strictly-speaking the same.
const DOCA = "{ \"foo\": 1.23e1, \"bar\": { \"baz\": true, \"abc\": 12 } }"
const DOCB = "{ \"bar\": { \"abc\": 12, \"baz\": true }, \"foo\": 12.3 }"

func hash(doc string) string {
    // Dumb af, but it's a cheap way to specific the most generic thing
    // you can :-/
    var v interface{}
    json.Unmarshal([]byte(doc), &v) // NB: You should handle errors :-/
    cdoc, _ := json.Marshal(v)
    sum := sha256.Sum256(cdoc)
    return hex.EncodeToString(sum[0:])
}

func main() {
    fmt.Println(DOCA)
    fmt.Printf("Hash: %s\n", hash(DOCA))
    fmt.Println(DOCB)
    fmt.Printf("Hash: %s\n", hash(DOCB))
}

该程序的输出(至少在golang docker容器中)是:

{ "foo": 1.23e1, "bar": { "baz": true, "abc": 12 } }
Hash: d50756fbb830f8335187a3f427603944c566772365d8d8e6f6760cd2868c8a73
{ "bar": { "abc": 12, "baz": true }, "foo": 12.3 }
Hash: d50756fbb830f8335187a3f427603944c566772365d8d8e6f6760cd2868c8a73

关于这种方法的好处在于,对于某些性能的成本,你可以避免在编写JSON时所做的任何愚蠢的垃圾(因此,与其他建议不同,你不必考虑你的内容)可能正在使用自定义Marshallers和诸如此类的东西)。当你在一年后的代码版本3.8中忘记这是一个问题时,这尤其是一个大问题,实现与编组顺序混淆的东西,并开始破坏事物。

当然,您始终可以将哈希添加到结果结构中,并使用地图中的额外项目再次进行编组。显然你想要优化一点性能,如果你完全担心它并正确处理错误,但无论如何这是一个很好的原型:-)

哦,如果你非常担心咬你的边缘情况,你也可以使用canonical JSON来编组,因为它是专门为这种类型的使用而设计的(但老实说,我在测试时无法想出一个例子) c-json工作的地方,但是默认的json没有)。

© www.soinside.com 2019 - 2024. All rights reserved.