golang使用bcrypt包对密码进行加密

bcrypt

bcrypt是一个由美国计算机科学家尼尔斯·普罗沃斯(Niels Provos)以及大卫·马齐耶(David Mazières)根据Blowfish加密算法所设计的密码散列函数,于1999年在USENIX中展示。实现中bcrypt会使用一个加盐的流程以防御彩虹表攻击,同时bcrypt还是适应性函数,它可以借由增加迭代之次数来抵御日益增进的电脑运算能力透过暴力法破解。

由bcrypt加密的文件可在所有支持的操作系统和处理器上进行转移。它的口令必须是8至56个字符,并将在内部被转化为448位的密钥。然而,所提供的所有字符都具有十分重要的意义。密码越强大,数据就越安全。

除了对数据进行加密,默认情况下,bcrypt在删除数据之前将使用随机数据三次覆盖原始输入文件,以阻挠可能会获得计算机数据的人恢复数据的尝试。如果您不想使用此功能,可设置禁用此功能。

bcrypt哈希示意图

下图为bcrypt哈希的示例图,其由四部分组成:
在这里插入图片描述

  • Prefix说明了使用的bcrypt的版本
  • Cost是进行哈希的次数-数字越大生成bcrypt的速度越慢,成本越大。同样也意味着如果密码库被盗,攻击者想通过暴力破解的方法猜测出用户密码的成本变得越昂贵。
  • Salt是添加到要进行哈希的字符串中的随机字符(21.25个字符),所以使用bcrypt时不需要我们在表里单独存储Salt。
  • Hashed Text是明文字符串最终被bcrypt应用这些设置哈希后的哈希文本。
    另外无论什么方法:每个密码加单独的盐进行哈希,使用bcrypt进行哈希等等,如果用户使用非常简单的密码例如password或123456,还是能被猜测出来的,所以在用户设置密码时应该禁止他们输入简单的密码。

go语言中使用bcrypt对密码进行加密

go语言库中,bcrypt只能做单向加密,而不能反向破解生成明文,但是可以对原密码和进行hash加密后的hash值进行比对判断是否相同,使用bcrypt进行加密,同一个密码每次生成的hash值都是不相同的。每次加密的时候首先会生成一个随机数就是盐,之后将这个随机数与密码进行hash。

// 加密密码
func HashAndSalt(pwd string) string {
	hash, err := bcrypt.GenerateFromPassword([]byte(pwd), bcrypt.MinCost)
	if err != nil {
		log.Println(err)
	}
	return string(hash)
}

// 验证密码
func ComparePasswords(hashedPwd string, plainPwd string) bool {
	byteHash := []byte(hashedPwd)
	err := bcrypt.CompareHashAndPassword(byteHash, []byte(plainPwd))
	if err != nil {
		log.Println(err)
		return false
	}
	return true
}

这里简单对两个方法封装了一下,方便后期调用。

在go语言中,bcrypt.GenerateFromPassword() 是对字符串进行加密hash的函数,其中第一个参数[]byte(pwd)是对原字符串转换为字节切片,第二个参数bcrypt.MinCost为对字符串进行哈希的次数,也就是上图中的Cost。bcrypt.CompareHashAndPassword()是对hash过的字符串和原字符串进行判断,其中第一个参数byteHash是hash加密过的hash值,第二个参数[]byte(plainPwd)是原字符串,bcrypt.CompareHashAndPassword()进行判断两个参数是否一个值。

示例:

func main() {
	pwd1 := "wlc1003.."
	pwd2 := "wlc1003.."
	pwd3 := "wlc1003"

	hash1 := utils.HashAndSalt(pwd1)
	hash2 := utils.HashAndSalt(pwd2)
	hash3 := utils.HashAndSalt(pwd3)

	fmt.Println(hash1)
	fmt.Println(hash2)
	fmt.Println(hash3)

	fmt.Println(utils.ComparePasswords(hash2, pwd1))
	fmt.Println(utils.ComparePasswords(hash3, pwd2))
	fmt.Println(utils.ComparePasswords(hash1, pwd2))
}
//输出
$2a$04$4MXIN0OQeiKf7HI.eKYw6eRM1mcjDrItX0wzgOSVgkczsvFj8ifuW
$2a$04$aJz4S67m.CTTP3gBiKoVZu3CTMujCImTqcUaPppcKzoUXtsIR.Z5.
$2a$04$OVXCGxnkIpvFSegtq20hHOhtvMwFIRp.iBog4E62CS9uaQ/PlDH5S

true
2023/07/16 21:53:24 crypto/bcrypt: hashedPassword is not the hash of the given password //表示不匹配
false
true

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个示例代码,用于演示如何在golang中实现基本的用户密码登录和加密储存功能: ```go package main import ( "fmt" "golang.org/x/crypto/bcrypt" ) var users = map[string]string{ "alice": "123456", "bob": "password", "eve": "qwerty", } func login(username, password string) bool { // 检查用户名是否存在 if hashedPassword, ok := users[username]; ok { // 检查密码是否正确 if err := bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password)); err == nil { return true } } return false } func register(username, password string) error { // 生成随机盐 salt, err := bcrypt.GenerateFromPassword([]byte(username), bcrypt.DefaultCost) if err != nil { return err } // 哈希密码并保存 hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) if err != nil { return err } users[username] = string(hashedPassword) return nil } func main() { // 测试注册和登录功能 username := "charlie" password := "zxcvbn" err := register(username, password) if err != nil { fmt.Printf("注册失败: %v\n", err) return } if login(username, password) { fmt.Printf("%s 登录成功\n", username) } else { fmt.Printf("%s 登录失败\n", username) } } ``` 在上面的代码中,我们使用golang的`bcrypt`来对密码进行哈希和验证。在`register`函数中,我们首先生成一个随机盐,并使用该盐和给定的密码生成哈希密码。然后,我们将用户名和哈希密码存储在`users`map中。 在`login`函数中,我们首先检查给定的用户名是否存在于`users`map中。如果存在,我们将存储的哈希密码和给定的密码进行比较。如果密码匹配,该函数返回`true`,否则返回`false`。 在`main`函数中,我们使用`register`函数注册了一个新用户,并使用`login`函数测试了该用户的登录过程。请注意,由于我们使用了随机盐和哈希密码,这种方法比简单密码储存更安全。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值