追加切片后,计算sha256会得出不同的结果,具体取决于是否在之前打印出切片 [英] Calculating sha256 gives different results after appending slices depending on if I print out the slice before or not

查看:55
本文介绍了追加切片后,计算sha256会得出不同的结果,具体取决于是否在之前打印出切片的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

  func getHash(input1字符串,input2hex字符串,input3hex字符串,input4字符串)(string,error){input1bytes:= [] byte(input1)firstHalfinput1Bytes:= input1bytes [:8]secondHalfinput1Bytes:= input1bytes [8:16]input4Bytes:= [] byte(input4)input3Bytes,err:= hex.DecodeString(input3hex)如果err!= nil {fmt.Println("err" + err.Error())}input2Bytes,err:= hex.DecodeString(input2hex)如果err!= nil {fmt.Println("err" + err.Error())}fullHashInputBytes:= append(firstHalfinput1Bytes,input2Bytes ...)//这是局部更改输出的可选打印:fmt.Println("fullHashInputBytes",fullHashInputBytes)fullHashInputBytes = append(fullHashInputBytes,secondHalfinput1Bytes ...)fullHashInputBytes = append(fullHashInputBytes,input3Bytes ...)fullHashInputBytes = append(fullHashInputBytes,input4Bytes ...)sha256:= sha256.Sum256(fullHashInputBytes)对于我:= 0;我<8;我++ {sha256 [i + 16] ^ = sha256 [i + 24]}哈希:= hex.EncodeToString(sha256 [:24])fmt.Println("hash",hash)返回哈希,无} 

操场上的日志是

 你好,操场fullHashInputBytes [84 72 73 83 73 83 78 79 30 0 22 121 57 203 102 102 148 210 196 34172 210 8 160 7]哈希0161d9de8dd815ca9f4e1c7bb8684562542cc24b1026321c哈希0161d9de8dd815ca9f4e1c7bb8684562542cc24b1026321c 

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

 你好,操场fullHashInputBytes [84 72 73 83 73 83 78 79 30 0 22 121 57 203 102 148 210 196 34172 210 8 160 7]哈希0161d9de8dd815ca9f4e1c7bb8684562542cc24b1026321c哈希d2de4ffb4e8790b8fd1ceeba726436fd97875a5740c27b47 

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

解决方案

这是因为您通过先附加到 firstHalfinput1Bytes 来创建 fullHashInputBytes :

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

这是 input1bytes 的一部分:

  firstHalfinput1Bytes:= input1bytes [:8] 

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

  secondHalfinput1Bytes:= input1bytes [8:16] 

因此,稍后再将 secondHalfinput1Bytes 附加到 fullHashInputBytes 时,可能最终会附加不同的内容.

这很可能不是您想要的.

如果您做到干净":

  var fullHashInputBytes [] bytefullHashInputBytes = append(fullHashInputBytes,firstHalfinput1Bytes ...)fullHashInputBytes = append(fullHashInputBytes,input2Bytes ...)//可选打印不会更改任何内容:fmt.Println("fullHashInputBytes",fullHashInputBytes)//...其余的附件... 

如果在本地或在转到游乐场上运行,则输出将相同./p>

为什么行为异常?

您的第一个附加对象是否覆盖 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 上,而是追加到新的切片上.

I am calculating a sha256 from multiple strings. I convert them to byte slices in a specific way and append them all together and then compute the hash using the built in library. However, depending on if I print out the slice before calculating the sha256 or not I wierdly get different results. When testing it in playground I cannot reproduce it.

The tested code can been seen and run on https://play.golang.org/p/z8XKx-p9huG where it actually gives the same result in both cases.

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
}

The logs on the playground are

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

but if I run EXACTLY the same code locally (just copy-paste it into a main.go and do go run main.go or go build . and ./test) I get

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

I'm using go version 1.13.4 but had the same issue with 1.10.4. I also get the same issue on both my local machine and when deployed to our server.

解决方案

This is because you create fullHashInputBytes by appending to firstHalfinput1Bytes first:

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

Which is a slice of the input1bytes:

firstHalfinput1Bytes := input1bytes[:8]

So the first append may overwrite the contents of input1bytes at indices higher than 7, which is actually the content of secondHalfinput1Bytes:

secondHalfinput1Bytes := input1bytes[8:16]

So later when you also append secondHalfinput1Bytes to fullHashInputBytes, you might end up appending different contents.

This is most likely not what you want.

If you do it "clean":

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...

Then output will be the same if you run it locally or on the Go Playground.

Why the deviant behavior?

Whether your first append overwrites input1bytes depends on whether the append can be performed "in-place", without having to allocate a new backing array, which depends on the capacity of firstHalfinput1Bytes, which is "inherited" from input1bytes:

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

(You may read about it in greater detail here: Concatenate two slices in Go).

The conversion []byte(input) only guarantees to have the bytes of input1, but the spec does not dictate how big the capacity of the resulting slice should be. And it may depend on platform / architecture. On the Go Playground the above conversion results in capacity = 16, on my local amd64 architecture I get capacity = 32.

One final piece: the capacity used for the slice of the result of the []byte(input) conversion may depend on what you do with the result slice. The compiler may make decisions to use lower capacity if you pass it to fmt.Println() as this signals that the slice may escape. Again, the decision made by the compiler is out of your hands.

Don't rely on such thing, do not write code that relies on the capacity of the resulting slice of a conversion. Do it in the "clean" way: do not append to firstHalfinput1Bytes but to a new slice.

这篇关于追加切片后,计算sha256会得出不同的结果,具体取决于是否在之前打印出切片的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆