java BCrypt 密码加密

密码加密说明

算法 安全性 密码专用 抗GPU攻击 抗ASIC攻击 加密结果是否为固定值 推荐程度
MD5 :cross_mark: 已破解 :cross_mark: :cross_mark: :cross_mark: :white_check_mark: 禁止使用
SHA-1 :cross_mark: 已破解 :cross_mark: :cross_mark: :cross_mark: :white_check_mark: 禁止使用
SHA-256 :white_check_mark: 安全 :cross_mark: :cross_mark: :cross_mark: :white_check_mark: 不用于密码
bcrypt :white_check_mark: 安全 :white_check_mark: :white_check_mark: :warning: 部分 :cross_mark: 推荐

核心说明:

  • 固定值 (:white_check_mark: 是):MD5、SHA-1、SHA-256 是传统的(加密)哈希函数,其设计是确定性的。对于相同的输入,无论何时何地计算,其输出(哈希值)永远相同。
  • 非固定值 (:cross_mark: 否):bcrypt 是密码哈希函数。其核心安全机制之一就是内置随机盐。即使对完全相同的密码,每次调用
    bcrypt 也会生成一个完全不同的随机盐,并最终产生一个截然不同的哈希值。这是它与传统哈希函数的本质区别,也是它更安全、专为密码存储而设计的关键特征。

org.mindrot:jbcrypt 使用示例

  • pom.xml
      <dependency>
          <groupId>org.mindrot</groupId>
          <artifactId>jbcrypt</artifactId>
          <version>0.4</version>
      </dependency>
    
  • Java
    package cn.com.xuxiaowei;
    
    import org.mindrot.jbcrypt.BCrypt;
    
    public class BCryptTests {
    
        public static void main(String[] args) {
            // 原始密码
            String password = "xuxiaowei";
            // 密码复杂度,默认:10
            // 可使用 BCrypt.gensalt(int) 指定密码复杂度。数字越大,速度越慢
            String gensalt = BCrypt.gensalt();
    
            // 密码加密
            String hashpw = BCrypt.hashpw(password, gensalt);
            // 示例:$2a$10$.Qhiq0ZLbPJPaRv2ezz1i.iFFNKp/A/c.Ou8iQv44GwpnC4PhIuei
            System.out.println(hashpw);
    
            // 密码对比
            boolean checkpw = BCrypt.checkpw(password, hashpw);
            System.out.println(checkpw);
        }
    
    }
    

org.springframework.security:spring-security-crypto 使用示例

  • pom.xml
      <dependency>
          <groupId>org.springframework.security</groupId>
          <artifactId>spring-security-crypto</artifactId>
          <version>5.7.11</version>
      </dependency>
    
  • Java
    1. 最简单实用方式
      package cn.com.xuxiaowei;
      
      import org.springframework.security.crypto.bcrypt.BCrypt;
      
      public class BCryptTests {
      
          public static void main(String[] args) {
              // 原始密码
              String password = "xuxiaowei";
              // 密码复杂度,默认:10
              // 可使用 BCrypt.gensalt(int) 指定密码复杂度。数字越大,速度越慢
              String gensalt = BCrypt.gensalt();
      
              // 密码加密
              String hashpw = BCrypt.hashpw(password, gensalt);
              // 示例:$2a$10$.Qhiq0ZLbPJPaRv2ezz1i.iFFNKp/A/c.Ou8iQv44GwpnC4PhIuei
              System.out.println(hashpw);
      
              // 密码对比
              boolean checkpw = BCrypt.checkpw(password, hashpw);
              System.out.println(checkpw);
          }
      
      }
      
    2. 使用 PasswordEncoder 接口
      package cn.com.xuxiaowei;
      
      import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
      import org.springframework.security.crypto.password.PasswordEncoder;
      
      public class BCryptTests {
      
          public static void main(String[] args) {
              // 原始密码
              String password = "xuxiaowei";
              // 密码复杂度,默认:10
              // 可使用 new BCryptPasswordEncoder(int) 指定密码复杂度。数字越大,速度越慢
              PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
      
              // 密码加密
              String encode = passwordEncoder.encode(password);
              // 示例:$2a$10$.Qhiq0ZLbPJPaRv2ezz1i.iFFNKp/A/c.Ou8iQv44GwpnC4PhIuei
              System.out.println(encode);
      
              // 密码对比
              boolean matches = passwordEncoder.matches(password, encode);
              System.out.println(matches);
          }
      
      }
      
    3. Spring Security 默认使用方式,密码对比时兼容多种加密方式,支持密码加密方式升级
      PasswordEncoder#upgradeEncoding(String)
      • 密码加密后,存在前缀:{bcrypt},代表密码加密方式
      package cn.com.xuxiaowei;
      
      import org.springframework.security.crypto.factory.PasswordEncoderFactories;
      import org.springframework.security.crypto.password.PasswordEncoder;
      
      public class BCryptTests {
      
          public static void main(String[] args) {
              // 原始密码
              String password = "xuxiaowei";
              // 密码复杂度:10
              PasswordEncoder passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
      
              // 密码加密
              String encode = passwordEncoder.encode(password);
              // 示例:{bcrypt}$2a$10$lNSOa/wFzp4jyyzalS4MGudghjJvHxy46GNPkl2Ce9UbSE66pScLy
              System.out.println(encode);
      
              // 密码对比
              boolean matches = passwordEncoder.matches(password, encode);
              System.out.println(matches);
          }
      
      }