普通方案
目前最多的存储方案是将明文密码做单向哈希后存储,其算法有一个特征:
无法通过哈希后的摘要(digest)恢复原始数据
常见的哈希算法有: SHA-256、SHA-1、MD5等
这些普通的哈希算法的特性有:
- 同一个密码,经过哈希时,总是得到唯一的确定的摘要
- 计算速度快
由于以上特性,可以建立一个常见的密码进行哈希后,得到一个摘要组合,然后与数据库中的密码进行对应,也就还原出来了密码,这个摘要组合也称为:rainbow table
进价方案
由于以上得到的密码摘要总是唯一确定的,为了不让其确定,可以在做哈希前或后,再加入相应的随机密钥,再做一次哈希等加密,来得到最后的密码,即常说的: 加盐(salt)
//import "crypto/md5"
//假设用户名abc,密码123456
h := md5.New()
io.WriteString(h, "需要加密的密码")
//pwmd5等于e10adc3949ba59abbe56e057f20f883e
pwmd5 :=fmt.Sprintf("%x", h.Sum(nil))
//指定两个 salt: salt1 = @#$% salt2 = ^&*()
salt1 := "@#$%"
salt2 := "^&*()"
//salt1+用户名+salt2+MD5拼接
io.WriteString(h, salt1)
io.WriteString(h, "abc")
io.WriteString(h, salt2)
io.WriteString(h, pwmd5)
last :=fmt.Sprintf("%x", h.Sum(nil))
专家方案
Scrypt 方案
其在做加密的时候,需要指定计算密码摘要所需要的资源与时间,即:计算强度
如果强度越大,也就越难建立 rainbow table,也就越难破解
http://code.google.com/p/go/source/browse?repo=crypto#hg%2Fscrypt
func TestScrypt(t *testing.T) {
key, err := scrypt.Key([]byte("1236"), []byte("abc"), 16384, 8, 1, 32)
if err != nil {
t.Fatalf("加密出错了!%v", err)
}
t.Logf("密码:%x %[1]T", key)
}