密码存储方案

普通方案

目前最多的存储方案是将明文密码做单向哈希后存储,其算法有一个特征:

无法通过哈希后的摘要(digest)恢复原始数据

常见的哈希算法有: SHA-256、SHA-1、MD5等

这些普通的哈希算法的特性有:

  1. 同一个密码,经过哈希时,总是得到唯一的确定的摘要
  2. 计算速度快

由于以上特性,可以建立一个常见的密码进行哈希后,得到一个摘要组合,然后与数据库中的密码进行对应,也就还原出来了密码,这个摘要组合也称为: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)
}