使用golang生成字符串的SHA哈希值

89

有人能向我展示如何使用Go生成一个字符串的SHA哈希值的工作示例吗?假设我有一个字符串myPassword := "beautiful"


12
如果你正在进行密码哈希,那么你不应该使用裸的SHA1 - 应该使用PBKDF2、SCRYPT或BCRYPT。 - Nick Johnson
8
仅仅因为SHA1算法可以使用,就使用未加盐和迭代的SHA1算法而不依赖第三方库是毫无意义的。相对而言,依赖第三方库要更好得多。 - Nick Johnson
3
问题不在于SHA1的强度,而是缺乏盐和密钥拉伸。仅添加盐是不够的,应该使用一个迭代算法。 - Nick Johnson
你指出只使用sha1的风险是正确的,但我们谈论的是最后的理论攻击可能性还是基本现实?SHA1攻击在很长一段时间内不会成为问题,而SHA 256(加盐)对于大多数用途来说已经足够强大了。 - Denys Séguret
我正在使用sha512。但是在阅读了关于彩虹攻击等方面的内容后,我对于存储密码哈希值并不太信任。 BCRYPT似乎是更好的选择。但是我所做的主要是为了一个实验性的个人项目,所以安全性方面并不需要太担心 :-) 感谢您的评论。 - Sankar
显示剩余3条评论
9个回答

106
一个例子:
import (
    "crypto/sha1"
    "encoding/base64"
)

func (ms *MapServer) storee(bv []byte) {
    hasher := sha1.New()
    hasher.Write(bv)
    sha := base64.URLEncoding.EncodeToString(hasher.Sum(nil))
        ...
}

在这个例子中,我从一个字节数组中生成了一个sha。您可以使用以下方法获取字节数组:
bv := []byte(myPassword) 

当然,如果不需要,您不必将其编码为base64:您可以使用Sum函数返回的原始字节数组。

下面的评论中似乎有一些小混淆。因此,让我们为下一个用户澄清有关转换为字符串的最佳实践:

  • 您永远不会将SHA作为字符串存储在数据库中,而是作为原始字节
  • 当您想向用户显示SHA时,常见的方法是十六进制
  • 当您需要字符串表示形式,因为它必须适合URL或文件名时,通常的解决方案是Base64, 它更加紧凑

19
表示 sha 的常规方法是使用十六进制编码而不是 base64,以字符串的形式呈现。 - Jeremy Wall
4
根据你的需求而定。十六进制编码对人类友好,但比base64更冗长。如果你想将哈希存储到数据库中、在json中发送它,或者像我的示例一样将其用作文件名,我认为base64更好。 - Denys Séguret
1
@DenysSéguret 如果你要将它存储在数据库中,最好只存储字节,因为通常不应该存储编码的数据库内容。 - Brian Leishman
@BrianLeishman 在我的答案中,我明确指出“你永远不会将SHA以字符串形式存储在数据库中,而是以原始字节的形式存储”。 - Denys Séguret
@DenysSéguret 噢,我的错,我是在回复你的评论“如果你想将哈希存储在数据库中... base64更好”。 - Brian Leishman
@BrianLeishman 是的,我看到这条评论可能会让人感到困惑。我甚至不会尝试猜测我6年前在这里解释了什么^^ - Denys Séguret

92

Go By Example有一篇关于sha1哈希的页面。

package main

import (
    "fmt"
    "crypto/sha1"
    "encoding/hex"
)

func main() {

    s := "sha1 this string"
    h := sha1.New()
    h.Write([]byte(s))
    sha1_hash := hex.EncodeToString(h.Sum(nil))

    fmt.Println(s, sha1_hash)
}

您可以在play.golang.org上运行此示例


28

Go语言官方文档中的http://golang.org/pkg/crypto/sha1/有一个示例可以演示此操作。虽然它是作为New函数的示例,但它是页面上唯一的示例,而且位于页面顶部附近,因此值得一看。完整示例如下:

代码:

h := sha1.New()
io.WriteString(h, "His money is twice tainted: 'taint yours and 'taint mine.")
fmt.Printf("% x", h.Sum(nil))

输出:

59 7f 6a 54 00 10 f9 4c 15 d7 18 06 a9 9a 2c 87 10 e7 47 bd


3
可以的。似乎很难找到许多隐藏的部分,这是一个可用性问题。 - Sankar
2
@SankarP:目前来看,特别是如果你不是每天都在使用Go编程语言的话,理解如何使用API可能有些困难。我发现阅读API源代码(通常很简单)更容易理解。随着时间的推移和更多在线第三方示例和文档的出现,这可能会变得更容易。 - Denys Séguret
1
@SankarP:尝试使用godock.org来更轻松地浏览标准库API。 - Isaiah
4
h.Write([]byte("some string"))比你给出的例子使用WriteString更为简洁。 - Brenden

23
您可以更加简洁和地道地完成这项任务:
// Assuming 'r' is set to some inbound net/http request
form_value := []byte(r.PostFormValue("login_password"))
sha1_hash := fmt.Sprintf("%x", sha1.Sum(form_value))

// Then output optionally, to test
fmt.Println(sha1_hash)

在这个简单的http.Request POST示例中,其包含一个login_password字段。值得注意的是,fmt.Sprintf()调用使用了%x将哈希值转换为十六进制,而无需包含import "encoding/hex"声明。
(我们使用fmt.Sprintf()而不是printf(),因为我们要输出一个字符串到变量赋值,而不是一个io.Writer接口。)
另外需要提及的是,sha1.Sum()函数的实例化方式与sha1.New()定义相同。
func New() hash.Hash {
    d := new(digest)
    d.Reset()
    return d
}

func Sum(data []byte) [Size]byte {
    var d digest
    d.Reset()
    d.Write(data)
    return d.checkSum()
}

这在发布时至少适用于Golang标准加密套件中的Sha库变体,例如Sha512
最后,如果有人想要,他们可以像func(h hash.Hash)String()string {...}一样遵循Golang的[to]String()实现来封装该过程。
这很可能超出了原始问题的期望范围。

1
感谢您提供的所有额外细节,韦伯斯特先生! - Mike Pearson

11
h := sha1.New()
h.Write(content)
sha := h.Sum(nil)  // "sha" is uint8 type, encoded in base16

shaStr := hex.EncodeToString(sha)  // String representation

fmt.Printf("%x\n", sha)
fmt.Println(shaStr)


8
以下是一些很好的例子: 第二个示例针对sha256,要执行sha1十六进制操作,您可以执行以下操作:
// Calculate the hexadecimal HMAC SHA1 of requestDate using sKey                
key := []byte(c.SKey)                                                           
h := hmac.New(sha1.New, key)                                                    
h.Write([]byte(requestDate))                                                    
hmacString := hex.EncodeToString(h.Sum(nil))

(from https://github.com/soniah/dnsmadeeasy)


4

这是一个可以用来生成SHA1哈希值的函数:

// SHA1 hashes using sha1 algorithm
func SHA1(text string) string {
    algorithm := sha1.New()
    algorithm.Write([]byte(text))
    return hex.EncodeToString(algorithm.Sum(nil))
}

我在这里整理了一组实用的哈希函数:https://github.com/shomali11/util
你将会找到 FNV32FNV32aFNV64FNV65aMD5SHA1SHA256SHA512

3
作为一个一行代码的哈希函数,Go 语言更加方便。
sha := sha256.Sum256([]byte())

结果是一个[]byte,可以转换为十六进制或base64。

1
// Get sha1 from string
func Hashstr(Txt string) string {
    h := sha1.New()
    h.Write([]byte(Txt))
    bs  := h.Sum(nil)
    sh:= string(fmt.Sprintf("%x\n", bs))
    return sh
}

速度和实用。 - Arthur Savage

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接