【问题标题】:How to calculate sha256 file checksum in Go如何在 Go 中计算 sha256 文件校验和
【发布时间】:2013-04-08 12:34:20
【问题描述】:

我需要用于计算 sha256 文件校验和的 Windows 实用程序,以便在我下载时 fedora 我可以从这里验证校验和:https://fedoraproject.org/static/checksums/Fedora-18-i386-CHECKSUM

来自http://support.microsoft.com/kb/889768 的 Microsoft 实用程序仅执行 md5 和 sha1。

我不想使用其他未签名且无法从 https 或我不知道的来源获得的可下载工具,因为通过未加密的连接或不受信任的连接下载未签名的代码没有任何意义源来验证另一个代码的签名以信任它。

幸运的是,谷歌提供了使用 https 进行所有下载的可能性,因此我可以通过安全连接下载 Go 并从那里开始。

下面是一个简单的代码,它可以处理小文件,但它不适用于大文件,因为它不是流式传输的。

package main

import (
    "io/ioutil"
    "crypto/sha256"
    "os"
    "log"
    "encoding/hex"
)

func main() {
    hasher := sha256.New()
    s, err := ioutil.ReadFile(os.Args[1])    
    hasher.Write(s)
    if err != nil {
        log.Fatal(err)
    }

    os.Stdout.WriteString(hex.EncodeToString(hasher.Sum(nil)))
}

如何让它使用流,以便它适用于任何文件大小。

【问题讨论】:

标签: file io cryptography go sha256


【解决方案1】:

crypto/sha256 godoc 实际上有一个 snippet 显示如何做到这一点(它与 James 的代码基本相同):

package main

import (
  "crypto/sha256"
  "fmt"
  "io"
  "log"
  "os"
)

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

  h := sha256.New()
  if _, err := io.Copy(h, f); err != nil {
    log.Fatal(err)
  }

  fmt.Printf("%x", h.Sum(nil))
}

【讨论】:

  • io.Copy 是如何工作的?文件是完全在内存中读取的,还是按...大小的块处理的?
  • 它由 32KB 的块处理:golang.org/src/io/io.go#L380 您可以通过使用 CopyBuffer 提供自己的缓冲区来更改它
【解决方案2】:

md5sum 的完整示例:

func md5sum(filePath string) (string, error) {
    file, err := os.Open(filePath)
    if err != nil {
        return "", err
    }
    defer file.Close()

    hash := md5.New()
    if _, err := io.Copy(hash, file); err != nil {
        return "", err
    }
    return hex.EncodeToString(hash.Sum(nil)), nil
}

EncodeToString 不会省略前导 0 字节,因此 fmt.Println(hex.EncodeToString([]byte{0x00, 0x00, 0xA, 0xB, 0xC})) 给出 00000a0b0c

【讨论】:

    【解决方案3】:

    SHA256 哈希器实现了io.Writer 接口,因此一种选择是使用io.Copy() 函数以块的形式从适当的io.Reader 复制数据。应该这样做:

    f, err := os.Open(os.Args[1])
    if err != nil {
        log.Fatal(err)
    }
    defer f.Close()
    if _, err := io.Copy(hasher, f); err != nil {
        log.Fatal(err)
    }
    

    【讨论】:

    • 如果我在循环中执行此操作,是否需要执行sha256.New()
    • @majidarif:您可以通过调用其Reset 方法重用哈希器。如果您不重置并开始计算第二个文件的哈希值,您将改为计算连接的两个文件的哈希值。话虽如此,如果您不尝试重用哈希器,您的代码可能会更具可读性。
    • io.Copy 是如何工作的?文件是完全在内存中读取的,还是按...大小的块处理的?
    • @Massimo:在一般情况下,它将使用 32 kB 缓冲区以块的形式复制数据。如文档所述,它将遵循 src.WriteTodest.ReadFrom 方法(如果存在)。它们可能具有不同的缓冲行为,但不应读取整个文件。
    猜你喜欢
    • 1970-01-01
    • 2017-04-21
    • 2022-12-03
    • 1970-01-01
    • 2012-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多