小编典典

追加切片后,计算sha256会得出不同的结果,具体取决于是否在之前打印出切片

go

我正在从多个字符串计算sha256。我以特定方式将它们转换为字节片,并将它们全部附加在一起,然后使用内置库计算哈希。但是,根据是否在计算sha256之前打印出切片,我会获得不同的结果。在操场上测试时,我无法复制它。

可以看到经过测试的代码,并可以在https://play.golang.org/p/z8XKx-p9huG上运行,在两种情况下,它实际上都可以提供相同的结果。

func getHash(input1 string, input2hex string, input3hex string, input4 string) (string, error) {
    input1bytes := []byte(input1)
    firstHalfinput1Bytes := input1bytes[:8]
    secondHalfinput1Bytes := input1bytes[8:16]

    input4Bytes := []byte(input4)

    input3Bytes, err := hex.DecodeString(input3hex)
    if err != nil {
        fmt.Println("err " + err.Error())
    }

    input2Bytes, err := hex.DecodeString(input2hex)
    if err != nil {
        fmt.Println("err " + err.Error())
    }

    fullHashInputBytes := append(firstHalfinput1Bytes, input2Bytes...)
    // THIS IS THE OPTIONAL PRINT WHICH CHANGES OUTPUT LOCALLY:
    fmt.Println("fullHashInputBytes", fullHashInputBytes)
    fullHashInputBytes = append(fullHashInputBytes, secondHalfinput1Bytes...)
    fullHashInputBytes = append(fullHashInputBytes, input3Bytes...)
    fullHashInputBytes = append(fullHashInputBytes, input4Bytes...)
    sha256 := sha256.Sum256(fullHashInputBytes)
    for i := 0; i < 8; i++ {
        sha256[i+16] ^= sha256[i+24]
    }
    hash := hex.EncodeToString(sha256[:24])
    fmt.Println("hash", hash)
    return hash, nil
}

操场上的日志是

Hello, playground
fullHashInputBytes [84 72 73 83 73 83 78 79 30 0 22 121 57 203 102 148 210 196 34 172 210 8 160 7]
hash 0161d9de8dd815ca9f4e1c7bb8684562542cc24b1026321c
hash 0161d9de8dd815ca9f4e1c7bb8684562542cc24b1026321c

但是如果我在本地运行完全相同的代码(只需将其复制粘贴到main.go中,然后执行go run main.goor go build .和和./test),我会得到

Hello, playground
fullHashInputBytes [84 72 73 83 73 83 78 79 30 0 22 121 57 203 102 148 210 196 34 172 210 8 160 7]
hash 0161d9de8dd815ca9f4e1c7bb8684562542cc24b1026321c
hash d2de4ffb4e8790b8fd1ceeba726436fd97875a5740c27b47

我使用的是go版本,1.13.4但与存在相同的问题1.10.4。在本地计算机上以及在将其部署到服务器时,我也会遇到相同的问题。


阅读 328

收藏
2020-07-02

共1个答案

小编典典

这是因为您fullHashInputBytes通过添加到firstHalfinput1Bytesfirst 来创建:

fullHashInputBytes := append(firstHalfinput1Bytes, input2Bytes...)

这是其中的一部分input1bytes

firstHalfinput1Bytes := input1bytes[:8]

因此,第一个附录可能会覆盖input1bytes索引高于7 的at的内容,实际上是以下内容secondHalfinput1Bytes

secondHalfinput1Bytes := input1bytes[8:16]

因此,稍后还要添加secondHalfinput1Bytes到时fullHashInputBytes,可能最终会添加不同的内容。

这很可能不是您想要的。

如果您做到“干净”:

var fullHashInputBytes []byte
fullHashInputBytes = append(fullHashInputBytes, firstHalfinput1Bytes...)
fullHashInputBytes = append(fullHashInputBytes, input2Bytes...)
// OPTIONAL print doesn't change anything:
fmt.Println("fullHashInputBytes", fullHashInputBytes)
// ...rest of your appends...

如果在本地或Go Playground上运行,则输出将相同。

为什么行为异常?

您的第一个追加input1bytes是否被覆盖取决于该追加是否可以“就地”执行而不必分配新的后备数组,这取决于firstHalfinput1Bytes“”从input1bytes以下继承的容量:

input1bytes := []byte(input1)
fmt.Println(cap(input1bytes))

转换
[]byte(input)只保证拥有的字节input1,但该规范并没有规定所产生的切片的容量有多大应该的。它可能取决于平台/体系结构。在Go
Playground上,上述转换导致capacity = 16我在本地amd64建筑上得到capacity = 32

最后一件:[]byte(input)转换结果切片所使用的容量可能取决于您对结果切片的处理方式。如果将其传递给编译器,则编译器可能会决定使用较低的容量,fmt.Println()因为这表明片可能会逃逸。再次,由编译器做出的决定是您无法控制的。

不要依靠这种东西,不要编写依赖于转换结果片的容量的代码。以“干净”的方式进行:不要追加到firstHalfinput1Bytes新的切片上。

2020-07-02