前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >BCrypt加密算法

BCrypt加密算法

作者头像
十玖八柒
发布2022-08-01 09:31:51
1.8K0
发布2022-08-01 09:31:51
举报
文章被收录于专栏:ahzoo.cn的博客分享

盐(Salt)的基本原则:

  1. 使用CSPRNG(Cryptographically Secure Pseudo-Random Number Generator)生成盐(java.security.secureRandom),而不是普通的随机数算法。CSPRNG跟普通的随机数生成算法,比如C语言标准库里面的rand()方法,有很大不同。正如它的名字所揭示,CSPRNG是加密安全的,这也表明了它产生的随机数更加随机,且不可预测。
  2. 盐不能太短。如果盐很短,那意味着密码+盐组成的字符串的长度和取值空间都有限。破解者完全可以为 密码+盐 的所有组合建立彩虹表。
  3. 盐不能重复使用。如果所有用户的密码都使用同一个盐进行加密。那么不管盐有多复杂、多大的长度,破解者都可以很容易的使用这个固定盐重新建立彩虹表,破解你的所有用户的密码。所以应当在每一次需要保存新的密码时,都生成一个新的盐,并跟加密后的hash值保存在一起。

注意:有些人可能会将每个用户都不同的字段(uid、手机号之类的)来作为盐。很明显这是不规范的,几乎违背了上面三条盐的生成规则。 在实际项目中,盐不一定要加在最前面或最后面,也可以插在中间,或者分开插入,还可以使用倒序,等等,进行灵活调整 ​

随机盐生成

示例: 生成一个16位的随机盐

代码语言:javascript
复制
import java.security.SecureRandom;

public class MethodTest{
	@Test
    public void toRText() {
        byte[] values = new byte[16];

        System.out.println(Arrays.toString(values));

        SecureRandom random = new SecureRandom();
        random.nextBytes(values);

        System.out.println(Arrays.toString(values));
 //       System.out.println(Base64.toBase64String(values));
     		//需要导入cn.hutool依赖
        System.out.println(HexUtil.encodeHexStr(values)); 
    }
}

加盐方式

传统的无加盐的加密方式很容易被彩虹表破解;当然,如果你盐加的不够也是一样的,从数学角度来讲,使用固定盐和没加盐几乎无异。

彩虹表就是穷举密码和对应摘要的一个表.。有了这个表,就可以通过遍历的方式破解密码

最早的MD5或SHA-1方式:

代码语言:javascript
复制
md5(md5(password) + salt)

现在大部分的加盐加密都将MD5或SHA-1替换为了更为安全的哈希函数:SHA-256或者SHA-512:

代码语言:javascript
复制
sha512(sha512(password) + salt)

上面的加盐方式都需要将盐值另外·储存,而是BCrypt则是通过加密密码得到,这样每个密码的盐值也是不同的:

代码语言:javascript
复制
bcrypt(sha512(password), salt)

//或者

bcrypt(sha512(password), salt, cost)

使用BCrypt加盐的方式一方面不用另外储存盐值了,另一方面可以大大拖慢破译者的破译速度; 由于BCrypt是采用慢哈希算法,一个明文映射多个密文,所以跟SHA比起来要慢的多(比如加密同一串字符,SHA可能只需要1微妙,而BCrypt可能需要0.1秒); 通过调整 cost 参数,可以调整该函数慢到什么程度。假设让 BCrypt 计算一次需要 0.5 秒,遍历 6 位的简单密码,需要的时间为:((26 * 2 + 10)^6) / 10 秒,约 900 年。 一般来说,SHA加盐的方式就已经很安全了,除非涉及绝密信息,并且可以牺牲一定性能时,才有必要考虑 BCrypt 加密

做了这么多操作主要还是为了下面两点:

  1. 用户明文密码不会被攻击者拿到(网络拦截、彩虹表、暴力破解)
  2. 攻击者无法使用摘要密码登录

BCrypt

前面做了那么多铺垫,现在正式进入正题。 ​

先来看下BCrypt生成的密文

图片
图片

说明:

  • BCrypt: 2a代表BCrypt加密版本号。
  • Rouds: 迭代次方数,10是默认值。可以设置范围为4-31。最终迭代次数为2的Rouds次方。
  • Salt: 22位的盐值(即上述的real_salt)。
  • Hash:明文password和Salt一起hash加密后生成的密文,长度31位。

示例:

代码语言:javascript
复制
    @Test
    public void BCryptTest() {
        //{加密
        //原文
        String password = "123456";
        //BCrypt.hashpw(加密原文, BCrypt.gensalt( cost(加密强度)默认为10,推荐设为12 ));
        String hashPw = BCrypt.hashpw(password, BCrypt.gensalt());
//            String hashPw = BCrypt.hashpw(password, BCrypt.gensalt(12));
        System.out.println(hashPw);

        //{验证
        //原文
        String newPassword = "123456";
//        String hashNPw = BCrypt.hashpw(newPassword, BCrypt.gensalt(12));
        //验证
        boolean checkpw = BCrypt.checkpw(newPassword, hashPw);
        if (checkpw) {
            System.out.println("验证成功");
        } else {
            System.out.println("验证失败");
        }

    }

BCrypt包可在多个依赖中引入:

代码语言:javascript
复制
<!--Bcrypt包依赖1 选择任一即可-->
	<dependency>
			<groupId>cn.hutool</groupId>
			<artifactId>hutool-all</artifactId>
			<version>4.6.10</version>
			<scope>compile</scope>
		</dependency>



<!--Bcrypt包依赖2 选择任一即可
    <dependency>
      <groupId>org.mindrot</groupId>
      <artifactId>jbcrypt</artifactId>
      <version>0.4</version>
    </dependency>
-->
<!--Bcrypt包依赖3 选择任一即可
    <dependency>
      <groupId>org.springframework.security</groupId>
      <artifactId>spring-security-web</artifactId>
      <version>5.5.1</version>
    </dependency>
-->

后记

BCrypt官网

大公司是如何使用BCrypt配合加密使用的呢?

分享一篇Dropbox公司发布的博文: How Dropbox securely stores your passwords 总结一下:

  1. 首先使用SHA-512,将用户密码归一化为64字节hash值。
  2. 然后使用BCrypt算法。
  3. 最后使用AES加密。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-12-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
    • 随机盐生成
    • 加盐方式
    • BCrypt
    • 后记
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档