当前位置: 代码迷 >> 综合 >> 基于BCrypt进行密码加密
  详细解决方案

基于BCrypt进行密码加密

热度:24   发布时间:2024-01-24 21:09:23.0

之前写了一篇文章关于MD5加密的文章 MD5+盐,但是如果知道加盐的规则,很容易进行反向破解,也不安全。

因此引入BCrypt加密算法进行加密


1.为什么BCrypt比MD5+盐更加安全?

      BCrpyt也是输入的字符串+盐,但是与MD5+盐的主要区别是:每次加的盐不同,导致每次生成的结果也不相同。无法比对!

2.使用Bcrypt(注解开发)

      结合SpringSecurity提供的BCryptPasswordEncoder类,实现Spring的PasswordEncoder接口使用BCrypt强哈希方法来加密密码。每次加密后结果不同。

    2.1引入依赖

 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency>

      2.2书写配置类

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests()                                //所有security全注解配置实现的开端,表示开始说明需要的权限  第一部分:拦截的路径     第二部分:访问该路径需要的权限.antMatchers("/**").permitAll()         //antMatchers   拦截路径    permitAll任何权限都可以进行访问 .hasAnyAuthority   特殊权限才可访问.anyRequest().authenticated()                       //anyRequest    任何的请求   authenticated   认证后才可访问.and().csrf().disable();                            //必要参数(固定写法)    使csrf拦截失效}
}

     2.3将BCryptPasswordEncoder当做bean对象,方便注入

@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder(){return new BCryptPasswordEncoder();
}

3.BCrypt的使用

    3.1加密使用:

(在使用处注入BCryptPasswordEncoder)

String encodePassword = encoder.encode(admin.getPassword());

encode源码:(关键在于genSalt()导致盐不同)

 public String encode(CharSequence rawPassword) {String salt;if (this.strength > 0) {if (this.random != null) {salt = BCrypt.gensalt(this.strength, this.random);} else {salt = BCrypt.gensalt(this.strength);}} else {salt = BCrypt.gensalt();}return BCrypt.hashpw(rawPassword.toString(), salt);}

主要是调用Bcrypt.hashpw(string,salt);        //salt是随机的,不固定

贴出genSalt()源码:

 public static String gensalt(int log_rounds, SecureRandom random) {if (log_rounds >= 4 && log_rounds <= 31) {StringBuilder rs = new StringBuilder();byte[] rnd = new byte[16];random.nextBytes(rnd);rs.append("$2a$");if (log_rounds < 10) {rs.append("0");}rs.append(log_rounds);rs.append("$");encode_base64(rnd, rnd.length, rs);return rs.toString();} else {throw new IllegalArgumentException("Bad number of rounds");}}public static String gensalt(int log_rounds) {return gensalt(log_rounds, new SecureRandom());}

     3.2对比并返回对比结果

Boolean isEqual = encoder.matches(admin.getPassword(),encodePassword);

   源码为:

public boolean matches(CharSequence rawPassword, String encodedPassword) {if (encodedPassword != null && encodedPassword.length() != 0) {if (!this.BCRYPT_PATTERN.matcher(encodedPassword).matches()) {this.logger.warn("Encoded password does not look like BCrypt");return false;} else {return BCrypt.checkpw(rawPassword.toString(), encodedPassword);}} else {this.logger.warn("Empty encoded password");return false;}}

主要是使用了BCrypt.checkpw(string,encoderString);//对比两个字符串是否相等,

再往下追踪源码:

 public static boolean checkpw(String plaintext, String hashed) {return equalsNoEarlyReturn(hashed, hashpw(plaintext, hashed));}static boolean equalsNoEarlyReturn(String a, String b) {char[] caa = a.toCharArray();char[] cab = b.toCharArray();if (caa.length != cab.length) {return false;} else {byte ret = 0;for(int i = 0; i < caa.length; ++i) {ret = (byte)(ret | caa[i] ^ cab[i]);}return ret == 0;}}

首先对传入的string,按照encoderString加密方式进行加密。

然后按照位比较,一致返回true,反之返回false

  相关解决方案