【问题标题】:sha256 sum does not match the gzip command outputsha256 sum 与 gzip 命令输出不匹配
【发布时间】:2018-12-14 20:59:20
【问题描述】:

我正在尝试在 Go 中计算 gzip 压缩文件的 sha256 和,但我的输出与 gzip 命令的输出不匹配。

我有一个函数 Compress 可以压缩 io.Reader 的内容,在我的例子中是一个文件。

func Compress(r io.Reader) (io.Reader, error) {
    var buf bytes.Buffer
    zw := gzip.NewWriter(&buf)
    if _, err := io.Copy(zw, r); err != nil {
        return nil, err
    }
    if err := zw.Close(); err != nil {
        return nil, err
    }
    return &buf, nil
}

然后我有一个函数Sum256 计算读取器的 sha256 和。

func Sum256(r io.Reader) (sum []byte, err error) {
    h := sha256.New()
    if _, err := io.Copy(h, r); err != nil {
        return nil, err
    }
    return h.Sum(nil), nil
}

我的 main 函数打开一个文件,对其进行 gzip 压缩,然后计算压缩内容的 sha256 和。问题是输出与gzip 命令的输出不匹配。输入文件hello.txt 包含一个单词hello,末尾没有换行符。

func main() {
    uncompressed, err := os.Open("hello.txt")
    if err != nil {
        log.Fatal(err)
    }
    defer uncompressed.Close()

    sum, err := Sum256(uncompressed)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%x  %s\n", sum, uncompressed.Name())

    uncompressed.Seek(0, 0)
    compressed, err := Compress(uncompressed)
    if err != nil {
        log.Fatal(err)
    }

    sum, err = Sum256(compressed)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%x  %s.gz\n", sum, uncompressed.Name())
}

gzip 结果:

$ sha256sum hello.txt
2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824  hello.txt

$ gzip -c hello.txt | sha256sum
809d7f11e97291d06189e82ca09a1a0a4a66a3c85a24ac7ff389ae6fbe02bcce  -

$ gzip -nc hello.txt | sha256sum
f901eda57fd86d4239806fd4b76f64036c1c20711267a7bc776ab2aa45069b2a  -

我的程序结果:

$ go run main.go
# match
2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824  hello.txt
# mismatch
3429ae8bc6346f1e4fb67b7d788f85f4637e726a725cf4b66c521903d0ab3b07  hello.txt.gz

知道为什么输出不匹配或如何解决这个问题吗?我曾尝试使用io.Pipeioutil.TempFile 文件和其他解决相同问题的方法。

【问题讨论】:

  • Gzip 不是唯一/单一/确定性压缩。不同的算法可能会产生不同的压缩输出。对于相同的输入,不同的 gzip 算法产生不同的输出是完全可以的。
  • Gzip 不需要为特定输入生成特定输出。它只需要生成与 gzip 兼容的输出即可解压缩。

标签: go hash gzip


【解决方案1】:

特别要注意,如果你运行命令:

gzip -c hello.txt

输出将包含文件名 hello.txt。您可以使用 hexdump 看到这一点:

$触摸你好.txt; gzip -c hello.txt |十六进制转储 -C 00000000 1f 8b 08 08 广告 1b 14 5c 00 03 68 65 6c 6c 6f 2e |.......\..你好。| 00000010 74 78 74 00 03 00 00 00 00 00 00 00 00 00 |txt…………| 0000001e

如果您只是将数据复制到程序中的 Gzip 流中,则文件名将不存在。所以你必须得到不同的结果,SHA-256总和应该不同。

但是,即使您修复了这个特定的缺陷......您仍然不能保证通过在同一文件上运行 Gzip 获得相同的结果。

如果您希望校验和相同,请改为对解压缩的数据运行校验和。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-10
    • 1970-01-01
    • 2021-06-15
    • 1970-01-01
    • 2020-10-18
    相关资源
    最近更新 更多